ueditor.all.js 1.1 MB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837288382883928840288412884228843288442884528846288472884828849288502885128852288532885428855288562885728858288592886028861288622886328864288652886628867288682886928870288712887228873288742887528876288772887828879288802888128882288832888428885288862888728888288892889028891288922889328894288952889628897288982889928900289012890228903289042890528906289072890828909289102891128912289132891428915289162891728918289192892028921289222892328924289252892628927289282892928930289312893228933289342893528936289372893828939289402894128942289432894428945289462894728948289492895028951289522895328954289552895628957289582895928960289612896228963289642896528966289672896828969289702897128972289732897428975289762897728978289792898028981289822898328984289852898628987289882898928990289912899228993289942899528996289972899828999290002900129002290032900429005290062900729008290092901029011290122901329014290152901629017290182901929020290212902229023290242902529026290272902829029290302903129032290332903429035290362903729038290392904029041290422904329044290452904629047290482904929050290512905229053290542905529056290572905829059290602906129062290632906429065290662906729068290692907029071290722907329074290752907629077290782907929080290812908229083290842908529086290872908829089290902909129092290932909429095290962909729098290992910029101291022910329104291052910629107291082910929110291112911229113291142911529116291172911829119291202912129122291232912429125291262912729128291292913029131291322913329134291352913629137291382913929140291412914229143291442914529146291472914829149291502915129152291532915429155291562915729158291592916029161291622916329164291652916629167291682916929170291712917229173291742917529176291772917829179291802918129182291832918429185291862918729188291892919029191291922919329194291952919629197291982919929200292012920229203292042920529206292072920829209292102921129212292132921429215292162921729218292192922029221292222922329224292252922629227292282922929230292312923229233292342923529236292372923829239292402924129242292432924429245292462924729248292492925029251292522925329254292552925629257292582925929260292612926229263292642926529266292672926829269292702927129272292732927429275292762927729278292792928029281292822928329284292852928629287292882928929290292912929229293292942929529296292972929829299293002930129302293032930429305293062930729308293092931029311293122931329314293152931629317293182931929320293212932229323293242932529326293272932829329293302933129332293332933429335293362933729338293392934029341293422934329344293452934629347293482934929350293512935229353293542935529356293572935829359293602936129362293632936429365293662936729368293692937029371293722937329374293752937629377293782937929380293812938229383293842938529386293872938829389293902939129392293932939429395293962939729398293992940029401294022940329404294052940629407294082940929410294112941229413294142941529416294172941829419294202942129422294232942429425294262942729428294292943029431294322943329434294352943629437294382943929440294412944229443294442944529446294472944829449294502945129452294532945429455294562945729458294592946029461294622946329464294652946629467294682946929470294712947229473294742947529476294772947829479294802948129482294832948429485294862948729488294892949029491294922949329494294952949629497294982949929500295012950229503295042950529506295072950829509295102951129512295132951429515295162951729518295192952029521295222952329524295252952629527295282952929530295312953229533295342953529536295372953829539295402954129542295432954429545295462954729548295492955029551295522955329554295552955629557295582955929560
  1. /*!
  2. * UEditor
  3. * version: ueditor
  4. * build: Wed Dec 26 2018 17:25:05 GMT+0800 (CST)
  5. */
  6. /* eslint-disable */
  7. (function(){
  8. // editor.js
  9. UEDITOR_CONFIG = window.UEDITOR_CONFIG || {};
  10. var baidu = window.baidu || {};
  11. window.baidu = baidu;
  12. window.UE = baidu.editor = window.UE || {};
  13. UE.plugins = {};
  14. UE.commands = {};
  15. UE.instants = {};
  16. UE.I18N = {};
  17. UE._customizeUI = {};
  18. UE.version = "1.4.3";
  19. var dom = UE.dom = {};
  20. // core/browser.js
  21. /**
  22. * 浏览器判断模块
  23. * @file
  24. * @module UE.browser
  25. * @since 1.2.6.1
  26. */
  27. /**
  28. * 提供浏览器检测的模块
  29. * @unfile
  30. * @module UE.browser
  31. */
  32. var browser = UE.browser = function(){
  33. var agent = navigator.userAgent.toLowerCase(),
  34. opera = window.opera,
  35. browser = {
  36. /**
  37. * @property {boolean} ie 检测当前浏览器是否为IE
  38. * @example
  39. * ```javascript
  40. * if ( UE.browser.ie ) {
  41. * console.log( '当前浏览器是IE' );
  42. * }
  43. * ```
  44. */
  45. ie : /(msie\s|trident.*rv:)([\w.]+)/.test(agent),
  46. /**
  47. * @property {boolean} opera 检测当前浏览器是否为Opera
  48. * @example
  49. * ```javascript
  50. * if ( UE.browser.opera ) {
  51. * console.log( '当前浏览器是Opera' );
  52. * }
  53. * ```
  54. */
  55. opera : ( !!opera && opera.version ),
  56. /**
  57. * @property {boolean} webkit 检测当前浏览器是否是webkit内核的浏览器
  58. * @example
  59. * ```javascript
  60. * if ( UE.browser.webkit ) {
  61. * console.log( '当前浏览器是webkit内核浏览器' );
  62. * }
  63. * ```
  64. */
  65. webkit : ( agent.indexOf( ' applewebkit/' ) > -1 ),
  66. /**
  67. * @property {boolean} mac 检测当前浏览器是否是运行在mac平台下
  68. * @example
  69. * ```javascript
  70. * if ( UE.browser.mac ) {
  71. * console.log( '当前浏览器运行在mac平台下' );
  72. * }
  73. * ```
  74. */
  75. mac : ( agent.indexOf( 'macintosh' ) > -1 ),
  76. /**
  77. * @property {boolean} quirks 检测当前浏览器是否处于“怪异模式”下
  78. * @example
  79. * ```javascript
  80. * if ( UE.browser.quirks ) {
  81. * console.log( '当前浏览器运行处于“怪异模式”' );
  82. * }
  83. * ```
  84. */
  85. quirks : ( document.compatMode == 'BackCompat' )
  86. };
  87. /**
  88. * @property {boolean} gecko 检测当前浏览器内核是否是gecko内核
  89. * @example
  90. * ```javascript
  91. * if ( UE.browser.gecko ) {
  92. * console.log( '当前浏览器内核是gecko内核' );
  93. * }
  94. * ```
  95. */
  96. browser.gecko =( navigator.product == 'Gecko' && !browser.webkit && !browser.opera && !browser.ie);
  97. var version = 0;
  98. // Internet Explorer 6.0+
  99. if ( browser.ie ){
  100. var v1 = agent.match(/(?:msie\s([\w.]+))/);
  101. var v2 = agent.match(/(?:trident.*rv:([\w.]+))/);
  102. if(v1 && v2 && v1[1] && v2[1]){
  103. version = Math.max(v1[1]*1,v2[1]*1);
  104. }else if(v1 && v1[1]){
  105. version = v1[1]*1;
  106. }else if(v2 && v2[1]){
  107. version = v2[1]*1;
  108. }else{
  109. version = 0;
  110. }
  111. browser.ie11Compat = document.documentMode == 11;
  112. /**
  113. * @property { boolean } ie9Compat 检测浏览器模式是否为 IE9 兼容模式
  114. * @warning 如果浏览器不是IE, 则该值为undefined
  115. * @example
  116. * ```javascript
  117. * if ( UE.browser.ie9Compat ) {
  118. * console.log( '当前浏览器运行在IE9兼容模式下' );
  119. * }
  120. * ```
  121. */
  122. browser.ie9Compat = document.documentMode == 9;
  123. /**
  124. * @property { boolean } ie8 检测浏览器是否是IE8浏览器
  125. * @warning 如果浏览器不是IE, 则该值为undefined
  126. * @example
  127. * ```javascript
  128. * if ( UE.browser.ie8 ) {
  129. * console.log( '当前浏览器是IE8浏览器' );
  130. * }
  131. * ```
  132. */
  133. browser.ie8 = !!document.documentMode;
  134. /**
  135. * @property { boolean } ie8Compat 检测浏览器模式是否为 IE8 兼容模式
  136. * @warning 如果浏览器不是IE, 则该值为undefined
  137. * @example
  138. * ```javascript
  139. * if ( UE.browser.ie8Compat ) {
  140. * console.log( '当前浏览器运行在IE8兼容模式下' );
  141. * }
  142. * ```
  143. */
  144. browser.ie8Compat = document.documentMode == 8;
  145. /**
  146. * @property { boolean } ie7Compat 检测浏览器模式是否为 IE7 兼容模式
  147. * @warning 如果浏览器不是IE, 则该值为undefined
  148. * @example
  149. * ```javascript
  150. * if ( UE.browser.ie7Compat ) {
  151. * console.log( '当前浏览器运行在IE7兼容模式下' );
  152. * }
  153. * ```
  154. */
  155. browser.ie7Compat = ( ( version == 7 && !document.documentMode )
  156. || document.documentMode == 7 );
  157. /**
  158. * @property { boolean } ie6Compat 检测浏览器模式是否为 IE6 模式 或者怪异模式
  159. * @warning 如果浏览器不是IE, 则该值为undefined
  160. * @example
  161. * ```javascript
  162. * if ( UE.browser.ie6Compat ) {
  163. * console.log( '当前浏览器运行在IE6模式或者怪异模式下' );
  164. * }
  165. * ```
  166. */
  167. browser.ie6Compat = ( version < 7 || browser.quirks );
  168. browser.ie9above = version > 8;
  169. browser.ie9below = version < 9;
  170. browser.ie11above = version > 10;
  171. browser.ie11below = version < 11;
  172. }
  173. // Gecko.
  174. if ( browser.gecko ){
  175. var geckoRelease = agent.match( /rv:([\d\.]+)/ );
  176. if ( geckoRelease )
  177. {
  178. geckoRelease = geckoRelease[1].split( '.' );
  179. version = geckoRelease[0] * 10000 + ( geckoRelease[1] || 0 ) * 100 + ( geckoRelease[2] || 0 ) * 1;
  180. }
  181. }
  182. /**
  183. * @property { Number } chrome 检测当前浏览器是否为Chrome, 如果是,则返回Chrome的大版本号
  184. * @warning 如果浏览器不是chrome, 则该值为undefined
  185. * @example
  186. * ```javascript
  187. * if ( UE.browser.chrome ) {
  188. * console.log( '当前浏览器是Chrome' );
  189. * }
  190. * ```
  191. */
  192. if (/chrome\/(\d+\.\d)/i.test(agent)) {
  193. browser.chrome = + RegExp['\x241'];
  194. }
  195. /**
  196. * @property { Number } safari 检测当前浏览器是否为Safari, 如果是,则返回Safari的大版本号
  197. * @warning 如果浏览器不是safari, 则该值为undefined
  198. * @example
  199. * ```javascript
  200. * if ( UE.browser.safari ) {
  201. * console.log( '当前浏览器是Safari' );
  202. * }
  203. * ```
  204. */
  205. if(/(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(agent) && !/chrome/i.test(agent)){
  206. browser.safari = + (RegExp['\x241'] || RegExp['\x242']);
  207. }
  208. // Opera 9.50+
  209. if ( browser.opera )
  210. version = parseFloat( opera.version() );
  211. // WebKit 522+ (Safari 3+)
  212. if ( browser.webkit )
  213. version = parseFloat( agent.match( / applewebkit\/(\d+)/ )[1] );
  214. /**
  215. * @property { Number } version 检测当前浏览器版本号
  216. * @remind
  217. * <ul>
  218. * <li>IE系列返回值为5,6,7,8,9,10等</li>
  219. * <li>gecko系列会返回10900,158900等</li>
  220. * <li>webkit系列会返回其build号 (如 522等)</li>
  221. * </ul>
  222. * @example
  223. * ```javascript
  224. * console.log( '当前浏览器版本号是: ' + UE.browser.version );
  225. * ```
  226. */
  227. browser.version = version;
  228. /**
  229. * @property { boolean } isCompatible 检测当前浏览器是否能够与UEditor良好兼容
  230. * @example
  231. * ```javascript
  232. * if ( UE.browser.isCompatible ) {
  233. * console.log( '浏览器与UEditor能够良好兼容' );
  234. * }
  235. * ```
  236. */
  237. browser.isCompatible =
  238. !browser.mobile && (
  239. ( browser.ie && version >= 6 ) ||
  240. ( browser.gecko && version >= 10801 ) ||
  241. ( browser.opera && version >= 9.5 ) ||
  242. ( browser.air && version >= 1 ) ||
  243. ( browser.webkit && version >= 522 ) ||
  244. false );
  245. return browser;
  246. }();
  247. //快捷方式
  248. var ie = browser.ie,
  249. webkit = browser.webkit,
  250. gecko = browser.gecko,
  251. opera = browser.opera;
  252. // core/utils.js
  253. /**
  254. * 工具函数包
  255. * @file
  256. * @module UE.utils
  257. * @since 1.2.6.1
  258. */
  259. /**
  260. * UEditor封装使用的静态工具函数
  261. * @module UE.utils
  262. * @unfile
  263. */
  264. var utils = UE.utils = {
  265. /**
  266. * 用给定的迭代器遍历对象
  267. * @method each
  268. * @param { Object } obj 需要遍历的对象
  269. * @param { Function } iterator 迭代器, 该方法接受两个参数, 第一个参数是当前所处理的value, 第二个参数是当前遍历对象的key
  270. * @example
  271. * ```javascript
  272. * var demoObj = {
  273. * key1: 1,
  274. * key2: 2
  275. * };
  276. *
  277. * //output: key1: 1, key2: 2
  278. * UE.utils.each( demoObj, funciton ( value, key ) {
  279. *
  280. * console.log( key + ":" + value );
  281. *
  282. * } );
  283. * ```
  284. */
  285. /**
  286. * 用给定的迭代器遍历数组或类数组对象
  287. * @method each
  288. * @param { Array } array 需要遍历的数组或者类数组
  289. * @param { Function } iterator 迭代器, 该方法接受两个参数, 第一个参数是当前所处理的value, 第二个参数是当前遍历对象的key
  290. * @example
  291. * ```javascript
  292. * var divs = document.getElmentByTagNames( "div" );
  293. *
  294. * //output: 0: DIV, 1: DIV ...
  295. * UE.utils.each( divs, funciton ( value, key ) {
  296. *
  297. * console.log( key + ":" + value.tagName );
  298. *
  299. * } );
  300. * ```
  301. */
  302. each : function(obj, iterator, context) {
  303. if (obj == null) return;
  304. if (obj.length === +obj.length) {
  305. for (var i = 0, l = obj.length; i < l; i++) {
  306. if(iterator.call(context, obj[i], i, obj) === false)
  307. return false;
  308. }
  309. } else {
  310. for (var key in obj) {
  311. if (obj.hasOwnProperty(key)) {
  312. if(iterator.call(context, obj[key], key, obj) === false)
  313. return false;
  314. }
  315. }
  316. }
  317. },
  318. /**
  319. * 以给定对象作为原型创建一个新对象
  320. * @method makeInstance
  321. * @param { Object } protoObject 该对象将作为新创建对象的原型
  322. * @return { Object } 新的对象, 该对象的原型是给定的protoObject对象
  323. * @example
  324. * ```javascript
  325. *
  326. * var protoObject = { sayHello: function () { console.log('Hello UEditor!'); } };
  327. *
  328. * var newObject = UE.utils.makeInstance( protoObject );
  329. * //output: Hello UEditor!
  330. * newObject.sayHello();
  331. * ```
  332. */
  333. makeInstance:function (obj) {
  334. var noop = new Function();
  335. noop.prototype = obj;
  336. obj = new noop;
  337. noop.prototype = null;
  338. return obj;
  339. },
  340. /**
  341. * 将source对象中的属性扩展到target对象上
  342. * @method extend
  343. * @remind 该方法将强制把source对象上的属性复制到target对象上
  344. * @see UE.utils.extend(Object,Object,Boolean)
  345. * @param { Object } target 目标对象, 新的属性将附加到该对象上
  346. * @param { Object } source 源对象, 该对象的属性会被附加到target对象上
  347. * @return { Object } 返回target对象
  348. * @example
  349. * ```javascript
  350. *
  351. * var target = { name: 'target', sex: 1 },
  352. * source = { name: 'source', age: 17 };
  353. *
  354. * UE.utils.extend( target, source );
  355. *
  356. * //output: { name: 'source', sex: 1, age: 17 }
  357. * console.log( target );
  358. *
  359. * ```
  360. */
  361. /**
  362. * 将source对象中的属性扩展到target对象上, 根据指定的isKeepTarget值决定是否保留目标对象中与
  363. * 源对象属性名相同的属性值。
  364. * @method extend
  365. * @param { Object } target 目标对象, 新的属性将附加到该对象上
  366. * @param { Object } source 源对象, 该对象的属性会被附加到target对象上
  367. * @param { Boolean } isKeepTarget 是否保留目标对象中与源对象中属性名相同的属性
  368. * @return { Object } 返回target对象
  369. * @example
  370. * ```javascript
  371. *
  372. * var target = { name: 'target', sex: 1 },
  373. * source = { name: 'source', age: 17 };
  374. *
  375. * UE.utils.extend( target, source, true );
  376. *
  377. * //output: { name: 'target', sex: 1, age: 17 }
  378. * console.log( target );
  379. *
  380. * ```
  381. */
  382. extend:function (t, s, b) {
  383. if (s) {
  384. for (var k in s) {
  385. if (!b || !t.hasOwnProperty(k)) {
  386. t[k] = s[k];
  387. }
  388. }
  389. }
  390. return t;
  391. },
  392. /**
  393. * 将给定的多个对象的属性复制到目标对象target上
  394. * @method extend2
  395. * @remind 该方法将强制把源对象上的属性复制到target对象上
  396. * @remind 该方法支持两个及以上的参数, 从第二个参数开始, 其属性都会被复制到第一个参数上。 如果遇到同名的属性,
  397. * 将会覆盖掉之前的值。
  398. * @param { Object } target 目标对象, 新的属性将附加到该对象上
  399. * @param { Object... } source 源对象, 支持多个对象, 该对象的属性会被附加到target对象上
  400. * @return { Object } 返回target对象
  401. * @example
  402. * ```javascript
  403. *
  404. * var target = {},
  405. * source1 = { name: 'source', age: 17 },
  406. * source2 = { title: 'dev' };
  407. *
  408. * UE.utils.extend2( target, source1, source2 );
  409. *
  410. * //output: { name: 'source', age: 17, title: 'dev' }
  411. * console.log( target );
  412. *
  413. * ```
  414. */
  415. extend2:function (t) {
  416. var a = arguments;
  417. for (var i = 1; i < a.length; i++) {
  418. var x = a[i];
  419. for (var k in x) {
  420. if (!t.hasOwnProperty(k)) {
  421. t[k] = x[k];
  422. }
  423. }
  424. }
  425. return t;
  426. },
  427. /**
  428. * 模拟继承机制, 使得subClass继承自superClass
  429. * @method inherits
  430. * @param { Object } subClass 子类对象
  431. * @param { Object } superClass 超类对象
  432. * @warning 该方法只能让subClass继承超类的原型, subClass对象自身的属性和方法不会被继承
  433. * @return { Object } 继承superClass后的子类对象
  434. * @example
  435. * ```javascript
  436. * function SuperClass(){
  437. * this.name = "小李";
  438. * }
  439. *
  440. * SuperClass.prototype = {
  441. * hello:function(str){
  442. * console.log(this.name + str);
  443. * }
  444. * }
  445. *
  446. * function SubClass(){
  447. * this.name = "小张";
  448. * }
  449. *
  450. * UE.utils.inherits(SubClass,SuperClass);
  451. *
  452. * var sub = new SubClass();
  453. * //output: '小张早上好!
  454. * sub.hello("早上好!");
  455. * ```
  456. */
  457. inherits:function (subClass, superClass) {
  458. var oldP = subClass.prototype,
  459. newP = utils.makeInstance(superClass.prototype);
  460. utils.extend(newP, oldP, true);
  461. subClass.prototype = newP;
  462. return (newP.constructor = subClass);
  463. },
  464. /**
  465. * 用指定的context对象作为函数fn的上下文
  466. * @method bind
  467. * @param { Function } fn 需要绑定上下文的函数对象
  468. * @param { Object } content 函数fn新的上下文对象
  469. * @return { Function } 一个新的函数, 该函数作为原始函数fn的代理, 将完成fn的上下文调换工作。
  470. * @example
  471. * ```javascript
  472. *
  473. * var name = 'window',
  474. * newTest = null;
  475. *
  476. * function test () {
  477. * console.log( this.name );
  478. * }
  479. *
  480. * newTest = UE.utils.bind( test, { name: 'object' } );
  481. *
  482. * //output: object
  483. * newTest();
  484. *
  485. * //output: window
  486. * test();
  487. *
  488. * ```
  489. */
  490. bind:function (fn, context) {
  491. return function () {
  492. return fn.apply(context, arguments);
  493. };
  494. },
  495. /**
  496. * 创建延迟指定时间后执行的函数fn
  497. * @method defer
  498. * @param { Function } fn 需要延迟执行的函数对象
  499. * @param { int } delay 延迟的时间, 单位是毫秒
  500. * @warning 该方法的时间控制是不精确的,仅仅只能保证函数的执行是在给定的时间之后,
  501. * 而不能保证刚好到达延迟时间时执行。
  502. * @return { Function } 目标函数fn的代理函数, 只有执行该函数才能起到延时效果
  503. * @example
  504. * ```javascript
  505. * var start = 0;
  506. *
  507. * function test(){
  508. * console.log( new Date() - start );
  509. * }
  510. *
  511. * var testDefer = UE.utils.defer( test, 1000 );
  512. * //
  513. * start = new Date();
  514. * //output: (大约在1000毫秒之后输出) 1000
  515. * testDefer();
  516. * ```
  517. */
  518. /**
  519. * 创建延迟指定时间后执行的函数fn, 如果在延迟时间内再次执行该方法, 将会根据指定的exclusion的值,
  520. * 决定是否取消前一次函数的执行, 如果exclusion的值为true, 则取消执行,反之,将继续执行前一个方法。
  521. * @method defer
  522. * @param { Function } fn 需要延迟执行的函数对象
  523. * @param { int } delay 延迟的时间, 单位是毫秒
  524. * @param { Boolean } exclusion 如果在延迟时间内再次执行该函数,该值将决定是否取消执行前一次函数的执行,
  525. * 值为true表示取消执行, 反之则将在执行前一次函数之后才执行本次函数调用。
  526. * @warning 该方法的时间控制是不精确的,仅仅只能保证函数的执行是在给定的时间之后,
  527. * 而不能保证刚好到达延迟时间时执行。
  528. * @return { Function } 目标函数fn的代理函数, 只有执行该函数才能起到延时效果
  529. * @example
  530. * ```javascript
  531. *
  532. * function test(){
  533. * console.log(1);
  534. * }
  535. *
  536. * var testDefer = UE.utils.defer( test, 1000, true );
  537. *
  538. * //output: (两次调用仅有一次输出) 1
  539. * testDefer();
  540. * testDefer();
  541. * ```
  542. */
  543. defer:function (fn, delay, exclusion) {
  544. var timerID;
  545. return function () {
  546. if (exclusion) {
  547. clearTimeout(timerID);
  548. }
  549. timerID = setTimeout(fn, delay);
  550. };
  551. },
  552. /**
  553. * 获取元素item在数组array中首次出现的位置, 如果未找到item, 则返回-1
  554. * @method indexOf
  555. * @remind 该方法的匹配过程使用的是恒等“===”
  556. * @param { Array } array 需要查找的数组对象
  557. * @param { * } item 需要在目标数组中查找的值
  558. * @return { int } 返回item在目标数组array中首次出现的位置, 如果在数组中未找到item, 则返回-1
  559. * @example
  560. * ```javascript
  561. * var item = 1,
  562. * arr = [ 3, 4, 6, 8, 1, 1, 2 ];
  563. *
  564. * //output: 4
  565. * console.log( UE.utils.indexOf( arr, item ) );
  566. * ```
  567. */
  568. /**
  569. * 获取元素item数组array中首次出现的位置, 如果未找到item, 则返回-1。通过start的值可以指定搜索的起始位置。
  570. * @method indexOf
  571. * @remind 该方法的匹配过程使用的是恒等“===”
  572. * @param { Array } array 需要查找的数组对象
  573. * @param { * } item 需要在目标数组中查找的值
  574. * @param { int } start 搜索的起始位置
  575. * @return { int } 返回item在目标数组array中的start位置之后首次出现的位置, 如果在数组中未找到item, 则返回-1
  576. * @example
  577. * ```javascript
  578. * var item = 1,
  579. * arr = [ 3, 4, 6, 8, 1, 2, 8, 3, 2, 1, 1, 4 ];
  580. *
  581. * //output: 9
  582. * console.log( UE.utils.indexOf( arr, item, 5 ) );
  583. * ```
  584. */
  585. indexOf:function (array, item, start) {
  586. var index = -1;
  587. start = this.isNumber(start) ? start : 0;
  588. this.each(array, function (v, i) {
  589. if (i >= start && v === item) {
  590. index = i;
  591. return false;
  592. }
  593. });
  594. return index;
  595. },
  596. /**
  597. * 移除数组array中所有的元素item
  598. * @method removeItem
  599. * @param { Array } array 要移除元素的目标数组
  600. * @param { * } item 将要被移除的元素
  601. * @remind 该方法的匹配过程使用的是恒等“===”
  602. * @example
  603. * ```javascript
  604. * var arr = [ 4, 5, 7, 1, 3, 4, 6 ];
  605. *
  606. * UE.utils.removeItem( arr, 4 );
  607. * //output: [ 5, 7, 1, 3, 6 ]
  608. * console.log( arr );
  609. *
  610. * ```
  611. */
  612. removeItem:function (array, item) {
  613. for (var i = 0, l = array.length; i < l; i++) {
  614. if (array[i] === item) {
  615. array.splice(i, 1);
  616. i--;
  617. }
  618. }
  619. },
  620. /**
  621. * 删除字符串str的首尾空格
  622. * @method trim
  623. * @param { String } str 需要删除首尾空格的字符串
  624. * @return { String } 删除了首尾的空格后的字符串
  625. * @example
  626. * ```javascript
  627. *
  628. * var str = " UEdtior ";
  629. *
  630. * //output: 9
  631. * console.log( str.length );
  632. *
  633. * //output: 7
  634. * console.log( UE.utils.trim( " UEdtior " ).length );
  635. *
  636. * //output: 9
  637. * console.log( str.length );
  638. *
  639. * ```
  640. */
  641. trim:function (str) {
  642. return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, '');
  643. },
  644. /**
  645. * 将字符串str以','分隔成数组后,将该数组转换成哈希对象, 其生成的hash对象的key为数组中的元素, value为1
  646. * @method listToMap
  647. * @warning 该方法在生成的hash对象中,会为每一个key同时生成一个另一个全大写的key。
  648. * @param { String } str 该字符串将被以','分割为数组, 然后进行转化
  649. * @return { Object } 转化之后的hash对象
  650. * @example
  651. * ```javascript
  652. *
  653. * //output: Object {UEdtior: 1, UEDTIOR: 1, Hello: 1, HELLO: 1}
  654. * console.log( UE.utils.listToMap( 'UEdtior,Hello' ) );
  655. *
  656. * ```
  657. */
  658. /**
  659. * 将字符串数组转换成哈希对象, 其生成的hash对象的key为数组中的元素, value为1
  660. * @method listToMap
  661. * @warning 该方法在生成的hash对象中,会为每一个key同时生成一个另一个全大写的key。
  662. * @param { Array } arr 字符串数组
  663. * @return { Object } 转化之后的hash对象
  664. * @example
  665. * ```javascript
  666. *
  667. * //output: Object {UEdtior: 1, UEDTIOR: 1, Hello: 1, HELLO: 1}
  668. * console.log( UE.utils.listToMap( [ 'UEdtior', 'Hello' ] ) );
  669. *
  670. * ```
  671. */
  672. listToMap:function (list) {
  673. if (!list)return {};
  674. list = utils.isArray(list) ? list : list.split(',');
  675. for (var i = 0, ci, obj = {}; ci = list[i++];) {
  676. obj[ci.toUpperCase()] = obj[ci] = 1;
  677. }
  678. return obj;
  679. },
  680. /**
  681. * 将str中的html符号转义,将转义“',&,<,",>”五个字符
  682. * @method unhtml
  683. * @param { String } str 需要转义的字符串
  684. * @return { String } 转义后的字符串
  685. * @example
  686. * ```javascript
  687. * var html = '<body>&</body>';
  688. *
  689. * //output: &lt;body&gt;&amp;&lt;/body&gt;
  690. * console.log( UE.utils.unhtml( html ) );
  691. *
  692. * ```
  693. */
  694. unhtml:function (str, reg) {
  695. return str ? str.replace(reg || /[&<">'](?:(amp|lt|quot|gt|#39|nbsp|#\d+);)?/g, function (a, b) {
  696. if (b) {
  697. return a;
  698. } else {
  699. return {
  700. '<':'&lt;',
  701. '&':'&amp;',
  702. '"':'&quot;',
  703. '>':'&gt;',
  704. "'":'&#39;'
  705. }[a]
  706. }
  707. }) : '';
  708. },
  709. /**
  710. * 将url中的html字符转义, 仅转义 ', ", <, > 四个字符
  711. * @param { String } str 需要转义的字符串
  712. * @param { RegExp } reg 自定义的正则
  713. * @return { String } 转义后的字符串
  714. */
  715. unhtmlForUrl:function (str, reg) {
  716. return str ? str.replace(reg || /[<">']/g, function (a) {
  717. return {
  718. '<':'&lt;',
  719. '&':'&amp;',
  720. '"':'&quot;',
  721. '>':'&gt;',
  722. "'":'&#39;'
  723. }[a]
  724. }) : '';
  725. },
  726. /**
  727. * 将str中的转义字符还原成html字符
  728. * @see UE.utils.unhtml(String);
  729. * @method html
  730. * @param { String } str 需要逆转义的字符串
  731. * @return { String } 逆转义后的字符串
  732. * @example
  733. * ```javascript
  734. *
  735. * var str = '&lt;body&gt;&amp;&lt;/body&gt;';
  736. *
  737. * //output: <body>&</body>
  738. * console.log( UE.utils.html( str ) );
  739. *
  740. * ```
  741. */
  742. html:function (str) {
  743. return str ? str.replace(/&((g|l|quo)t|amp|#39|nbsp);/g, function (m) {
  744. return {
  745. '&lt;':'<',
  746. '&amp;':'&',
  747. '&quot;':'"',
  748. '&gt;':'>',
  749. '&#39;':"'",
  750. '&nbsp;':' '
  751. }[m]
  752. }) : '';
  753. },
  754. /**
  755. * 将css样式转换为驼峰的形式
  756. * @method cssStyleToDomStyle
  757. * @param { String } cssName 需要转换的css样式名
  758. * @return { String } 转换成驼峰形式后的css样式名
  759. * @example
  760. * ```javascript
  761. *
  762. * var str = 'border-top';
  763. *
  764. * //output: borderTop
  765. * console.log( UE.utils.cssStyleToDomStyle( str ) );
  766. *
  767. * ```
  768. */
  769. cssStyleToDomStyle:function () {
  770. var test = document.createElement('div').style,
  771. cache = {
  772. 'float':test.cssFloat != undefined ? 'cssFloat' : test.styleFloat != undefined ? 'styleFloat' : 'float'
  773. };
  774. return function (cssName) {
  775. return cache[cssName] || (cache[cssName] = cssName.toLowerCase().replace(/-./g, function (match) {
  776. return match.charAt(1).toUpperCase();
  777. }));
  778. };
  779. }(),
  780. /**
  781. * 动态加载文件到doc中
  782. * @method loadFile
  783. * @param { DomDocument } document 需要加载资源文件的文档对象
  784. * @param { Object } options 加载资源文件的属性集合, 取值请参考代码示例
  785. * @example
  786. * ```javascript
  787. *
  788. * UE.utils.loadFile( document, {
  789. * src:"test.js",
  790. * tag:"script",
  791. * type:"text/javascript",
  792. * defer:"defer"
  793. * } );
  794. *
  795. * ```
  796. */
  797. /**
  798. * 动态加载文件到doc中,加载成功后执行的回调函数fn
  799. * @method loadFile
  800. * @param { DomDocument } document 需要加载资源文件的文档对象
  801. * @param { Object } options 加载资源文件的属性集合, 该集合支持的值是script标签和style标签支持的所有属性。
  802. * @param { Function } fn 资源文件加载成功之后执行的回调
  803. * @warning 对于在同一个文档中多次加载同一URL的文件, 该方法会在第一次加载之后缓存该请求,
  804. * 在此之后的所有同一URL的请求, 将会直接触发回调。
  805. * @example
  806. * ```javascript
  807. *
  808. * UE.utils.loadFile( document, {
  809. * src:"test.js",
  810. * tag:"script",
  811. * type:"text/javascript",
  812. * defer:"defer"
  813. * }, function () {
  814. * console.log('加载成功');
  815. * } );
  816. *
  817. * ```
  818. */
  819. loadFile:function () {
  820. var tmpList = [];
  821. function getItem(doc, obj) {
  822. try {
  823. for (var i = 0, ci; ci = tmpList[i++];) {
  824. if (ci.doc === doc && ci.url == (obj.src || obj.href)) {
  825. return ci;
  826. }
  827. }
  828. } catch (e) {
  829. return null;
  830. }
  831. }
  832. return function (doc, obj, fn) {
  833. var item = getItem(doc, obj);
  834. if (item) {
  835. if (item.ready) {
  836. fn && fn();
  837. } else {
  838. item.funs.push(fn)
  839. }
  840. return;
  841. }
  842. tmpList.push({
  843. doc:doc,
  844. url:obj.src || obj.href,
  845. funs:[fn]
  846. });
  847. if (!doc.body) {
  848. var html = [];
  849. for (var p in obj) {
  850. if (p == 'tag')continue;
  851. html.push(p + '="' + obj[p] + '"')
  852. }
  853. doc.write('<' + obj.tag + ' ' + html.join(' ') + ' ></' + obj.tag + '>');
  854. return;
  855. }
  856. if (obj.id && doc.getElementById(obj.id)) {
  857. return;
  858. }
  859. var element = doc.createElement(obj.tag);
  860. delete obj.tag;
  861. for (var p in obj) {
  862. element.setAttribute(p, obj[p]);
  863. }
  864. element.onload = element.onreadystatechange = function () {
  865. if (!this.readyState || /loaded|complete/.test(this.readyState)) {
  866. item = getItem(doc, obj);
  867. if (item.funs.length > 0) {
  868. item.ready = 1;
  869. for (var fi; fi = item.funs.pop();) {
  870. fi();
  871. }
  872. }
  873. element.onload = element.onreadystatechange = null;
  874. }
  875. };
  876. element.onerror = function () {
  877. throw Error('The load ' + (obj.href || obj.src) + ' fails,check the url settings of file ueditor.config.js ')
  878. };
  879. doc.getElementsByTagName("head")[0].appendChild(element);
  880. }
  881. }(),
  882. /**
  883. * 判断obj对象是否为空
  884. * @method isEmptyObject
  885. * @param { * } obj 需要判断的对象
  886. * @remind 如果判断的对象是NULL, 将直接返回true, 如果是数组且为空, 返回true, 如果是字符串, 且字符串为空,
  887. * 返回true, 如果是普通对象, 且该对象没有任何实例属性, 返回true
  888. * @return { Boolean } 对象是否为空
  889. * @example
  890. * ```javascript
  891. *
  892. * //output: true
  893. * console.log( UE.utils.isEmptyObject( {} ) );
  894. *
  895. * //output: true
  896. * console.log( UE.utils.isEmptyObject( [] ) );
  897. *
  898. * //output: true
  899. * console.log( UE.utils.isEmptyObject( "" ) );
  900. *
  901. * //output: false
  902. * console.log( UE.utils.isEmptyObject( { key: 1 } ) );
  903. *
  904. * //output: false
  905. * console.log( UE.utils.isEmptyObject( [1] ) );
  906. *
  907. * //output: false
  908. * console.log( UE.utils.isEmptyObject( "1" ) );
  909. *
  910. * ```
  911. */
  912. isEmptyObject:function (obj) {
  913. if (obj == null) return true;
  914. if (this.isArray(obj) || this.isString(obj)) return obj.length === 0;
  915. for (var key in obj) if (obj.hasOwnProperty(key)) return false;
  916. return true;
  917. },
  918. /**
  919. * 把rgb格式的颜色值转换成16进制格式
  920. * @method fixColor
  921. * @param { String } rgb格式的颜色值
  922. * @param { String }
  923. * @example
  924. * rgb(255,255,255) => "#ffffff"
  925. */
  926. fixColor:function (name, value) {
  927. if (/color/i.test(name) && /rgba?/.test(value)) {
  928. var array = value.split(",");
  929. if (array.length > 3)
  930. return "";
  931. value = "#";
  932. for (var i = 0, color; color = array[i++];) {
  933. color = parseInt(color.replace(/[^\d]/gi, ''), 10).toString(16);
  934. value += color.length == 1 ? "0" + color : color;
  935. }
  936. value = value.toUpperCase();
  937. }
  938. return value;
  939. },
  940. /**
  941. * 只针对border,padding,margin做了处理,因为性能问题
  942. * @public
  943. * @function
  944. * @param {String} val style字符串
  945. */
  946. optCss:function (val) {
  947. var padding, margin, border;
  948. val = val.replace(/(padding|margin|border)\-([^:]+):([^;]+);?/gi, function (str, key, name, val) {
  949. if (val.split(' ').length == 1) {
  950. switch (key) {
  951. case 'padding':
  952. !padding && (padding = {});
  953. padding[name] = val;
  954. return '';
  955. case 'margin':
  956. !margin && (margin = {});
  957. margin[name] = val;
  958. return '';
  959. case 'border':
  960. return val == 'initial' ? '' : str;
  961. }
  962. }
  963. return str;
  964. });
  965. function opt(obj, name) {
  966. if (!obj) {
  967. return '';
  968. }
  969. var t = obj.top , b = obj.bottom, l = obj.left, r = obj.right, val = '';
  970. if (!t || !l || !b || !r) {
  971. for (var p in obj) {
  972. val += ';' + name + '-' + p + ':' + obj[p] + ';';
  973. }
  974. } else {
  975. val += ';' + name + ':' +
  976. (t == b && b == l && l == r ? t :
  977. t == b && l == r ? (t + ' ' + l) :
  978. l == r ? (t + ' ' + l + ' ' + b) : (t + ' ' + r + ' ' + b + ' ' + l)) + ';'
  979. }
  980. return val;
  981. }
  982. val += opt(padding, 'padding') + opt(margin, 'margin');
  983. return val.replace(/^[ \n\r\t;]*|[ \n\r\t]*$/, '').replace(/;([ \n\r\t]+)|\1;/g, ';')
  984. .replace(/(&((l|g)t|quot|#39))?;{2,}/g, function (a, b) {
  985. return b ? b + ";;" : ';'
  986. });
  987. },
  988. /**
  989. * 克隆对象
  990. * @method clone
  991. * @param { Object } source 源对象
  992. * @return { Object } source的一个副本
  993. */
  994. /**
  995. * 深度克隆对象,将source的属性克隆到target对象, 会覆盖target重名的属性。
  996. * @method clone
  997. * @param { Object } source 源对象
  998. * @param { Object } target 目标对象
  999. * @return { Object } 附加了source对象所有属性的target对象
  1000. */
  1001. clone:function (source, target) {
  1002. var tmp;
  1003. target = target || {};
  1004. for (var i in source) {
  1005. if (source.hasOwnProperty(i)) {
  1006. tmp = source[i];
  1007. if (typeof tmp == 'object') {
  1008. target[i] = utils.isArray(tmp) ? [] : {};
  1009. utils.clone(source[i], target[i])
  1010. } else {
  1011. target[i] = tmp;
  1012. }
  1013. }
  1014. }
  1015. return target;
  1016. },
  1017. /**
  1018. * 把cm/pt为单位的值转换为px为单位的值
  1019. * @method transUnitToPx
  1020. * @param { String } 待转换的带单位的字符串
  1021. * @return { String } 转换为px为计量单位的值的字符串
  1022. * @example
  1023. * ```javascript
  1024. *
  1025. * //output: 500px
  1026. * console.log( UE.utils.transUnitToPx( '20cm' ) );
  1027. *
  1028. * //output: 27px
  1029. * console.log( UE.utils.transUnitToPx( '20pt' ) );
  1030. *
  1031. * ```
  1032. */
  1033. transUnitToPx:function (val) {
  1034. if (!/(pt|cm)/.test(val)) {
  1035. return val
  1036. }
  1037. var unit;
  1038. val.replace(/([\d.]+)(\w+)/, function (str, v, u) {
  1039. val = v;
  1040. unit = u;
  1041. });
  1042. switch (unit) {
  1043. case 'cm':
  1044. val = parseFloat(val) * 25;
  1045. break;
  1046. case 'pt':
  1047. val = Math.round(parseFloat(val) * 96 / 72);
  1048. }
  1049. return val + (val ? 'px' : '');
  1050. },
  1051. /**
  1052. * 在dom树ready之后执行给定的回调函数
  1053. * @method domReady
  1054. * @remind 如果在执行该方法的时候, dom树已经ready, 那么回调函数将立刻执行
  1055. * @param { Function } fn dom树ready之后的回调函数
  1056. * @example
  1057. * ```javascript
  1058. *
  1059. * UE.utils.domReady( function () {
  1060. *
  1061. * console.log('123');
  1062. *
  1063. * } );
  1064. *
  1065. * ```
  1066. */
  1067. domReady:function () {
  1068. var fnArr = [];
  1069. function doReady(doc) {
  1070. //确保onready只执行一次
  1071. doc.isReady = true;
  1072. for (var ci; ci = fnArr.pop(); ci()) {
  1073. }
  1074. }
  1075. return function (onready, win) {
  1076. win = win || window;
  1077. var doc = win.document;
  1078. onready && fnArr.push(onready);
  1079. if (doc.readyState === "complete") {
  1080. doReady(doc);
  1081. } else {
  1082. doc.isReady && doReady(doc);
  1083. if (browser.ie && browser.version != 11) {
  1084. (function () {
  1085. if (doc.isReady) return;
  1086. try {
  1087. doc.documentElement.doScroll("left");
  1088. } catch (error) {
  1089. setTimeout(arguments.callee, 0);
  1090. return;
  1091. }
  1092. doReady(doc);
  1093. })();
  1094. win.attachEvent('onload', function () {
  1095. doReady(doc)
  1096. });
  1097. } else {
  1098. doc.addEventListener("DOMContentLoaded", function () {
  1099. doc.removeEventListener("DOMContentLoaded", arguments.callee, false);
  1100. doReady(doc);
  1101. }, false);
  1102. win.addEventListener('load', function () {
  1103. doReady(doc)
  1104. }, false);
  1105. }
  1106. }
  1107. }
  1108. }(),
  1109. /**
  1110. * 动态添加css样式
  1111. * @method cssRule
  1112. * @param { String } 节点名称
  1113. * @grammar UE.utils.cssRule('添加的样式的节点名称',['样式','放到哪个document上'])
  1114. * @grammar UE.utils.cssRule('body','body{background:#ccc}') => null //给body添加背景颜色
  1115. * @grammar UE.utils.cssRule('body') =>样式的字符串 //取得key值为body的样式的内容,如果没有找到key值先关的样式将返回空,例如刚才那个背景颜色,将返回 body{background:#ccc}
  1116. * @grammar UE.utils.cssRule('body',document) => 返回指定key的样式,并且指定是哪个document
  1117. * @grammar UE.utils.cssRule('body','') =>null //清空给定的key值的背景颜色
  1118. */
  1119. cssRule:browser.ie && browser.version != 11 ? function (key, style, doc) {
  1120. var indexList, index;
  1121. if(style === undefined || style && style.nodeType && style.nodeType == 9){
  1122. //获取样式
  1123. doc = style && style.nodeType && style.nodeType == 9 ? style : (doc || document);
  1124. indexList = doc.indexList || (doc.indexList = {});
  1125. index = indexList[key];
  1126. if(index !== undefined){
  1127. return doc.styleSheets[index].cssText
  1128. }
  1129. return undefined;
  1130. }
  1131. doc = doc || document;
  1132. indexList = doc.indexList || (doc.indexList = {});
  1133. index = indexList[key];
  1134. //清除样式
  1135. if(style === ''){
  1136. if(index!== undefined){
  1137. doc.styleSheets[index].cssText = '';
  1138. delete indexList[key];
  1139. return true
  1140. }
  1141. return false;
  1142. }
  1143. //添加样式
  1144. if(index!== undefined){
  1145. sheetStyle = doc.styleSheets[index];
  1146. }else{
  1147. sheetStyle = doc.createStyleSheet('', index = doc.styleSheets.length);
  1148. indexList[key] = index;
  1149. }
  1150. sheetStyle.cssText = style;
  1151. }: function (key, style, doc) {
  1152. var head, node;
  1153. if(style === undefined || style && style.nodeType && style.nodeType == 9){
  1154. //获取样式
  1155. doc = style && style.nodeType && style.nodeType == 9 ? style : (doc || document);
  1156. node = doc.getElementById(key);
  1157. return node ? node.innerHTML : undefined;
  1158. }
  1159. doc = doc || document;
  1160. node = doc.getElementById(key);
  1161. //清除样式
  1162. if(style === ''){
  1163. if(node){
  1164. node.parentNode.removeChild(node);
  1165. return true
  1166. }
  1167. return false;
  1168. }
  1169. //添加样式
  1170. if(node){
  1171. node.innerHTML = style;
  1172. }else{
  1173. node = doc.createElement('style');
  1174. node.id = key;
  1175. node.innerHTML = style;
  1176. doc.getElementsByTagName('head')[0].appendChild(node);
  1177. }
  1178. },
  1179. sort:function(array,compareFn){
  1180. compareFn = compareFn || function(item1, item2){ return item1.localeCompare(item2);};
  1181. for(var i= 0,len = array.length; i<len; i++){
  1182. for(var j = i,length = array.length; j<length; j++){
  1183. if(compareFn(array[i], array[j]) > 0){
  1184. var t = array[i];
  1185. array[i] = array[j];
  1186. array[j] = t;
  1187. }
  1188. }
  1189. }
  1190. return array;
  1191. },
  1192. serializeParam:function (json) {
  1193. var strArr = [];
  1194. for (var i in json) {
  1195. //忽略默认的几个参数
  1196. if(i=="method" || i=="timeout" || i=="async") continue;
  1197. //传递过来的对象和函数不在提交之列
  1198. if (!((typeof json[i]).toLowerCase() == "function" || (typeof json[i]).toLowerCase() == "object")) {
  1199. strArr.push( encodeURIComponent(i) + "="+encodeURIComponent(json[i]) );
  1200. } else if (utils.isArray(json[i])) {
  1201. //支持传数组内容
  1202. for(var j = 0; j < json[i].length; j++) {
  1203. strArr.push( encodeURIComponent(i) + "[]="+encodeURIComponent(json[i][j]) );
  1204. }
  1205. }
  1206. }
  1207. return strArr.join("&");
  1208. },
  1209. formatUrl:function (url) {
  1210. var u = url.replace(/&&/g, '&');
  1211. u = u.replace(/\?&/g, '?');
  1212. u = u.replace(/&$/g, '');
  1213. u = u.replace(/&#/g, '#');
  1214. u = u.replace(/&+/g, '&');
  1215. return u;
  1216. },
  1217. isCrossDomainUrl:function (url) {
  1218. var a = document.createElement('a');
  1219. a.href = url;
  1220. if (browser.ie) {
  1221. a.href = a.href;
  1222. }
  1223. return !(a.protocol == location.protocol && a.hostname == location.hostname &&
  1224. (a.port == location.port || (a.port == '80' && location.port == '') || (a.port == '' && location.port == '80')));
  1225. },
  1226. clearEmptyAttrs : function(obj){
  1227. for(var p in obj){
  1228. if(obj[p] === ''){
  1229. delete obj[p]
  1230. }
  1231. }
  1232. return obj;
  1233. },
  1234. str2json : function(s){
  1235. if (!utils.isString(s)) return null;
  1236. if (window.JSON) {
  1237. return JSON.parse(s);
  1238. } else {
  1239. return (new Function("return " + utils.trim(s || '')))();
  1240. }
  1241. },
  1242. json2str : (function(){
  1243. if (window.JSON) {
  1244. return JSON.stringify;
  1245. } else {
  1246. var escapeMap = {
  1247. "\b": '\\b',
  1248. "\t": '\\t',
  1249. "\n": '\\n',
  1250. "\f": '\\f',
  1251. "\r": '\\r',
  1252. '"' : '\\"',
  1253. "\\": '\\\\'
  1254. };
  1255. function encodeString(source) {
  1256. if (/["\\\x00-\x1f]/.test(source)) {
  1257. source = source.replace(
  1258. /["\\\x00-\x1f]/g,
  1259. function (match) {
  1260. var c = escapeMap[match];
  1261. if (c) {
  1262. return c;
  1263. }
  1264. c = match.charCodeAt();
  1265. return "\\u00"
  1266. + Math.floor(c / 16).toString(16)
  1267. + (c % 16).toString(16);
  1268. });
  1269. }
  1270. return '"' + source + '"';
  1271. }
  1272. function encodeArray(source) {
  1273. var result = ["["],
  1274. l = source.length,
  1275. preComma, i, item;
  1276. for (i = 0; i < l; i++) {
  1277. item = source[i];
  1278. switch (typeof item) {
  1279. case "undefined":
  1280. case "function":
  1281. case "unknown":
  1282. break;
  1283. default:
  1284. if(preComma) {
  1285. result.push(',');
  1286. }
  1287. result.push(utils.json2str(item));
  1288. preComma = 1;
  1289. }
  1290. }
  1291. result.push("]");
  1292. return result.join("");
  1293. }
  1294. function pad(source) {
  1295. return source < 10 ? '0' + source : source;
  1296. }
  1297. function encodeDate(source){
  1298. return '"' + source.getFullYear() + "-"
  1299. + pad(source.getMonth() + 1) + "-"
  1300. + pad(source.getDate()) + "T"
  1301. + pad(source.getHours()) + ":"
  1302. + pad(source.getMinutes()) + ":"
  1303. + pad(source.getSeconds()) + '"';
  1304. }
  1305. return function (value) {
  1306. switch (typeof value) {
  1307. case 'undefined':
  1308. return 'undefined';
  1309. case 'number':
  1310. return isFinite(value) ? String(value) : "null";
  1311. case 'string':
  1312. return encodeString(value);
  1313. case 'boolean':
  1314. return String(value);
  1315. default:
  1316. if (value === null) {
  1317. return 'null';
  1318. } else if (utils.isArray(value)) {
  1319. return encodeArray(value);
  1320. } else if (utils.isDate(value)) {
  1321. return encodeDate(value);
  1322. } else {
  1323. var result = ['{'],
  1324. encode = utils.json2str,
  1325. preComma,
  1326. item;
  1327. for (var key in value) {
  1328. if (Object.prototype.hasOwnProperty.call(value, key)) {
  1329. item = value[key];
  1330. switch (typeof item) {
  1331. case 'undefined':
  1332. case 'unknown':
  1333. case 'function':
  1334. break;
  1335. default:
  1336. if (preComma) {
  1337. result.push(',');
  1338. }
  1339. preComma = 1;
  1340. result.push(encode(key) + ':' + encode(item));
  1341. }
  1342. }
  1343. }
  1344. result.push('}');
  1345. return result.join('');
  1346. }
  1347. }
  1348. };
  1349. }
  1350. })()
  1351. };
  1352. /**
  1353. * 判断给定的对象是否是字符串
  1354. * @method isString
  1355. * @param { * } object 需要判断的对象
  1356. * @return { Boolean } 给定的对象是否是字符串
  1357. */
  1358. /**
  1359. * 判断给定的对象是否是数组
  1360. * @method isArray
  1361. * @param { * } object 需要判断的对象
  1362. * @return { Boolean } 给定的对象是否是数组
  1363. */
  1364. /**
  1365. * 判断给定的对象是否是一个Function
  1366. * @method isFunction
  1367. * @param { * } object 需要判断的对象
  1368. * @return { Boolean } 给定的对象是否是Function
  1369. */
  1370. /**
  1371. * 判断给定的对象是否是Number
  1372. * @method isNumber
  1373. * @param { * } object 需要判断的对象
  1374. * @return { Boolean } 给定的对象是否是Number
  1375. */
  1376. /**
  1377. * 判断给定的对象是否是一个正则表达式
  1378. * @method isRegExp
  1379. * @param { * } object 需要判断的对象
  1380. * @return { Boolean } 给定的对象是否是正则表达式
  1381. */
  1382. /**
  1383. * 判断给定的对象是否是一个普通对象
  1384. * @method isObject
  1385. * @param { * } object 需要判断的对象
  1386. * @return { Boolean } 给定的对象是否是普通对象
  1387. */
  1388. utils.each(['String', 'Function', 'Array', 'Number', 'RegExp', 'Object', 'Date'], function (v) {
  1389. UE.utils['is' + v] = function (obj) {
  1390. return Object.prototype.toString.apply(obj) == '[object ' + v + ']';
  1391. }
  1392. });
  1393. // core/EventBase.js
  1394. /**
  1395. * UE采用的事件基类
  1396. * @file
  1397. * @module UE
  1398. * @class EventBase
  1399. * @since 1.2.6.1
  1400. */
  1401. /**
  1402. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  1403. * @unfile
  1404. * @module UE
  1405. */
  1406. /**
  1407. * UE采用的事件基类,继承此类的对应类将获取addListener,removeListener,fireEvent方法。
  1408. * 在UE中,Editor以及所有ui实例都继承了该类,故可以在对应的ui对象以及editor对象上使用上述方法。
  1409. * @unfile
  1410. * @module UE
  1411. * @class EventBase
  1412. */
  1413. /**
  1414. * 通过此构造器,子类可以继承EventBase获取事件监听的方法
  1415. * @constructor
  1416. * @example
  1417. * ```javascript
  1418. * UE.EventBase.call(editor);
  1419. * ```
  1420. */
  1421. var EventBase = UE.EventBase = function () {};
  1422. EventBase.prototype = {
  1423. /**
  1424. * 注册事件监听器
  1425. * @method addListener
  1426. * @param { String } types 监听的事件名称,同时监听多个事件使用空格分隔
  1427. * @param { Function } fn 监听的事件被触发时,会执行该回调函数
  1428. * @waining 事件被触发时,监听的函数假如返回的值恒等于true,回调函数的队列中后面的函数将不执行
  1429. * @example
  1430. * ```javascript
  1431. * editor.addListener('selectionchange',function(){
  1432. * console.log("选区已经变化!");
  1433. * })
  1434. * editor.addListener('beforegetcontent aftergetcontent',function(type){
  1435. * if(type == 'beforegetcontent'){
  1436. * //do something
  1437. * }else{
  1438. * //do something
  1439. * }
  1440. * console.log(this.getContent) // this是注册的事件的编辑器实例
  1441. * })
  1442. * ```
  1443. * @see UE.EventBase:fireEvent(String)
  1444. */
  1445. addListener:function (types, listener) {
  1446. types = utils.trim(types).split(/\s+/);
  1447. for (var i = 0, ti; ti = types[i++];) {
  1448. getListener(this, ti, true).push(listener);
  1449. }
  1450. },
  1451. on : function(types, listener){
  1452. return this.addListener(types,listener);
  1453. },
  1454. off : function(types, listener){
  1455. return this.removeListener(types, listener)
  1456. },
  1457. trigger:function(){
  1458. return this.fireEvent.apply(this,arguments);
  1459. },
  1460. /**
  1461. * 移除事件监听器
  1462. * @method removeListener
  1463. * @param { String } types 移除的事件名称,同时移除多个事件使用空格分隔
  1464. * @param { Function } fn 移除监听事件的函数引用
  1465. * @example
  1466. * ```javascript
  1467. * //changeCallback为方法体
  1468. * editor.removeListener("selectionchange",changeCallback);
  1469. * ```
  1470. */
  1471. removeListener:function (types, listener) {
  1472. types = utils.trim(types).split(/\s+/);
  1473. for (var i = 0, ti; ti = types[i++];) {
  1474. utils.removeItem(getListener(this, ti) || [], listener);
  1475. }
  1476. },
  1477. /**
  1478. * 触发事件
  1479. * @method fireEvent
  1480. * @param { String } types 触发的事件名称,同时触发多个事件使用空格分隔
  1481. * @remind 该方法会触发addListener
  1482. * @return { * } 返回触发事件的队列中,最后执行的回调函数的返回值
  1483. * @example
  1484. * ```javascript
  1485. * editor.fireEvent("selectionchange");
  1486. * ```
  1487. */
  1488. /**
  1489. * 触发事件
  1490. * @method fireEvent
  1491. * @param { String } types 触发的事件名称,同时触发多个事件使用空格分隔
  1492. * @param { *... } options 可选参数,可以传入一个或多个参数,会传给事件触发的回调函数
  1493. * @return { * } 返回触发事件的队列中,最后执行的回调函数的返回值
  1494. * @example
  1495. * ```javascript
  1496. *
  1497. * editor.addListener( "selectionchange", function ( type, arg1, arg2 ) {
  1498. *
  1499. * console.log( arg1 + " " + arg2 );
  1500. *
  1501. * } );
  1502. *
  1503. * //触发selectionchange事件, 会执行上面的事件监听器
  1504. * //output: Hello World
  1505. * editor.fireEvent("selectionchange", "Hello", "World");
  1506. * ```
  1507. */
  1508. fireEvent:function () {
  1509. var types = arguments[0];
  1510. types = utils.trim(types).split(' ');
  1511. for (var i = 0, ti; ti = types[i++];) {
  1512. var listeners = getListener(this, ti),
  1513. r, t, k;
  1514. if (listeners) {
  1515. k = listeners.length;
  1516. while (k--) {
  1517. if(!listeners[k])continue;
  1518. t = listeners[k].apply(this, arguments);
  1519. if(t === true){
  1520. return t;
  1521. }
  1522. if (t !== undefined) {
  1523. r = t;
  1524. }
  1525. }
  1526. }
  1527. if (t = this['on' + ti.toLowerCase()]) {
  1528. r = t.apply(this, arguments);
  1529. }
  1530. }
  1531. return r;
  1532. }
  1533. };
  1534. /**
  1535. * 获得对象所拥有监听类型的所有监听器
  1536. * @unfile
  1537. * @module UE
  1538. * @since 1.2.6.1
  1539. * @method getListener
  1540. * @public
  1541. * @param { Object } obj 查询监听器的对象
  1542. * @param { String } type 事件类型
  1543. * @param { Boolean } force 为true且当前所有type类型的侦听器不存在时,创建一个空监听器数组
  1544. * @return { Array } 监听器数组
  1545. */
  1546. function getListener(obj, type, force) {
  1547. var allListeners;
  1548. type = type.toLowerCase();
  1549. return ( ( allListeners = ( obj.__allListeners || force && ( obj.__allListeners = {} ) ) )
  1550. && ( allListeners[type] || force && ( allListeners[type] = [] ) ) );
  1551. }
  1552. // core/dtd.js
  1553. ///import editor.js
  1554. ///import core/dom/dom.js
  1555. ///import core/utils.js
  1556. /**
  1557. * dtd html语义化的体现类
  1558. * @constructor
  1559. * @namespace dtd
  1560. */
  1561. var dtd = dom.dtd = (function() {
  1562. function _( s ) {
  1563. for (var k in s) {
  1564. s[k.toUpperCase()] = s[k];
  1565. }
  1566. return s;
  1567. }
  1568. var X = utils.extend2;
  1569. var A = _({isindex:1,fieldset:1}),
  1570. B = _({input:1,button:1,select:1,textarea:1,label:1}),
  1571. C = X( _({a:1}), B ),
  1572. D = X( {iframe:1}, C ),
  1573. 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}),
  1574. F = _({ins:1,del:1,script:1,style:1}),
  1575. 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 ),
  1576. 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 ),
  1577. I = X( _({p:1}), H ),
  1578. J = X( _({iframe:1}), H, B ),
  1579. 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}),
  1580. L = X( _({a:0}), J ),//a不能被切开,所以把他
  1581. M = _({tr:1}),
  1582. N = _({'#':1}),
  1583. O = X( _({param:1}), K ),
  1584. P = X( _({form:1}), A, D, E, I ),
  1585. Q = _({li:1,ol:1,ul:1}),
  1586. R = _({style:1,script:1}),
  1587. S = _({base:1,link:1,meta:1,title:1}),
  1588. T = X( S, R ),
  1589. U = _({head:1,body:1}),
  1590. V = _({html:1});
  1591. 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}),
  1592. 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});
  1593. return _({
  1594. // $ 表示自定的属性
  1595. // body外的元素列表.
  1596. $nonBodyContent: X( V, U, S ),
  1597. //块结构元素列表
  1598. $block : block,
  1599. //内联元素列表
  1600. $inline : L,
  1601. $inlineWithA : X(_({a:1}),L),
  1602. $body : X( _({script:1,style:1}), block ),
  1603. $cdata : _({script:1,style:1}),
  1604. //自闭和元素
  1605. $empty : empty,
  1606. //不是自闭合,但不能让range选中里边
  1607. $nonChild : _({iframe:1,textarea:1}),
  1608. //列表元素列表
  1609. $listItem : _({dd:1,dt:1,li:1}),
  1610. //列表根元素列表
  1611. $list: _({ul:1,ol:1,dl:1}),
  1612. //不能认为是空的元素
  1613. $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}),
  1614. //如果没有子节点就可以删除的元素列表,像span,a
  1615. $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}),
  1616. $removeEmptyBlock : _({'p':1,'div':1}),
  1617. //在table元素里的元素列表
  1618. $tableContent : _({caption:1,col:1,colgroup:1,tbody:1,td:1,tfoot:1,th:1,thead:1,tr:1,table:1}),
  1619. //不转换的标签
  1620. $notTransContent : _({pre:1,script:1,style:1,textarea:1}),
  1621. html: U,
  1622. head: T,
  1623. style: N,
  1624. script: N,
  1625. body: P,
  1626. base: {},
  1627. link: {},
  1628. meta: {},
  1629. title: N,
  1630. col : {},
  1631. tr : _({td:1,th:1}),
  1632. img : {},
  1633. embed: {},
  1634. colgroup : _({thead:1,col:1,tbody:1,tr:1,tfoot:1}),
  1635. noscript : P,
  1636. td : P,
  1637. br : {},
  1638. th : P,
  1639. center : P,
  1640. kbd : L,
  1641. button : X( I, E ),
  1642. basefont : {},
  1643. h5 : L,
  1644. h4 : L,
  1645. samp : L,
  1646. h6 : L,
  1647. ol : Q,
  1648. h1 : L,
  1649. h3 : L,
  1650. option : N,
  1651. h2 : L,
  1652. form : X( A, D, E, I ),
  1653. select : _({optgroup:1,option:1}),
  1654. font : L,
  1655. ins : L,
  1656. menu : Q,
  1657. abbr : L,
  1658. label : L,
  1659. table : _({thead:1,col:1,tbody:1,tr:1,colgroup:1,caption:1,tfoot:1}),
  1660. code : L,
  1661. tfoot : M,
  1662. cite : L,
  1663. li : P,
  1664. input : {},
  1665. iframe : P,
  1666. strong : L,
  1667. textarea : N,
  1668. noframes : P,
  1669. big : L,
  1670. small : L,
  1671. //trace:
  1672. span :_({'#':1,br:1,b:1,strong:1,u:1,i:1,em:1,sub:1,sup:1,strike:1,span:1}),
  1673. hr : L,
  1674. dt : L,
  1675. sub : L,
  1676. optgroup : _({option:1}),
  1677. param : {},
  1678. bdo : L,
  1679. 'var' : L,
  1680. div : P,
  1681. object : O,
  1682. sup : L,
  1683. dd : P,
  1684. strike : L,
  1685. area : {},
  1686. dir : Q,
  1687. map : X( _({area:1,form:1,p:1}), A, F, E ),
  1688. applet : O,
  1689. dl : _({dt:1,dd:1}),
  1690. del : L,
  1691. isindex : {},
  1692. fieldset : X( _({legend:1}), K ),
  1693. thead : M,
  1694. ul : Q,
  1695. acronym : L,
  1696. b : L,
  1697. a : X( _({a:1}), J ),
  1698. blockquote :X(_({td:1,tr:1,tbody:1,li:1}),P),
  1699. caption : L,
  1700. i : L,
  1701. u : L,
  1702. tbody : M,
  1703. s : L,
  1704. address : X( D, I ),
  1705. tt : L,
  1706. legend : L,
  1707. q : L,
  1708. pre : X( G, C ),
  1709. p : X(_({'a':1}),L),
  1710. em :L,
  1711. dfn : L
  1712. });
  1713. })();
  1714. // core/domUtils.js
  1715. /**
  1716. * Dom操作工具包
  1717. * @file
  1718. * @module UE.dom.domUtils
  1719. * @since 1.2.6.1
  1720. */
  1721. /**
  1722. * Dom操作工具包
  1723. * @unfile
  1724. * @module UE.dom.domUtils
  1725. */
  1726. function getDomNode(node, start, ltr, startFromChild, fn, guard) {
  1727. var tmpNode = startFromChild && node[start],
  1728. parent;
  1729. !tmpNode && (tmpNode = node[ltr]);
  1730. while (!tmpNode && (parent = (parent || node).parentNode)) {
  1731. if (parent.tagName == 'BODY' || guard && !guard(parent)) {
  1732. return null;
  1733. }
  1734. tmpNode = parent[ltr];
  1735. }
  1736. if (tmpNode && fn && !fn(tmpNode)) {
  1737. return getDomNode(tmpNode, start, ltr, false, fn);
  1738. }
  1739. return tmpNode;
  1740. }
  1741. var attrFix = ie && browser.version < 9 ? {
  1742. tabindex:"tabIndex",
  1743. readonly:"readOnly",
  1744. "for":"htmlFor",
  1745. "class":"className",
  1746. maxlength:"maxLength",
  1747. cellspacing:"cellSpacing",
  1748. cellpadding:"cellPadding",
  1749. rowspan:"rowSpan",
  1750. colspan:"colSpan",
  1751. usemap:"useMap",
  1752. frameborder:"frameBorder"
  1753. } : {
  1754. tabindex:"tabIndex",
  1755. readonly:"readOnly"
  1756. },
  1757. styleBlock = utils.listToMap([
  1758. '-webkit-box', '-moz-box', 'block' ,
  1759. 'list-item' , 'table' , 'table-row-group' ,
  1760. 'table-header-group', 'table-footer-group' ,
  1761. 'table-row' , 'table-column-group' , 'table-column' ,
  1762. 'table-cell' , 'table-caption'
  1763. ]);
  1764. var domUtils = dom.domUtils = {
  1765. //节点常量
  1766. NODE_ELEMENT:1,
  1767. NODE_DOCUMENT:9,
  1768. NODE_TEXT:3,
  1769. NODE_COMMENT:8,
  1770. NODE_DOCUMENT_FRAGMENT:11,
  1771. //位置关系
  1772. POSITION_IDENTICAL:0,
  1773. POSITION_DISCONNECTED:1,
  1774. POSITION_FOLLOWING:2,
  1775. POSITION_PRECEDING:4,
  1776. POSITION_IS_CONTAINED:8,
  1777. POSITION_CONTAINS:16,
  1778. //ie6使用其他的会有一段空白出现
  1779. fillChar:ie && browser.version == '6' ? '\ufeff' : '\u200B',
  1780. //-------------------------Node部分--------------------------------
  1781. keys:{
  1782. /*Backspace*/ 8:1, /*Delete*/ 46:1,
  1783. /*Shift*/ 16:1, /*Ctrl*/ 17:1, /*Alt*/ 18:1,
  1784. 37:1, 38:1, 39:1, 40:1,
  1785. 13:1 /*enter*/
  1786. },
  1787. /**
  1788. * 获取节点A相对于节点B的位置关系
  1789. * @method getPosition
  1790. * @param { Node } nodeA 需要查询位置关系的节点A
  1791. * @param { Node } nodeB 需要查询位置关系的节点B
  1792. * @return { Number } 节点A与节点B的关系
  1793. * @example
  1794. * ```javascript
  1795. * //output: 20
  1796. * var position = UE.dom.domUtils.getPosition( document.documentElement, document.body );
  1797. *
  1798. * switch ( position ) {
  1799. *
  1800. * //0
  1801. * case UE.dom.domUtils.POSITION_IDENTICAL:
  1802. * console.log('元素相同');
  1803. * break;
  1804. * //1
  1805. * case UE.dom.domUtils.POSITION_DISCONNECTED:
  1806. * console.log('两个节点在不同的文档中');
  1807. * break;
  1808. * //2
  1809. * case UE.dom.domUtils.POSITION_FOLLOWING:
  1810. * console.log('节点A在节点B之后');
  1811. * break;
  1812. * //4
  1813. * case UE.dom.domUtils.POSITION_PRECEDING;
  1814. * console.log('节点A在节点B之前');
  1815. * break;
  1816. * //8
  1817. * case UE.dom.domUtils.POSITION_IS_CONTAINED:
  1818. * console.log('节点A被节点B包含');
  1819. * break;
  1820. * case 10:
  1821. * console.log('节点A被节点B包含且节点A在节点B之后');
  1822. * break;
  1823. * //16
  1824. * case UE.dom.domUtils.POSITION_CONTAINS:
  1825. * console.log('节点A包含节点B');
  1826. * break;
  1827. * case 20:
  1828. * console.log('节点A包含节点B且节点A在节点B之前');
  1829. * break;
  1830. *
  1831. * }
  1832. * ```
  1833. */
  1834. getPosition:function (nodeA, nodeB) {
  1835. // 如果两个节点是同一个节点
  1836. if (nodeA === nodeB) {
  1837. // domUtils.POSITION_IDENTICAL
  1838. return 0;
  1839. }
  1840. var node,
  1841. parentsA = [nodeA],
  1842. parentsB = [nodeB];
  1843. node = nodeA;
  1844. while (node = node.parentNode) {
  1845. // 如果nodeB是nodeA的祖先节点
  1846. if (node === nodeB) {
  1847. // domUtils.POSITION_IS_CONTAINED + domUtils.POSITION_FOLLOWING
  1848. return 10;
  1849. }
  1850. parentsA.push(node);
  1851. }
  1852. node = nodeB;
  1853. while (node = node.parentNode) {
  1854. // 如果nodeA是nodeB的祖先节点
  1855. if (node === nodeA) {
  1856. // domUtils.POSITION_CONTAINS + domUtils.POSITION_PRECEDING
  1857. return 20;
  1858. }
  1859. parentsB.push(node);
  1860. }
  1861. parentsA.reverse();
  1862. parentsB.reverse();
  1863. if (parentsA[0] !== parentsB[0]) {
  1864. // domUtils.POSITION_DISCONNECTED
  1865. return 1;
  1866. }
  1867. var i = -1;
  1868. while (i++, parentsA[i] === parentsB[i]) {
  1869. }
  1870. nodeA = parentsA[i];
  1871. nodeB = parentsB[i];
  1872. while (nodeA = nodeA.nextSibling) {
  1873. if (nodeA === nodeB) {
  1874. // domUtils.POSITION_PRECEDING
  1875. return 4
  1876. }
  1877. }
  1878. // domUtils.POSITION_FOLLOWING
  1879. return 2;
  1880. },
  1881. /**
  1882. * 检测节点node在父节点中的索引位置
  1883. * @method getNodeIndex
  1884. * @param { Node } node 需要检测的节点对象
  1885. * @return { Number } 该节点在父节点中的位置
  1886. * @see UE.dom.domUtils.getNodeIndex(Node,Boolean)
  1887. */
  1888. /**
  1889. * 检测节点node在父节点中的索引位置, 根据给定的mergeTextNode参数决定是否要合并多个连续的文本节点为一个节点
  1890. * @method getNodeIndex
  1891. * @param { Node } node 需要检测的节点对象
  1892. * @param { Boolean } mergeTextNode 是否合并多个连续的文本节点为一个节点
  1893. * @return { Number } 该节点在父节点中的位置
  1894. * @example
  1895. * ```javascript
  1896. *
  1897. * var node = document.createElement("div");
  1898. *
  1899. * node.appendChild( document.createTextNode( "hello" ) );
  1900. * node.appendChild( document.createTextNode( "world" ) );
  1901. * node.appendChild( node = document.createElement( "div" ) );
  1902. *
  1903. * //output: 2
  1904. * console.log( UE.dom.domUtils.getNodeIndex( node ) );
  1905. *
  1906. * //output: 1
  1907. * console.log( UE.dom.domUtils.getNodeIndex( node, true ) );
  1908. *
  1909. * ```
  1910. */
  1911. getNodeIndex:function (node, ignoreTextNode) {
  1912. var preNode = node,
  1913. i = 0;
  1914. while (preNode = preNode.previousSibling) {
  1915. if (ignoreTextNode && preNode.nodeType == 3) {
  1916. if(preNode.nodeType != preNode.nextSibling.nodeType ){
  1917. i++;
  1918. }
  1919. continue;
  1920. }
  1921. i++;
  1922. }
  1923. return i;
  1924. },
  1925. /**
  1926. * 检测节点node是否在给定的document对象上
  1927. * @method inDoc
  1928. * @param { Node } node 需要检测的节点对象
  1929. * @param { DomDocument } doc 需要检测的document对象
  1930. * @return { Boolean } 该节点node是否在给定的document的dom树上
  1931. * @example
  1932. * ```javascript
  1933. *
  1934. * var node = document.createElement("div");
  1935. *
  1936. * //output: false
  1937. * console.log( UE.do.domUtils.inDoc( node, document ) );
  1938. *
  1939. * document.body.appendChild( node );
  1940. *
  1941. * //output: true
  1942. * console.log( UE.do.domUtils.inDoc( node, document ) );
  1943. *
  1944. * ```
  1945. */
  1946. inDoc:function (node, doc) {
  1947. return domUtils.getPosition(node, doc) == 10;
  1948. },
  1949. /**
  1950. * 根据给定的过滤规则filterFn, 查找符合该过滤规则的node节点的第一个祖先节点,
  1951. * 查找的起点是给定node节点的父节点。
  1952. * @method findParent
  1953. * @param { Node } node 需要查找的节点
  1954. * @param { Function } filterFn 自定义的过滤方法。
  1955. * @warning 查找的终点是到body节点为止
  1956. * @remind 自定义的过滤方法filterFn接受一个Node对象作为参数, 该对象代表当前执行检测的祖先节点。 如果该
  1957. * 节点满足过滤条件, 则要求返回true, 这时将直接返回该节点作为findParent()的结果, 否则, 请返回false。
  1958. * @return { Node | Null } 如果找到符合过滤条件的节点, 就返回该节点, 否则返回NULL
  1959. * @example
  1960. * ```javascript
  1961. * var filterNode = UE.dom.domUtils.findParent( document.body.firstChild, function ( node ) {
  1962. *
  1963. * //由于查找的终点是body节点, 所以永远也不会匹配当前过滤器的条件, 即这里永远会返回false
  1964. * return node.tagName === "HTML";
  1965. *
  1966. * } );
  1967. *
  1968. * //output: true
  1969. * console.log( filterNode === null );
  1970. * ```
  1971. */
  1972. /**
  1973. * 根据给定的过滤规则filterFn, 查找符合该过滤规则的node节点的第一个祖先节点,
  1974. * 如果includeSelf的值为true,则查找的起点是给定的节点node, 否则, 起点是node的父节点
  1975. * @method findParent
  1976. * @param { Node } node 需要查找的节点
  1977. * @param { Function } filterFn 自定义的过滤方法。
  1978. * @param { Boolean } includeSelf 查找过程是否包含自身
  1979. * @warning 查找的终点是到body节点为止
  1980. * @remind 自定义的过滤方法filterFn接受一个Node对象作为参数, 该对象代表当前执行检测的祖先节点。 如果该
  1981. * 节点满足过滤条件, 则要求返回true, 这时将直接返回该节点作为findParent()的结果, 否则, 请返回false。
  1982. * @remind 如果includeSelf为true, 则过滤器第一次执行时的参数会是节点本身。
  1983. * 反之, 过滤器第一次执行时的参数将是该节点的父节点。
  1984. * @return { Node | Null } 如果找到符合过滤条件的节点, 就返回该节点, 否则返回NULL
  1985. * @example
  1986. * ```html
  1987. * <body>
  1988. *
  1989. * <div id="test">
  1990. * </div>
  1991. *
  1992. * <script type="text/javascript">
  1993. *
  1994. * //output: DIV, BODY
  1995. * var filterNode = UE.dom.domUtils.findParent( document.getElementById( "test" ), function ( node ) {
  1996. *
  1997. * console.log( node.tagName );
  1998. * return false;
  1999. *
  2000. * }, true );
  2001. *
  2002. * </script>
  2003. * </body>
  2004. * ```
  2005. */
  2006. findParent:function (node, filterFn, includeSelf) {
  2007. if (node && !domUtils.isBody(node)) {
  2008. node = includeSelf ? node : node.parentNode;
  2009. while (node) {
  2010. if (!filterFn || filterFn(node) || domUtils.isBody(node)) {
  2011. return filterFn && !filterFn(node) && domUtils.isBody(node) ? null : node;
  2012. }
  2013. node = node.parentNode;
  2014. }
  2015. }
  2016. return null;
  2017. },
  2018. /**
  2019. * 查找node的节点名为tagName的第一个祖先节点, 查找的起点是node节点的父节点。
  2020. * @method findParentByTagName
  2021. * @param { Node } node 需要查找的节点对象
  2022. * @param { Array } tagNames 需要查找的父节点的名称数组
  2023. * @warning 查找的终点是到body节点为止
  2024. * @return { Node | NULL } 如果找到符合条件的节点, 则返回该节点, 否则返回NULL
  2025. * @example
  2026. * ```javascript
  2027. * var node = UE.dom.domUtils.findParentByTagName( document.getElementsByTagName("div")[0], [ "BODY" ] );
  2028. * //output: BODY
  2029. * console.log( node.tagName );
  2030. * ```
  2031. */
  2032. /**
  2033. * 查找node的节点名为tagName的祖先节点, 如果includeSelf的值为true,则查找的起点是给定的节点node,
  2034. * 否则, 起点是node的父节点。
  2035. * @method findParentByTagName
  2036. * @param { Node } node 需要查找的节点对象
  2037. * @param { Array } tagNames 需要查找的父节点的名称数组
  2038. * @param { Boolean } includeSelf 查找过程是否包含node节点自身
  2039. * @warning 查找的终点是到body节点为止
  2040. * @return { Node | NULL } 如果找到符合条件的节点, 则返回该节点, 否则返回NULL
  2041. * @example
  2042. * ```javascript
  2043. * var queryTarget = document.getElementsByTagName("div")[0];
  2044. * var node = UE.dom.domUtils.findParentByTagName( queryTarget, [ "DIV" ], true );
  2045. * //output: true
  2046. * console.log( queryTarget === node );
  2047. * ```
  2048. */
  2049. findParentByTagName:function (node, tagNames, includeSelf, excludeFn) {
  2050. tagNames = utils.listToMap(utils.isArray(tagNames) ? tagNames : [tagNames]);
  2051. return domUtils.findParent(node, function (node) {
  2052. return tagNames[node.tagName] && !(excludeFn && excludeFn(node));
  2053. }, includeSelf);
  2054. },
  2055. /**
  2056. * 查找节点node的祖先节点集合, 查找的起点是给定节点的父节点,结果集中不包含给定的节点。
  2057. * @method findParents
  2058. * @param { Node } node 需要查找的节点对象
  2059. * @return { Array } 给定节点的祖先节点数组
  2060. * @grammar UE.dom.domUtils.findParents(node) => Array //返回一个祖先节点数组集合,不包含自身
  2061. * @grammar UE.dom.domUtils.findParents(node,includeSelf) => Array //返回一个祖先节点数组集合,includeSelf指定是否包含自身
  2062. * @grammar UE.dom.domUtils.findParents(node,includeSelf,filterFn) => Array //返回一个祖先节点数组集合,filterFn指定过滤条件,返回true的node将被选取
  2063. * @grammar UE.dom.domUtils.findParents(node,includeSelf,filterFn,closerFirst) => Array //返回一个祖先节点数组集合,closerFirst为true的话,node的直接父亲节点是数组的第0个
  2064. */
  2065. /**
  2066. * 查找节点node的祖先节点集合, 如果includeSelf的值为true,
  2067. * 则返回的结果集中允许出现当前给定的节点, 否则, 该节点不会出现在其结果集中。
  2068. * @method findParents
  2069. * @param { Node } node 需要查找的节点对象
  2070. * @param { Boolean } includeSelf 查找的结果中是否允许包含当前查找的节点对象
  2071. * @return { Array } 给定节点的祖先节点数组
  2072. */
  2073. findParents:function (node, includeSelf, filterFn, closerFirst) {
  2074. var parents = includeSelf && ( filterFn && filterFn(node) || !filterFn ) ? [node] : [];
  2075. while (node = domUtils.findParent(node, filterFn)) {
  2076. parents.push(node);
  2077. }
  2078. return closerFirst ? parents : parents.reverse();
  2079. },
  2080. /**
  2081. * 在节点node后面插入新节点newNode
  2082. * @method insertAfter
  2083. * @param { Node } node 目标节点
  2084. * @param { Node } newNode 新插入的节点, 该节点将置于目标节点之后
  2085. * @return { Node } 新插入的节点
  2086. */
  2087. insertAfter:function (node, newNode) {
  2088. return node.nextSibling ? node.parentNode.insertBefore(newNode, node.nextSibling):
  2089. node.parentNode.appendChild(newNode);
  2090. },
  2091. /**
  2092. * 删除节点node及其下属的所有节点
  2093. * @method remove
  2094. * @param { Node } node 需要删除的节点对象
  2095. * @return { Node } 返回刚删除的节点对象
  2096. * @example
  2097. * ```html
  2098. * <div id="test">
  2099. * <div id="child">你好</div>
  2100. * </div>
  2101. * <script>
  2102. * UE.dom.domUtils.remove( document.body, false );
  2103. * //output: false
  2104. * console.log( document.getElementById( "child" ) !== null );
  2105. * </script>
  2106. * ```
  2107. */
  2108. /**
  2109. * 删除节点node,并根据keepChildren的值决定是否保留子节点
  2110. * @method remove
  2111. * @param { Node } node 需要删除的节点对象
  2112. * @param { Boolean } keepChildren 是否需要保留子节点
  2113. * @return { Node } 返回刚删除的节点对象
  2114. * @example
  2115. * ```html
  2116. * <div id="test">
  2117. * <div id="child">你好</div>
  2118. * </div>
  2119. * <script>
  2120. * UE.dom.domUtils.remove( document.body, true );
  2121. * //output: true
  2122. * console.log( document.getElementById( "child" ) !== null );
  2123. * </script>
  2124. * ```
  2125. */
  2126. remove:function (node, keepChildren) {
  2127. var parent = node.parentNode,
  2128. child;
  2129. if (parent) {
  2130. if (keepChildren && node.hasChildNodes()) {
  2131. while (child = node.firstChild) {
  2132. parent.insertBefore(child, node);
  2133. }
  2134. }
  2135. parent.removeChild(node);
  2136. }
  2137. return node;
  2138. },
  2139. /**
  2140. * 取得node节点的下一个兄弟节点, 如果该节点其后没有兄弟节点, 则递归查找其父节点之后的第一个兄弟节点,
  2141. * 直到找到满足条件的节点或者递归到BODY节点之后才会结束。
  2142. * @method getNextDomNode
  2143. * @param { Node } node 需要获取其后的兄弟节点的节点对象
  2144. * @return { Node | NULL } 如果找满足条件的节点, 则返回该节点, 否则返回NULL
  2145. * @example
  2146. * ```html
  2147. * <body>
  2148. * <div id="test">
  2149. * <span></span>
  2150. * </div>
  2151. * <i>xxx</i>
  2152. * </body>
  2153. * <script>
  2154. *
  2155. * //output: i节点
  2156. * console.log( UE.dom.domUtils.getNextDomNode( document.getElementById( "test" ) ) );
  2157. *
  2158. * </script>
  2159. * ```
  2160. * @example
  2161. * ```html
  2162. * <body>
  2163. * <div>
  2164. * <span></span>
  2165. * <i id="test">xxx</i>
  2166. * </div>
  2167. * <b>xxx</b>
  2168. * </body>
  2169. * <script>
  2170. *
  2171. * //由于id为test的i节点之后没有兄弟节点, 则查找其父节点(div)后面的兄弟节点
  2172. * //output: b节点
  2173. * console.log( UE.dom.domUtils.getNextDomNode( document.getElementById( "test" ) ) );
  2174. *
  2175. * </script>
  2176. * ```
  2177. */
  2178. /**
  2179. * 取得node节点的下一个兄弟节点, 如果startFromChild的值为ture,则先获取其子节点,
  2180. * 如果有子节点则直接返回第一个子节点;如果没有子节点或者startFromChild的值为false,
  2181. * 则执行<a href="#UE.dom.domUtils.getNextDomNode(Node)">getNextDomNode(Node node)</a>的查找过程。
  2182. * @method getNextDomNode
  2183. * @param { Node } node 需要获取其后的兄弟节点的节点对象
  2184. * @param { Boolean } startFromChild 查找过程是否从其子节点开始
  2185. * @return { Node | NULL } 如果找满足条件的节点, 则返回该节点, 否则返回NULL
  2186. * @see UE.dom.domUtils.getNextDomNode(Node)
  2187. */
  2188. getNextDomNode:function (node, startFromChild, filterFn, guard) {
  2189. return getDomNode(node, 'firstChild', 'nextSibling', startFromChild, filterFn, guard);
  2190. },
  2191. getPreDomNode:function (node, startFromChild, filterFn, guard) {
  2192. return getDomNode(node, 'lastChild', 'previousSibling', startFromChild, filterFn, guard);
  2193. },
  2194. /**
  2195. * 检测节点node是否属是UEditor定义的bookmark节点
  2196. * @method isBookmarkNode
  2197. * @private
  2198. * @param { Node } node 需要检测的节点对象
  2199. * @return { Boolean } 是否是bookmark节点
  2200. * @example
  2201. * ```html
  2202. * <span id="_baidu_bookmark_1"></span>
  2203. * <script>
  2204. * var bookmarkNode = document.getElementById("_baidu_bookmark_1");
  2205. * //output: true
  2206. * console.log( UE.dom.domUtils.isBookmarkNode( bookmarkNode ) );
  2207. * </script>
  2208. * ```
  2209. */
  2210. isBookmarkNode:function (node) {
  2211. return node.nodeType == 1 && node.id && /^_baidu_bookmark_/i.test(node.id);
  2212. },
  2213. /**
  2214. * 获取节点node所属的window对象
  2215. * @method getWindow
  2216. * @param { Node } node 节点对象
  2217. * @return { Window } 当前节点所属的window对象
  2218. * @example
  2219. * ```javascript
  2220. * //output: true
  2221. * console.log( UE.dom.domUtils.getWindow( document.body ) === window );
  2222. * ```
  2223. */
  2224. getWindow:function (node) {
  2225. var doc = node.ownerDocument || node;
  2226. return doc.defaultView || doc.parentWindow;
  2227. },
  2228. /**
  2229. * 获取离nodeA与nodeB最近的公共的祖先节点
  2230. * @method getCommonAncestor
  2231. * @param { Node } nodeA 第一个节点
  2232. * @param { Node } nodeB 第二个节点
  2233. * @remind 如果给定的两个节点是同一个节点, 将直接返回该节点。
  2234. * @return { Node | NULL } 如果未找到公共节点, 返回NULL, 否则返回最近的公共祖先节点。
  2235. * @example
  2236. * ```javascript
  2237. * var commonAncestor = UE.dom.domUtils.getCommonAncestor( document.body, document.body.firstChild );
  2238. * //output: true
  2239. * console.log( commonAncestor.tagName.toLowerCase() === 'body' );
  2240. * ```
  2241. */
  2242. getCommonAncestor:function (nodeA, nodeB) {
  2243. if (nodeA === nodeB)
  2244. return nodeA;
  2245. var parentsA = [nodeA] , parentsB = [nodeB], parent = nodeA, i = -1;
  2246. while (parent = parent.parentNode) {
  2247. if (parent === nodeB) {
  2248. return parent;
  2249. }
  2250. parentsA.push(parent);
  2251. }
  2252. parent = nodeB;
  2253. while (parent = parent.parentNode) {
  2254. if (parent === nodeA)
  2255. return parent;
  2256. parentsB.push(parent);
  2257. }
  2258. parentsA.reverse();
  2259. parentsB.reverse();
  2260. while (i++, parentsA[i] === parentsB[i]) {
  2261. }
  2262. return i == 0 ? null : parentsA[i - 1];
  2263. },
  2264. /**
  2265. * 清除node节点左右连续为空的兄弟inline节点
  2266. * @method clearEmptySibling
  2267. * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
  2268. * 则这些兄弟节点将被删除
  2269. * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext) //ignoreNext指定是否忽略右边空节点
  2270. * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext,ignorePre) //ignorePre指定是否忽略左边空节点
  2271. * @example
  2272. * ```html
  2273. * <body>
  2274. * <div></div>
  2275. * <span id="test"></span>
  2276. * <i></i>
  2277. * <b></b>
  2278. * <em>xxx</em>
  2279. * <span></span>
  2280. * </body>
  2281. * <script>
  2282. *
  2283. * UE.dom.domUtils.clearEmptySibling( document.getElementById( "test" ) );
  2284. *
  2285. * //output: <div></div><span id="test"></span><em>xxx</em><span></span>
  2286. * console.log( document.body.innerHTML );
  2287. *
  2288. * </script>
  2289. * ```
  2290. */
  2291. /**
  2292. * 清除node节点左右连续为空的兄弟inline节点, 如果ignoreNext的值为true,
  2293. * 则忽略对右边兄弟节点的操作。
  2294. * @method clearEmptySibling
  2295. * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
  2296. * @param { Boolean } ignoreNext 是否忽略忽略对右边的兄弟节点的操作
  2297. * 则这些兄弟节点将被删除
  2298. * @see UE.dom.domUtils.clearEmptySibling(Node)
  2299. */
  2300. /**
  2301. * 清除node节点左右连续为空的兄弟inline节点, 如果ignoreNext的值为true,
  2302. * 则忽略对右边兄弟节点的操作, 如果ignorePre的值为true,则忽略对左边兄弟节点的操作。
  2303. * @method clearEmptySibling
  2304. * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
  2305. * @param { Boolean } ignoreNext 是否忽略忽略对右边的兄弟节点的操作
  2306. * @param { Boolean } ignorePre 是否忽略忽略对左边的兄弟节点的操作
  2307. * 则这些兄弟节点将被删除
  2308. * @see UE.dom.domUtils.clearEmptySibling(Node)
  2309. */
  2310. clearEmptySibling:function (node, ignoreNext, ignorePre) {
  2311. function clear(next, dir) {
  2312. var tmpNode;
  2313. while (next && !domUtils.isBookmarkNode(next) && (domUtils.isEmptyInlineElement(next)
  2314. //这里不能把空格算进来会吧空格干掉,出现文字间的空格丢掉了
  2315. || !new RegExp('[^\t\n\r' + domUtils.fillChar + ']').test(next.nodeValue) )) {
  2316. tmpNode = next[dir];
  2317. domUtils.remove(next);
  2318. next = tmpNode;
  2319. }
  2320. }
  2321. !ignoreNext && clear(node.nextSibling, 'nextSibling');
  2322. !ignorePre && clear(node.previousSibling, 'previousSibling');
  2323. },
  2324. /**
  2325. * 将一个文本节点textNode拆分成两个文本节点,offset指定拆分位置
  2326. * @method split
  2327. * @param { Node } textNode 需要拆分的文本节点对象
  2328. * @param { int } offset 需要拆分的位置, 位置计算从0开始
  2329. * @return { Node } 拆分后形成的新节点
  2330. * @example
  2331. * ```html
  2332. * <div id="test">abcdef</div>
  2333. * <script>
  2334. * var newNode = UE.dom.domUtils.split( document.getElementById( "test" ).firstChild, 3 );
  2335. * //output: def
  2336. * console.log( newNode.nodeValue );
  2337. * </script>
  2338. * ```
  2339. */
  2340. split:function (node, offset) {
  2341. var doc = node.ownerDocument;
  2342. if (browser.ie && offset == node.nodeValue.length) {
  2343. var next = doc.createTextNode('');
  2344. return domUtils.insertAfter(node, next);
  2345. }
  2346. var retval = node.splitText(offset);
  2347. //ie8下splitText不会跟新childNodes,我们手动触发他的更新
  2348. if (browser.ie8) {
  2349. var tmpNode = doc.createTextNode('');
  2350. domUtils.insertAfter(retval, tmpNode);
  2351. domUtils.remove(tmpNode);
  2352. }
  2353. return retval;
  2354. },
  2355. /**
  2356. * 检测文本节点textNode是否为空节点(包括空格、换行、占位符等字符)
  2357. * @method isWhitespace
  2358. * @param { Node } node 需要检测的节点对象
  2359. * @return { Boolean } 检测的节点是否为空
  2360. * @example
  2361. * ```html
  2362. * <div id="test">
  2363. *
  2364. * </div>
  2365. * <script>
  2366. * //output: true
  2367. * console.log( UE.dom.domUtils.isWhitespace( document.getElementById("test").firstChild ) );
  2368. * </script>
  2369. * ```
  2370. */
  2371. isWhitespace:function (node) {
  2372. return !new RegExp('[^ \t\n\r' + domUtils.fillChar + ']').test(node.nodeValue);
  2373. },
  2374. /**
  2375. * 获取元素element相对于viewport的位置坐标
  2376. * @method getXY
  2377. * @param { Node } element 需要计算位置的节点对象
  2378. * @return { Object } 返回形如{x:left,y:top}的一个key-value映射对象, 其中键x代表水平偏移距离,
  2379. * y代表垂直偏移距离。
  2380. *
  2381. * @example
  2382. * ```javascript
  2383. * var location = UE.dom.domUtils.getXY( document.getElementById("test") );
  2384. * //output: test的坐标为: 12, 24
  2385. * console.log( 'test的坐标为: ', location.x, ',', location.y );
  2386. * ```
  2387. */
  2388. getXY:function (element) {
  2389. var x = 0, y = 0;
  2390. while (element.offsetParent) {
  2391. y += element.offsetTop;
  2392. x += element.offsetLeft;
  2393. element = element.offsetParent;
  2394. }
  2395. return { 'x':x, 'y':y};
  2396. },
  2397. /**
  2398. * 为元素element绑定原生DOM事件,type为事件类型,handler为处理函数
  2399. * @method on
  2400. * @param { Node } element 需要绑定事件的节点对象
  2401. * @param { String } type 绑定的事件类型
  2402. * @param { Function } handler 事件处理器
  2403. * @example
  2404. * ```javascript
  2405. * UE.dom.domUtils.on(document.body,"click",function(e){
  2406. * //e为事件对象,this为被点击元素对戏那个
  2407. * });
  2408. * ```
  2409. */
  2410. /**
  2411. * 为元素element绑定原生DOM事件,type为事件类型,handler为处理函数
  2412. * @method on
  2413. * @param { Node } element 需要绑定事件的节点对象
  2414. * @param { Array } type 绑定的事件类型数组
  2415. * @param { Function } handler 事件处理器
  2416. * @example
  2417. * ```javascript
  2418. * UE.dom.domUtils.on(document.body,["click","mousedown"],function(evt){
  2419. * //evt为事件对象,this为被点击元素对象
  2420. * });
  2421. * ```
  2422. */
  2423. on:function (element, type, handler) {
  2424. var types = utils.isArray(type) ? type : utils.trim(type).split(/\s+/),
  2425. k = types.length;
  2426. if (k) while (k--) {
  2427. type = types[k];
  2428. if (element.addEventListener) {
  2429. element.addEventListener(type, handler, false);
  2430. } else {
  2431. if (!handler._d) {
  2432. handler._d = {
  2433. els : []
  2434. };
  2435. }
  2436. var key = type + handler.toString(),index = utils.indexOf(handler._d.els,element);
  2437. if (!handler._d[key] || index == -1) {
  2438. if(index == -1){
  2439. handler._d.els.push(element);
  2440. }
  2441. if(!handler._d[key]){
  2442. handler._d[key] = function (evt) {
  2443. return handler.call(evt.srcElement, evt || window.event);
  2444. };
  2445. }
  2446. element.attachEvent('on' + type, handler._d[key]);
  2447. }
  2448. }
  2449. }
  2450. element = null;
  2451. },
  2452. /**
  2453. * 解除DOM事件绑定
  2454. * @method un
  2455. * @param { Node } element 需要解除事件绑定的节点对象
  2456. * @param { String } type 需要接触绑定的事件类型
  2457. * @param { Function } handler 对应的事件处理器
  2458. * @example
  2459. * ```javascript
  2460. * UE.dom.domUtils.un(document.body,"click",function(evt){
  2461. * //evt为事件对象,this为被点击元素对象
  2462. * });
  2463. * ```
  2464. */
  2465. /**
  2466. * 解除DOM事件绑定
  2467. * @method un
  2468. * @param { Node } element 需要解除事件绑定的节点对象
  2469. * @param { Array } type 需要接触绑定的事件类型数组
  2470. * @param { Function } handler 对应的事件处理器
  2471. * @example
  2472. * ```javascript
  2473. * UE.dom.domUtils.un(document.body, ["click","mousedown"],function(evt){
  2474. * //evt为事件对象,this为被点击元素对象
  2475. * });
  2476. * ```
  2477. */
  2478. un:function (element, type, handler) {
  2479. var types = utils.isArray(type) ? type : utils.trim(type).split(/\s+/),
  2480. k = types.length;
  2481. if (k) while (k--) {
  2482. type = types[k];
  2483. if (element.removeEventListener) {
  2484. element.removeEventListener(type, handler, false);
  2485. } else {
  2486. var key = type + handler.toString();
  2487. try{
  2488. element.detachEvent('on' + type, handler._d ? handler._d[key] : handler);
  2489. }catch(e){}
  2490. if (handler._d && handler._d[key]) {
  2491. var index = utils.indexOf(handler._d.els,element);
  2492. if(index!=-1){
  2493. handler._d.els.splice(index,1);
  2494. }
  2495. handler._d.els.length == 0 && delete handler._d[key];
  2496. }
  2497. }
  2498. }
  2499. },
  2500. /**
  2501. * 比较节点nodeA与节点nodeB是否具有相同的标签名、属性名以及属性值
  2502. * @method isSameElement
  2503. * @param { Node } nodeA 需要比较的节点
  2504. * @param { Node } nodeB 需要比较的节点
  2505. * @return { Boolean } 两个节点是否具有相同的标签名、属性名以及属性值
  2506. * @example
  2507. * ```html
  2508. * <span style="font-size:12px">ssss</span>
  2509. * <span style="font-size:12px">bbbbb</span>
  2510. * <span style="font-size:13px">ssss</span>
  2511. * <span style="font-size:14px">bbbbb</span>
  2512. *
  2513. * <script>
  2514. *
  2515. * var nodes = document.getElementsByTagName( "span" );
  2516. *
  2517. * //output: true
  2518. * console.log( UE.dom.domUtils.isSameElement( nodes[0], nodes[1] ) );
  2519. *
  2520. * //output: false
  2521. * console.log( UE.dom.domUtils.isSameElement( nodes[2], nodes[3] ) );
  2522. *
  2523. * </script>
  2524. * ```
  2525. */
  2526. isSameElement:function (nodeA, nodeB) {
  2527. if (nodeA.tagName != nodeB.tagName) {
  2528. return false;
  2529. }
  2530. var thisAttrs = nodeA.attributes,
  2531. otherAttrs = nodeB.attributes;
  2532. if (!ie && thisAttrs.length != otherAttrs.length) {
  2533. return false;
  2534. }
  2535. var attrA, attrB, al = 0, bl = 0;
  2536. for (var i = 0; attrA = thisAttrs[i++];) {
  2537. if (attrA.nodeName == 'style') {
  2538. if (attrA.specified) {
  2539. al++;
  2540. }
  2541. if (domUtils.isSameStyle(nodeA, nodeB)) {
  2542. continue;
  2543. } else {
  2544. return false;
  2545. }
  2546. }
  2547. if (ie) {
  2548. if (attrA.specified) {
  2549. al++;
  2550. attrB = otherAttrs.getNamedItem(attrA.nodeName);
  2551. } else {
  2552. continue;
  2553. }
  2554. } else {
  2555. attrB = nodeB.attributes[attrA.nodeName];
  2556. }
  2557. if (!attrB.specified || attrA.nodeValue != attrB.nodeValue) {
  2558. return false;
  2559. }
  2560. }
  2561. // 有可能attrB的属性包含了attrA的属性之外还有自己的属性
  2562. if (ie) {
  2563. for (i = 0; attrB = otherAttrs[i++];) {
  2564. if (attrB.specified) {
  2565. bl++;
  2566. }
  2567. }
  2568. if (al != bl) {
  2569. return false;
  2570. }
  2571. }
  2572. return true;
  2573. },
  2574. /**
  2575. * 判断节点nodeA与节点nodeB的元素的style属性是否一致
  2576. * @method isSameStyle
  2577. * @param { Node } nodeA 需要比较的节点
  2578. * @param { Node } nodeB 需要比较的节点
  2579. * @return { Boolean } 两个节点是否具有相同的style属性值
  2580. * @example
  2581. * ```html
  2582. * <span style="font-size:12px">ssss</span>
  2583. * <span style="font-size:12px">bbbbb</span>
  2584. * <span style="font-size:13px">ssss</span>
  2585. * <span style="font-size:14px">bbbbb</span>
  2586. *
  2587. * <script>
  2588. *
  2589. * var nodes = document.getElementsByTagName( "span" );
  2590. *
  2591. * //output: true
  2592. * console.log( UE.dom.domUtils.isSameStyle( nodes[0], nodes[1] ) );
  2593. *
  2594. * //output: false
  2595. * console.log( UE.dom.domUtils.isSameStyle( nodes[2], nodes[3] ) );
  2596. *
  2597. * </script>
  2598. * ```
  2599. */
  2600. isSameStyle:function (nodeA, nodeB) {
  2601. var styleA = nodeA.style.cssText.replace(/( ?; ?)/g, ';').replace(/( ?: ?)/g, ':'),
  2602. styleB = nodeB.style.cssText.replace(/( ?; ?)/g, ';').replace(/( ?: ?)/g, ':');
  2603. if (browser.opera) {
  2604. styleA = nodeA.style;
  2605. styleB = nodeB.style;
  2606. if (styleA.length != styleB.length)
  2607. return false;
  2608. for (var p in styleA) {
  2609. if (/^(\d+|csstext)$/i.test(p)) {
  2610. continue;
  2611. }
  2612. if (styleA[p] != styleB[p]) {
  2613. return false;
  2614. }
  2615. }
  2616. return true;
  2617. }
  2618. if (!styleA || !styleB) {
  2619. return styleA == styleB;
  2620. }
  2621. styleA = styleA.split(';');
  2622. styleB = styleB.split(';');
  2623. if (styleA.length != styleB.length) {
  2624. return false;
  2625. }
  2626. for (var i = 0, ci; ci = styleA[i++];) {
  2627. if (utils.indexOf(styleB, ci) == -1) {
  2628. return false;
  2629. }
  2630. }
  2631. return true;
  2632. },
  2633. /**
  2634. * 检查节点node是否为block元素
  2635. * @method isBlockElm
  2636. * @param { Node } node 需要检测的节点对象
  2637. * @return { Boolean } 是否是block元素节点
  2638. * @warning 该方法的判断规则如下: 如果该元素原本是block元素, 则不论该元素当前的css样式是什么都会返回true;
  2639. * 否则,检测该元素的css样式, 如果该元素当前是block元素, 则返回true。 其余情况下都返回false。
  2640. * @example
  2641. * ```html
  2642. * <span id="test1" style="display: block"></span>
  2643. * <span id="test2"></span>
  2644. * <div id="test3" style="display: inline"></div>
  2645. *
  2646. * <script>
  2647. *
  2648. * //output: true
  2649. * console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test1") ) );
  2650. *
  2651. * //output: false
  2652. * console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test2") ) );
  2653. *
  2654. * //output: true
  2655. * console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test3") ) );
  2656. *
  2657. * </script>
  2658. * ```
  2659. */
  2660. isBlockElm:function (node) {
  2661. return node.nodeType == 1 && (dtd.$block[node.tagName] || styleBlock[domUtils.getComputedStyle(node, 'display')]) && !dtd.$nonChild[node.tagName];
  2662. },
  2663. /**
  2664. * 检测node节点是否为body节点
  2665. * @method isBody
  2666. * @param { Element } node 需要检测的dom元素
  2667. * @return { Boolean } 给定的元素是否是body元素
  2668. * @example
  2669. * ```javascript
  2670. * //output: true
  2671. * console.log( UE.dom.domUtils.isBody( document.body ) );
  2672. * ```
  2673. */
  2674. isBody:function (node) {
  2675. return node && node.nodeType == 1 && node.tagName.toLowerCase() == 'body';
  2676. },
  2677. /**
  2678. * 以node节点为分界,将该节点的指定祖先节点parent拆分成两个独立的节点,
  2679. * 拆分形成的两个节点之间是node节点
  2680. * @method breakParent
  2681. * @param { Node } node 作为分界的节点对象
  2682. * @param { Node } parent 该节点必须是node节点的祖先节点, 且是block节点。
  2683. * @return { Node } 给定的node分界节点
  2684. * @example
  2685. * ```javascript
  2686. *
  2687. * var node = document.createElement("span"),
  2688. * wrapNode = document.createElement( "div" ),
  2689. * parent = document.createElement("p");
  2690. *
  2691. * parent.appendChild( node );
  2692. * wrapNode.appendChild( parent );
  2693. *
  2694. * //拆分前
  2695. * //output: <p><span></span></p>
  2696. * console.log( wrapNode.innerHTML );
  2697. *
  2698. *
  2699. * UE.dom.domUtils.breakParent( node, parent );
  2700. * //拆分后
  2701. * //output: <p></p><span></span><p></p>
  2702. * console.log( wrapNode.innerHTML );
  2703. *
  2704. * ```
  2705. */
  2706. breakParent:function (node, parent) {
  2707. var tmpNode,
  2708. parentClone = node,
  2709. clone = node,
  2710. leftNodes,
  2711. rightNodes;
  2712. do {
  2713. parentClone = parentClone.parentNode;
  2714. if (leftNodes) {
  2715. tmpNode = parentClone.cloneNode(false);
  2716. tmpNode.appendChild(leftNodes);
  2717. leftNodes = tmpNode;
  2718. tmpNode = parentClone.cloneNode(false);
  2719. tmpNode.appendChild(rightNodes);
  2720. rightNodes = tmpNode;
  2721. } else {
  2722. leftNodes = parentClone.cloneNode(false);
  2723. rightNodes = leftNodes.cloneNode(false);
  2724. }
  2725. while (tmpNode = clone.previousSibling) {
  2726. leftNodes.insertBefore(tmpNode, leftNodes.firstChild);
  2727. }
  2728. while (tmpNode = clone.nextSibling) {
  2729. rightNodes.appendChild(tmpNode);
  2730. }
  2731. clone = parentClone;
  2732. } while (parent !== parentClone);
  2733. tmpNode = parent.parentNode;
  2734. tmpNode.insertBefore(leftNodes, parent);
  2735. tmpNode.insertBefore(rightNodes, parent);
  2736. tmpNode.insertBefore(node, rightNodes);
  2737. domUtils.remove(parent);
  2738. return node;
  2739. },
  2740. /**
  2741. * 检查节点node是否是空inline节点
  2742. * @method isEmptyInlineElement
  2743. * @param { Node } node 需要检测的节点对象
  2744. * @return { Number } 如果给定的节点是空的inline节点, 则返回1, 否则返回0。
  2745. * @example
  2746. * ```html
  2747. * <b><i></i></b> => 1
  2748. * <b><i></i><u></u></b> => 1
  2749. * <b></b> => 1
  2750. * <b>xx<i></i></b> => 0
  2751. * ```
  2752. */
  2753. isEmptyInlineElement:function (node) {
  2754. if (node.nodeType != 1 || !dtd.$removeEmpty[ node.tagName ]) {
  2755. return 0;
  2756. }
  2757. node = node.firstChild;
  2758. while (node) {
  2759. //如果是创建的bookmark就跳过
  2760. if (domUtils.isBookmarkNode(node)) {
  2761. return 0;
  2762. }
  2763. if (node.nodeType == 1 && !domUtils.isEmptyInlineElement(node) ||
  2764. node.nodeType == 3 && !domUtils.isWhitespace(node)
  2765. ) {
  2766. return 0;
  2767. }
  2768. node = node.nextSibling;
  2769. }
  2770. return 1;
  2771. },
  2772. /**
  2773. * 删除node节点下首尾两端的空白文本子节点
  2774. * @method trimWhiteTextNode
  2775. * @param { Element } node 需要执行删除操作的元素对象
  2776. * @example
  2777. * ```javascript
  2778. * var node = document.createElement("div");
  2779. *
  2780. * node.appendChild( document.createTextNode( "" ) );
  2781. *
  2782. * node.appendChild( document.createElement("div") );
  2783. *
  2784. * node.appendChild( document.createTextNode( "" ) );
  2785. *
  2786. * //3
  2787. * console.log( node.childNodes.length );
  2788. *
  2789. * UE.dom.domUtils.trimWhiteTextNode( node );
  2790. *
  2791. * //1
  2792. * console.log( node.childNodes.length );
  2793. * ```
  2794. */
  2795. trimWhiteTextNode:function (node) {
  2796. function remove(dir) {
  2797. var child;
  2798. while ((child = node[dir]) && child.nodeType == 3 && domUtils.isWhitespace(child)) {
  2799. node.removeChild(child);
  2800. }
  2801. }
  2802. remove('firstChild');
  2803. remove('lastChild');
  2804. },
  2805. /**
  2806. * 合并node节点下相同的子节点
  2807. * @name mergeChild
  2808. * @desc
  2809. * UE.dom.domUtils.mergeChild(node,tagName) //tagName要合并的子节点的标签
  2810. * @example
  2811. * <p><span style="font-size:12px;">xx<span style="font-size:12px;">aa</span>xx</span></p>
  2812. * ==> UE.dom.domUtils.mergeChild(node,'span')
  2813. * <p><span style="font-size:12px;">xxaaxx</span></p>
  2814. */
  2815. mergeChild:function (node, tagName, attrs) {
  2816. var list = domUtils.getElementsByTagName(node, node.tagName.toLowerCase());
  2817. for (var i = 0, ci; ci = list[i++];) {
  2818. if (!ci.parentNode || domUtils.isBookmarkNode(ci)) {
  2819. continue;
  2820. }
  2821. //span单独处理
  2822. if (ci.tagName.toLowerCase() == 'span') {
  2823. if (node === ci.parentNode) {
  2824. domUtils.trimWhiteTextNode(node);
  2825. if (node.childNodes.length == 1) {
  2826. node.style.cssText = ci.style.cssText + ";" + node.style.cssText;
  2827. domUtils.remove(ci, true);
  2828. continue;
  2829. }
  2830. }
  2831. ci.style.cssText = node.style.cssText + ';' + ci.style.cssText;
  2832. if (attrs) {
  2833. var style = attrs.style;
  2834. if (style) {
  2835. style = style.split(';');
  2836. for (var j = 0, s; s = style[j++];) {
  2837. ci.style[utils.cssStyleToDomStyle(s.split(':')[0])] = s.split(':')[1];
  2838. }
  2839. }
  2840. }
  2841. if (domUtils.isSameStyle(ci, node)) {
  2842. domUtils.remove(ci, true);
  2843. }
  2844. continue;
  2845. }
  2846. if (domUtils.isSameElement(node, ci)) {
  2847. domUtils.remove(ci, true);
  2848. }
  2849. }
  2850. },
  2851. /**
  2852. * 原生方法getElementsByTagName的封装
  2853. * @method getElementsByTagName
  2854. * @param { Node } node 目标节点对象
  2855. * @param { String } tagName 需要查找的节点的tagName, 多个tagName以空格分割
  2856. * @return { Array } 符合条件的节点集合
  2857. */
  2858. getElementsByTagName:function (node, name,filter) {
  2859. if(filter && utils.isString(filter)){
  2860. var className = filter;
  2861. filter = function(node){return domUtils.hasClass(node,className)}
  2862. }
  2863. name = utils.trim(name).replace(/[ ]{2,}/g,' ').split(' ');
  2864. var arr = [];
  2865. for(var n = 0,ni;ni=name[n++];){
  2866. var list = node.getElementsByTagName(ni);
  2867. for (var i = 0, ci; ci = list[i++];) {
  2868. if(!filter || filter(ci))
  2869. arr.push(ci);
  2870. }
  2871. }
  2872. return arr;
  2873. },
  2874. /**
  2875. * 将节点node提取到父节点上
  2876. * @method mergeToParent
  2877. * @param { Element } node 需要提取的元素对象
  2878. * @example
  2879. * ```html
  2880. * <div id="parent">
  2881. * <div id="sub">
  2882. * <span id="child"></span>
  2883. * </div>
  2884. * </div>
  2885. *
  2886. * <script>
  2887. *
  2888. * var child = document.getElementById( "child" );
  2889. *
  2890. * //output: sub
  2891. * console.log( child.parentNode.id );
  2892. *
  2893. * UE.dom.domUtils.mergeToParent( child );
  2894. *
  2895. * //output: parent
  2896. * console.log( child.parentNode.id );
  2897. *
  2898. * </script>
  2899. * ```
  2900. */
  2901. mergeToParent:function (node) {
  2902. var parent = node.parentNode;
  2903. while (parent && dtd.$removeEmpty[parent.tagName]) {
  2904. if (parent.tagName == node.tagName || parent.tagName == 'A') {//针对a标签单独处理
  2905. domUtils.trimWhiteTextNode(parent);
  2906. //span需要特殊处理 不处理这样的情况 <span stlye="color:#fff">xxx<span style="color:#ccc">xxx</span>xxx</span>
  2907. if (parent.tagName == 'SPAN' && !domUtils.isSameStyle(parent, node)
  2908. || (parent.tagName == 'A' && node.tagName == 'SPAN')) {
  2909. if (parent.childNodes.length > 1 || parent !== node.parentNode) {
  2910. node.style.cssText = parent.style.cssText + ";" + node.style.cssText;
  2911. parent = parent.parentNode;
  2912. continue;
  2913. } else {
  2914. parent.style.cssText += ";" + node.style.cssText;
  2915. //trace:952 a标签要保持下划线
  2916. if (parent.tagName == 'A') {
  2917. parent.style.textDecoration = 'underline';
  2918. }
  2919. }
  2920. }
  2921. if (parent.tagName != 'A') {
  2922. parent === node.parentNode && domUtils.remove(node, true);
  2923. break;
  2924. }
  2925. }
  2926. parent = parent.parentNode;
  2927. }
  2928. },
  2929. /**
  2930. * 合并节点node的左右兄弟节点
  2931. * @method mergeSibling
  2932. * @param { Element } node 需要合并的目标节点
  2933. * @example
  2934. * ```html
  2935. * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
  2936. *
  2937. * <script>
  2938. * var demoNode = document.getElementById("test");
  2939. * UE.dom.domUtils.mergeSibling( demoNode );
  2940. * //output: xxxxoooxxxx
  2941. * console.log( demoNode.innerHTML );
  2942. * </script>
  2943. * ```
  2944. */
  2945. /**
  2946. * 合并节点node的左右兄弟节点, 可以根据给定的条件选择是否忽略合并左节点。
  2947. * @method mergeSibling
  2948. * @param { Element } node 需要合并的目标节点
  2949. * @param { Boolean } ignorePre 是否忽略合并左节点
  2950. * @example
  2951. * ```html
  2952. * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
  2953. *
  2954. * <script>
  2955. * var demoNode = document.getElementById("test");
  2956. * UE.dom.domUtils.mergeSibling( demoNode, true );
  2957. * //output: oooxxxx
  2958. * console.log( demoNode.innerHTML );
  2959. * </script>
  2960. * ```
  2961. */
  2962. /**
  2963. * 合并节点node的左右兄弟节点,可以根据给定的条件选择是否忽略合并左右节点。
  2964. * @method mergeSibling
  2965. * @param { Element } node 需要合并的目标节点
  2966. * @param { Boolean } ignorePre 是否忽略合并左节点
  2967. * @param { Boolean } ignoreNext 是否忽略合并右节点
  2968. * @remind 如果同时忽略左右节点, 则该操作什么也不会做
  2969. * @example
  2970. * ```html
  2971. * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
  2972. *
  2973. * <script>
  2974. * var demoNode = document.getElementById("test");
  2975. * UE.dom.domUtils.mergeSibling( demoNode, false, true );
  2976. * //output: xxxxooo
  2977. * console.log( demoNode.innerHTML );
  2978. * </script>
  2979. * ```
  2980. */
  2981. mergeSibling:function (node, ignorePre, ignoreNext) {
  2982. function merge(rtl, start, node) {
  2983. var next;
  2984. if ((next = node[rtl]) && !domUtils.isBookmarkNode(next) && next.nodeType == 1 && domUtils.isSameElement(node, next)) {
  2985. while (next.firstChild) {
  2986. if (start == 'firstChild') {
  2987. node.insertBefore(next.lastChild, node.firstChild);
  2988. } else {
  2989. node.appendChild(next.firstChild);
  2990. }
  2991. }
  2992. domUtils.remove(next);
  2993. }
  2994. }
  2995. !ignorePre && merge('previousSibling', 'firstChild', node);
  2996. !ignoreNext && merge('nextSibling', 'lastChild', node);
  2997. },
  2998. /**
  2999. * 设置节点node及其子节点不会被选中
  3000. * @method unSelectable
  3001. * @param { Element } node 需要执行操作的dom元素
  3002. * @remind 执行该操作后的节点, 将不能被鼠标选中
  3003. * @example
  3004. * ```javascript
  3005. * UE.dom.domUtils.unSelectable( document.body );
  3006. * ```
  3007. */
  3008. unSelectable:ie && browser.ie9below || browser.opera ? function (node) {
  3009. //for ie9
  3010. node.onselectstart = function () {
  3011. return false;
  3012. };
  3013. node.onclick = node.onkeyup = node.onkeydown = function () {
  3014. return false;
  3015. };
  3016. node.unselectable = 'on';
  3017. node.setAttribute("unselectable", "on");
  3018. for (var i = 0, ci; ci = node.all[i++];) {
  3019. switch (ci.tagName.toLowerCase()) {
  3020. case 'iframe' :
  3021. case 'textarea' :
  3022. case 'input' :
  3023. case 'select' :
  3024. break;
  3025. default :
  3026. ci.unselectable = 'on';
  3027. node.setAttribute("unselectable", "on");
  3028. }
  3029. }
  3030. } : function (node) {
  3031. node.style.MozUserSelect =
  3032. node.style.webkitUserSelect =
  3033. node.style.msUserSelect =
  3034. node.style.KhtmlUserSelect = 'none';
  3035. },
  3036. /**
  3037. * 删除节点node上的指定属性名称的属性
  3038. * @method removeAttributes
  3039. * @param { Node } node 需要删除属性的节点对象
  3040. * @param { String } attrNames 可以是空格隔开的多个属性名称,该操作将会依次删除相应的属性
  3041. * @example
  3042. * ```html
  3043. * <div id="wrap">
  3044. * <span style="font-size:14px;" id="test" name="followMe">xxxxx</span>
  3045. * </div>
  3046. *
  3047. * <script>
  3048. *
  3049. * UE.dom.domUtils.removeAttributes( document.getElementById( "test" ), "id name" );
  3050. *
  3051. * //output: <span style="font-size:14px;">xxxxx</span>
  3052. * console.log( document.getElementById("wrap").innerHTML );
  3053. *
  3054. * </script>
  3055. * ```
  3056. */
  3057. /**
  3058. * 删除节点node上的指定属性名称的属性
  3059. * @method removeAttributes
  3060. * @param { Node } node 需要删除属性的节点对象
  3061. * @param { Array } attrNames 需要删除的属性名数组
  3062. * @example
  3063. * ```html
  3064. * <div id="wrap">
  3065. * <span style="font-size:14px;" id="test" name="followMe">xxxxx</span>
  3066. * </div>
  3067. *
  3068. * <script>
  3069. *
  3070. * UE.dom.domUtils.removeAttributes( document.getElementById( "test" ), ["id", "name"] );
  3071. *
  3072. * //output: <span style="font-size:14px;">xxxxx</span>
  3073. * console.log( document.getElementById("wrap").innerHTML );
  3074. *
  3075. * </script>
  3076. * ```
  3077. */
  3078. removeAttributes:function (node, attrNames) {
  3079. attrNames = utils.isArray(attrNames) ? attrNames : utils.trim(attrNames).replace(/[ ]{2,}/g,' ').split(' ');
  3080. for (var i = 0, ci; ci = attrNames[i++];) {
  3081. ci = attrFix[ci] || ci;
  3082. switch (ci) {
  3083. case 'className':
  3084. node[ci] = '';
  3085. break;
  3086. case 'style':
  3087. node.style.cssText = '';
  3088. var val = node.getAttributeNode('style');
  3089. !browser.ie && val && node.removeAttributeNode(val);
  3090. }
  3091. node.removeAttribute(ci);
  3092. }
  3093. },
  3094. /**
  3095. * 在doc下创建一个标签名为tag,属性为attrs的元素
  3096. * @method createElement
  3097. * @param { DomDocument } doc 新创建的元素属于该document节点创建
  3098. * @param { String } tagName 需要创建的元素的标签名
  3099. * @param { Object } attrs 新创建的元素的属性key-value集合
  3100. * @return { Element } 新创建的元素对象
  3101. * @example
  3102. * ```javascript
  3103. * var ele = UE.dom.domUtils.createElement( document, 'div', {
  3104. * id: 'test'
  3105. * } );
  3106. *
  3107. * //output: DIV
  3108. * console.log( ele.tagName );
  3109. *
  3110. * //output: test
  3111. * console.log( ele.id );
  3112. *
  3113. * ```
  3114. */
  3115. createElement:function (doc, tag, attrs) {
  3116. return domUtils.setAttributes(doc.createElement(tag), attrs)
  3117. },
  3118. /**
  3119. * 为节点node添加属性attrs,attrs为属性键值对
  3120. * @method setAttributes
  3121. * @param { Element } node 需要设置属性的元素对象
  3122. * @param { Object } attrs 需要设置的属性名-值对
  3123. * @return { Element } 设置属性的元素对象
  3124. * @example
  3125. * ```html
  3126. * <span id="test"></span>
  3127. *
  3128. * <script>
  3129. *
  3130. * var testNode = UE.dom.domUtils.setAttributes( document.getElementById( "test" ), {
  3131. * id: 'demo'
  3132. * } );
  3133. *
  3134. * //output: demo
  3135. * console.log( testNode.id );
  3136. *
  3137. * </script>
  3138. *
  3139. */
  3140. setAttributes:function (node, attrs) {
  3141. for (var attr in attrs) {
  3142. if(attrs.hasOwnProperty(attr)){
  3143. var value = attrs[attr];
  3144. switch (attr) {
  3145. case 'class':
  3146. //ie下要这样赋值,setAttribute不起作用
  3147. node.className = value;
  3148. break;
  3149. case 'style' :
  3150. node.style.cssText = node.style.cssText + ";" + value;
  3151. break;
  3152. case 'innerHTML':
  3153. node[attr] = value;
  3154. break;
  3155. case 'value':
  3156. node.value = value;
  3157. break;
  3158. default:
  3159. node.setAttribute(attrFix[attr] || attr, value);
  3160. }
  3161. }
  3162. }
  3163. return node;
  3164. },
  3165. /**
  3166. * 获取元素element经过计算后的样式值
  3167. * @method getComputedStyle
  3168. * @param { Element } element 需要获取样式的元素对象
  3169. * @param { String } styleName 需要获取的样式名
  3170. * @return { String } 获取到的样式值
  3171. * @example
  3172. * ```html
  3173. * <style type="text/css">
  3174. * #test {
  3175. * font-size: 15px;
  3176. * }
  3177. * </style>
  3178. *
  3179. * <span id="test"></span>
  3180. *
  3181. * <script>
  3182. * //output: 15px
  3183. * console.log( UE.dom.domUtils.getComputedStyle( document.getElementById( "test" ), 'font-size' ) );
  3184. * </script>
  3185. * ```
  3186. */
  3187. getComputedStyle:function (element, styleName) {
  3188. //一下的属性单独处理
  3189. var pros = 'width height top left';
  3190. if(pros.indexOf(styleName) > -1){
  3191. return element['offset' + styleName.replace(/^\w/,function(s){return s.toUpperCase()})] + 'px';
  3192. }
  3193. //忽略文本节点
  3194. if (element.nodeType == 3) {
  3195. element = element.parentNode;
  3196. }
  3197. //ie下font-size若body下定义了font-size,则从currentStyle里会取到这个font-size. 取不到实际值,故此修改.
  3198. if (browser.ie && browser.version < 9 && styleName == 'font-size' && !element.style.fontSize &&
  3199. !dtd.$empty[element.tagName] && !dtd.$nonChild[element.tagName]) {
  3200. var span = element.ownerDocument.createElement('span');
  3201. span.style.cssText = 'padding:0;border:0;font-family:simsun;';
  3202. span.innerHTML = '.';
  3203. element.appendChild(span);
  3204. var result = span.offsetHeight;
  3205. element.removeChild(span);
  3206. span = null;
  3207. return result + 'px';
  3208. }
  3209. try {
  3210. var value = domUtils.getStyle(element, styleName) ||
  3211. (window.getComputedStyle ? domUtils.getWindow(element).getComputedStyle(element, '').getPropertyValue(styleName) :
  3212. ( element.currentStyle || element.style )[utils.cssStyleToDomStyle(styleName)]);
  3213. } catch (e) {
  3214. return "";
  3215. }
  3216. return utils.transUnitToPx(utils.fixColor(styleName, value));
  3217. },
  3218. /**
  3219. * 删除元素element指定的className
  3220. * @method removeClasses
  3221. * @param { Element } ele 需要删除class的元素节点
  3222. * @param { String } classNames 需要删除的className, 多个className之间以空格分开
  3223. * @example
  3224. * ```html
  3225. * <span id="test" class="test1 test2 test3">xxx</span>
  3226. *
  3227. * <script>
  3228. *
  3229. * var testNode = document.getElementById( "test" );
  3230. * UE.dom.domUtils.removeClasses( testNode, "test1 test2" );
  3231. *
  3232. * //output: test3
  3233. * console.log( testNode.className );
  3234. *
  3235. * </script>
  3236. * ```
  3237. */
  3238. /**
  3239. * 删除元素element指定的className
  3240. * @method removeClasses
  3241. * @param { Element } ele 需要删除class的元素节点
  3242. * @param { Array } classNames 需要删除的className数组
  3243. * @example
  3244. * ```html
  3245. * <span id="test" class="test1 test2 test3">xxx</span>
  3246. *
  3247. * <script>
  3248. *
  3249. * var testNode = document.getElementById( "test" );
  3250. * UE.dom.domUtils.removeClasses( testNode, ["test1", "test2"] );
  3251. *
  3252. * //output: test3
  3253. * console.log( testNode.className );
  3254. *
  3255. * </script>
  3256. * ```
  3257. */
  3258. removeClasses:function (elm, classNames) {
  3259. classNames = utils.isArray(classNames) ? classNames :
  3260. utils.trim(classNames).replace(/[ ]{2,}/g,' ').split(' ');
  3261. for(var i = 0,ci,cls = elm.className;ci=classNames[i++];){
  3262. cls = cls.replace(new RegExp('\\b' + ci + '\\b'),'')
  3263. }
  3264. cls = utils.trim(cls).replace(/[ ]{2,}/g,' ');
  3265. if(cls){
  3266. elm.className = cls;
  3267. }else{
  3268. domUtils.removeAttributes(elm,['class']);
  3269. }
  3270. },
  3271. /**
  3272. * 给元素element添加className
  3273. * @method addClass
  3274. * @param { Node } ele 需要增加className的元素
  3275. * @param { String } classNames 需要添加的className, 多个className之间以空格分割
  3276. * @remind 相同的类名不会被重复添加
  3277. * @example
  3278. * ```html
  3279. * <span id="test" class="cls1 cls2"></span>
  3280. *
  3281. * <script>
  3282. * var testNode = document.getElementById("test");
  3283. *
  3284. * UE.dom.domUtils.addClass( testNode, "cls2 cls3 cls4" );
  3285. *
  3286. * //output: cl1 cls2 cls3 cls4
  3287. * console.log( testNode.className );
  3288. *
  3289. * <script>
  3290. * ```
  3291. */
  3292. /**
  3293. * 给元素element添加className
  3294. * @method addClass
  3295. * @param { Node } ele 需要增加className的元素
  3296. * @param { Array } classNames 需要添加的className的数组
  3297. * @remind 相同的类名不会被重复添加
  3298. * @example
  3299. * ```html
  3300. * <span id="test" class="cls1 cls2"></span>
  3301. *
  3302. * <script>
  3303. * var testNode = document.getElementById("test");
  3304. *
  3305. * UE.dom.domUtils.addClass( testNode, ["cls2", "cls3", "cls4"] );
  3306. *
  3307. * //output: cl1 cls2 cls3 cls4
  3308. * console.log( testNode.className );
  3309. *
  3310. * <script>
  3311. * ```
  3312. */
  3313. addClass:function (elm, classNames) {
  3314. if(!elm)return;
  3315. classNames = utils.trim(classNames).replace(/[ ]{2,}/g,' ').split(' ');
  3316. for(var i = 0,ci,cls = elm.className;ci=classNames[i++];){
  3317. if(!new RegExp('\\b' + ci + '\\b').test(cls)){
  3318. cls += ' ' + ci;
  3319. }
  3320. }
  3321. elm.className = utils.trim(cls);
  3322. },
  3323. /**
  3324. * 判断元素element是否包含给定的样式类名className
  3325. * @method hasClass
  3326. * @param { Node } ele 需要检测的元素
  3327. * @param { String } classNames 需要检测的className, 多个className之间用空格分割
  3328. * @return { Boolean } 元素是否包含所有给定的className
  3329. * @example
  3330. * ```html
  3331. * <span id="test1" class="cls1 cls2"></span>
  3332. *
  3333. * <script>
  3334. * var test1 = document.getElementById("test1");
  3335. *
  3336. * //output: false
  3337. * console.log( UE.dom.domUtils.hasClass( test1, "cls2 cls1 cls3" ) );
  3338. *
  3339. * //output: true
  3340. * console.log( UE.dom.domUtils.hasClass( test1, "cls2 cls1" ) );
  3341. * </script>
  3342. * ```
  3343. */
  3344. /**
  3345. * 判断元素element是否包含给定的样式类名className
  3346. * @method hasClass
  3347. * @param { Node } ele 需要检测的元素
  3348. * @param { Array } classNames 需要检测的className数组
  3349. * @return { Boolean } 元素是否包含所有给定的className
  3350. * @example
  3351. * ```html
  3352. * <span id="test1" class="cls1 cls2"></span>
  3353. *
  3354. * <script>
  3355. * var test1 = document.getElementById("test1");
  3356. *
  3357. * //output: false
  3358. * console.log( UE.dom.domUtils.hasClass( test1, [ "cls2", "cls1", "cls3" ] ) );
  3359. *
  3360. * //output: true
  3361. * console.log( UE.dom.domUtils.hasClass( test1, [ "cls2", "cls1" ]) );
  3362. * </script>
  3363. * ```
  3364. */
  3365. hasClass:function (element, className) {
  3366. if(utils.isRegExp(className)){
  3367. return className.test(element.className)
  3368. }
  3369. className = utils.trim(className).replace(/[ ]{2,}/g,' ').split(' ');
  3370. for(var i = 0,ci,cls = element.className;ci=className[i++];){
  3371. if(!new RegExp('\\b' + ci + '\\b','i').test(cls)){
  3372. return false;
  3373. }
  3374. }
  3375. return i - 1 == className.length;
  3376. },
  3377. /**
  3378. * 阻止事件默认行为
  3379. * @method preventDefault
  3380. * @param { Event } evt 需要阻止默认行为的事件对象
  3381. * @example
  3382. * ```javascript
  3383. * UE.dom.domUtils.preventDefault( evt );
  3384. * ```
  3385. */
  3386. preventDefault:function (evt) {
  3387. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  3388. },
  3389. /**
  3390. * 删除元素element指定的样式
  3391. * @method removeStyle
  3392. * @param { Element } element 需要删除样式的元素
  3393. * @param { String } styleName 需要删除的样式名
  3394. * @example
  3395. * ```html
  3396. * <span id="test" style="color: red; background: blue;"></span>
  3397. *
  3398. * <script>
  3399. *
  3400. * var testNode = document.getElementById("test");
  3401. *
  3402. * UE.dom.domUtils.removeStyle( testNode, 'color' );
  3403. *
  3404. * //output: background: blue;
  3405. * console.log( testNode.style.cssText );
  3406. *
  3407. * </script>
  3408. * ```
  3409. */
  3410. removeStyle:function (element, name) {
  3411. if(browser.ie ){
  3412. //针对color先单独处理一下
  3413. if(name == 'color'){
  3414. name = '(^|;)' + name;
  3415. }
  3416. element.style.cssText = element.style.cssText.replace(new RegExp(name + '[^:]*:[^;]+;?','ig'),'')
  3417. }else{
  3418. if (element.style.removeProperty) {
  3419. element.style.removeProperty (name);
  3420. }else {
  3421. element.style.removeAttribute (utils.cssStyleToDomStyle(name));
  3422. }
  3423. }
  3424. if (!element.style.cssText) {
  3425. domUtils.removeAttributes(element, ['style']);
  3426. }
  3427. },
  3428. /**
  3429. * 获取元素element的style属性的指定值
  3430. * @method getStyle
  3431. * @param { Element } element 需要获取属性值的元素
  3432. * @param { String } styleName 需要获取的style的名称
  3433. * @warning 该方法仅获取元素style属性中所标明的值
  3434. * @return { String } 该元素包含指定的style属性值
  3435. * @example
  3436. * ```html
  3437. * <div id="test" style="color: red;"></div>
  3438. *
  3439. * <script>
  3440. *
  3441. * var testNode = document.getElementById( "test" );
  3442. *
  3443. * //output: red
  3444. * console.log( UE.dom.domUtils.getStyle( testNode, "color" ) );
  3445. *
  3446. * //output: ""
  3447. * console.log( UE.dom.domUtils.getStyle( testNode, "background" ) );
  3448. *
  3449. * </script>
  3450. * ```
  3451. */
  3452. getStyle:function (element, name) {
  3453. var value = element.style[ utils.cssStyleToDomStyle(name) ];
  3454. return utils.fixColor(name, value);
  3455. },
  3456. /**
  3457. * 为元素element设置样式属性值
  3458. * @method setStyle
  3459. * @param { Element } element 需要设置样式的元素
  3460. * @param { String } styleName 样式名
  3461. * @param { String } styleValue 样式值
  3462. * @example
  3463. * ```html
  3464. * <div id="test"></div>
  3465. *
  3466. * <script>
  3467. *
  3468. * var testNode = document.getElementById( "test" );
  3469. *
  3470. * //output: ""
  3471. * console.log( testNode.style.color );
  3472. *
  3473. * UE.dom.domUtils.setStyle( testNode, 'color', 'red' );
  3474. * //output: "red"
  3475. * console.log( testNode.style.color );
  3476. *
  3477. * </script>
  3478. * ```
  3479. */
  3480. setStyle:function (element, name, value) {
  3481. element.style[utils.cssStyleToDomStyle(name)] = value;
  3482. if(!utils.trim(element.style.cssText)){
  3483. this.removeAttributes(element,'style')
  3484. }
  3485. },
  3486. /**
  3487. * 为元素element设置多个样式属性值
  3488. * @method setStyles
  3489. * @param { Element } element 需要设置样式的元素
  3490. * @param { Object } styles 样式名值对
  3491. * @example
  3492. * ```html
  3493. * <div id="test"></div>
  3494. *
  3495. * <script>
  3496. *
  3497. * var testNode = document.getElementById( "test" );
  3498. *
  3499. * //output: ""
  3500. * console.log( testNode.style.color );
  3501. *
  3502. * UE.dom.domUtils.setStyles( testNode, {
  3503. * 'color': 'red'
  3504. * } );
  3505. * //output: "red"
  3506. * console.log( testNode.style.color );
  3507. *
  3508. * </script>
  3509. * ```
  3510. */
  3511. setStyles:function (element, styles) {
  3512. for (var name in styles) {
  3513. if (styles.hasOwnProperty(name)) {
  3514. domUtils.setStyle(element, name, styles[name]);
  3515. }
  3516. }
  3517. },
  3518. /**
  3519. * 删除_moz_dirty属性
  3520. * @private
  3521. * @method removeDirtyAttr
  3522. */
  3523. removeDirtyAttr:function (node) {
  3524. for (var i = 0, ci, nodes = node.getElementsByTagName('*'); ci = nodes[i++];) {
  3525. ci.removeAttribute('_moz_dirty');
  3526. }
  3527. node.removeAttribute('_moz_dirty');
  3528. },
  3529. /**
  3530. * 获取子节点的数量
  3531. * @method getChildCount
  3532. * @param { Element } node 需要检测的元素
  3533. * @return { Number } 给定的node元素的子节点数量
  3534. * @example
  3535. * ```html
  3536. * <div id="test">
  3537. * <span></span>
  3538. * </div>
  3539. *
  3540. * <script>
  3541. *
  3542. * //output: 3
  3543. * console.log( UE.dom.domUtils.getChildCount( document.getElementById("test") ) );
  3544. *
  3545. * </script>
  3546. * ```
  3547. */
  3548. /**
  3549. * 根据给定的过滤规则, 获取符合条件的子节点的数量
  3550. * @method getChildCount
  3551. * @param { Element } node 需要检测的元素
  3552. * @param { Function } fn 过滤器, 要求对符合条件的子节点返回true, 反之则要求返回false
  3553. * @return { Number } 符合过滤条件的node元素的子节点数量
  3554. * @example
  3555. * ```html
  3556. * <div id="test">
  3557. * <span></span>
  3558. * </div>
  3559. *
  3560. * <script>
  3561. *
  3562. * //output: 1
  3563. * console.log( UE.dom.domUtils.getChildCount( document.getElementById("test"), function ( node ) {
  3564. *
  3565. * return node.nodeType === 1;
  3566. *
  3567. * } ) );
  3568. *
  3569. * </script>
  3570. * ```
  3571. */
  3572. getChildCount:function (node, fn) {
  3573. var count = 0, first = node.firstChild;
  3574. fn = fn || function () {
  3575. return 1;
  3576. };
  3577. while (first) {
  3578. if (fn(first)) {
  3579. count++;
  3580. }
  3581. first = first.nextSibling;
  3582. }
  3583. return count;
  3584. },
  3585. /**
  3586. * 判断给定节点是否为空节点
  3587. * @method isEmptyNode
  3588. * @param { Node } node 需要检测的节点对象
  3589. * @return { Boolean } 节点是否为空
  3590. * @example
  3591. * ```javascript
  3592. * UE.dom.domUtils.isEmptyNode( document.body );
  3593. * ```
  3594. */
  3595. isEmptyNode:function (node) {
  3596. return !node.firstChild || domUtils.getChildCount(node, function (node) {
  3597. return !domUtils.isBr(node) && !domUtils.isBookmarkNode(node) && !domUtils.isWhitespace(node)
  3598. }) == 0
  3599. },
  3600. clearSelectedArr:function (nodes) {
  3601. var node;
  3602. while (node = nodes.pop()) {
  3603. domUtils.removeAttributes(node, ['class']);
  3604. }
  3605. },
  3606. /**
  3607. * 将显示区域滚动到指定节点的位置
  3608. * @method scrollToView
  3609. * @param {Node} node 节点
  3610. * @param {window} win window对象
  3611. * @param {Number} offsetTop 距离上方的偏移量
  3612. */
  3613. scrollToView:function (node, win, offsetTop) {
  3614. var getViewPaneSize = function () {
  3615. var doc = win.document,
  3616. mode = doc.compatMode == 'CSS1Compat';
  3617. return {
  3618. width:( mode ? doc.documentElement.clientWidth : doc.body.clientWidth ) || 0,
  3619. height:( mode ? doc.documentElement.clientHeight : doc.body.clientHeight ) || 0
  3620. };
  3621. },
  3622. getScrollPosition = function (win) {
  3623. if ('pageXOffset' in win) {
  3624. return {
  3625. x:win.pageXOffset || 0,
  3626. y:win.pageYOffset || 0
  3627. };
  3628. }
  3629. else {
  3630. var doc = win.document;
  3631. return {
  3632. x:doc.documentElement.scrollLeft || doc.body.scrollLeft || 0,
  3633. y:doc.documentElement.scrollTop || doc.body.scrollTop || 0
  3634. };
  3635. }
  3636. };
  3637. var winHeight = getViewPaneSize().height, offset = winHeight * -1 + offsetTop;
  3638. offset += (node.offsetHeight || 0);
  3639. var elementPosition = domUtils.getXY(node);
  3640. offset += elementPosition.y;
  3641. var currentScroll = getScrollPosition(win).y;
  3642. // offset += 50;
  3643. if (offset > currentScroll || offset < currentScroll - winHeight) {
  3644. win.scrollTo(0, offset + (offset < 0 ? -20 : 20));
  3645. }
  3646. },
  3647. /**
  3648. * 判断给定节点是否为br
  3649. * @method isBr
  3650. * @param { Node } node 需要判断的节点对象
  3651. * @return { Boolean } 给定的节点是否是br节点
  3652. */
  3653. isBr:function (node) {
  3654. return node.nodeType == 1 && node.tagName == 'BR';
  3655. },
  3656. /**
  3657. * 判断给定的节点是否是一个“填充”节点
  3658. * @private
  3659. * @method isFillChar
  3660. * @param { Node } node 需要判断的节点
  3661. * @param { Boolean } isInStart 是否从节点内容的开始位置匹配
  3662. * @returns { Boolean } 节点是否是填充节点
  3663. */
  3664. isFillChar:function (node,isInStart) {
  3665. if(node.nodeType != 3)
  3666. return false;
  3667. var text = node.nodeValue;
  3668. if(isInStart){
  3669. return new RegExp('^' + domUtils.fillChar).test(text)
  3670. }
  3671. return !text.replace(new RegExp(domUtils.fillChar,'g'), '').length
  3672. },
  3673. isStartInblock:function (range) {
  3674. var tmpRange = range.cloneRange(),
  3675. flag = 0,
  3676. start = tmpRange.startContainer,
  3677. tmp;
  3678. if(start.nodeType == 1 && start.childNodes[tmpRange.startOffset]){
  3679. start = start.childNodes[tmpRange.startOffset];
  3680. var pre = start.previousSibling;
  3681. while(pre && domUtils.isFillChar(pre)){
  3682. start = pre;
  3683. pre = pre.previousSibling;
  3684. }
  3685. }
  3686. if(this.isFillChar(start,true) && tmpRange.startOffset == 1){
  3687. tmpRange.setStartBefore(start);
  3688. start = tmpRange.startContainer;
  3689. }
  3690. while (start && domUtils.isFillChar(start)) {
  3691. tmp = start;
  3692. start = start.previousSibling
  3693. }
  3694. if (tmp) {
  3695. tmpRange.setStartBefore(tmp);
  3696. start = tmpRange.startContainer;
  3697. }
  3698. if (start.nodeType == 1 && domUtils.isEmptyNode(start) && tmpRange.startOffset == 1) {
  3699. tmpRange.setStart(start, 0).collapse(true);
  3700. }
  3701. while (!tmpRange.startOffset) {
  3702. start = tmpRange.startContainer;
  3703. if (domUtils.isBlockElm(start) || domUtils.isBody(start)) {
  3704. flag = 1;
  3705. break;
  3706. }
  3707. var pre = tmpRange.startContainer.previousSibling,
  3708. tmpNode;
  3709. if (!pre) {
  3710. tmpRange.setStartBefore(tmpRange.startContainer);
  3711. } else {
  3712. while (pre && domUtils.isFillChar(pre)) {
  3713. tmpNode = pre;
  3714. pre = pre.previousSibling;
  3715. }
  3716. if (tmpNode) {
  3717. tmpRange.setStartBefore(tmpNode);
  3718. } else {
  3719. tmpRange.setStartBefore(tmpRange.startContainer);
  3720. }
  3721. }
  3722. }
  3723. return flag && !domUtils.isBody(tmpRange.startContainer) ? 1 : 0;
  3724. },
  3725. /**
  3726. * 判断给定的元素是否是一个空元素
  3727. * @method isEmptyBlock
  3728. * @param { Element } node 需要判断的元素
  3729. * @return { Boolean } 是否是空元素
  3730. * @example
  3731. * ```html
  3732. * <div id="test"></div>
  3733. *
  3734. * <script>
  3735. * //output: true
  3736. * console.log( UE.dom.domUtils.isEmptyBlock( document.getElementById("test") ) );
  3737. * </script>
  3738. * ```
  3739. */
  3740. /**
  3741. * 根据指定的判断规则判断给定的元素是否是一个空元素
  3742. * @method isEmptyBlock
  3743. * @param { Element } node 需要判断的元素
  3744. * @param { RegExp } reg 对内容执行判断的正则表达式对象
  3745. * @return { Boolean } 是否是空元素
  3746. */
  3747. isEmptyBlock:function (node,reg) {
  3748. // HaoChuan9421
  3749. if(!node){
  3750. return;
  3751. }
  3752. if(node.nodeType != 1)
  3753. return 0;
  3754. reg = reg || new RegExp('[ \xa0\t\r\n' + domUtils.fillChar + ']', 'g');
  3755. if (node[browser.ie ? 'innerText' : 'textContent'].replace(reg, '').length > 0) {
  3756. return 0;
  3757. }
  3758. for (var n in dtd.$isNotEmpty) {
  3759. if (node.getElementsByTagName(n).length) {
  3760. return 0;
  3761. }
  3762. }
  3763. return 1;
  3764. },
  3765. /**
  3766. * 移动元素使得该元素的位置移动指定的偏移量的距离
  3767. * @method setViewportOffset
  3768. * @param { Element } element 需要设置偏移量的元素
  3769. * @param { Object } offset 偏移量, 形如{ left: 100, top: 50 }的一个键值对, 表示该元素将在
  3770. * 现有的位置上向水平方向偏移offset.left的距离, 在竖直方向上偏移
  3771. * offset.top的距离
  3772. * @example
  3773. * ```html
  3774. * <div id="test" style="top: 100px; left: 50px; position: absolute;"></div>
  3775. *
  3776. * <script>
  3777. *
  3778. * var testNode = document.getElementById("test");
  3779. *
  3780. * UE.dom.domUtils.setViewportOffset( testNode, {
  3781. * left: 200,
  3782. * top: 50
  3783. * } );
  3784. *
  3785. * //output: top: 300px; left: 100px; position: absolute;
  3786. * console.log( testNode.style.cssText );
  3787. *
  3788. * </script>
  3789. * ```
  3790. */
  3791. setViewportOffset:function (element, offset) {
  3792. var left = parseInt(element.style.left) | 0;
  3793. var top = parseInt(element.style.top) | 0;
  3794. var rect = element.getBoundingClientRect();
  3795. var offsetLeft = offset.left - rect.left;
  3796. var offsetTop = offset.top - rect.top;
  3797. if (offsetLeft) {
  3798. element.style.left = left + offsetLeft + 'px';
  3799. }
  3800. if (offsetTop) {
  3801. element.style.top = top + offsetTop + 'px';
  3802. }
  3803. },
  3804. /**
  3805. * 用“填充字符”填充节点
  3806. * @method fillNode
  3807. * @private
  3808. * @param { DomDocument } doc 填充的节点所在的docment对象
  3809. * @param { Node } node 需要填充的节点对象
  3810. * @example
  3811. * ```html
  3812. * <div id="test"></div>
  3813. *
  3814. * <script>
  3815. * var testNode = document.getElementById("test");
  3816. *
  3817. * //output: 0
  3818. * console.log( testNode.childNodes.length );
  3819. *
  3820. * UE.dom.domUtils.fillNode( document, testNode );
  3821. *
  3822. * //output: 1
  3823. * console.log( testNode.childNodes.length );
  3824. *
  3825. * </script>
  3826. * ```
  3827. */
  3828. fillNode:function (doc, node) {
  3829. var tmpNode = browser.ie ? doc.createTextNode(domUtils.fillChar) : doc.createElement('br');
  3830. node.innerHTML = '';
  3831. node.appendChild(tmpNode);
  3832. },
  3833. /**
  3834. * 把节点src的所有子节点追加到另一个节点tag上去
  3835. * @method moveChild
  3836. * @param { Node } src 源节点, 该节点下的所有子节点将被移除
  3837. * @param { Node } tag 目标节点, 从源节点移除的子节点将被追加到该节点下
  3838. * @example
  3839. * ```html
  3840. * <div id="test1">
  3841. * <span></span>
  3842. * </div>
  3843. * <div id="test2">
  3844. * <div></div>
  3845. * </div>
  3846. *
  3847. * <script>
  3848. *
  3849. * var test1 = document.getElementById("test1"),
  3850. * test2 = document.getElementById("test2");
  3851. *
  3852. * UE.dom.domUtils.moveChild( test1, test2 );
  3853. *
  3854. * //output: ""(空字符串)
  3855. * console.log( test1.innerHTML );
  3856. *
  3857. * //output: "<div></div><span></span>"
  3858. * console.log( test2.innerHTML );
  3859. *
  3860. * </script>
  3861. * ```
  3862. */
  3863. /**
  3864. * 把节点src的所有子节点移动到另一个节点tag上去, 可以通过dir参数控制附加的行为是“追加”还是“插入顶部”
  3865. * @method moveChild
  3866. * @param { Node } src 源节点, 该节点下的所有子节点将被移除
  3867. * @param { Node } tag 目标节点, 从源节点移除的子节点将被附加到该节点下
  3868. * @param { Boolean } dir 附加方式, 如果为true, 则附加进去的节点将被放到目标节点的顶部, 反之,则放到末尾
  3869. * @example
  3870. * ```html
  3871. * <div id="test1">
  3872. * <span></span>
  3873. * </div>
  3874. * <div id="test2">
  3875. * <div></div>
  3876. * </div>
  3877. *
  3878. * <script>
  3879. *
  3880. * var test1 = document.getElementById("test1"),
  3881. * test2 = document.getElementById("test2");
  3882. *
  3883. * UE.dom.domUtils.moveChild( test1, test2, true );
  3884. *
  3885. * //output: ""(空字符串)
  3886. * console.log( test1.innerHTML );
  3887. *
  3888. * //output: "<span></span><div></div>"
  3889. * console.log( test2.innerHTML );
  3890. *
  3891. * </script>
  3892. * ```
  3893. */
  3894. moveChild:function (src, tag, dir) {
  3895. while (src.firstChild) {
  3896. if (dir && tag.firstChild) {
  3897. tag.insertBefore(src.lastChild, tag.firstChild);
  3898. } else {
  3899. tag.appendChild(src.firstChild);
  3900. }
  3901. }
  3902. },
  3903. /**
  3904. * 判断节点的标签上是否不存在任何属性
  3905. * @method hasNoAttributes
  3906. * @private
  3907. * @param { Node } node 需要检测的节点对象
  3908. * @return { Boolean } 节点是否不包含任何属性
  3909. * @example
  3910. * ```html
  3911. * <div id="test"><span>xxxx</span></div>
  3912. *
  3913. * <script>
  3914. *
  3915. * //output: false
  3916. * console.log( UE.dom.domUtils.hasNoAttributes( document.getElementById("test") ) );
  3917. *
  3918. * //output: true
  3919. * console.log( UE.dom.domUtils.hasNoAttributes( document.getElementById("test").firstChild ) );
  3920. *
  3921. * </script>
  3922. * ```
  3923. */
  3924. hasNoAttributes:function (node) {
  3925. return browser.ie ? /^<\w+\s*?>/.test(node.outerHTML) : node.attributes.length == 0;
  3926. },
  3927. /**
  3928. * 检测节点是否是UEditor所使用的辅助节点
  3929. * @method isCustomeNode
  3930. * @private
  3931. * @param { Node } node 需要检测的节点
  3932. * @remind 辅助节点是指编辑器要完成工作临时添加的节点, 在输出的时候将会从编辑器内移除, 不会影响最终的结果。
  3933. * @return { Boolean } 给定的节点是否是一个辅助节点
  3934. */
  3935. isCustomeNode:function (node) {
  3936. return node.nodeType == 1 && node.getAttribute('_ue_custom_node_');
  3937. },
  3938. /**
  3939. * 检测节点的标签是否是给定的标签
  3940. * @method isTagNode
  3941. * @param { Node } node 需要检测的节点对象
  3942. * @param { String } tagName 标签
  3943. * @return { Boolean } 节点的标签是否是给定的标签
  3944. * @example
  3945. * ```html
  3946. * <div id="test"></div>
  3947. *
  3948. * <script>
  3949. *
  3950. * //output: true
  3951. * console.log( UE.dom.domUtils.isTagNode( document.getElementById("test"), "div" ) );
  3952. *
  3953. * </script>
  3954. * ```
  3955. */
  3956. isTagNode:function (node, tagNames) {
  3957. return node.nodeType == 1 && new RegExp('\\b' + node.tagName + '\\b','i').test(tagNames)
  3958. },
  3959. /**
  3960. * 给定一个节点数组,在通过指定的过滤器过滤后, 获取其中满足过滤条件的第一个节点
  3961. * @method filterNodeList
  3962. * @param { Array } nodeList 需要过滤的节点数组
  3963. * @param { Function } fn 过滤器, 对符合条件的节点, 执行结果返回true, 反之则返回false
  3964. * @return { Node | NULL } 如果找到符合过滤条件的节点, 则返回该节点, 否则返回NULL
  3965. * @example
  3966. * ```javascript
  3967. * var divNodes = document.getElementsByTagName("div");
  3968. * divNodes = [].slice.call( divNodes, 0 );
  3969. *
  3970. * //output: null
  3971. * console.log( UE.dom.domUtils.filterNodeList( divNodes, function ( node ) {
  3972. * return node.tagName.toLowerCase() !== 'div';
  3973. * } ) );
  3974. * ```
  3975. */
  3976. /**
  3977. * 给定一个节点数组nodeList和一组标签名tagNames, 获取其中能够匹配标签名的节点集合中的第一个节点
  3978. * @method filterNodeList
  3979. * @param { Array } nodeList 需要过滤的节点数组
  3980. * @param { String } tagNames 需要匹配的标签名, 多个标签名之间用空格分割
  3981. * @return { Node | NULL } 如果找到标签名匹配的节点, 则返回该节点, 否则返回NULL
  3982. * @example
  3983. * ```javascript
  3984. * var divNodes = document.getElementsByTagName("div");
  3985. * divNodes = [].slice.call( divNodes, 0 );
  3986. *
  3987. * //output: null
  3988. * console.log( UE.dom.domUtils.filterNodeList( divNodes, 'a span' ) );
  3989. * ```
  3990. */
  3991. /**
  3992. * 给定一个节点数组,在通过指定的过滤器过滤后, 如果参数forAll为true, 则会返回所有满足过滤
  3993. * 条件的节点集合, 否则, 返回满足条件的节点集合中的第一个节点
  3994. * @method filterNodeList
  3995. * @param { Array } nodeList 需要过滤的节点数组
  3996. * @param { Function } fn 过滤器, 对符合条件的节点, 执行结果返回true, 反之则返回false
  3997. * @param { Boolean } forAll 是否返回整个节点数组, 如果该参数为false, 则返回节点集合中的第一个节点
  3998. * @return { Array | Node | NULL } 如果找到符合过滤条件的节点, 则根据参数forAll的值决定返回满足
  3999. * 过滤条件的节点数组或第一个节点, 否则返回NULL
  4000. * @example
  4001. * ```javascript
  4002. * var divNodes = document.getElementsByTagName("div");
  4003. * divNodes = [].slice.call( divNodes, 0 );
  4004. *
  4005. * //output: 3(假定有3个div)
  4006. * console.log( divNodes.length );
  4007. *
  4008. * var nodes = UE.dom.domUtils.filterNodeList( divNodes, function ( node ) {
  4009. * return node.tagName.toLowerCase() === 'div';
  4010. * }, true );
  4011. *
  4012. * //output: 3
  4013. * console.log( nodes.length );
  4014. *
  4015. * var node = UE.dom.domUtils.filterNodeList( divNodes, function ( node ) {
  4016. * return node.tagName.toLowerCase() === 'div';
  4017. * }, false );
  4018. *
  4019. * //output: div
  4020. * console.log( node.nodeName );
  4021. * ```
  4022. */
  4023. filterNodeList : function(nodelist,filter,forAll){
  4024. var results = [];
  4025. if(!utils .isFunction(filter)){
  4026. var str = filter;
  4027. filter = function(n){
  4028. return utils.indexOf(utils.isArray(str) ? str:str.split(' '), n.tagName.toLowerCase()) != -1
  4029. };
  4030. }
  4031. utils.each(nodelist,function(n){
  4032. filter(n) && results.push(n)
  4033. });
  4034. return results.length == 0 ? null : results.length == 1 || !forAll ? results[0] : results
  4035. },
  4036. /**
  4037. * 查询给定的range选区是否在给定的node节点内,且在该节点的最末尾
  4038. * @method isInNodeEndBoundary
  4039. * @param { UE.dom.Range } rng 需要判断的range对象, 该对象的startContainer不能为NULL
  4040. * @param node 需要检测的节点对象
  4041. * @return { Number } 如果给定的选取range对象是在node内部的最末端, 则返回1, 否则返回0
  4042. */
  4043. isInNodeEndBoundary : function (rng,node){
  4044. var start = rng.startContainer;
  4045. if(start.nodeType == 3 && rng.startOffset != start.nodeValue.length){
  4046. return 0;
  4047. }
  4048. if(start.nodeType == 1 && rng.startOffset != start.childNodes.length){
  4049. return 0;
  4050. }
  4051. while(start !== node){
  4052. if(start.nextSibling){
  4053. return 0
  4054. };
  4055. start = start.parentNode;
  4056. }
  4057. return 1;
  4058. },
  4059. isBoundaryNode : function (node,dir){
  4060. var tmp;
  4061. while(!domUtils.isBody(node)){
  4062. tmp = node;
  4063. node = node.parentNode;
  4064. if(tmp !== node[dir]){
  4065. return false;
  4066. }
  4067. }
  4068. return true;
  4069. },
  4070. fillHtml : browser.ie11below ? '&nbsp;' : '<br/>'
  4071. };
  4072. var fillCharReg = new RegExp(domUtils.fillChar, 'g');
  4073. // core/Range.js
  4074. /**
  4075. * Range封装
  4076. * @file
  4077. * @module UE.dom
  4078. * @class Range
  4079. * @since 1.2.6.1
  4080. */
  4081. /**
  4082. * dom操作封装
  4083. * @unfile
  4084. * @module UE.dom
  4085. */
  4086. /**
  4087. * Range实现类,本类是UEditor底层核心类,封装不同浏览器之间的Range操作。
  4088. * @unfile
  4089. * @module UE.dom
  4090. * @class Range
  4091. */
  4092. (function () {
  4093. var guid = 0,
  4094. fillChar = domUtils.fillChar,
  4095. fillData;
  4096. /**
  4097. * 更新range的collapse状态
  4098. * @param {Range} range range对象
  4099. */
  4100. function updateCollapse(range) {
  4101. range.collapsed =
  4102. range.startContainer && range.endContainer &&
  4103. range.startContainer === range.endContainer &&
  4104. range.startOffset == range.endOffset;
  4105. }
  4106. function selectOneNode(rng){
  4107. return !rng.collapsed && rng.startContainer.nodeType == 1 && rng.startContainer === rng.endContainer && rng.endOffset - rng.startOffset == 1
  4108. }
  4109. function setEndPoint(toStart, node, offset, range) {
  4110. //如果node是自闭合标签要处理
  4111. if (node.nodeType == 1 && (dtd.$empty[node.tagName] || dtd.$nonChild[node.tagName])) {
  4112. offset = domUtils.getNodeIndex(node) + (toStart ? 0 : 1);
  4113. node = node.parentNode;
  4114. }
  4115. if (toStart) {
  4116. range.startContainer = node;
  4117. range.startOffset = offset;
  4118. if (!range.endContainer) {
  4119. range.collapse(true);
  4120. }
  4121. } else {
  4122. range.endContainer = node;
  4123. range.endOffset = offset;
  4124. if (!range.startContainer) {
  4125. range.collapse(false);
  4126. }
  4127. }
  4128. updateCollapse(range);
  4129. return range;
  4130. }
  4131. function execContentsAction(range, action) {
  4132. //调整边界
  4133. //range.includeBookmark();
  4134. var start = range.startContainer,
  4135. end = range.endContainer,
  4136. startOffset = range.startOffset,
  4137. endOffset = range.endOffset,
  4138. doc = range.document,
  4139. frag = doc.createDocumentFragment(),
  4140. tmpStart, tmpEnd;
  4141. if (start.nodeType == 1) {
  4142. start = start.childNodes[startOffset] || (tmpStart = start.appendChild(doc.createTextNode('')));
  4143. }
  4144. if (end.nodeType == 1) {
  4145. end = end.childNodes[endOffset] || (tmpEnd = end.appendChild(doc.createTextNode('')));
  4146. }
  4147. if (start === end && start.nodeType == 3) {
  4148. frag.appendChild(doc.createTextNode(start.substringData(startOffset, endOffset - startOffset)));
  4149. //is not clone
  4150. if (action) {
  4151. start.deleteData(startOffset, endOffset - startOffset);
  4152. range.collapse(true);
  4153. }
  4154. return frag;
  4155. }
  4156. var current, currentLevel, clone = frag,
  4157. startParents = domUtils.findParents(start, true), endParents = domUtils.findParents(end, true);
  4158. for (var i = 0; startParents[i] == endParents[i];) {
  4159. i++;
  4160. }
  4161. for (var j = i, si; si = startParents[j]; j++) {
  4162. current = si.nextSibling;
  4163. if (si == start) {
  4164. if (!tmpStart) {
  4165. if (range.startContainer.nodeType == 3) {
  4166. clone.appendChild(doc.createTextNode(start.nodeValue.slice(startOffset)));
  4167. //is not clone
  4168. if (action) {
  4169. start.deleteData(startOffset, start.nodeValue.length - startOffset);
  4170. }
  4171. } else {
  4172. clone.appendChild(!action ? start.cloneNode(true) : start);
  4173. }
  4174. }
  4175. } else {
  4176. currentLevel = si.cloneNode(false);
  4177. clone.appendChild(currentLevel);
  4178. }
  4179. while (current) {
  4180. if (current === end || current === endParents[j]) {
  4181. break;
  4182. }
  4183. si = current.nextSibling;
  4184. clone.appendChild(!action ? current.cloneNode(true) : current);
  4185. current = si;
  4186. }
  4187. clone = currentLevel;
  4188. }
  4189. clone = frag;
  4190. if (!startParents[i]) {
  4191. clone.appendChild(startParents[i - 1].cloneNode(false));
  4192. clone = clone.firstChild;
  4193. }
  4194. for (var j = i, ei; ei = endParents[j]; j++) {
  4195. current = ei.previousSibling;
  4196. if (ei == end) {
  4197. if (!tmpEnd && range.endContainer.nodeType == 3) {
  4198. clone.appendChild(doc.createTextNode(end.substringData(0, endOffset)));
  4199. //is not clone
  4200. if (action) {
  4201. end.deleteData(0, endOffset);
  4202. }
  4203. }
  4204. } else {
  4205. currentLevel = ei.cloneNode(false);
  4206. clone.appendChild(currentLevel);
  4207. }
  4208. //如果两端同级,右边第一次已经被开始做了
  4209. if (j != i || !startParents[i]) {
  4210. while (current) {
  4211. if (current === start) {
  4212. break;
  4213. }
  4214. ei = current.previousSibling;
  4215. clone.insertBefore(!action ? current.cloneNode(true) : current, clone.firstChild);
  4216. current = ei;
  4217. }
  4218. }
  4219. clone = currentLevel;
  4220. }
  4221. if (action) {
  4222. range.setStartBefore(!endParents[i] ? endParents[i - 1] : !startParents[i] ? startParents[i - 1] : endParents[i]).collapse(true);
  4223. }
  4224. tmpStart && domUtils.remove(tmpStart);
  4225. tmpEnd && domUtils.remove(tmpEnd);
  4226. return frag;
  4227. }
  4228. /**
  4229. * 创建一个跟document绑定的空的Range实例
  4230. * @constructor
  4231. * @param { Document } document 新建的选区所属的文档对象
  4232. */
  4233. /**
  4234. * @property { Node } startContainer 当前Range的开始边界的容器节点, 可以是一个元素节点或者是文本节点
  4235. */
  4236. /**
  4237. * @property { Node } startOffset 当前Range的开始边界容器节点的偏移量, 如果是元素节点,
  4238. * 该值就是childNodes中的第几个节点, 如果是文本节点就是文本内容的第几个字符
  4239. */
  4240. /**
  4241. * @property { Node } endContainer 当前Range的结束边界的容器节点, 可以是一个元素节点或者是文本节点
  4242. */
  4243. /**
  4244. * @property { Node } endOffset 当前Range的结束边界容器节点的偏移量, 如果是元素节点,
  4245. * 该值就是childNodes中的第几个节点, 如果是文本节点就是文本内容的第几个字符
  4246. */
  4247. /**
  4248. * @property { Boolean } collapsed 当前Range是否闭合
  4249. * @default true
  4250. * @remind Range是闭合的时候, startContainer === endContainer && startOffset === endOffset
  4251. */
  4252. /**
  4253. * @property { Document } document 当前Range所属的Document对象
  4254. * @remind 不同range的的document属性可以是不同的
  4255. */
  4256. var Range = dom.Range = function (document) {
  4257. var me = this;
  4258. me.startContainer =
  4259. me.startOffset =
  4260. me.endContainer =
  4261. me.endOffset = null;
  4262. me.document = document;
  4263. me.collapsed = true;
  4264. };
  4265. /**
  4266. * 删除fillData
  4267. * @param doc
  4268. * @param excludeNode
  4269. */
  4270. function removeFillData(doc, excludeNode) {
  4271. try {
  4272. if (fillData && domUtils.inDoc(fillData, doc)) {
  4273. if (!fillData.nodeValue.replace(fillCharReg, '').length) {
  4274. var tmpNode = fillData.parentNode;
  4275. domUtils.remove(fillData);
  4276. while (tmpNode && domUtils.isEmptyInlineElement(tmpNode) &&
  4277. //safari的contains有bug
  4278. (browser.safari ? !(domUtils.getPosition(tmpNode,excludeNode) & domUtils.POSITION_CONTAINS) : !tmpNode.contains(excludeNode))
  4279. ) {
  4280. fillData = tmpNode.parentNode;
  4281. domUtils.remove(tmpNode);
  4282. tmpNode = fillData;
  4283. }
  4284. } else {
  4285. fillData.nodeValue = fillData.nodeValue.replace(fillCharReg, '');
  4286. }
  4287. }
  4288. } catch (e) {
  4289. }
  4290. }
  4291. /**
  4292. * @param node
  4293. * @param dir
  4294. */
  4295. function mergeSibling(node, dir) {
  4296. var tmpNode;
  4297. node = node[dir];
  4298. while (node && domUtils.isFillChar(node)) {
  4299. tmpNode = node[dir];
  4300. domUtils.remove(node);
  4301. node = tmpNode;
  4302. }
  4303. }
  4304. Range.prototype = {
  4305. /**
  4306. * 克隆选区的内容到一个DocumentFragment里
  4307. * @method cloneContents
  4308. * @return { DocumentFragment | NULL } 如果选区是闭合的将返回null, 否则, 返回包含所clone内容的DocumentFragment元素
  4309. * @example
  4310. * ```html
  4311. * <body>
  4312. * <!-- 中括号表示选区 -->
  4313. * <b>x<i>x[x</i>xx]x</b>
  4314. *
  4315. * <script>
  4316. * //range是已选中的选区
  4317. * var fragment = range.cloneContents(),
  4318. * node = document.createElement("div");
  4319. *
  4320. * node.appendChild( fragment );
  4321. *
  4322. * //output: <i>x</i>xx
  4323. * console.log( node.innerHTML );
  4324. *
  4325. * </script>
  4326. * </body>
  4327. * ```
  4328. */
  4329. cloneContents:function () {
  4330. return this.collapsed ? null : execContentsAction(this, 0);
  4331. },
  4332. /**
  4333. * 删除当前选区范围中的所有内容
  4334. * @method deleteContents
  4335. * @remind 执行完该操作后, 当前Range对象变成了闭合状态
  4336. * @return { UE.dom.Range } 当前操作的Range对象
  4337. * @example
  4338. * ```html
  4339. * <body>
  4340. * <!-- 中括号表示选区 -->
  4341. * <b>x<i>x[x</i>xx]x</b>
  4342. *
  4343. * <script>
  4344. * //range是已选中的选区
  4345. * range.deleteContents();
  4346. *
  4347. * //竖线表示闭合后的选区位置
  4348. * //output: <b>x<i>x</i>|x</b>
  4349. * console.log( document.body.innerHTML );
  4350. *
  4351. * //此时, range的各项属性为
  4352. * //output: B
  4353. * console.log( range.startContainer.tagName );
  4354. * //output: 2
  4355. * console.log( range.startOffset );
  4356. * //output: B
  4357. * console.log( range.endContainer.tagName );
  4358. * //output: 2
  4359. * console.log( range.endOffset );
  4360. * //output: true
  4361. * console.log( range.collapsed );
  4362. *
  4363. * </script>
  4364. * </body>
  4365. * ```
  4366. */
  4367. deleteContents:function () {
  4368. var txt;
  4369. if (!this.collapsed) {
  4370. execContentsAction(this, 1);
  4371. }
  4372. if (browser.webkit) {
  4373. txt = this.startContainer;
  4374. if (txt.nodeType == 3 && !txt.nodeValue.length) {
  4375. this.setStartBefore(txt).collapse(true);
  4376. domUtils.remove(txt);
  4377. }
  4378. }
  4379. return this;
  4380. },
  4381. /**
  4382. * 将当前选区的内容提取到一个DocumentFragment里
  4383. * @method extractContents
  4384. * @remind 执行该操作后, 选区将变成闭合状态
  4385. * @warning 执行该操作后, 原来选区所选中的内容将从dom树上剥离出来
  4386. * @return { DocumentFragment } 返回包含所提取内容的DocumentFragment对象
  4387. * @example
  4388. * ```html
  4389. * <body>
  4390. * <!-- 中括号表示选区 -->
  4391. * <b>x<i>x[x</i>xx]x</b>
  4392. *
  4393. * <script>
  4394. * //range是已选中的选区
  4395. * var fragment = range.extractContents(),
  4396. * node = document.createElement( "div" );
  4397. *
  4398. * node.appendChild( fragment );
  4399. *
  4400. * //竖线表示闭合后的选区位置
  4401. *
  4402. * //output: <b>x<i>x</i>|x</b>
  4403. * console.log( document.body.innerHTML );
  4404. * //output: <i>x</i>xx
  4405. * console.log( node.innerHTML );
  4406. *
  4407. * //此时, range的各项属性为
  4408. * //output: B
  4409. * console.log( range.startContainer.tagName );
  4410. * //output: 2
  4411. * console.log( range.startOffset );
  4412. * //output: B
  4413. * console.log( range.endContainer.tagName );
  4414. * //output: 2
  4415. * console.log( range.endOffset );
  4416. * //output: true
  4417. * console.log( range.collapsed );
  4418. *
  4419. * </script>
  4420. * </body>
  4421. */
  4422. extractContents:function () {
  4423. return this.collapsed ? null : execContentsAction(this, 2);
  4424. },
  4425. /**
  4426. * 设置Range的开始容器节点和偏移量
  4427. * @method setStart
  4428. * @remind 如果给定的节点是元素节点,那么offset指的是其子元素中索引为offset的元素,
  4429. * 如果是文本节点,那么offset指的是其文本内容的第offset个字符
  4430. * @remind 如果提供的容器节点是一个不能包含子元素的节点, 则该选区的开始容器将被设置
  4431. * 为该节点的父节点, 此时, 其距离开始容器的偏移量也变成了该节点在其父节点
  4432. * 中的索引
  4433. * @param { Node } node 将被设为当前选区开始边界容器的节点对象
  4434. * @param { int } offset 选区的开始位置偏移量
  4435. * @return { UE.dom.Range } 当前range对象
  4436. * @example
  4437. * ```html
  4438. * <!-- 选区 -->
  4439. * <b>xxx<i>x<span>xx</span>xx<em>xx</em>xxx</i>[xxx]</b>
  4440. *
  4441. * <script>
  4442. *
  4443. * //执行操作
  4444. * range.setStart( document.getElementsByTagName("i")[0], 1 );
  4445. *
  4446. * //此时, 选区变成了
  4447. * //<b>xxx<i>x[<span>xx</span>xx<em>xx</em>xxx</i>xxx]</b>
  4448. *
  4449. * </script>
  4450. * ```
  4451. * @example
  4452. * ```html
  4453. * <!-- 选区 -->
  4454. * <b>xxx<img>[xx]x</b>
  4455. *
  4456. * <script>
  4457. *
  4458. * //执行操作
  4459. * range.setStart( document.getElementsByTagName("img")[0], 3 );
  4460. *
  4461. * //此时, 选区变成了
  4462. * //<b>xxx[<img>xx]x</b>
  4463. *
  4464. * </script>
  4465. * ```
  4466. */
  4467. setStart:function (node, offset) {
  4468. return setEndPoint(true, node, offset, this);
  4469. },
  4470. /**
  4471. * 设置Range的结束容器和偏移量
  4472. * @method setEnd
  4473. * @param { Node } node 作为当前选区结束边界容器的节点对象
  4474. * @param { int } offset 结束边界的偏移量
  4475. * @see UE.dom.Range:setStart(Node,int)
  4476. * @return { UE.dom.Range } 当前range对象
  4477. */
  4478. setEnd:function (node, offset) {
  4479. return setEndPoint(false, node, offset, this);
  4480. },
  4481. /**
  4482. * 将Range开始位置设置到node节点之后
  4483. * @method setStartAfter
  4484. * @remind 该操作将会把给定节点的父节点作为range的开始容器, 且偏移量是该节点在其父节点中的位置索引+1
  4485. * @param { Node } node 选区的开始边界将紧接着该节点之后
  4486. * @return { UE.dom.Range } 当前range对象
  4487. * @example
  4488. * ```html
  4489. * <!-- 选区示例 -->
  4490. * <b>xx<i>xxx</i><span>xx[x</span>xxx]</b>
  4491. *
  4492. * <script>
  4493. *
  4494. * //执行操作
  4495. * range.setStartAfter( document.getElementsByTagName("i")[0] );
  4496. *
  4497. * //结果选区
  4498. * //<b>xx<i>xxx</i>[<span>xxx</span>xxx]</b>
  4499. *
  4500. * </script>
  4501. * ```
  4502. */
  4503. setStartAfter:function (node) {
  4504. return this.setStart(node.parentNode, domUtils.getNodeIndex(node) + 1);
  4505. },
  4506. /**
  4507. * 将Range开始位置设置到node节点之前
  4508. * @method setStartBefore
  4509. * @remind 该操作将会把给定节点的父节点作为range的开始容器, 且偏移量是该节点在其父节点中的位置索引
  4510. * @param { Node } node 新的选区开始位置在该节点之前
  4511. * @see UE.dom.Range:setStartAfter(Node)
  4512. * @return { UE.dom.Range } 当前range对象
  4513. */
  4514. setStartBefore:function (node) {
  4515. return this.setStart(node.parentNode, domUtils.getNodeIndex(node));
  4516. },
  4517. /**
  4518. * 将Range结束位置设置到node节点之后
  4519. * @method setEndAfter
  4520. * @remind 该操作将会把给定节点的父节点作为range的结束容器, 且偏移量是该节点在其父节点中的位置索引+1
  4521. * @param { Node } node 目标节点
  4522. * @see UE.dom.Range:setStartAfter(Node)
  4523. * @return { UE.dom.Range } 当前range对象
  4524. * @example
  4525. * ```html
  4526. * <!-- 选区示例 -->
  4527. * <b>[xx<i>xxx</i><span>xx]x</span>xxx</b>
  4528. *
  4529. * <script>
  4530. *
  4531. * //执行操作
  4532. * range.setStartAfter( document.getElementsByTagName("span")[0] );
  4533. *
  4534. * //结果选区
  4535. * //<b>[xx<i>xxx</i><span>xxx</span>]xxx</b>
  4536. *
  4537. * </script>
  4538. * ```
  4539. */
  4540. setEndAfter:function (node) {
  4541. return this.setEnd(node.parentNode, domUtils.getNodeIndex(node) + 1);
  4542. },
  4543. /**
  4544. * 将Range结束位置设置到node节点之前
  4545. * @method setEndBefore
  4546. * @remind 该操作将会把给定节点的父节点作为range的结束容器, 且偏移量是该节点在其父节点中的位置索引
  4547. * @param { Node } node 目标节点
  4548. * @see UE.dom.Range:setEndAfter(Node)
  4549. * @return { UE.dom.Range } 当前range对象
  4550. */
  4551. setEndBefore:function (node) {
  4552. return this.setEnd(node.parentNode, domUtils.getNodeIndex(node));
  4553. },
  4554. /**
  4555. * 设置Range的开始位置到node节点内的第一个子节点之前
  4556. * @method setStartAtFirst
  4557. * @remind 选区的开始容器将变成给定的节点, 且偏移量为0
  4558. * @remind 如果给定的节点是元素节点, 则该节点必须是允许包含子节点的元素。
  4559. * @param { Node } node 目标节点
  4560. * @see UE.dom.Range:setStartBefore(Node)
  4561. * @return { UE.dom.Range } 当前range对象
  4562. * @example
  4563. * ```html
  4564. * <!-- 选区示例 -->
  4565. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  4566. *
  4567. * <script>
  4568. *
  4569. * //执行操作
  4570. * range.setStartAtFirst( document.getElementsByTagName("i")[0] );
  4571. *
  4572. * //结果选区
  4573. * //<b>xx<i>[xxx</i><span>xx]x</span>xxx</b>
  4574. *
  4575. * </script>
  4576. * ```
  4577. */
  4578. setStartAtFirst:function (node) {
  4579. return this.setStart(node, 0);
  4580. },
  4581. /**
  4582. * 设置Range的开始位置到node节点内的最后一个节点之后
  4583. * @method setStartAtLast
  4584. * @remind 选区的开始容器将变成给定的节点, 且偏移量为该节点的子节点数
  4585. * @remind 如果给定的节点是元素节点, 则该节点必须是允许包含子节点的元素。
  4586. * @param { Node } node 目标节点
  4587. * @see UE.dom.Range:setStartAtFirst(Node)
  4588. * @return { UE.dom.Range } 当前range对象
  4589. */
  4590. setStartAtLast:function (node) {
  4591. return this.setStart(node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length);
  4592. },
  4593. /**
  4594. * 设置Range的结束位置到node节点内的第一个节点之前
  4595. * @method setEndAtFirst
  4596. * @param { Node } node 目标节点
  4597. * @remind 选区的结束容器将变成给定的节点, 且偏移量为0
  4598. * @remind node必须是一个元素节点, 且必须是允许包含子节点的元素。
  4599. * @see UE.dom.Range:setStartAtFirst(Node)
  4600. * @return { UE.dom.Range } 当前range对象
  4601. */
  4602. setEndAtFirst:function (node) {
  4603. return this.setEnd(node, 0);
  4604. },
  4605. /**
  4606. * 设置Range的结束位置到node节点内的最后一个节点之后
  4607. * @method setEndAtLast
  4608. * @param { Node } node 目标节点
  4609. * @remind 选区的结束容器将变成给定的节点, 且偏移量为该节点的子节点数量
  4610. * @remind node必须是一个元素节点, 且必须是允许包含子节点的元素。
  4611. * @see UE.dom.Range:setStartAtFirst(Node)
  4612. * @return { UE.dom.Range } 当前range对象
  4613. */
  4614. setEndAtLast:function (node) {
  4615. return this.setEnd(node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length);
  4616. },
  4617. /**
  4618. * 选中给定节点
  4619. * @method selectNode
  4620. * @remind 此时, 选区的开始容器和结束容器都是该节点的父节点, 其startOffset是该节点在父节点中的位置索引,
  4621. * 而endOffset为startOffset+1
  4622. * @param { Node } node 需要选中的节点
  4623. * @return { UE.dom.Range } 当前range对象,此时的range仅包含当前给定的节点对象
  4624. * @example
  4625. * ```html
  4626. * <!-- 选区示例 -->
  4627. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  4628. *
  4629. * <script>
  4630. *
  4631. * //执行操作
  4632. * range.selectNode( document.getElementsByTagName("i")[0] );
  4633. *
  4634. * //结果选区
  4635. * //<b>xx[<i>xxx</i>]<span>xxx</span>xxx</b>
  4636. *
  4637. * </script>
  4638. * ```
  4639. */
  4640. selectNode:function (node) {
  4641. return this.setStartBefore(node).setEndAfter(node);
  4642. },
  4643. /**
  4644. * 选中给定节点内部的所有节点
  4645. * @method selectNodeContents
  4646. * @remind 此时, 选区的开始容器和结束容器都是该节点, 其startOffset为0,
  4647. * 而endOffset是该节点的子节点数。
  4648. * @param { Node } node 目标节点, 当前range将包含该节点内的所有节点
  4649. * @return { UE.dom.Range } 当前range对象, 此时range仅包含给定节点的所有子节点
  4650. * @example
  4651. * ```html
  4652. * <!-- 选区示例 -->
  4653. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  4654. *
  4655. * <script>
  4656. *
  4657. * //执行操作
  4658. * range.selectNode( document.getElementsByTagName("b")[0] );
  4659. *
  4660. * //结果选区
  4661. * //<b>[xx<i>xxx</i><span>xxx</span>xxx]</b>
  4662. *
  4663. * </script>
  4664. * ```
  4665. */
  4666. selectNodeContents:function (node) {
  4667. return this.setStart(node, 0).setEndAtLast(node);
  4668. },
  4669. /**
  4670. * clone当前Range对象
  4671. * @method cloneRange
  4672. * @remind 返回的range是一个全新的range对象, 其内部所有属性与当前被clone的range相同。
  4673. * @return { UE.dom.Range } 当前range对象的一个副本
  4674. */
  4675. cloneRange:function () {
  4676. var me = this;
  4677. return new Range(me.document).setStart(me.startContainer, me.startOffset).setEnd(me.endContainer, me.endOffset);
  4678. },
  4679. /**
  4680. * 向当前选区的结束处闭合选区
  4681. * @method collapse
  4682. * @return { UE.dom.Range } 当前range对象
  4683. * @example
  4684. * ```html
  4685. * <!-- 选区示例 -->
  4686. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  4687. *
  4688. * <script>
  4689. *
  4690. * //执行操作
  4691. * range.collapse();
  4692. *
  4693. * //结果选区
  4694. * //“|”表示选区已闭合
  4695. * //<b>xx<i>xxx</i><span>xx|x</span>xxx</b>
  4696. *
  4697. * </script>
  4698. * ```
  4699. */
  4700. /**
  4701. * 闭合当前选区,根据给定的toStart参数项决定是向当前选区开始处闭合还是向结束处闭合,
  4702. * 如果toStart的值为true,则向开始位置闭合, 反之,向结束位置闭合。
  4703. * @method collapse
  4704. * @param { Boolean } toStart 是否向选区开始处闭合
  4705. * @return { UE.dom.Range } 当前range对象,此时range对象处于闭合状态
  4706. * @see UE.dom.Range:collapse()
  4707. * @example
  4708. * ```html
  4709. * <!-- 选区示例 -->
  4710. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  4711. *
  4712. * <script>
  4713. *
  4714. * //执行操作
  4715. * range.collapse( true );
  4716. *
  4717. * //结果选区
  4718. * //“|”表示选区已闭合
  4719. * //<b>xx<i>xxx</i><span>|xxx</span>xxx</b>
  4720. *
  4721. * </script>
  4722. * ```
  4723. */
  4724. collapse:function (toStart) {
  4725. var me = this;
  4726. if (toStart) {
  4727. me.endContainer = me.startContainer;
  4728. me.endOffset = me.startOffset;
  4729. } else {
  4730. me.startContainer = me.endContainer;
  4731. me.startOffset = me.endOffset;
  4732. }
  4733. me.collapsed = true;
  4734. return me;
  4735. },
  4736. /**
  4737. * 调整range的开始位置和结束位置,使其"收缩"到最小的位置
  4738. * @method shrinkBoundary
  4739. * @return { UE.dom.Range } 当前range对象
  4740. * @example
  4741. * ```html
  4742. * <span>xx<b>xx[</b>xxxxx]</span> => <span>xx<b>xx</b>[xxxxx]</span>
  4743. * ```
  4744. *
  4745. * @example
  4746. * ```html
  4747. * <!-- 选区示例 -->
  4748. * <b>x[xx</b><i>]xxx</i>
  4749. *
  4750. * <script>
  4751. *
  4752. * //执行收缩
  4753. * range.shrinkBoundary();
  4754. *
  4755. * //结果选区
  4756. * //<b>x[xx]</b><i>xxx</i>
  4757. * </script>
  4758. * ```
  4759. *
  4760. * @example
  4761. * ```html
  4762. * [<b><i>xxxx</i>xxxxxxx</b>] => <b><i>[xxxx</i>xxxxxxx]</b>
  4763. * ```
  4764. */
  4765. /**
  4766. * 调整range的开始位置和结束位置,使其"收缩"到最小的位置,
  4767. * 如果ignoreEnd的值为true,则忽略对结束位置的调整
  4768. * @method shrinkBoundary
  4769. * @param { Boolean } ignoreEnd 是否忽略对结束位置的调整
  4770. * @return { UE.dom.Range } 当前range对象
  4771. * @see UE.dom.domUtils.Range:shrinkBoundary()
  4772. */
  4773. shrinkBoundary:function (ignoreEnd) {
  4774. var me = this, child,
  4775. collapsed = me.collapsed;
  4776. function check(node){
  4777. return node.nodeType == 1 && !domUtils.isBookmarkNode(node) && !dtd.$empty[node.tagName] && !dtd.$nonChild[node.tagName]
  4778. }
  4779. while (me.startContainer.nodeType == 1 //是element
  4780. && (child = me.startContainer.childNodes[me.startOffset]) //子节点也是element
  4781. && check(child)) {
  4782. me.setStart(child, 0);
  4783. }
  4784. if (collapsed) {
  4785. return me.collapse(true);
  4786. }
  4787. if (!ignoreEnd) {
  4788. while (me.endContainer.nodeType == 1//是element
  4789. && me.endOffset > 0 //如果是空元素就退出 endOffset=0那么endOffst-1为负值,childNodes[endOffset]报错
  4790. && (child = me.endContainer.childNodes[me.endOffset - 1]) //子节点也是element
  4791. && check(child)) {
  4792. me.setEnd(child, child.childNodes.length);
  4793. }
  4794. }
  4795. return me;
  4796. },
  4797. /**
  4798. * 获取离当前选区内包含的所有节点最近的公共祖先节点,
  4799. * @method getCommonAncestor
  4800. * @remind 返回的公共祖先节点一定不是range自身的容器节点, 但有可能是一个文本节点
  4801. * @return { Node } 当前range对象内所有节点的公共祖先节点
  4802. * @example
  4803. * ```html
  4804. * //选区示例
  4805. * <span>xxx<b>x[x<em>xx]x</em>xxx</b>xx</span>
  4806. * <script>
  4807. *
  4808. * var node = range.getCommonAncestor();
  4809. *
  4810. * //公共祖先节点是: b节点
  4811. * //输出: B
  4812. * console.log(node.tagName);
  4813. *
  4814. * </script>
  4815. * ```
  4816. */
  4817. /**
  4818. * 获取当前选区所包含的所有节点的公共祖先节点, 可以根据给定的参数 includeSelf 决定获取到
  4819. * 的公共祖先节点是否可以是当前选区的startContainer或endContainer节点, 如果 includeSelf
  4820. * 的取值为true, 则返回的节点可以是自身的容器节点, 否则, 则不能是容器节点
  4821. * @method getCommonAncestor
  4822. * @param { Boolean } includeSelf 是否允许获取到的公共祖先节点是当前range对象的容器节点
  4823. * @return { Node } 当前range对象内所有节点的公共祖先节点
  4824. * @see UE.dom.Range:getCommonAncestor()
  4825. * @example
  4826. * ```html
  4827. * <body>
  4828. *
  4829. * <!-- 选区示例 -->
  4830. * <b>xxx<i>xxxx<span>xx[x</span>xx]x</i>xxxxxxx</b>
  4831. *
  4832. * <script>
  4833. *
  4834. * var node = range.getCommonAncestor( false );
  4835. *
  4836. * //这里的公共祖先节点是B而不是I, 是因为参数限制了获取到的节点不能是容器节点
  4837. * //output: B
  4838. * console.log( node.tagName );
  4839. *
  4840. * </script>
  4841. *
  4842. * </body>
  4843. * ```
  4844. */
  4845. /**
  4846. * 获取当前选区所包含的所有节点的公共祖先节点, 可以根据给定的参数 includeSelf 决定获取到
  4847. * 的公共祖先节点是否可以是当前选区的startContainer或endContainer节点, 如果 includeSelf
  4848. * 的取值为true, 则返回的节点可以是自身的容器节点, 否则, 则不能是容器节点; 同时可以根据
  4849. * ignoreTextNode 参数的取值决定是否忽略类型为文本节点的祖先节点。
  4850. * @method getCommonAncestor
  4851. * @param { Boolean } includeSelf 是否允许获取到的公共祖先节点是当前range对象的容器节点
  4852. * @param { Boolean } ignoreTextNode 获取祖先节点的过程中是否忽略类型为文本节点的祖先节点
  4853. * @return { Node } 当前range对象内所有节点的公共祖先节点
  4854. * @see UE.dom.Range:getCommonAncestor()
  4855. * @see UE.dom.Range:getCommonAncestor(Boolean)
  4856. * @example
  4857. * ```html
  4858. * <body>
  4859. *
  4860. * <!-- 选区示例 -->
  4861. * <b>xxx<i>xxxx<span>x[x]x</span>xxx</i>xxxxxxx</b>
  4862. *
  4863. * <script>
  4864. *
  4865. * var node = range.getCommonAncestor( true, false );
  4866. *
  4867. * //output: SPAN
  4868. * console.log( node.tagName );
  4869. *
  4870. * </script>
  4871. *
  4872. * </body>
  4873. * ```
  4874. */
  4875. getCommonAncestor:function (includeSelf, ignoreTextNode) {
  4876. var me = this,
  4877. start = me.startContainer,
  4878. end = me.endContainer;
  4879. if (start === end) {
  4880. if (includeSelf && selectOneNode(this)) {
  4881. start = start.childNodes[me.startOffset];
  4882. if(start.nodeType == 1)
  4883. return start;
  4884. }
  4885. //只有在上来就相等的情况下才会出现是文本的情况
  4886. return ignoreTextNode && start.nodeType == 3 ? start.parentNode : start;
  4887. }
  4888. return domUtils.getCommonAncestor(start, end);
  4889. },
  4890. /**
  4891. * 调整当前Range的开始和结束边界容器,如果是容器节点是文本节点,就调整到包含该文本节点的父节点上
  4892. * @method trimBoundary
  4893. * @remind 该操作有可能会引起文本节点被切开
  4894. * @return { UE.dom.Range } 当前range对象
  4895. * @example
  4896. * ```html
  4897. *
  4898. * //选区示例
  4899. * <b>xxx<i>[xxxxx]</i>xxx</b>
  4900. *
  4901. * <script>
  4902. * //未调整前, 选区的开始容器和结束都是文本节点
  4903. * //执行调整
  4904. * range.trimBoundary();
  4905. *
  4906. * //调整之后, 容器节点变成了i节点
  4907. * //<b>xxx[<i>xxxxx</i>]xxx</b>
  4908. * </script>
  4909. * ```
  4910. */
  4911. /**
  4912. * 调整当前Range的开始和结束边界容器,如果是容器节点是文本节点,就调整到包含该文本节点的父节点上,
  4913. * 可以根据 ignoreEnd 参数的值决定是否调整对结束边界的调整
  4914. * @method trimBoundary
  4915. * @param { Boolean } ignoreEnd 是否忽略对结束边界的调整
  4916. * @return { UE.dom.Range } 当前range对象
  4917. * @example
  4918. * ```html
  4919. *
  4920. * //选区示例
  4921. * <b>xxx<i>[xxxxx]</i>xxx</b>
  4922. *
  4923. * <script>
  4924. * //未调整前, 选区的开始容器和结束都是文本节点
  4925. * //执行调整
  4926. * range.trimBoundary( true );
  4927. *
  4928. * //调整之后, 开始容器节点变成了i节点
  4929. * //但是, 结束容器没有发生变化
  4930. * //<b>xxx[<i>xxxxx]</i>xxx</b>
  4931. * </script>
  4932. * ```
  4933. */
  4934. trimBoundary:function (ignoreEnd) {
  4935. this.txtToElmBoundary();
  4936. var start = this.startContainer,
  4937. offset = this.startOffset,
  4938. collapsed = this.collapsed,
  4939. end = this.endContainer;
  4940. if (start.nodeType == 3) {
  4941. if (offset == 0) {
  4942. this.setStartBefore(start);
  4943. } else {
  4944. if (offset >= start.nodeValue.length) {
  4945. this.setStartAfter(start);
  4946. } else {
  4947. var textNode = domUtils.split(start, offset);
  4948. //跟新结束边界
  4949. if (start === end) {
  4950. this.setEnd(textNode, this.endOffset - offset);
  4951. } else if (start.parentNode === end) {
  4952. this.endOffset += 1;
  4953. }
  4954. this.setStartBefore(textNode);
  4955. }
  4956. }
  4957. if (collapsed) {
  4958. return this.collapse(true);
  4959. }
  4960. }
  4961. if (!ignoreEnd) {
  4962. offset = this.endOffset;
  4963. end = this.endContainer;
  4964. if (end.nodeType == 3) {
  4965. if (offset == 0) {
  4966. this.setEndBefore(end);
  4967. } else {
  4968. offset < end.nodeValue.length && domUtils.split(end, offset);
  4969. this.setEndAfter(end);
  4970. }
  4971. }
  4972. }
  4973. return this;
  4974. },
  4975. /**
  4976. * 如果选区在文本的边界上,就扩展选区到文本的父节点上, 如果当前选区是闭合的, 则什么也不做
  4977. * @method txtToElmBoundary
  4978. * @remind 该操作不会修改dom节点
  4979. * @return { UE.dom.Range } 当前range对象
  4980. */
  4981. /**
  4982. * 如果选区在文本的边界上,就扩展选区到文本的父节点上, 如果当前选区是闭合的, 则根据参数项
  4983. * ignoreCollapsed 的值决定是否执行该调整
  4984. * @method txtToElmBoundary
  4985. * @param { Boolean } ignoreCollapsed 是否忽略选区的闭合状态, 如果该参数取值为true, 则
  4986. * 不论选区是否闭合, 都会执行该操作, 反之, 则不会对闭合的选区执行该操作
  4987. * @return { UE.dom.Range } 当前range对象
  4988. */
  4989. txtToElmBoundary:function (ignoreCollapsed) {
  4990. function adjust(r, c) {
  4991. var container = r[c + 'Container'],
  4992. offset = r[c + 'Offset'];
  4993. if (container.nodeType == 3) {
  4994. if (!offset) {
  4995. r['set' + c.replace(/(\w)/, function (a) {
  4996. return a.toUpperCase();
  4997. }) + 'Before'](container);
  4998. } else if (offset >= container.nodeValue.length) {
  4999. r['set' + c.replace(/(\w)/, function (a) {
  5000. return a.toUpperCase();
  5001. }) + 'After' ](container);
  5002. }
  5003. }
  5004. }
  5005. if (ignoreCollapsed || !this.collapsed) {
  5006. adjust(this, 'start');
  5007. adjust(this, 'end');
  5008. }
  5009. return this;
  5010. },
  5011. /**
  5012. * 在当前选区的开始位置前插入节点,新插入的节点会被该range包含
  5013. * @method insertNode
  5014. * @param { Node } node 需要插入的节点
  5015. * @remind 插入的节点可以是一个DocumentFragment依次插入多个节点
  5016. * @return { UE.dom.Range } 当前range对象
  5017. */
  5018. insertNode:function (node) {
  5019. var first = node, length = 1;
  5020. if (node.nodeType == 11) {
  5021. first = node.firstChild;
  5022. length = node.childNodes.length;
  5023. }
  5024. this.trimBoundary(true);
  5025. var start = this.startContainer,
  5026. offset = this.startOffset;
  5027. var nextNode = start.childNodes[ offset ];
  5028. if (nextNode) {
  5029. start.insertBefore(node, nextNode);
  5030. } else {
  5031. start.appendChild(node);
  5032. }
  5033. if (first.parentNode === this.endContainer) {
  5034. this.endOffset = this.endOffset + length;
  5035. }
  5036. return this.setStartBefore(first);
  5037. },
  5038. /**
  5039. * 闭合选区到当前选区的开始位置, 并且定位光标到闭合后的位置
  5040. * @method setCursor
  5041. * @return { UE.dom.Range } 当前range对象
  5042. * @see UE.dom.Range:collapse()
  5043. */
  5044. /**
  5045. * 闭合选区,可以根据参数toEnd的值控制选区是向前闭合还是向后闭合, 并且定位光标到闭合后的位置。
  5046. * @method setCursor
  5047. * @param { Boolean } toEnd 是否向后闭合, 如果为true, 则闭合选区时, 将向结束容器方向闭合,
  5048. * 反之,则向开始容器方向闭合
  5049. * @return { UE.dom.Range } 当前range对象
  5050. * @see UE.dom.Range:collapse(Boolean)
  5051. */
  5052. setCursor:function (toEnd, noFillData) {
  5053. return this.collapse(!toEnd).select(noFillData);
  5054. },
  5055. /**
  5056. * 创建当前range的一个书签,记录下当前range的位置,方便当dom树改变时,还能找回原来的选区位置
  5057. * @method createBookmark
  5058. * @param { Boolean } serialize 控制返回的标记位置是对当前位置的引用还是ID,如果该值为true,则
  5059. * 返回标记位置的ID, 反之则返回标记位置节点的引用
  5060. * @return { Object } 返回一个书签记录键值对, 其包含的key有: start => 开始标记的ID或者引用,
  5061. * end => 结束标记的ID或引用, id => 当前标记的类型, 如果为true,则表示
  5062. * 返回的记录的类型为ID, 反之则为引用
  5063. */
  5064. createBookmark:function (serialize, same) {
  5065. var endNode,
  5066. startNode = this.document.createElement('span');
  5067. startNode.style.cssText = 'display:none;line-height:0px;';
  5068. startNode.appendChild(this.document.createTextNode('\u200D'));
  5069. startNode.id = '_baidu_bookmark_start_' + (same ? '' : guid++);
  5070. if (!this.collapsed) {
  5071. endNode = startNode.cloneNode(true);
  5072. endNode.id = '_baidu_bookmark_end_' + (same ? '' : guid++);
  5073. }
  5074. this.insertNode(startNode);
  5075. if (endNode) {
  5076. this.collapse().insertNode(endNode).setEndBefore(endNode);
  5077. }
  5078. this.setStartAfter(startNode);
  5079. return {
  5080. start:serialize ? startNode.id : startNode,
  5081. end:endNode ? serialize ? endNode.id : endNode : null,
  5082. id:serialize
  5083. }
  5084. },
  5085. /**
  5086. * 调整当前range的边界到书签位置,并删除该书签对象所标记的位置内的节点
  5087. * @method moveToBookmark
  5088. * @param { BookMark } bookmark createBookmark所创建的标签对象
  5089. * @return { UE.dom.Range } 当前range对象
  5090. * @see UE.dom.Range:createBookmark(Boolean)
  5091. */
  5092. moveToBookmark:function (bookmark) {
  5093. var start = bookmark.id ? this.document.getElementById(bookmark.start) : bookmark.start,
  5094. end = bookmark.end && bookmark.id ? this.document.getElementById(bookmark.end) : bookmark.end;
  5095. this.setStartBefore(start);
  5096. domUtils.remove(start);
  5097. if (end) {
  5098. this.setEndBefore(end);
  5099. domUtils.remove(end);
  5100. } else {
  5101. this.collapse(true);
  5102. }
  5103. return this;
  5104. },
  5105. /**
  5106. * 调整range的边界,使其"放大"到最近的父节点
  5107. * @method enlarge
  5108. * @remind 会引起选区的变化
  5109. * @return { UE.dom.Range } 当前range对象
  5110. */
  5111. /**
  5112. * 调整range的边界,使其"放大"到最近的父节点,根据参数 toBlock 的取值, 可以
  5113. * 要求扩大之后的父节点是block节点
  5114. * @method enlarge
  5115. * @param { Boolean } toBlock 是否要求扩大之后的父节点必须是block节点
  5116. * @return { UE.dom.Range } 当前range对象
  5117. */
  5118. enlarge:function (toBlock, stopFn) {
  5119. var isBody = domUtils.isBody,
  5120. pre, node, tmp = this.document.createTextNode('');
  5121. if (toBlock) {
  5122. node = this.startContainer;
  5123. if (node.nodeType == 1) {
  5124. if (node.childNodes[this.startOffset]) {
  5125. pre = node = node.childNodes[this.startOffset]
  5126. } else {
  5127. node.appendChild(tmp);
  5128. pre = node = tmp;
  5129. }
  5130. } else {
  5131. pre = node;
  5132. }
  5133. while (1) {
  5134. if (domUtils.isBlockElm(node)) {
  5135. node = pre;
  5136. while ((pre = node.previousSibling) && !domUtils.isBlockElm(pre)) {
  5137. node = pre;
  5138. }
  5139. this.setStartBefore(node);
  5140. break;
  5141. }
  5142. pre = node;
  5143. node = node.parentNode;
  5144. }
  5145. node = this.endContainer;
  5146. if (node.nodeType == 1) {
  5147. if (pre = node.childNodes[this.endOffset]) {
  5148. node.insertBefore(tmp, pre);
  5149. } else {
  5150. node.appendChild(tmp);
  5151. }
  5152. pre = node = tmp;
  5153. } else {
  5154. pre = node;
  5155. }
  5156. while (1) {
  5157. if (domUtils.isBlockElm(node)) {
  5158. node = pre;
  5159. while ((pre = node.nextSibling) && !domUtils.isBlockElm(pre)) {
  5160. node = pre;
  5161. }
  5162. this.setEndAfter(node);
  5163. break;
  5164. }
  5165. pre = node;
  5166. node = node.parentNode;
  5167. }
  5168. if (tmp.parentNode === this.endContainer) {
  5169. this.endOffset--;
  5170. }
  5171. domUtils.remove(tmp);
  5172. }
  5173. // 扩展边界到最大
  5174. if (!this.collapsed) {
  5175. while (this.startOffset == 0) {
  5176. if (stopFn && stopFn(this.startContainer)) {
  5177. break;
  5178. }
  5179. if (isBody(this.startContainer)) {
  5180. break;
  5181. }
  5182. this.setStartBefore(this.startContainer);
  5183. }
  5184. while (this.endOffset == (this.endContainer.nodeType == 1 ? this.endContainer.childNodes.length : this.endContainer.nodeValue.length)) {
  5185. if (stopFn && stopFn(this.endContainer)) {
  5186. break;
  5187. }
  5188. if (isBody(this.endContainer)) {
  5189. break;
  5190. }
  5191. this.setEndAfter(this.endContainer);
  5192. }
  5193. }
  5194. return this;
  5195. },
  5196. enlargeToBlockElm:function(ignoreEnd){
  5197. while(!domUtils.isBlockElm(this.startContainer)){
  5198. this.setStartBefore(this.startContainer);
  5199. }
  5200. if(!ignoreEnd){
  5201. while(!domUtils.isBlockElm(this.endContainer)){
  5202. this.setEndAfter(this.endContainer);
  5203. }
  5204. }
  5205. return this;
  5206. },
  5207. /**
  5208. * 调整Range的边界,使其"缩小"到最合适的位置
  5209. * @method adjustmentBoundary
  5210. * @return { UE.dom.Range } 当前range对象
  5211. * @see UE.dom.Range:shrinkBoundary()
  5212. */
  5213. adjustmentBoundary:function () {
  5214. if (!this.collapsed) {
  5215. while (!domUtils.isBody(this.startContainer) &&
  5216. this.startOffset == this.startContainer[this.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length &&
  5217. this.startContainer[this.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length
  5218. ) {
  5219. this.setStartAfter(this.startContainer);
  5220. }
  5221. while (!domUtils.isBody(this.endContainer) && !this.endOffset &&
  5222. this.endContainer[this.endContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length
  5223. ) {
  5224. this.setEndBefore(this.endContainer);
  5225. }
  5226. }
  5227. return this;
  5228. },
  5229. /**
  5230. * 给range选区中的内容添加给定的inline标签
  5231. * @method applyInlineStyle
  5232. * @param { String } tagName 需要添加的标签名
  5233. * @example
  5234. * ```html
  5235. * <p>xxxx[xxxx]x</p> ==> range.applyInlineStyle("strong") ==> <p>xxxx[<strong>xxxx</strong>]x</p>
  5236. * ```
  5237. */
  5238. /**
  5239. * 给range选区中的内容添加给定的inline标签, 并且为标签附加上一些初始化属性。
  5240. * @method applyInlineStyle
  5241. * @param { String } tagName 需要添加的标签名
  5242. * @param { Object } attrs 跟随新添加的标签的属性
  5243. * @return { UE.dom.Range } 当前选区
  5244. * @example
  5245. * ```html
  5246. * <p>xxxx[xxxx]x</p>
  5247. *
  5248. * ==>
  5249. *
  5250. * <!-- 执行操作 -->
  5251. * range.applyInlineStyle("strong",{"style":"font-size:12px"})
  5252. *
  5253. * ==>
  5254. *
  5255. * <p>xxxx[<strong style="font-size:12px">xxxx</strong>]x</p>
  5256. * ```
  5257. */
  5258. applyInlineStyle:function (tagName, attrs, list) {
  5259. if (this.collapsed)return this;
  5260. this.trimBoundary().enlarge(false,
  5261. function (node) {
  5262. return node.nodeType == 1 && domUtils.isBlockElm(node)
  5263. }).adjustmentBoundary();
  5264. var bookmark = this.createBookmark(),
  5265. end = bookmark.end,
  5266. filterFn = function (node) {
  5267. return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' : !domUtils.isWhitespace(node);
  5268. },
  5269. current = domUtils.getNextDomNode(bookmark.start, false, filterFn),
  5270. node,
  5271. pre,
  5272. range = this.cloneRange();
  5273. while (current && (domUtils.getPosition(current, end) & domUtils.POSITION_PRECEDING)) {
  5274. if (current.nodeType == 3 || dtd[tagName][current.tagName]) {
  5275. range.setStartBefore(current);
  5276. node = current;
  5277. while (node && (node.nodeType == 3 || dtd[tagName][node.tagName]) && node !== end) {
  5278. pre = node;
  5279. node = domUtils.getNextDomNode(node, node.nodeType == 1, null, function (parent) {
  5280. return dtd[tagName][parent.tagName];
  5281. });
  5282. }
  5283. var frag = range.setEndAfter(pre).extractContents(), elm;
  5284. if (list && list.length > 0) {
  5285. var level, top;
  5286. top = level = list[0].cloneNode(false);
  5287. for (var i = 1, ci; ci = list[i++];) {
  5288. level.appendChild(ci.cloneNode(false));
  5289. level = level.firstChild;
  5290. }
  5291. elm = level;
  5292. } else {
  5293. elm = range.document.createElement(tagName);
  5294. }
  5295. if (attrs) {
  5296. domUtils.setAttributes(elm, attrs);
  5297. }
  5298. elm.appendChild(frag);
  5299. range.insertNode(list ? top : elm);
  5300. //处理下滑线在a上的情况
  5301. var aNode;
  5302. if (tagName == 'span' && attrs.style && /text\-decoration/.test(attrs.style) && (aNode = domUtils.findParentByTagName(elm, 'a', true))) {
  5303. domUtils.setAttributes(aNode, attrs);
  5304. domUtils.remove(elm, true);
  5305. elm = aNode;
  5306. } else {
  5307. domUtils.mergeSibling(elm);
  5308. domUtils.clearEmptySibling(elm);
  5309. }
  5310. //去除子节点相同的
  5311. domUtils.mergeChild(elm, attrs);
  5312. current = domUtils.getNextDomNode(elm, false, filterFn);
  5313. domUtils.mergeToParent(elm);
  5314. if (node === end) {
  5315. break;
  5316. }
  5317. } else {
  5318. current = domUtils.getNextDomNode(current, true, filterFn);
  5319. }
  5320. }
  5321. return this.moveToBookmark(bookmark);
  5322. },
  5323. /**
  5324. * 移除当前选区内指定的inline标签,但保留其中的内容
  5325. * @method removeInlineStyle
  5326. * @param { String } tagName 需要移除的标签名
  5327. * @return { UE.dom.Range } 当前的range对象
  5328. * @example
  5329. * ```html
  5330. * xx[x<span>xxx<em>yyy</em>zz]z</span> => range.removeInlineStyle(["em"]) => xx[x<span>xxxyyyzz]z</span>
  5331. * ```
  5332. */
  5333. /**
  5334. * 移除当前选区内指定的一组inline标签,但保留其中的内容
  5335. * @method removeInlineStyle
  5336. * @param { Array } tagNameArr 需要移除的标签名的数组
  5337. * @return { UE.dom.Range } 当前的range对象
  5338. * @see UE.dom.Range:removeInlineStyle(String)
  5339. */
  5340. removeInlineStyle:function (tagNames) {
  5341. if (this.collapsed)return this;
  5342. tagNames = utils.isArray(tagNames) ? tagNames : [tagNames];
  5343. this.shrinkBoundary().adjustmentBoundary();
  5344. var start = this.startContainer, end = this.endContainer;
  5345. while (1) {
  5346. if (start.nodeType == 1) {
  5347. if (utils.indexOf(tagNames, start.tagName.toLowerCase()) > -1) {
  5348. break;
  5349. }
  5350. if (start.tagName.toLowerCase() == 'body') {
  5351. start = null;
  5352. break;
  5353. }
  5354. }
  5355. start = start.parentNode;
  5356. }
  5357. while (1) {
  5358. if (end.nodeType == 1) {
  5359. if (utils.indexOf(tagNames, end.tagName.toLowerCase()) > -1) {
  5360. break;
  5361. }
  5362. if (end.tagName.toLowerCase() == 'body') {
  5363. end = null;
  5364. break;
  5365. }
  5366. }
  5367. end = end.parentNode;
  5368. }
  5369. var bookmark = this.createBookmark(),
  5370. frag,
  5371. tmpRange;
  5372. if (start) {
  5373. tmpRange = this.cloneRange().setEndBefore(bookmark.start).setStartBefore(start);
  5374. frag = tmpRange.extractContents();
  5375. tmpRange.insertNode(frag);
  5376. domUtils.clearEmptySibling(start, true);
  5377. start.parentNode.insertBefore(bookmark.start, start);
  5378. }
  5379. if (end) {
  5380. tmpRange = this.cloneRange().setStartAfter(bookmark.end).setEndAfter(end);
  5381. frag = tmpRange.extractContents();
  5382. tmpRange.insertNode(frag);
  5383. domUtils.clearEmptySibling(end, false, true);
  5384. end.parentNode.insertBefore(bookmark.end, end.nextSibling);
  5385. }
  5386. var current = domUtils.getNextDomNode(bookmark.start, false, function (node) {
  5387. return node.nodeType == 1;
  5388. }), next;
  5389. while (current && current !== bookmark.end) {
  5390. next = domUtils.getNextDomNode(current, true, function (node) {
  5391. return node.nodeType == 1;
  5392. });
  5393. if (utils.indexOf(tagNames, current.tagName.toLowerCase()) > -1) {
  5394. domUtils.remove(current, true);
  5395. }
  5396. current = next;
  5397. }
  5398. return this.moveToBookmark(bookmark);
  5399. },
  5400. /**
  5401. * 获取当前选中的自闭合的节点
  5402. * @method getClosedNode
  5403. * @return { Node | NULL } 如果当前选中的是自闭合节点, 则返回该节点, 否则返回NULL
  5404. */
  5405. getClosedNode:function () {
  5406. var node;
  5407. if (!this.collapsed) {
  5408. var range = this.cloneRange().adjustmentBoundary().shrinkBoundary();
  5409. if (selectOneNode(range)) {
  5410. var child = range.startContainer.childNodes[range.startOffset];
  5411. if (child && child.nodeType == 1 && (dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName])) {
  5412. node = child;
  5413. }
  5414. }
  5415. }
  5416. return node;
  5417. },
  5418. /**
  5419. * 在页面上高亮range所表示的选区
  5420. * @method select
  5421. * @return { UE.dom.Range } 返回当前Range对象
  5422. */
  5423. //这里不区分ie9以上,trace:3824
  5424. select:browser.ie ? function (noFillData, textRange) {
  5425. var nativeRange;
  5426. if (!this.collapsed)
  5427. this.shrinkBoundary();
  5428. var node = this.getClosedNode();
  5429. if (node && !textRange) {
  5430. try {
  5431. nativeRange = this.document.body.createControlRange();
  5432. nativeRange.addElement(node);
  5433. nativeRange.select();
  5434. } catch (e) {}
  5435. return this;
  5436. }
  5437. var bookmark = this.createBookmark(),
  5438. start = bookmark.start,
  5439. end;
  5440. nativeRange = this.document.body.createTextRange();
  5441. nativeRange.moveToElementText(start);
  5442. nativeRange.moveStart('character', 1);
  5443. if (!this.collapsed) {
  5444. var nativeRangeEnd = this.document.body.createTextRange();
  5445. end = bookmark.end;
  5446. nativeRangeEnd.moveToElementText(end);
  5447. nativeRange.setEndPoint('EndToEnd', nativeRangeEnd);
  5448. } else {
  5449. if (!noFillData && this.startContainer.nodeType != 3) {
  5450. //使用<span>|x<span>固定住光标
  5451. var tmpText = this.document.createTextNode(fillChar),
  5452. tmp = this.document.createElement('span');
  5453. tmp.appendChild(this.document.createTextNode(fillChar));
  5454. start.parentNode.insertBefore(tmp, start);
  5455. start.parentNode.insertBefore(tmpText, start);
  5456. //当点b,i,u时,不能清除i上边的b
  5457. removeFillData(this.document, tmpText);
  5458. fillData = tmpText;
  5459. mergeSibling(tmp, 'previousSibling');
  5460. mergeSibling(start, 'nextSibling');
  5461. nativeRange.moveStart('character', -1);
  5462. nativeRange.collapse(true);
  5463. }
  5464. }
  5465. this.moveToBookmark(bookmark);
  5466. tmp && domUtils.remove(tmp);
  5467. //IE在隐藏状态下不支持range操作,catch一下
  5468. try {
  5469. nativeRange.select();
  5470. } catch (e) {
  5471. }
  5472. return this;
  5473. } : function (notInsertFillData) {
  5474. function checkOffset(rng){
  5475. function check(node,offset,dir){
  5476. if(node.nodeType == 3 && node.nodeValue.length < offset){
  5477. rng[dir + 'Offset'] = node.nodeValue.length
  5478. }
  5479. }
  5480. check(rng.startContainer,rng.startOffset,'start');
  5481. check(rng.endContainer,rng.endOffset,'end');
  5482. }
  5483. var win = domUtils.getWindow(this.document),
  5484. sel = win.getSelection(),
  5485. txtNode;
  5486. //FF下关闭自动长高时滚动条在关闭dialog时会跳
  5487. //ff下如果不body.focus将不能定位闭合光标到编辑器内
  5488. browser.gecko ? this.document.body.focus() : win.focus();
  5489. if (sel) {
  5490. sel.removeAllRanges();
  5491. // trace:870 chrome/safari后边是br对于闭合得range不能定位 所以去掉了判断
  5492. // this.startContainer.nodeType != 3 &&! ((child = this.startContainer.childNodes[this.startOffset]) && child.nodeType == 1 && child.tagName == 'BR'
  5493. if (this.collapsed && !notInsertFillData) {
  5494. // //opear如果没有节点接着,原生的不能够定位,不能在body的第一级插入空白节点
  5495. // if (notInsertFillData && browser.opera && !domUtils.isBody(this.startContainer) && this.startContainer.nodeType == 1) {
  5496. // var tmp = this.document.createTextNode('');
  5497. // this.insertNode(tmp).setStart(tmp, 0).collapse(true);
  5498. // }
  5499. //
  5500. //处理光标落在文本节点的情况
  5501. //处理以下的情况
  5502. //<b>|xxxx</b>
  5503. //<b>xxxx</b>|xxxx
  5504. //xxxx<b>|</b>
  5505. var start = this.startContainer,child = start;
  5506. if(start.nodeType == 1){
  5507. child = start.childNodes[this.startOffset];
  5508. }
  5509. if( !(start.nodeType == 3 && this.startOffset) &&
  5510. (child ?
  5511. (!child.previousSibling || child.previousSibling.nodeType != 3)
  5512. :
  5513. (!start.lastChild || start.lastChild.nodeType != 3)
  5514. )
  5515. ){
  5516. txtNode = this.document.createTextNode(fillChar);
  5517. //跟着前边走
  5518. this.insertNode(txtNode);
  5519. removeFillData(this.document, txtNode);
  5520. mergeSibling(txtNode, 'previousSibling');
  5521. mergeSibling(txtNode, 'nextSibling');
  5522. fillData = txtNode;
  5523. this.setStart(txtNode, browser.webkit ? 1 : 0).collapse(true);
  5524. }
  5525. }
  5526. var nativeRange = this.document.createRange();
  5527. if(this.collapsed && browser.opera && this.startContainer.nodeType == 1){
  5528. var child = this.startContainer.childNodes[this.startOffset];
  5529. if(!child){
  5530. //往前靠拢
  5531. child = this.startContainer.lastChild;
  5532. if( child && domUtils.isBr(child)){
  5533. this.setStartBefore(child).collapse(true);
  5534. }
  5535. }else{
  5536. //向后靠拢
  5537. while(child && domUtils.isBlockElm(child)){
  5538. if(child.nodeType == 1 && child.childNodes[0]){
  5539. child = child.childNodes[0]
  5540. }else{
  5541. break;
  5542. }
  5543. }
  5544. child && this.setStartBefore(child).collapse(true)
  5545. }
  5546. }
  5547. //是createAddress最后一位算的不准,现在这里进行微调
  5548. checkOffset(this);
  5549. nativeRange.setStart(this.startContainer, this.startOffset);
  5550. nativeRange.setEnd(this.endContainer, this.endOffset);
  5551. sel.addRange(nativeRange);
  5552. }
  5553. return this;
  5554. },
  5555. /**
  5556. * 滚动到当前range开始的位置
  5557. * @method scrollToView
  5558. * @param { Window } win 当前range对象所属的window对象
  5559. * @return { UE.dom.Range } 当前Range对象
  5560. */
  5561. /**
  5562. * 滚动到距离当前range开始位置 offset 的位置处
  5563. * @method scrollToView
  5564. * @param { Window } win 当前range对象所属的window对象
  5565. * @param { Number } offset 距离range开始位置处的偏移量, 如果为正数, 则向下偏移, 反之, 则向上偏移
  5566. * @return { UE.dom.Range } 当前Range对象
  5567. */
  5568. scrollToView:function (win, offset) {
  5569. win = win ? window : domUtils.getWindow(this.document);
  5570. var me = this,
  5571. span = me.document.createElement('span');
  5572. //trace:717
  5573. span.innerHTML = '&nbsp;';
  5574. me.cloneRange().insertNode(span);
  5575. domUtils.scrollToView(span, win, offset);
  5576. domUtils.remove(span);
  5577. return me;
  5578. },
  5579. /**
  5580. * 判断当前选区内容是否占位符
  5581. * @private
  5582. * @method inFillChar
  5583. * @return { Boolean } 如果是占位符返回true,否则返回false
  5584. */
  5585. inFillChar : function(){
  5586. var start = this.startContainer;
  5587. if(this.collapsed && start.nodeType == 3
  5588. && start.nodeValue.replace(new RegExp('^' + domUtils.fillChar),'').length + 1 == start.nodeValue.length
  5589. ){
  5590. return true;
  5591. }
  5592. return false;
  5593. },
  5594. /**
  5595. * 保存
  5596. * @method createAddress
  5597. * @private
  5598. * @return { Boolean } 返回开始和结束的位置
  5599. * @example
  5600. * ```html
  5601. * <body>
  5602. * <p>
  5603. * aaaa
  5604. * <em>
  5605. * <!-- 选区开始 -->
  5606. * bbbb
  5607. * <!-- 选区结束 -->
  5608. * </em>
  5609. * </p>
  5610. *
  5611. * <script>
  5612. * //output: {startAddress:[0,1,0,0],endAddress:[0,1,0,4]}
  5613. * console.log( range.createAddress() );
  5614. * </script>
  5615. * </body>
  5616. * ```
  5617. */
  5618. createAddress : function(ignoreEnd,ignoreTxt){
  5619. var addr = {},me = this;
  5620. function getAddress(isStart){
  5621. var node = isStart ? me.startContainer : me.endContainer;
  5622. var parents = domUtils.findParents(node,true,function(node){return !domUtils.isBody(node)}),
  5623. addrs = [];
  5624. for(var i = 0,ci;ci = parents[i++];){
  5625. addrs.push(domUtils.getNodeIndex(ci,ignoreTxt));
  5626. }
  5627. var firstIndex = 0;
  5628. if(ignoreTxt){
  5629. if(node.nodeType == 3){
  5630. var tmpNode = node.previousSibling;
  5631. while(tmpNode && tmpNode.nodeType == 3){
  5632. firstIndex += tmpNode.nodeValue.replace(fillCharReg,'').length;
  5633. tmpNode = tmpNode.previousSibling;
  5634. }
  5635. firstIndex += (isStart ? me.startOffset : me.endOffset)// - (fillCharReg.test(node.nodeValue) ? 1 : 0 )
  5636. }else{
  5637. node = node.childNodes[ isStart ? me.startOffset : me.endOffset];
  5638. if(node){
  5639. firstIndex = domUtils.getNodeIndex(node,ignoreTxt);
  5640. }else{
  5641. node = isStart ? me.startContainer : me.endContainer;
  5642. var first = node.firstChild;
  5643. while(first){
  5644. if(domUtils.isFillChar(first)){
  5645. first = first.nextSibling;
  5646. continue;
  5647. }
  5648. firstIndex++;
  5649. if(first.nodeType == 3){
  5650. while( first && first.nodeType == 3){
  5651. first = first.nextSibling;
  5652. }
  5653. }else{
  5654. first = first.nextSibling;
  5655. }
  5656. }
  5657. }
  5658. }
  5659. }else{
  5660. firstIndex = isStart ? domUtils.isFillChar(node) ? 0 : me.startOffset : me.endOffset
  5661. }
  5662. if(firstIndex < 0){
  5663. firstIndex = 0;
  5664. }
  5665. addrs.push(firstIndex);
  5666. return addrs;
  5667. }
  5668. addr.startAddress = getAddress(true);
  5669. if(!ignoreEnd){
  5670. addr.endAddress = me.collapsed ? [].concat(addr.startAddress) : getAddress();
  5671. }
  5672. return addr;
  5673. },
  5674. /**
  5675. * 保存
  5676. * @method createAddress
  5677. * @private
  5678. * @return { Boolean } 返回开始和结束的位置
  5679. * @example
  5680. * ```html
  5681. * <body>
  5682. * <p>
  5683. * aaaa
  5684. * <em>
  5685. * <!-- 选区开始 -->
  5686. * bbbb
  5687. * <!-- 选区结束 -->
  5688. * </em>
  5689. * </p>
  5690. *
  5691. * <script>
  5692. * var range = editor.selection.getRange();
  5693. * range.moveToAddress({startAddress:[0,1,0,0],endAddress:[0,1,0,4]});
  5694. * range.select();
  5695. * //output: 'bbbb'
  5696. * console.log(editor.selection.getText());
  5697. * </script>
  5698. * </body>
  5699. * ```
  5700. */
  5701. moveToAddress : function(addr,ignoreEnd){
  5702. var me = this;
  5703. function getNode(address,isStart){
  5704. var tmpNode = me.document.body,
  5705. parentNode,offset;
  5706. for(var i= 0,ci,l=address.length;i<l;i++){
  5707. ci = address[i];
  5708. parentNode = tmpNode;
  5709. tmpNode = tmpNode.childNodes[ci];
  5710. if(!tmpNode){
  5711. offset = ci;
  5712. break;
  5713. }
  5714. }
  5715. if(isStart){
  5716. if(tmpNode){
  5717. me.setStartBefore(tmpNode)
  5718. }else{
  5719. me.setStart(parentNode,offset)
  5720. }
  5721. }else{
  5722. if(tmpNode){
  5723. me.setEndBefore(tmpNode)
  5724. }else{
  5725. me.setEnd(parentNode,offset)
  5726. }
  5727. }
  5728. }
  5729. getNode(addr.startAddress,true);
  5730. !ignoreEnd && addr.endAddress && getNode(addr.endAddress);
  5731. return me;
  5732. },
  5733. /**
  5734. * 判断给定的Range对象是否和当前Range对象表示的是同一个选区
  5735. * @method equals
  5736. * @param { UE.dom.Range } 需要判断的Range对象
  5737. * @return { Boolean } 如果给定的Range对象与当前Range对象表示的是同一个选区, 则返回true, 否则返回false
  5738. */
  5739. equals : function(rng){
  5740. for(var p in this){
  5741. if(this.hasOwnProperty(p)){
  5742. if(this[p] !== rng[p])
  5743. return false
  5744. }
  5745. }
  5746. return true;
  5747. },
  5748. /**
  5749. * 遍历range内的节点。每当遍历一个节点时, 都会执行参数项 doFn 指定的函数, 该函数的接受当前遍历的节点
  5750. * 作为其参数。
  5751. * @method traversal
  5752. * @param { Function } doFn 对每个遍历的节点要执行的方法, 该方法接受当前遍历的节点作为其参数
  5753. * @return { UE.dom.Range } 当前range对象
  5754. * @example
  5755. * ```html
  5756. *
  5757. * <body>
  5758. *
  5759. * <!-- 选区开始 -->
  5760. * <span></span>
  5761. * <a></a>
  5762. * <!-- 选区结束 -->
  5763. * </body>
  5764. *
  5765. * <script>
  5766. *
  5767. * //output: <span></span><a></a>
  5768. * console.log( range.cloneContents() );
  5769. *
  5770. * range.traversal( function ( node ) {
  5771. *
  5772. * if ( node.nodeType === 1 ) {
  5773. * node.className = "test";
  5774. * }
  5775. *
  5776. * } );
  5777. *
  5778. * //output: <span class="test"></span><a class="test"></a>
  5779. * console.log( range.cloneContents() );
  5780. *
  5781. * </script>
  5782. * ```
  5783. */
  5784. /**
  5785. * 遍历range内的节点。
  5786. * 每当遍历一个节点时, 都会执行参数项 doFn 指定的函数, 该函数的接受当前遍历的节点
  5787. * 作为其参数。
  5788. * 可以通过参数项 filterFn 来指定一个过滤器, 只有符合该过滤器过滤规则的节点才会触
  5789. * 发doFn函数的执行
  5790. * @method traversal
  5791. * @param { Function } doFn 对每个遍历的节点要执行的方法, 该方法接受当前遍历的节点作为其参数
  5792. * @param { Function } filterFn 过滤器, 该函数接受当前遍历的节点作为参数, 如果该节点满足过滤
  5793. * 规则, 请返回true, 该节点会触发doFn, 否则, 请返回false, 则该节点不
  5794. * 会触发doFn。
  5795. * @return { UE.dom.Range } 当前range对象
  5796. * @see UE.dom.Range:traversal(Function)
  5797. * @example
  5798. * ```html
  5799. *
  5800. * <body>
  5801. *
  5802. * <!-- 选区开始 -->
  5803. * <span></span>
  5804. * <a></a>
  5805. * <!-- 选区结束 -->
  5806. * </body>
  5807. *
  5808. * <script>
  5809. *
  5810. * //output: <span></span><a></a>
  5811. * console.log( range.cloneContents() );
  5812. *
  5813. * range.traversal( function ( node ) {
  5814. *
  5815. * node.className = "test";
  5816. *
  5817. * }, function ( node ) {
  5818. * return node.nodeType === 1;
  5819. * } );
  5820. *
  5821. * //output: <span class="test"></span><a class="test"></a>
  5822. * console.log( range.cloneContents() );
  5823. *
  5824. * </script>
  5825. * ```
  5826. */
  5827. traversal:function(doFn,filterFn){
  5828. if (this.collapsed)
  5829. return this;
  5830. var bookmark = this.createBookmark(),
  5831. end = bookmark.end,
  5832. current = domUtils.getNextDomNode(bookmark.start, false, filterFn);
  5833. while (current && current !== end && (domUtils.getPosition(current, end) & domUtils.POSITION_PRECEDING)) {
  5834. var tmpNode = domUtils.getNextDomNode(current,false,filterFn);
  5835. doFn(current);
  5836. current = tmpNode;
  5837. }
  5838. return this.moveToBookmark(bookmark);
  5839. }
  5840. };
  5841. })();
  5842. // core/Selection.js
  5843. /**
  5844. * 选集
  5845. * @file
  5846. * @module UE.dom
  5847. * @class Selection
  5848. * @since 1.2.6.1
  5849. */
  5850. /**
  5851. * 选区集合
  5852. * @unfile
  5853. * @module UE.dom
  5854. * @class Selection
  5855. */
  5856. (function () {
  5857. function getBoundaryInformation( range, start ) {
  5858. var getIndex = domUtils.getNodeIndex;
  5859. range = range.duplicate();
  5860. range.collapse( start );
  5861. var parent = range.parentElement();
  5862. //如果节点里没有子节点,直接退出
  5863. if ( !parent.hasChildNodes() ) {
  5864. return {container:parent, offset:0};
  5865. }
  5866. var siblings = parent.children,
  5867. child,
  5868. testRange = range.duplicate(),
  5869. startIndex = 0, endIndex = siblings.length - 1, index = -1,
  5870. distance;
  5871. while ( startIndex <= endIndex ) {
  5872. index = Math.floor( (startIndex + endIndex) / 2 );
  5873. child = siblings[index];
  5874. testRange.moveToElementText( child );
  5875. var position = testRange.compareEndPoints( 'StartToStart', range );
  5876. if ( position > 0 ) {
  5877. endIndex = index - 1;
  5878. } else if ( position < 0 ) {
  5879. startIndex = index + 1;
  5880. } else {
  5881. //trace:1043
  5882. return {container:parent, offset:getIndex( child )};
  5883. }
  5884. }
  5885. if ( index == -1 ) {
  5886. testRange.moveToElementText( parent );
  5887. testRange.setEndPoint( 'StartToStart', range );
  5888. distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length;
  5889. siblings = parent.childNodes;
  5890. if ( !distance ) {
  5891. child = siblings[siblings.length - 1];
  5892. return {container:child, offset:child.nodeValue.length};
  5893. }
  5894. var i = siblings.length;
  5895. while ( distance > 0 ){
  5896. distance -= siblings[ --i ].nodeValue.length;
  5897. }
  5898. return {container:siblings[i], offset:-distance};
  5899. }
  5900. testRange.collapse( position > 0 );
  5901. testRange.setEndPoint( position > 0 ? 'StartToStart' : 'EndToStart', range );
  5902. distance = testRange.text.replace( /(\r\n|\r)/g, '\n' ).length;
  5903. if ( !distance ) {
  5904. return dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName] ?
  5905. {container:parent, offset:getIndex( child ) + (position > 0 ? 0 : 1)} :
  5906. {container:child, offset:position > 0 ? 0 : child.childNodes.length}
  5907. }
  5908. while ( distance > 0 ) {
  5909. try {
  5910. var pre = child;
  5911. child = child[position > 0 ? 'previousSibling' : 'nextSibling'];
  5912. distance -= child.nodeValue.length;
  5913. } catch ( e ) {
  5914. return {container:parent, offset:getIndex( pre )};
  5915. }
  5916. }
  5917. return {container:child, offset:position > 0 ? -distance : child.nodeValue.length + distance}
  5918. }
  5919. /**
  5920. * 将ieRange转换为Range对象
  5921. * @param {Range} ieRange ieRange对象
  5922. * @param {Range} range Range对象
  5923. * @return {Range} range 返回转换后的Range对象
  5924. */
  5925. function transformIERangeToRange( ieRange, range ) {
  5926. if ( ieRange.item ) {
  5927. range.selectNode( ieRange.item( 0 ) );
  5928. } else {
  5929. var bi = getBoundaryInformation( ieRange, true );
  5930. range.setStart( bi.container, bi.offset );
  5931. if ( ieRange.compareEndPoints( 'StartToEnd', ieRange ) != 0 ) {
  5932. bi = getBoundaryInformation( ieRange, false );
  5933. range.setEnd( bi.container, bi.offset );
  5934. }
  5935. }
  5936. return range;
  5937. }
  5938. /**
  5939. * 获得ieRange
  5940. * @param {Selection} sel Selection对象
  5941. * @return {ieRange} 得到ieRange
  5942. */
  5943. function _getIERange( sel ) {
  5944. var ieRange;
  5945. //ie下有可能报错
  5946. try {
  5947. ieRange = sel.getNative().createRange();
  5948. } catch ( e ) {
  5949. return null;
  5950. }
  5951. var el = ieRange.item ? ieRange.item( 0 ) : ieRange.parentElement();
  5952. if ( ( el.ownerDocument || el ) === sel.document ) {
  5953. return ieRange;
  5954. }
  5955. return null;
  5956. }
  5957. var Selection = dom.Selection = function ( doc ) {
  5958. var me = this, iframe;
  5959. me.document = doc;
  5960. if ( browser.ie9below ) {
  5961. iframe = domUtils.getWindow( doc ).frameElement;
  5962. domUtils.on( iframe, 'beforedeactivate', function () {
  5963. me._bakIERange = me.getIERange();
  5964. } );
  5965. domUtils.on( iframe, 'activate', function () {
  5966. try {
  5967. if ( !_getIERange( me ) && me._bakIERange ) {
  5968. me._bakIERange.select();
  5969. }
  5970. } catch ( ex ) {
  5971. }
  5972. me._bakIERange = null;
  5973. } );
  5974. }
  5975. iframe = doc = null;
  5976. };
  5977. Selection.prototype = {
  5978. rangeInBody : function(rng,txtRange){
  5979. var node = browser.ie9below || txtRange ? rng.item ? rng.item() : rng.parentElement() : rng.startContainer;
  5980. return node === this.document.body || domUtils.inDoc(node,this.document);
  5981. },
  5982. /**
  5983. * 获取原生seleciton对象
  5984. * @method getNative
  5985. * @return { Object } 获得selection对象
  5986. * @example
  5987. * ```javascript
  5988. * editor.selection.getNative();
  5989. * ```
  5990. */
  5991. getNative:function () {
  5992. var doc = this.document;
  5993. try {
  5994. return !doc ? null : browser.ie9below ? doc.selection : domUtils.getWindow( doc ).getSelection();
  5995. } catch ( e ) {
  5996. return null;
  5997. }
  5998. },
  5999. /**
  6000. * 获得ieRange
  6001. * @method getIERange
  6002. * @return { Object } 返回ie原生的Range
  6003. * @example
  6004. * ```javascript
  6005. * editor.selection.getIERange();
  6006. * ```
  6007. */
  6008. getIERange:function () {
  6009. var ieRange = _getIERange( this );
  6010. if ( !ieRange ) {
  6011. if ( this._bakIERange ) {
  6012. return this._bakIERange;
  6013. }
  6014. }
  6015. return ieRange;
  6016. },
  6017. /**
  6018. * 缓存当前选区的range和选区的开始节点
  6019. * @method cache
  6020. */
  6021. cache:function () {
  6022. this.clear();
  6023. this._cachedRange = this.getRange();
  6024. this._cachedStartElement = this.getStart();
  6025. this._cachedStartElementPath = this.getStartElementPath();
  6026. },
  6027. /**
  6028. * 获取选区开始位置的父节点到body
  6029. * @method getStartElementPath
  6030. * @return { Array } 返回父节点集合
  6031. * @example
  6032. * ```javascript
  6033. * editor.selection.getStartElementPath();
  6034. * ```
  6035. */
  6036. getStartElementPath:function () {
  6037. if ( this._cachedStartElementPath ) {
  6038. return this._cachedStartElementPath;
  6039. }
  6040. var start = this.getStart();
  6041. if ( start ) {
  6042. return domUtils.findParents( start, true, null, true )
  6043. }
  6044. return [];
  6045. },
  6046. /**
  6047. * 清空缓存
  6048. * @method clear
  6049. */
  6050. clear:function () {
  6051. this._cachedStartElementPath = this._cachedRange = this._cachedStartElement = null;
  6052. },
  6053. /**
  6054. * 编辑器是否得到了选区
  6055. * @method isFocus
  6056. */
  6057. isFocus:function () {
  6058. try {
  6059. if(browser.ie9below){
  6060. var nativeRange = _getIERange(this);
  6061. return !!(nativeRange && this.rangeInBody(nativeRange));
  6062. }else{
  6063. return !!this.getNative().rangeCount;
  6064. }
  6065. } catch ( e ) {
  6066. return false;
  6067. }
  6068. },
  6069. /**
  6070. * 获取选区对应的Range
  6071. * @method getRange
  6072. * @return { Object } 得到Range对象
  6073. * @example
  6074. * ```javascript
  6075. * editor.selection.getRange();
  6076. * ```
  6077. */
  6078. getRange:function () {
  6079. var me = this;
  6080. function optimze( range ) {
  6081. var child = me.document.body.firstChild,
  6082. collapsed = range.collapsed;
  6083. while ( child && child.firstChild ) {
  6084. range.setStart( child, 0 );
  6085. child = child.firstChild;
  6086. }
  6087. if ( !range.startContainer ) {
  6088. range.setStart( me.document.body, 0 )
  6089. }
  6090. if ( collapsed ) {
  6091. range.collapse( true );
  6092. }
  6093. }
  6094. if ( me._cachedRange != null ) {
  6095. return this._cachedRange;
  6096. }
  6097. var range = new baidu.editor.dom.Range( me.document );
  6098. if ( browser.ie9below ) {
  6099. var nativeRange = me.getIERange();
  6100. if ( nativeRange ) {
  6101. //备份的_bakIERange可能已经实效了,dom树发生了变化比如从源码模式切回来,所以try一下,实效就放到body开始位置
  6102. try{
  6103. transformIERangeToRange( nativeRange, range );
  6104. }catch(e){
  6105. optimze( range );
  6106. }
  6107. } else {
  6108. optimze( range );
  6109. }
  6110. } else {
  6111. var sel = me.getNative();
  6112. if ( sel && sel.rangeCount ) {
  6113. var firstRange = sel.getRangeAt( 0 );
  6114. var lastRange = sel.getRangeAt( sel.rangeCount - 1 );
  6115. range.setStart( firstRange.startContainer, firstRange.startOffset ).setEnd( lastRange.endContainer, lastRange.endOffset );
  6116. if ( range.collapsed && domUtils.isBody( range.startContainer ) && !range.startOffset ) {
  6117. optimze( range );
  6118. }
  6119. } else {
  6120. //trace:1734 有可能已经不在dom树上了,标识的节点
  6121. if ( this._bakRange && domUtils.inDoc( this._bakRange.startContainer, this.document ) ){
  6122. return this._bakRange;
  6123. }
  6124. optimze( range );
  6125. }
  6126. }
  6127. return this._bakRange = range;
  6128. },
  6129. /**
  6130. * 获取开始元素,用于状态反射
  6131. * @method getStart
  6132. * @return { Element } 获得开始元素
  6133. * @example
  6134. * ```javascript
  6135. * editor.selection.getStart();
  6136. * ```
  6137. */
  6138. getStart:function () {
  6139. if ( this._cachedStartElement ) {
  6140. return this._cachedStartElement;
  6141. }
  6142. var range = browser.ie9below ? this.getIERange() : this.getRange(),
  6143. tmpRange,
  6144. start, tmp, parent;
  6145. if ( browser.ie9below ) {
  6146. if ( !range ) {
  6147. //todo 给第一个值可能会有问题
  6148. return this.document.body.firstChild;
  6149. }
  6150. //control元素
  6151. if ( range.item ){
  6152. return range.item( 0 );
  6153. }
  6154. tmpRange = range.duplicate();
  6155. //修正ie下<b>x</b>[xx] 闭合后 <b>x|</b>xx
  6156. tmpRange.text.length > 0 && tmpRange.moveStart( 'character', 1 );
  6157. tmpRange.collapse( 1 );
  6158. start = tmpRange.parentElement();
  6159. parent = tmp = range.parentElement();
  6160. while ( tmp = tmp.parentNode ) {
  6161. if ( tmp == start ) {
  6162. start = parent;
  6163. break;
  6164. }
  6165. }
  6166. } else {
  6167. range.shrinkBoundary();
  6168. start = range.startContainer;
  6169. if ( start.nodeType == 1 && start.hasChildNodes() ){
  6170. start = start.childNodes[Math.min( start.childNodes.length - 1, range.startOffset )];
  6171. }
  6172. if ( start.nodeType == 3 ){
  6173. return start.parentNode;
  6174. }
  6175. }
  6176. return start;
  6177. },
  6178. /**
  6179. * 得到选区中的文本
  6180. * @method getText
  6181. * @return { String } 选区中包含的文本
  6182. * @example
  6183. * ```javascript
  6184. * editor.selection.getText();
  6185. * ```
  6186. */
  6187. getText:function () {
  6188. var nativeSel, nativeRange;
  6189. if ( this.isFocus() && (nativeSel = this.getNative()) ) {
  6190. nativeRange = browser.ie9below ? nativeSel.createRange() : nativeSel.getRangeAt( 0 );
  6191. return browser.ie9below ? nativeRange.text : nativeRange.toString();
  6192. }
  6193. return '';
  6194. },
  6195. /**
  6196. * 清除选区
  6197. * @method clearRange
  6198. * @example
  6199. * ```javascript
  6200. * editor.selection.clearRange();
  6201. * ```
  6202. */
  6203. clearRange : function(){
  6204. this.getNative()[browser.ie9below ? 'empty' : 'removeAllRanges']();
  6205. }
  6206. };
  6207. })();
  6208. // core/Editor.js
  6209. /**
  6210. * 编辑器主类,包含编辑器提供的大部分公用接口
  6211. * @file
  6212. * @module UE
  6213. * @class Editor
  6214. * @since 1.2.6.1
  6215. */
  6216. /**
  6217. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  6218. * @unfile
  6219. * @module UE
  6220. */
  6221. /**
  6222. * UEditor的核心类,为用户提供与编辑器交互的接口。
  6223. * @unfile
  6224. * @module UE
  6225. * @class Editor
  6226. */
  6227. (function () {
  6228. var uid = 0, _selectionChangeTimer;
  6229. /**
  6230. * 获取编辑器的html内容,赋值到编辑器所在表单的textarea文本域里面
  6231. * @private
  6232. * @method setValue
  6233. * @param { UE.Editor } editor 编辑器事例
  6234. */
  6235. function setValue(form, editor) {
  6236. var textarea;
  6237. if (editor.textarea) {
  6238. if (utils.isString(editor.textarea)) {
  6239. for (var i = 0, ti, tis = domUtils.getElementsByTagName(form, 'textarea'); ti = tis[i++];) {
  6240. if (ti.id == 'ueditor_textarea_' + editor.options.textarea) {
  6241. textarea = ti;
  6242. break;
  6243. }
  6244. }
  6245. } else {
  6246. textarea = editor.textarea;
  6247. }
  6248. }
  6249. if (!textarea) {
  6250. form.appendChild(textarea = domUtils.createElement(document, 'textarea', {
  6251. 'name': editor.options.textarea,
  6252. 'id': 'ueditor_textarea_' + editor.options.textarea,
  6253. 'style': "display:none"
  6254. }));
  6255. //不要产生多个textarea
  6256. editor.textarea = textarea;
  6257. }
  6258. !textarea.getAttribute('name') && textarea.setAttribute('name', editor.options.textarea );
  6259. textarea.value = editor.hasContents() ?
  6260. (editor.options.allHtmlEnabled ? editor.getAllHtml() : editor.getContent(null, null, true)) :
  6261. ''
  6262. }
  6263. function loadPlugins(me){
  6264. //初始化插件
  6265. for (var pi in UE.plugins) {
  6266. UE.plugins[pi].call(me);
  6267. }
  6268. }
  6269. function checkCurLang(I18N){
  6270. for(var lang in I18N){
  6271. return lang
  6272. }
  6273. }
  6274. function langReadied(me){
  6275. me.langIsReady = true;
  6276. me.fireEvent("langReady");
  6277. }
  6278. /**
  6279. * 编辑器准备就绪后会触发该事件
  6280. * @module UE
  6281. * @class Editor
  6282. * @event ready
  6283. * @remind render方法执行完成之后,会触发该事件
  6284. * @remind
  6285. * @example
  6286. * ```javascript
  6287. * editor.addListener( 'ready', function( editor ) {
  6288. * editor.execCommand( 'focus' ); //编辑器家在完成后,让编辑器拿到焦点
  6289. * } );
  6290. * ```
  6291. */
  6292. /**
  6293. * 执行destroy方法,会触发该事件
  6294. * @module UE
  6295. * @class Editor
  6296. * @event destroy
  6297. * @see UE.Editor:destroy()
  6298. */
  6299. /**
  6300. * 执行reset方法,会触发该事件
  6301. * @module UE
  6302. * @class Editor
  6303. * @event reset
  6304. * @see UE.Editor:reset()
  6305. */
  6306. /**
  6307. * 执行focus方法,会触发该事件
  6308. * @module UE
  6309. * @class Editor
  6310. * @event focus
  6311. * @see UE.Editor:focus(Boolean)
  6312. */
  6313. /**
  6314. * 语言加载完成会触发该事件
  6315. * @module UE
  6316. * @class Editor
  6317. * @event langReady
  6318. */
  6319. /**
  6320. * 运行命令之后会触发该命令
  6321. * @module UE
  6322. * @class Editor
  6323. * @event beforeExecCommand
  6324. */
  6325. /**
  6326. * 运行命令之后会触发该命令
  6327. * @module UE
  6328. * @class Editor
  6329. * @event afterExecCommand
  6330. */
  6331. /**
  6332. * 运行命令之前会触发该命令
  6333. * @module UE
  6334. * @class Editor
  6335. * @event firstBeforeExecCommand
  6336. */
  6337. /**
  6338. * 在getContent方法执行之前会触发该事件
  6339. * @module UE
  6340. * @class Editor
  6341. * @event beforeGetContent
  6342. * @see UE.Editor:getContent()
  6343. */
  6344. /**
  6345. * 在getContent方法执行之后会触发该事件
  6346. * @module UE
  6347. * @class Editor
  6348. * @event afterGetContent
  6349. * @see UE.Editor:getContent()
  6350. */
  6351. /**
  6352. * 在getAllHtml方法执行时会触发该事件
  6353. * @module UE
  6354. * @class Editor
  6355. * @event getAllHtml
  6356. * @see UE.Editor:getAllHtml()
  6357. */
  6358. /**
  6359. * 在setContent方法执行之前会触发该事件
  6360. * @module UE
  6361. * @class Editor
  6362. * @event beforeSetContent
  6363. * @see UE.Editor:setContent(String)
  6364. */
  6365. /**
  6366. * 在setContent方法执行之后会触发该事件
  6367. * @module UE
  6368. * @class Editor
  6369. * @event afterSetContent
  6370. * @see UE.Editor:setContent(String)
  6371. */
  6372. /**
  6373. * 每当编辑器内部选区发生改变时,将触发该事件
  6374. * @event selectionchange
  6375. * @warning 该事件的触发非常频繁,不建议在该事件的处理过程中做重量级的处理
  6376. * @example
  6377. * ```javascript
  6378. * editor.addListener( 'selectionchange', function( editor ) {
  6379. * console.log('选区发生改变');
  6380. * }
  6381. */
  6382. /**
  6383. * 在所有selectionchange的监听函数执行之前,会触发该事件
  6384. * @module UE
  6385. * @class Editor
  6386. * @event beforeSelectionChange
  6387. * @see UE.Editor:selectionchange
  6388. */
  6389. /**
  6390. * 在所有selectionchange的监听函数执行完之后,会触发该事件
  6391. * @module UE
  6392. * @class Editor
  6393. * @event afterSelectionChange
  6394. * @see UE.Editor:selectionchange
  6395. */
  6396. /**
  6397. * 编辑器内容发生改变时会触发该事件
  6398. * @module UE
  6399. * @class Editor
  6400. * @event contentChange
  6401. */
  6402. /**
  6403. * 以默认参数构建一个编辑器实例
  6404. * @constructor
  6405. * @remind 通过 改构造方法实例化的编辑器,不带ui层.需要render到一个容器,编辑器实例才能正常渲染到页面
  6406. * @example
  6407. * ```javascript
  6408. * var editor = new UE.Editor();
  6409. * editor.execCommand('blod');
  6410. * ```
  6411. * @see UE.Config
  6412. */
  6413. /**
  6414. * 以给定的参数集合创建一个编辑器实例,对于未指定的参数,将应用默认参数。
  6415. * @constructor
  6416. * @remind 通过 改构造方法实例化的编辑器,不带ui层.需要render到一个容器,编辑器实例才能正常渲染到页面
  6417. * @param { Object } setting 创建编辑器的参数
  6418. * @example
  6419. * ```javascript
  6420. * var editor = new UE.Editor();
  6421. * editor.execCommand('blod');
  6422. * ```
  6423. * @see UE.Config
  6424. */
  6425. var Editor = UE.Editor = function (options) {
  6426. var me = this;
  6427. me.uid = uid++;
  6428. EventBase.call(me);
  6429. me.commands = {};
  6430. me.options = utils.extend(utils.clone(options || {}), UEDITOR_CONFIG, true);
  6431. me.shortcutkeys = {};
  6432. me.inputRules = [];
  6433. me.outputRules = [];
  6434. //设置默认的常用属性
  6435. me.setOpt(Editor.defaultOptions(me));
  6436. /* 尝试异步加载后台配置 */
  6437. me.loadServerConfig();
  6438. if(!utils.isEmptyObject(UE.I18N)){
  6439. //修改默认的语言类型
  6440. me.options.lang = checkCurLang(UE.I18N);
  6441. UE.plugin.load(me);
  6442. langReadied(me);
  6443. }else{
  6444. utils.loadFile(document, {
  6445. src: me.options.langPath + me.options.lang + "/" + me.options.lang + ".js",
  6446. tag: "script",
  6447. type: "text/javascript",
  6448. defer: "defer"
  6449. }, function () {
  6450. UE.plugin.load(me);
  6451. langReadied(me);
  6452. });
  6453. }
  6454. UE.instants['ueditorInstant' + me.uid] = me;
  6455. };
  6456. Editor.prototype = {
  6457. registerCommand : function(name,obj){
  6458. this.commands[name] = obj;
  6459. },
  6460. /**
  6461. * 编辑器对外提供的监听ready事件的接口, 通过调用该方法,达到的效果与监听ready事件是一致的
  6462. * @method ready
  6463. * @param { Function } fn 编辑器ready之后所执行的回调, 如果在注册事件之前编辑器已经ready,将会
  6464. * 立即触发该回调。
  6465. * @remind 需要等待编辑器加载完成后才能执行的代码,可以使用该方法传入
  6466. * @example
  6467. * ```javascript
  6468. * editor.ready( function( editor ) {
  6469. * editor.setContent('初始化完毕');
  6470. * } );
  6471. * ```
  6472. * @see UE.Editor.event:ready
  6473. */
  6474. ready: function (fn) {
  6475. var me = this;
  6476. if (fn) {
  6477. me.isReady ? fn.apply(me) : me.addListener('ready', fn);
  6478. }
  6479. },
  6480. /**
  6481. * 该方法是提供给插件里面使用,设置配置项默认值
  6482. * @method setOpt
  6483. * @warning 三处设置配置项的优先级: 实例化时传入参数 > setOpt()设置 > config文件里设置
  6484. * @warning 该方法仅供编辑器插件内部和编辑器初始化时调用,其他地方不能调用。
  6485. * @param { String } key 编辑器的可接受的选项名称
  6486. * @param { * } val 该选项可接受的值
  6487. * @example
  6488. * ```javascript
  6489. * editor.setOpt( 'initContent', '欢迎使用编辑器' );
  6490. * ```
  6491. */
  6492. /**
  6493. * 该方法是提供给插件里面使用,以{key:value}集合的方式设置插件内用到的配置项默认值
  6494. * @method setOpt
  6495. * @warning 三处设置配置项的优先级: 实例化时传入参数 > setOpt()设置 > config文件里设置
  6496. * @warning 该方法仅供编辑器插件内部和编辑器初始化时调用,其他地方不能调用。
  6497. * @param { Object } options 将要设置的选项的键值对对象
  6498. * @example
  6499. * ```javascript
  6500. * editor.setOpt( {
  6501. * 'initContent': '欢迎使用编辑器'
  6502. * } );
  6503. * ```
  6504. */
  6505. setOpt: function (key, val) {
  6506. var obj = {};
  6507. if (utils.isString(key)) {
  6508. obj[key] = val
  6509. } else {
  6510. obj = key;
  6511. }
  6512. utils.extend(this.options, obj, true);
  6513. },
  6514. getOpt:function(key){
  6515. return this.options[key]
  6516. },
  6517. /**
  6518. * 销毁编辑器实例,使用textarea代替
  6519. * @method destroy
  6520. * @example
  6521. * ```javascript
  6522. * editor.destroy();
  6523. * ```
  6524. */
  6525. destroy: function () {
  6526. var me = this;
  6527. me.fireEvent('destroy');
  6528. var container = me.container.parentNode;
  6529. var textarea = me.textarea;
  6530. if (!textarea) {
  6531. textarea = document.createElement('textarea');
  6532. container.parentNode.insertBefore(textarea, container);
  6533. } else {
  6534. textarea.style.display = ''
  6535. }
  6536. textarea.style.width = me.iframe.offsetWidth + 'px';
  6537. textarea.style.height = me.iframe.offsetHeight + 'px';
  6538. textarea.value = me.getContent();
  6539. textarea.id = me.key;
  6540. container.innerHTML = '';
  6541. domUtils.remove(container);
  6542. var key = me.key;
  6543. //trace:2004
  6544. for (var p in me) {
  6545. if (me.hasOwnProperty(p)) {
  6546. delete this[p];
  6547. }
  6548. }
  6549. UE.delEditor(key);
  6550. },
  6551. /**
  6552. * 渲染编辑器的DOM到指定容器
  6553. * @method render
  6554. * @param { String } containerId 指定一个容器ID
  6555. * @remind 执行该方法,会触发ready事件
  6556. * @warning 必须且只能调用一次
  6557. */
  6558. /**
  6559. * 渲染编辑器的DOM到指定容器
  6560. * @method render
  6561. * @param { Element } containerDom 直接指定容器对象
  6562. * @remind 执行该方法,会触发ready事件
  6563. * @warning 必须且只能调用一次
  6564. */
  6565. render: function (container) {
  6566. var me = this,
  6567. options = me.options,
  6568. getStyleValue=function(attr){
  6569. return parseInt(domUtils.getComputedStyle(container,attr));
  6570. };
  6571. if (utils.isString(container)) {
  6572. container = document.getElementById(container);
  6573. }
  6574. if (container) {
  6575. if(options.initialFrameWidth){
  6576. options.minFrameWidth = options.initialFrameWidth
  6577. }else{
  6578. options.minFrameWidth = options.initialFrameWidth = container.offsetWidth;
  6579. }
  6580. if(options.initialFrameHeight){
  6581. options.minFrameHeight = options.initialFrameHeight
  6582. }else{
  6583. options.initialFrameHeight = options.minFrameHeight = container.offsetHeight;
  6584. }
  6585. container.style.width = /%$/.test(options.initialFrameWidth) ? '100%' : options.initialFrameWidth-
  6586. getStyleValue("padding-left")- getStyleValue("padding-right") +'px';
  6587. container.style.height = /%$/.test(options.initialFrameHeight) ? '100%' : options.initialFrameHeight -
  6588. getStyleValue("padding-top")- getStyleValue("padding-bottom") +'px';
  6589. container.style.zIndex = options.zIndex;
  6590. var html = ( ie && browser.version < 9 ? '' : '<!DOCTYPE html>') +
  6591. '<html xmlns=\'http://www.w3.org/1999/xhtml\' class=\'view\' ><head>' +
  6592. '<style type=\'text/css\'>' +
  6593. //设置四周的留边
  6594. '.view{padding:0;word-wrap:break-word;cursor:text;height:90%;}\n' +
  6595. //设置默认字体和字号
  6596. //font-family不能呢随便改,在safari下fillchar会有解析问题
  6597. 'body{margin:0;font-family:sans-serif;font-size:12px;}' +
  6598. //设置段落间距
  6599. 'p{margin:0;}</style>' +
  6600. ( options.iframeCssUrl ? '<link rel=\'stylesheet\' type=\'text/css\' href=\'' + utils.unhtml(options.iframeCssUrl) + '\'/>' : '' ) +
  6601. (options.initialStyle ? '<style>' + options.initialStyle + '</style>' : '') +
  6602. '</head><body class=\'view\' ></body>' +
  6603. '<script type=\'text/javascript\' ' + (ie ? 'defer=\'defer\'' : '' ) +' id=\'_initialScript\'>' +
  6604. 'setTimeout(function(){editor = window.parent.UE.instants[\'ueditorInstant' + me.uid + '\'];editor._setup(document);},0);' +
  6605. 'var _tmpScript = document.getElementById(\'_initialScript\');_tmpScript.parentNode.removeChild(_tmpScript);</script></html>';
  6606. container.appendChild(domUtils.createElement(document, 'iframe', {
  6607. id: 'ueditor_' + me.uid,
  6608. width: "100%",
  6609. height: "100%",
  6610. frameborder: "0",
  6611. //先注释掉了,加的原因忘记了,但开启会直接导致全屏模式下内容多时不会出现滚动条
  6612. // scrolling :'no',
  6613. src: 'javascript:void(function(){document.open();' + (options.customDomain && document.domain != location.hostname ? 'document.domain="' + document.domain + '";' : '') +
  6614. 'document.write("' + html + '");document.close();}())'
  6615. }));
  6616. container.style.overflow = 'hidden';
  6617. //解决如果是给定的百分比,会导致高度算不对的问题
  6618. setTimeout(function(){
  6619. if( /%$/.test(options.initialFrameWidth)){
  6620. options.minFrameWidth = options.initialFrameWidth = container.offsetWidth;
  6621. //如果这里给定宽度,会导致ie在拖动窗口大小时,编辑区域不随着变化
  6622. // container.style.width = options.initialFrameWidth + 'px';
  6623. }
  6624. if(/%$/.test(options.initialFrameHeight)){
  6625. options.minFrameHeight = options.initialFrameHeight = container.offsetHeight;
  6626. container.style.height = options.initialFrameHeight + 'px';
  6627. }
  6628. })
  6629. }
  6630. },
  6631. /**
  6632. * 编辑器初始化
  6633. * @method _setup
  6634. * @private
  6635. * @param { Element } doc 编辑器Iframe中的文档对象
  6636. */
  6637. _setup: function (doc) {
  6638. var me = this,
  6639. options = me.options;
  6640. if (ie) {
  6641. doc.body.disabled = true;
  6642. doc.body.contentEditable = true;
  6643. doc.body.disabled = false;
  6644. } else {
  6645. doc.body.contentEditable = true;
  6646. }
  6647. doc.body.spellcheck = false;
  6648. me.document = doc;
  6649. me.window = doc.defaultView || doc.parentWindow;
  6650. me.iframe = me.window.frameElement;
  6651. me.body = doc.body;
  6652. me.selection = new dom.Selection(doc);
  6653. //gecko初始化就能得到range,无法判断isFocus了
  6654. var geckoSel;
  6655. if (browser.gecko && (geckoSel = this.selection.getNative())) {
  6656. geckoSel.removeAllRanges();
  6657. }
  6658. this._initEvents();
  6659. //为form提交提供一个隐藏的textarea
  6660. for (var form = this.iframe.parentNode; !domUtils.isBody(form); form = form.parentNode) {
  6661. if (form.tagName == 'FORM') {
  6662. me.form = form;
  6663. if(me.options.autoSyncData){
  6664. domUtils.on(me.window,'blur',function(){
  6665. setValue(form,me);
  6666. });
  6667. }else{
  6668. domUtils.on(form, 'submit', function () {
  6669. setValue(this, me);
  6670. });
  6671. }
  6672. break;
  6673. }
  6674. }
  6675. if (options.initialContent) {
  6676. if (options.autoClearinitialContent) {
  6677. var oldExecCommand = me.execCommand;
  6678. me.execCommand = function () {
  6679. me.fireEvent('firstBeforeExecCommand');
  6680. return oldExecCommand.apply(me, arguments);
  6681. };
  6682. this._setDefaultContent(options.initialContent);
  6683. } else
  6684. this.setContent(options.initialContent, false, true);
  6685. }
  6686. //编辑器不能为空内容
  6687. if (domUtils.isEmptyNode(me.body)) {
  6688. me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
  6689. }
  6690. //如果要求focus, 就把光标定位到内容开始
  6691. if (options.focus) {
  6692. setTimeout(function () {
  6693. me.focus(me.options.focusInEnd);
  6694. //如果自动清除开着,就不需要做selectionchange;
  6695. !me.options.autoClearinitialContent && me._selectionChange();
  6696. }, 0);
  6697. }
  6698. if (!me.container) {
  6699. me.container = this.iframe.parentNode;
  6700. }
  6701. if (options.fullscreen && me.ui) {
  6702. me.ui.setFullScreen(true);
  6703. }
  6704. try {
  6705. me.document.execCommand('2D-position', false, false);
  6706. } catch (e) {
  6707. }
  6708. try {
  6709. me.document.execCommand('enableInlineTableEditing', false, false);
  6710. } catch (e) {
  6711. }
  6712. try {
  6713. me.document.execCommand('enableObjectResizing', false, false);
  6714. } catch (e) {
  6715. }
  6716. //挂接快捷键
  6717. me._bindshortcutKeys();
  6718. me.isReady = 1;
  6719. me.fireEvent('ready');
  6720. options.onready && options.onready.call(me);
  6721. if (!browser.ie9below) {
  6722. domUtils.on(me.window, ['blur', 'focus'], function (e) {
  6723. //chrome下会出现alt+tab切换时,导致选区位置不对
  6724. if (e.type == 'blur') {
  6725. me._bakRange = me.selection.getRange();
  6726. try {
  6727. me._bakNativeRange = me.selection.getNative().getRangeAt(0);
  6728. me.selection.getNative().removeAllRanges();
  6729. } catch (e) {
  6730. me._bakNativeRange = null;
  6731. }
  6732. } else {
  6733. try {
  6734. me._bakRange && me._bakRange.select();
  6735. } catch (e) {
  6736. }
  6737. }
  6738. });
  6739. }
  6740. //trace:1518 ff3.6body不够寛,会导致点击空白处无法获得焦点
  6741. if (browser.gecko && browser.version <= 10902) {
  6742. //修复ff3.6初始化进来,不能点击获得焦点
  6743. me.body.contentEditable = false;
  6744. setTimeout(function () {
  6745. me.body.contentEditable = true;
  6746. }, 100);
  6747. setInterval(function () {
  6748. me.body.style.height = me.iframe.offsetHeight - 20 + 'px'
  6749. }, 100)
  6750. }
  6751. !options.isShow && me.setHide();
  6752. options.readonly && me.setDisabled();
  6753. },
  6754. /**
  6755. * 同步数据到编辑器所在的form
  6756. * 从编辑器的容器节点向上查找form元素,若找到,就同步编辑内容到找到的form里,为提交数据做准备,主要用于是手动提交的情况
  6757. * 后台取得数据的键值,使用你容器上的name属性,如果没有就使用参数里的textarea项
  6758. * @method sync
  6759. * @example
  6760. * ```javascript
  6761. * editor.sync();
  6762. * form.sumbit(); //form变量已经指向了form元素
  6763. * ```
  6764. */
  6765. /**
  6766. * 根据传入的formId,在页面上查找要同步数据的表单,若找到,就同步编辑内容到找到的form里,为提交数据做准备
  6767. * 后台取得数据的键值,该键值默认使用给定的编辑器容器的name属性,如果没有name属性则使用参数项里给定的“textarea”项
  6768. * @method sync
  6769. * @param { String } formID 指定一个要同步数据的form的id,编辑器的数据会同步到你指定form下
  6770. */
  6771. sync: function (formId) {
  6772. var me = this,
  6773. form = formId ? document.getElementById(formId) :
  6774. domUtils.findParent(me.iframe.parentNode, function (node) {
  6775. return node.tagName == 'FORM'
  6776. }, true);
  6777. form && setValue(form, me);
  6778. },
  6779. /**
  6780. * 设置编辑器高度
  6781. * @method setHeight
  6782. * @remind 当配置项autoHeightEnabled为真时,该方法无效
  6783. * @param { Number } number 设置的高度值,纯数值,不带单位
  6784. * @example
  6785. * ```javascript
  6786. * editor.setHeight(number);
  6787. * ```
  6788. */
  6789. setHeight: function (height,notSetHeight) {
  6790. if (height !== parseInt(this.iframe.parentNode.style.height)) {
  6791. this.iframe.parentNode.style.height = height + 'px';
  6792. }
  6793. !notSetHeight && (this.options.minFrameHeight = this.options.initialFrameHeight = height);
  6794. this.body.style.height = height + 'px';
  6795. !notSetHeight && this.trigger('setHeight')
  6796. },
  6797. /**
  6798. * 为编辑器的编辑命令提供快捷键
  6799. * 这个接口是为插件扩展提供的接口,主要是为新添加的插件,如果需要添加快捷键,所提供的接口
  6800. * @method addshortcutkey
  6801. * @param { Object } keyset 命令名和快捷键键值对对象,多个按钮的快捷键用“+”分隔
  6802. * @example
  6803. * ```javascript
  6804. * editor.addshortcutkey({
  6805. * "Bold" : "ctrl+66",//^B
  6806. * "Italic" : "ctrl+73", //^I
  6807. * });
  6808. * ```
  6809. */
  6810. /**
  6811. * 这个接口是为插件扩展提供的接口,主要是为新添加的插件,如果需要添加快捷键,所提供的接口
  6812. * @method addshortcutkey
  6813. * @param { String } cmd 触发快捷键时,响应的命令
  6814. * @param { String } keys 快捷键的字符串,多个按钮用“+”分隔
  6815. * @example
  6816. * ```javascript
  6817. * editor.addshortcutkey("Underline", "ctrl+85"); //^U
  6818. * ```
  6819. */
  6820. addshortcutkey: function (cmd, keys) {
  6821. var obj = {};
  6822. if (keys) {
  6823. obj[cmd] = keys
  6824. } else {
  6825. obj = cmd;
  6826. }
  6827. utils.extend(this.shortcutkeys, obj)
  6828. },
  6829. /**
  6830. * 对编辑器设置keydown事件监听,绑定快捷键和命令,当快捷键组合触发成功,会响应对应的命令
  6831. * @method _bindshortcutKeys
  6832. * @private
  6833. */
  6834. _bindshortcutKeys: function () {
  6835. var me = this, shortcutkeys = this.shortcutkeys;
  6836. me.addListener('keydown', function (type, e) {
  6837. var keyCode = e.keyCode || e.which;
  6838. for (var i in shortcutkeys) {
  6839. var tmp = shortcutkeys[i].split(',');
  6840. for (var t = 0, ti; ti = tmp[t++];) {
  6841. ti = ti.split(':');
  6842. var key = ti[0], param = ti[1];
  6843. if (/^(ctrl)(\+shift)?\+(\d+)$/.test(key.toLowerCase()) || /^(\d+)$/.test(key)) {
  6844. if (( (RegExp.$1 == 'ctrl' ? (e.ctrlKey || e.metaKey) : 0)
  6845. && (RegExp.$2 != "" ? e[RegExp.$2.slice(1) + "Key"] : 1)
  6846. && keyCode == RegExp.$3
  6847. ) ||
  6848. keyCode == RegExp.$1
  6849. ) {
  6850. if (me.queryCommandState(i,param) != -1)
  6851. me.execCommand(i, param);
  6852. domUtils.preventDefault(e);
  6853. }
  6854. }
  6855. }
  6856. }
  6857. });
  6858. },
  6859. /**
  6860. * 获取编辑器的内容
  6861. * @method getContent
  6862. * @warning 该方法获取到的是经过编辑器内置的过滤规则进行过滤后得到的内容
  6863. * @return { String } 编辑器的内容字符串, 如果编辑器的内容为空,或者是空的标签内容(如:”&lt;p&gt;&lt;br/&gt;&lt;/p&gt;“), 则返回空字符串
  6864. * @example
  6865. * ```javascript
  6866. * //编辑器html内容:<p>1<strong>2<em>34</em>5</strong>6</p>
  6867. * var content = editor.getContent(); //返回值:<p>1<strong>2<em>34</em>5</strong>6</p>
  6868. * ```
  6869. */
  6870. /**
  6871. * 获取编辑器的内容。 可以通过参数定义编辑器内置的判空规则
  6872. * @method getContent
  6873. * @param { Function } fn 自定的判空规则, 要求该方法返回一个boolean类型的值,
  6874. * 代表当前编辑器的内容是否空,
  6875. * 如果返回true, 则该方法将直接返回空字符串;如果返回false,则编辑器将返回
  6876. * 经过内置过滤规则处理后的内容。
  6877. * @remind 该方法在处理包含有初始化内容的时候能起到很好的作用。
  6878. * @warning 该方法获取到的是经过编辑器内置的过滤规则进行过滤后得到的内容
  6879. * @return { String } 编辑器的内容字符串
  6880. * @example
  6881. * ```javascript
  6882. * // editor 是一个编辑器的实例
  6883. * var content = editor.getContent( function ( editor ) {
  6884. * return editor.body.innerHTML === '欢迎使用UEditor'; //返回空字符串
  6885. * } );
  6886. * ```
  6887. */
  6888. getContent: function (cmd, fn,notSetCursor,ignoreBlank,formatter) {
  6889. var me = this;
  6890. if (cmd && utils.isFunction(cmd)) {
  6891. fn = cmd;
  6892. cmd = '';
  6893. }
  6894. // if (fn ? !fn() : !this.hasContents()) {
  6895. // return '';
  6896. // }
  6897. me.fireEvent('beforegetcontent');
  6898. // var root = UE.htmlparser(me.body.innerHTML,ignoreBlank);
  6899. // me.filterOutputRule(root);
  6900. // me.fireEvent('aftergetcontent', cmd,root);
  6901. // return root.toHtml(formatter);
  6902. return me.body.innerHTML;
  6903. },
  6904. /**
  6905. * 取得完整的html代码,可以直接显示成完整的html文档
  6906. * @method getAllHtml
  6907. * @return { String } 编辑器的内容html文档字符串
  6908. * @eaxmple
  6909. * ```javascript
  6910. * editor.getAllHtml(); //返回格式大致是: <html><head>...</head><body>...</body></html>
  6911. * ```
  6912. */
  6913. getAllHtml: function () {
  6914. var me = this,
  6915. headHtml = [],
  6916. html = '';
  6917. me.fireEvent('getAllHtml', headHtml);
  6918. if (browser.ie && browser.version > 8) {
  6919. var headHtmlForIE9 = '';
  6920. utils.each(me.document.styleSheets, function (si) {
  6921. headHtmlForIE9 += ( si.href ? '<link rel="stylesheet" type="text/css" href="' + si.href + '" />' : '<style>' + si.cssText + '</style>');
  6922. });
  6923. utils.each(me.document.getElementsByTagName('script'), function (si) {
  6924. headHtmlForIE9 += si.outerHTML;
  6925. });
  6926. }
  6927. return '<html><head>' + (me.options.charset ? '<meta http-equiv="Content-Type" content="text/html; charset=' + me.options.charset + '"/>' : '')
  6928. + (headHtmlForIE9 || me.document.getElementsByTagName('head')[0].innerHTML) + headHtml.join('\n') + '</head>'
  6929. + '<body ' + (ie && browser.version < 9 ? 'class="view"' : '') + '>' + me.getContent(null, null, true) + '</body></html>';
  6930. },
  6931. /**
  6932. * 得到编辑器的纯文本内容,但会保留段落格式
  6933. * @method getPlainTxt
  6934. * @return { String } 编辑器带段落格式的纯文本内容字符串
  6935. * @example
  6936. * ```javascript
  6937. * //编辑器html内容:<p><strong>1</strong></p><p><strong>2</strong></p>
  6938. * console.log(editor.getPlainTxt()); //输出:"1\n2\n
  6939. * ```
  6940. */
  6941. getPlainTxt: function () {
  6942. var reg = new RegExp(domUtils.fillChar, 'g'),
  6943. html = this.body.innerHTML.replace(/[\n\r]/g, '');//ie要先去了\n在处理
  6944. html = html.replace(/<(p|div)[^>]*>(<br\/?>|&nbsp;)<\/\1>/gi, '\n')
  6945. .replace(/<br\/?>/gi, '\n')
  6946. .replace(/<[^>/]+>/g, '')
  6947. .replace(/(\n)?<\/([^>]+)>/g, function (a, b, c) {
  6948. return dtd.$block[c] ? '\n' : b ? b : '';
  6949. });
  6950. //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
  6951. return html.replace(reg, '').replace(/\u00a0/g, ' ').replace(/&nbsp;/g, ' ');
  6952. },
  6953. /**
  6954. * 获取编辑器中的纯文本内容,没有段落格式
  6955. * @method getContentTxt
  6956. * @return { String } 编辑器不带段落格式的纯文本内容字符串
  6957. * @example
  6958. * ```javascript
  6959. * //编辑器html内容:<p><strong>1</strong></p><p><strong>2</strong></p>
  6960. * console.log(editor.getPlainTxt()); //输出:"12
  6961. * ```
  6962. */
  6963. getContentTxt: function () {
  6964. var reg = new RegExp(domUtils.fillChar, 'g');
  6965. //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
  6966. return this.body[browser.ie ? 'innerText' : 'textContent'].replace(reg, '').replace(/\u00a0/g, ' ');
  6967. },
  6968. /**
  6969. * 设置编辑器的内容,可修改编辑器当前的html内容
  6970. * @method setContent
  6971. * @warning 通过该方法插入的内容,是经过编辑器内置的过滤规则进行过滤后得到的内容
  6972. * @warning 该方法会触发selectionchange事件
  6973. * @param { String } html 要插入的html内容
  6974. * @example
  6975. * ```javascript
  6976. * editor.getContent('<p>test</p>');
  6977. * ```
  6978. */
  6979. /**
  6980. * 设置编辑器的内容,可修改编辑器当前的html内容
  6981. * @method setContent
  6982. * @warning 通过该方法插入的内容,是经过编辑器内置的过滤规则进行过滤后得到的内容
  6983. * @warning 该方法会触发selectionchange事件
  6984. * @param { String } html 要插入的html内容
  6985. * @param { Boolean } isAppendTo 若传入true,不清空原来的内容,在最后插入内容,否则,清空内容再插入
  6986. * @example
  6987. * ```javascript
  6988. * //假设设置前的编辑器内容是 <p>old text</p>
  6989. * editor.setContent('<p>new text</p>', true); //插入的结果是<p>old text</p><p>new text</p>
  6990. * ```
  6991. */
  6992. setContent: function (html, isAppendTo, notFireSelectionchange) {
  6993. var me = this;
  6994. me.fireEvent('beforesetcontent', html);
  6995. // var root = UE.htmlparser(html);
  6996. // me.filterInputRule(root);
  6997. // html = root.toHtml();
  6998. me.body.innerHTML = (isAppendTo ? me.body.innerHTML : '') + html;
  6999. function isCdataDiv(node){
  7000. return node.tagName == 'DIV' && node.getAttribute('cdata_tag');
  7001. }
  7002. //给文本或者inline节点套p标签
  7003. if (me.options.enterTag == 'p') {
  7004. var child = this.body.firstChild, tmpNode;
  7005. if (!child || child.nodeType == 1 &&
  7006. (dtd.$cdata[child.tagName] || isCdataDiv(child) ||
  7007. domUtils.isCustomeNode(child)
  7008. )
  7009. && child === this.body.lastChild) {
  7010. this.body.innerHTML = '<p>' + (browser.ie ? '&nbsp;' : '<br/>') + '</p>' + this.body.innerHTML;
  7011. } else {
  7012. var p = me.document.createElement('p');
  7013. while (child) {
  7014. while (child && (child.nodeType == 3 || child.nodeType == 1 && dtd.p[child.tagName] && !dtd.$cdata[child.tagName])) {
  7015. tmpNode = child.nextSibling;
  7016. p.appendChild(child);
  7017. child = tmpNode;
  7018. }
  7019. if (p.firstChild) {
  7020. if (!child) {
  7021. me.body.appendChild(p);
  7022. break;
  7023. } else {
  7024. child.parentNode.insertBefore(p, child);
  7025. p = me.document.createElement('p');
  7026. }
  7027. }
  7028. child = child.nextSibling;
  7029. }
  7030. }
  7031. }
  7032. me.fireEvent('aftersetcontent');
  7033. me.fireEvent('contentchange');
  7034. !notFireSelectionchange && me._selectionChange();
  7035. //清除保存的选区
  7036. me._bakRange = me._bakIERange = me._bakNativeRange = null;
  7037. //trace:1742 setContent后gecko能得到焦点问题
  7038. var geckoSel;
  7039. if (browser.gecko && (geckoSel = this.selection.getNative())) {
  7040. geckoSel.removeAllRanges();
  7041. }
  7042. if(me.options.autoSyncData){
  7043. me.form && setValue(me.form,me);
  7044. }
  7045. },
  7046. /**
  7047. * 让编辑器获得焦点,默认focus到编辑器头部
  7048. * @method focus
  7049. * @example
  7050. * ```javascript
  7051. * editor.focus()
  7052. * ```
  7053. */
  7054. /**
  7055. * 让编辑器获得焦点,toEnd确定focus位置
  7056. * @method focus
  7057. * @param { Boolean } toEnd 默认focus到编辑器头部,toEnd为true时focus到内容尾部
  7058. * @example
  7059. * ```javascript
  7060. * editor.focus(true)
  7061. * ```
  7062. */
  7063. focus: function (toEnd) {
  7064. try {
  7065. var me = this,
  7066. rng = me.selection.getRange();
  7067. if (toEnd) {
  7068. var node = me.body.lastChild;
  7069. if(node && node.nodeType == 1 && !dtd.$empty[node.tagName]){
  7070. if(domUtils.isEmptyBlock(node)){
  7071. rng.setStartAtFirst(node)
  7072. }else{
  7073. rng.setStartAtLast(node)
  7074. }
  7075. rng.collapse(true);
  7076. }
  7077. rng.setCursor(true);
  7078. } else {
  7079. if(!rng.collapsed && domUtils.isBody(rng.startContainer) && rng.startOffset == 0){
  7080. var node = me.body.firstChild;
  7081. if(node && node.nodeType == 1 && !dtd.$empty[node.tagName]){
  7082. rng.setStartAtFirst(node).collapse(true);
  7083. }
  7084. }
  7085. rng.select(true);
  7086. }
  7087. this.fireEvent('focus selectionchange');
  7088. } catch (e) {
  7089. }
  7090. },
  7091. isFocus:function(){
  7092. return this.selection.isFocus();
  7093. },
  7094. blur:function(){
  7095. var sel = this.selection.getNative();
  7096. if(sel.empty && browser.ie){
  7097. var nativeRng = document.body.createTextRange();
  7098. nativeRng.moveToElementText(document.body);
  7099. nativeRng.collapse(true);
  7100. nativeRng.select();
  7101. sel.empty()
  7102. }else{
  7103. sel.removeAllRanges()
  7104. }
  7105. //this.fireEvent('blur selectionchange');
  7106. },
  7107. /**
  7108. * 初始化UE事件及部分事件代理
  7109. * @method _initEvents
  7110. * @private
  7111. */
  7112. _initEvents: function () {
  7113. var me = this,
  7114. doc = me.document,
  7115. win = me.window;
  7116. me._proxyDomEvent = utils.bind(me._proxyDomEvent, me);
  7117. domUtils.on(doc, ['click', 'contextmenu', 'mousedown', 'keydown', 'keyup', 'keypress', 'mouseup', 'mouseover', 'mouseout', 'selectstart'], me._proxyDomEvent);
  7118. domUtils.on(win, ['focus', 'blur'], me._proxyDomEvent);
  7119. domUtils.on(me.body,'drop',function(e){
  7120. //阻止ff下默认的弹出新页面打开图片
  7121. if(browser.gecko && e.stopPropagation) { e.stopPropagation(); }
  7122. me.fireEvent('contentchange')
  7123. });
  7124. domUtils.on(doc, ['mouseup', 'keydown'], function (evt) {
  7125. //特殊键不触发selectionchange
  7126. if (evt.type == 'keydown' && (evt.ctrlKey || evt.metaKey || evt.shiftKey || evt.altKey)) {
  7127. return;
  7128. }
  7129. if (evt.button == 2)return;
  7130. me._selectionChange(250, evt);
  7131. });
  7132. },
  7133. /**
  7134. * 触发事件代理
  7135. * @method _proxyDomEvent
  7136. * @private
  7137. * @return { * } fireEvent的返回值
  7138. * @see UE.EventBase:fireEvent(String)
  7139. */
  7140. _proxyDomEvent: function (evt) {
  7141. if(this.fireEvent('before' + evt.type.replace(/^on/, '').toLowerCase()) === false){
  7142. return false;
  7143. }
  7144. if(this.fireEvent(evt.type.replace(/^on/, ''), evt) === false){
  7145. return false;
  7146. }
  7147. return this.fireEvent('after' + evt.type.replace(/^on/, '').toLowerCase())
  7148. },
  7149. /**
  7150. * 变化选区
  7151. * @method _selectionChange
  7152. * @private
  7153. */
  7154. _selectionChange: function (delay, evt) {
  7155. var me = this;
  7156. //有光标才做selectionchange 为了解决未focus时点击source不能触发更改工具栏状态的问题(source命令notNeedUndo=1)
  7157. // if ( !me.selection.isFocus() ){
  7158. // return;
  7159. // }
  7160. var hackForMouseUp = false;
  7161. var mouseX, mouseY;
  7162. if (browser.ie && browser.version < 9 && evt && evt.type == 'mouseup') {
  7163. var range = this.selection.getRange();
  7164. if (!range.collapsed) {
  7165. hackForMouseUp = true;
  7166. mouseX = evt.clientX;
  7167. mouseY = evt.clientY;
  7168. }
  7169. }
  7170. clearTimeout(_selectionChangeTimer);
  7171. _selectionChangeTimer = setTimeout(function () {
  7172. if (!me.selection || !me.selection.getNative()) {
  7173. return;
  7174. }
  7175. //修复一个IE下的bug: 鼠标点击一段已选择的文本中间时,可能在mouseup后的一段时间内取到的range是在selection的type为None下的错误值.
  7176. //IE下如果用户是拖拽一段已选择文本,则不会触发mouseup事件,所以这里的特殊处理不会对其有影响
  7177. var ieRange;
  7178. if (hackForMouseUp && me.selection.getNative().type == 'None') {
  7179. ieRange = me.document.body.createTextRange();
  7180. try {
  7181. ieRange.moveToPoint(mouseX, mouseY);
  7182. } catch (ex) {
  7183. ieRange = null;
  7184. }
  7185. }
  7186. var bakGetIERange;
  7187. if (ieRange) {
  7188. bakGetIERange = me.selection.getIERange;
  7189. me.selection.getIERange = function () {
  7190. return ieRange;
  7191. };
  7192. }
  7193. me.selection.cache();
  7194. if (bakGetIERange) {
  7195. me.selection.getIERange = bakGetIERange;
  7196. }
  7197. if (me.selection._cachedRange && me.selection._cachedStartElement) {
  7198. me.fireEvent('beforeselectionchange');
  7199. // 第二个参数causeByUi为true代表由用户交互造成的selectionchange.
  7200. me.fireEvent('selectionchange', !!evt);
  7201. me.fireEvent('afterselectionchange');
  7202. me.selection.clear();
  7203. }
  7204. }, delay || 50);
  7205. },
  7206. /**
  7207. * 执行编辑命令
  7208. * @method _callCmdFn
  7209. * @private
  7210. * @param { String } fnName 函数名称
  7211. * @param { * } args 传给命令函数的参数
  7212. * @return { * } 返回命令函数运行的返回值
  7213. */
  7214. _callCmdFn: function (fnName, args) {
  7215. var cmdName = args[0].toLowerCase(),
  7216. cmd, cmdFn;
  7217. cmd = this.commands[cmdName] || UE.commands[cmdName];
  7218. cmdFn = cmd && cmd[fnName];
  7219. //没有querycommandstate或者没有command的都默认返回0
  7220. if ((!cmd || !cmdFn) && fnName == 'queryCommandState') {
  7221. return 0;
  7222. } else if (cmdFn) {
  7223. return cmdFn.apply(this, args);
  7224. }
  7225. },
  7226. /**
  7227. * 执行编辑命令cmdName,完成富文本编辑效果
  7228. * @method execCommand
  7229. * @param { String } cmdName 需要执行的命令
  7230. * @remind 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
  7231. * @return { * } 返回命令函数运行的返回值
  7232. * @example
  7233. * ```javascript
  7234. * editor.execCommand(cmdName);
  7235. * ```
  7236. */
  7237. execCommand: function (cmdName) {
  7238. cmdName = cmdName.toLowerCase();
  7239. var me = this,
  7240. result,
  7241. cmd = me.commands[cmdName] || UE.commands[cmdName];
  7242. if (!cmd || !cmd.execCommand) {
  7243. return null;
  7244. }
  7245. if (!cmd.notNeedUndo && !me.__hasEnterExecCommand) {
  7246. me.__hasEnterExecCommand = true;
  7247. if (me.queryCommandState.apply(me,arguments) != -1) {
  7248. me.fireEvent('saveScene');
  7249. me.fireEvent.apply(me, ['beforeexeccommand', cmdName].concat(arguments));
  7250. result = this._callCmdFn('execCommand', arguments);
  7251. //保存场景时,做了内容对比,再看是否进行contentchange触发,这里多触发了一次,去掉
  7252. // (!cmd.ignoreContentChange && !me._ignoreContentChange) && me.fireEvent('contentchange');
  7253. me.fireEvent.apply(me, ['afterexeccommand', cmdName].concat(arguments));
  7254. me.fireEvent('saveScene');
  7255. }
  7256. me.__hasEnterExecCommand = false;
  7257. } else {
  7258. result = this._callCmdFn('execCommand', arguments);
  7259. (!me.__hasEnterExecCommand && !cmd.ignoreContentChange && !me._ignoreContentChange) && me.fireEvent('contentchange')
  7260. }
  7261. (!me.__hasEnterExecCommand && !cmd.ignoreContentChange && !me._ignoreContentChange) && me._selectionChange();
  7262. return result;
  7263. },
  7264. /**
  7265. * 根据传入的command命令,查选编辑器当前的选区,返回命令的状态
  7266. * @method queryCommandState
  7267. * @param { String } cmdName 需要查询的命令名称
  7268. * @remind 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
  7269. * @return { Number } number 返回放前命令的状态,返回值三种情况:(-1|0|1)
  7270. * @example
  7271. * ```javascript
  7272. * editor.queryCommandState(cmdName) => (-1|0|1)
  7273. * ```
  7274. * @see COMMAND.LIST
  7275. */
  7276. queryCommandState: function (cmdName) {
  7277. return this._callCmdFn('queryCommandState', arguments);
  7278. },
  7279. /**
  7280. * 根据传入的command命令,查选编辑器当前的选区,根据命令返回相关的值
  7281. * @method queryCommandValue
  7282. * @param { String } cmdName 需要查询的命令名称
  7283. * @remind 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
  7284. * @remind 只有部分插件有此方法
  7285. * @return { * } 返回每个命令特定的当前状态值
  7286. * @grammar editor.queryCommandValue(cmdName) => {*}
  7287. * @see COMMAND.LIST
  7288. */
  7289. queryCommandValue: function (cmdName) {
  7290. return this._callCmdFn('queryCommandValue', arguments);
  7291. },
  7292. /**
  7293. * 检查编辑区域中是否有内容
  7294. * @method hasContents
  7295. * @remind 默认有文本内容,或者有以下节点都不认为是空
  7296. * table,ul,ol,dl,iframe,area,base,col,hr,img,embed,input,link,meta,param
  7297. * @return { Boolean } 检查有内容返回true,否则返回false
  7298. * @example
  7299. * ```javascript
  7300. * editor.hasContents()
  7301. * ```
  7302. */
  7303. /**
  7304. * 检查编辑区域中是否有内容,若包含参数tags中的节点类型,直接返回true
  7305. * @method hasContents
  7306. * @param { Array } tags 传入数组判断时用到的节点类型
  7307. * @return { Boolean } 若文档中包含tags数组里对应的tag,返回true,否则返回false
  7308. * @example
  7309. * ```javascript
  7310. * editor.hasContents(['span']);
  7311. * ```
  7312. */
  7313. hasContents: function (tags) {
  7314. if (tags) {
  7315. for (var i = 0, ci; ci = tags[i++];) {
  7316. if (this.document.getElementsByTagName(ci).length > 0) {
  7317. return true;
  7318. }
  7319. }
  7320. }
  7321. if (!domUtils.isEmptyBlock(this.body)) {
  7322. return true
  7323. }
  7324. //随时添加,定义的特殊标签如果存在,不能认为是空
  7325. tags = ['div'];
  7326. for (i = 0; ci = tags[i++];) {
  7327. var nodes = domUtils.getElementsByTagName(this.document, ci);
  7328. for (var n = 0, cn; cn = nodes[n++];) {
  7329. if (domUtils.isCustomeNode(cn)) {
  7330. return true;
  7331. }
  7332. }
  7333. }
  7334. return false;
  7335. },
  7336. /**
  7337. * 重置编辑器,可用来做多个tab使用同一个编辑器实例
  7338. * @method reset
  7339. * @remind 此方法会清空编辑器内容,清空回退列表,会触发reset事件
  7340. * @example
  7341. * ```javascript
  7342. * editor.reset()
  7343. * ```
  7344. */
  7345. reset: function () {
  7346. this.fireEvent('reset');
  7347. },
  7348. /**
  7349. * 设置当前编辑区域可以编辑
  7350. * @method setEnabled
  7351. * @example
  7352. * ```javascript
  7353. * editor.setEnabled()
  7354. * ```
  7355. */
  7356. setEnabled: function () {
  7357. var me = this, range;
  7358. if (me.body.contentEditable == 'false') {
  7359. me.body.contentEditable = true;
  7360. range = me.selection.getRange();
  7361. //有可能内容丢失了
  7362. try {
  7363. range.moveToBookmark(me.lastBk);
  7364. delete me.lastBk
  7365. } catch (e) {
  7366. range.setStartAtFirst(me.body).collapse(true)
  7367. }
  7368. range.select(true);
  7369. if (me.bkqueryCommandState) {
  7370. me.queryCommandState = me.bkqueryCommandState;
  7371. delete me.bkqueryCommandState;
  7372. }
  7373. if (me.bkqueryCommandValue) {
  7374. me.queryCommandValue = me.bkqueryCommandValue;
  7375. delete me.bkqueryCommandValue;
  7376. }
  7377. me.fireEvent('selectionchange');
  7378. }
  7379. },
  7380. enable: function () {
  7381. return this.setEnabled();
  7382. },
  7383. /** 设置当前编辑区域不可编辑
  7384. * @method setDisabled
  7385. */
  7386. /** 设置当前编辑区域不可编辑,except中的命令除外
  7387. * @method setDisabled
  7388. * @param { String } except 例外命令的字符串
  7389. * @remind 即使设置了disable,此处配置的例外命令仍然可以执行
  7390. * @example
  7391. * ```javascript
  7392. * editor.setDisabled('bold'); //禁用工具栏中除加粗之外的所有功能
  7393. * ```
  7394. */
  7395. /** 设置当前编辑区域不可编辑,except中的命令除外
  7396. * @method setDisabled
  7397. * @param { Array } except 例外命令的字符串数组,数组中的命令仍然可以执行
  7398. * @remind 即使设置了disable,此处配置的例外命令仍然可以执行
  7399. * @example
  7400. * ```javascript
  7401. * editor.setDisabled(['bold','insertimage']); //禁用工具栏中除加粗和插入图片之外的所有功能
  7402. * ```
  7403. */
  7404. setDisabled: function (except) {
  7405. var me = this;
  7406. except = except ? utils.isArray(except) ? except : [except] : [];
  7407. if (me.body.contentEditable == 'true') {
  7408. if (!me.lastBk) {
  7409. me.lastBk = me.selection.getRange().createBookmark(true);
  7410. }
  7411. me.body.contentEditable = false;
  7412. me.bkqueryCommandState = me.queryCommandState;
  7413. me.bkqueryCommandValue = me.queryCommandValue;
  7414. me.queryCommandState = function (type) {
  7415. if (utils.indexOf(except, type) != -1) {
  7416. return me.bkqueryCommandState.apply(me, arguments);
  7417. }
  7418. return -1;
  7419. };
  7420. me.queryCommandValue = function (type) {
  7421. if (utils.indexOf(except, type) != -1) {
  7422. return me.bkqueryCommandValue.apply(me, arguments);
  7423. }
  7424. return null;
  7425. };
  7426. me.fireEvent('selectionchange');
  7427. }
  7428. },
  7429. disable: function (except) {
  7430. return this.setDisabled(except);
  7431. },
  7432. /**
  7433. * 设置默认内容
  7434. * @method _setDefaultContent
  7435. * @private
  7436. * @param { String } cont 要存入的内容
  7437. */
  7438. _setDefaultContent: function () {
  7439. function clear() {
  7440. var me = this;
  7441. if (me.document.getElementById('initContent')) {
  7442. me.body.innerHTML = '<p>' + (ie ? '' : '<br/>') + '</p>';
  7443. me.removeListener('firstBeforeExecCommand focus', clear);
  7444. setTimeout(function () {
  7445. me.focus();
  7446. me._selectionChange();
  7447. }, 0)
  7448. }
  7449. }
  7450. return function (cont) {
  7451. var me = this;
  7452. me.body.innerHTML = '<p id="initContent">' + cont + '</p>';
  7453. me.addListener('firstBeforeExecCommand focus', clear);
  7454. }
  7455. }(),
  7456. /**
  7457. * 显示编辑器
  7458. * @method setShow
  7459. * @example
  7460. * ```javascript
  7461. * editor.setShow()
  7462. * ```
  7463. */
  7464. setShow: function () {
  7465. var me = this, range = me.selection.getRange();
  7466. if (me.container.style.display == 'none') {
  7467. //有可能内容丢失了
  7468. try {
  7469. range.moveToBookmark(me.lastBk);
  7470. delete me.lastBk
  7471. } catch (e) {
  7472. range.setStartAtFirst(me.body).collapse(true)
  7473. }
  7474. //ie下focus实效,所以做了个延迟
  7475. setTimeout(function () {
  7476. range.select(true);
  7477. }, 100);
  7478. me.container.style.display = '';
  7479. }
  7480. },
  7481. show: function () {
  7482. return this.setShow();
  7483. },
  7484. /**
  7485. * 隐藏编辑器
  7486. * @method setHide
  7487. * @example
  7488. * ```javascript
  7489. * editor.setHide()
  7490. * ```
  7491. */
  7492. setHide: function () {
  7493. var me = this;
  7494. if (!me.lastBk) {
  7495. me.lastBk = me.selection.getRange().createBookmark(true);
  7496. }
  7497. me.container.style.display = 'none'
  7498. },
  7499. hide: function () {
  7500. return this.setHide();
  7501. },
  7502. /**
  7503. * 根据指定的路径,获取对应的语言资源
  7504. * @method getLang
  7505. * @param { String } path 路径根据的是lang目录下的语言文件的路径结构
  7506. * @return { Object | String } 根据路径返回语言资源的Json格式对象或者语言字符串
  7507. * @example
  7508. * ```javascript
  7509. * editor.getLang('contextMenu.delete'); //如果当前是中文,那返回是的是'删除'
  7510. * ```
  7511. */
  7512. getLang: function (path) {
  7513. // HaoChuan9421
  7514. if(!this.options){
  7515. return '';
  7516. }
  7517. var lang = UE.I18N[this.options.lang];
  7518. if (!lang) {
  7519. throw Error("not import language file");
  7520. }
  7521. path = (path || "").split(".");
  7522. for (var i = 0, ci; ci = path[i++];) {
  7523. lang = lang[ci];
  7524. if (!lang)break;
  7525. }
  7526. return lang;
  7527. },
  7528. /**
  7529. * 计算编辑器html内容字符串的长度
  7530. * @method getContentLength
  7531. * @return { Number } 返回计算的长度
  7532. * @example
  7533. * ```javascript
  7534. * //编辑器html内容<p><strong>132</strong></p>
  7535. * editor.getContentLength() //返回27
  7536. * ```
  7537. */
  7538. /**
  7539. * 计算编辑器当前纯文本内容的长度
  7540. * @method getContentLength
  7541. * @param { Boolean } ingoneHtml 传入true时,只按照纯文本来计算
  7542. * @return { Number } 返回计算的长度,内容中有hr/img/iframe标签,长度加1
  7543. * @example
  7544. * ```javascript
  7545. * //编辑器html内容<p><strong>132</strong></p>
  7546. * editor.getContentLength() //返回3
  7547. * ```
  7548. */
  7549. getContentLength: function (ingoneHtml, tagNames) {
  7550. var count = this.getContent(false,false,true).length;
  7551. if (ingoneHtml) {
  7552. tagNames = (tagNames || []).concat([ 'hr', 'img', 'iframe']);
  7553. count = this.getContentTxt().replace(/[\t\r\n]+/g, '').length;
  7554. for (var i = 0, ci; ci = tagNames[i++];) {
  7555. count += this.document.getElementsByTagName(ci).length;
  7556. }
  7557. }
  7558. return count;
  7559. },
  7560. /**
  7561. * 注册输入过滤规则
  7562. * @method addInputRule
  7563. * @param { Function } rule 要添加的过滤规则
  7564. * @example
  7565. * ```javascript
  7566. * editor.addInputRule(function(root){
  7567. * $.each(root.getNodesByTagName('div'),function(i,node){
  7568. * node.tagName="p";
  7569. * });
  7570. * });
  7571. * ```
  7572. */
  7573. addInputRule: function (rule) {
  7574. this.inputRules.push(rule);
  7575. },
  7576. /**
  7577. * 执行注册的过滤规则
  7578. * @method filterInputRule
  7579. * @param { UE.uNode } root 要过滤的uNode节点
  7580. * @remind 执行editor.setContent方法和执行'inserthtml'命令后,会运行该过滤函数
  7581. * @example
  7582. * ```javascript
  7583. * editor.filterInputRule(editor.body);
  7584. * ```
  7585. * @see UE.Editor:addInputRule
  7586. */
  7587. filterInputRule: function (root) {
  7588. for (var i = 0, ci; ci = this.inputRules[i++];) {
  7589. ci.call(this, root)
  7590. }
  7591. },
  7592. /**
  7593. * 注册输出过滤规则
  7594. * @method addOutputRule
  7595. * @param { Function } rule 要添加的过滤规则
  7596. * @example
  7597. * ```javascript
  7598. * editor.addOutputRule(function(root){
  7599. * $.each(root.getNodesByTagName('p'),function(i,node){
  7600. * node.tagName="div";
  7601. * });
  7602. * });
  7603. * ```
  7604. */
  7605. addOutputRule: function (rule) {
  7606. this.outputRules.push(rule)
  7607. },
  7608. /**
  7609. * 根据输出过滤规则,过滤编辑器内容
  7610. * @method filterOutputRule
  7611. * @remind 执行editor.getContent方法的时候,会先运行该过滤函数
  7612. * @param { UE.uNode } root 要过滤的uNode节点
  7613. * @example
  7614. * ```javascript
  7615. * editor.filterOutputRule(editor.body);
  7616. * ```
  7617. * @see UE.Editor:addOutputRule
  7618. */
  7619. filterOutputRule: function (root) {
  7620. for (var i = 0, ci; ci = this.outputRules[i++];) {
  7621. ci.call(this, root)
  7622. }
  7623. },
  7624. /**
  7625. * 根据action名称获取请求的路径
  7626. * @method getActionUrl
  7627. * @remind 假如没有设置serverUrl,会根据imageUrl设置默认的controller路径
  7628. * @param { String } action action名称
  7629. * @example
  7630. * ```javascript
  7631. * editor.getActionUrl('config'); //返回 "/ueditor/php/controller.php?action=config"
  7632. * editor.getActionUrl('image'); //返回 "/ueditor/php/controller.php?action=uplaodimage"
  7633. * editor.getActionUrl('scrawl'); //返回 "/ueditor/php/controller.php?action=uplaodscrawl"
  7634. * editor.getActionUrl('imageManager'); //返回 "/ueditor/php/controller.php?action=listimage"
  7635. * ```
  7636. */
  7637. getActionUrl: function(action){
  7638. var actionName = this.getOpt(action) || action,
  7639. imageUrl = this.getOpt('imageUrl'),
  7640. serverUrl = this.getOpt('serverUrl');
  7641. if(!serverUrl && imageUrl) {
  7642. serverUrl = imageUrl.replace(/^(.*[\/]).+([\.].+)$/, '$1controller$2');
  7643. }
  7644. if(serverUrl) {
  7645. serverUrl = serverUrl + (serverUrl.indexOf('?') == -1 ? '?':'&') + 'action=' + (actionName || '');
  7646. return utils.formatUrl(serverUrl);
  7647. } else {
  7648. return '';
  7649. }
  7650. }
  7651. };
  7652. utils.inherits(Editor, EventBase);
  7653. })();
  7654. // core/Editor.defaultoptions.js
  7655. //维护编辑器一下默认的不在插件中的配置项
  7656. UE.Editor.defaultOptions = function(editor){
  7657. var _url = editor.options.UEDITOR_HOME_URL;
  7658. return {
  7659. isShow: true,
  7660. initialContent: '',
  7661. initialStyle:'',
  7662. autoClearinitialContent: false,
  7663. iframeCssUrl: _url + 'themes/iframe.css',
  7664. textarea: 'editorValue',
  7665. focus: false,
  7666. focusInEnd: true,
  7667. autoClearEmptyNode: true,
  7668. fullscreen: false,
  7669. readonly: false,
  7670. zIndex: 999,
  7671. imagePopup: true,
  7672. enterTag: 'p',
  7673. customDomain: false,
  7674. lang: 'zh-cn',
  7675. langPath: _url + 'lang/',
  7676. theme: 'default',
  7677. themePath: _url + 'themes/',
  7678. allHtmlEnabled: false,
  7679. scaleEnabled: false,
  7680. tableNativeEditInFF: false,
  7681. autoSyncData : true,
  7682. fileNameFormat: '{time}{rand:6}'
  7683. }
  7684. };
  7685. // core/loadconfig.js
  7686. (function(){
  7687. UE.Editor.prototype.loadServerConfig = function(){
  7688. var me = this;
  7689. setTimeout(function(){
  7690. try{
  7691. me.options.imageUrl && me.setOpt('serverUrl', me.options.imageUrl.replace(/^(.*[\/]).+([\.].+)$/, '$1controller$2'));
  7692. var configUrl = me.getActionUrl('config'),
  7693. isJsonp = utils.isCrossDomainUrl(configUrl);
  7694. /* 发出ajax请求 */
  7695. me._serverConfigLoaded = false;
  7696. configUrl && UE.ajax.request(configUrl,{
  7697. 'method': 'GET',
  7698. 'dataType': isJsonp ? 'jsonp':'',
  7699. 'onsuccess':function(r){
  7700. try {
  7701. var config = isJsonp ? r:eval("("+r.responseText+")");
  7702. utils.extend(me.options, config);
  7703. me.fireEvent('serverConfigLoaded');
  7704. me._serverConfigLoaded = true;
  7705. } catch (e) {
  7706. showErrorMsg(me.getLang('loadconfigFormatError'));
  7707. }
  7708. },
  7709. 'onerror':function(){
  7710. showErrorMsg(me.getLang('loadconfigHttpError'));
  7711. }
  7712. });
  7713. } catch(e){
  7714. showErrorMsg(me.getLang('loadconfigError'));
  7715. }
  7716. });
  7717. function showErrorMsg(msg) {
  7718. console && console.error(msg);
  7719. //me.fireEvent('showMessage', {
  7720. // 'title': msg,
  7721. // 'type': 'error'
  7722. //});
  7723. }
  7724. };
  7725. UE.Editor.prototype.isServerConfigLoaded = function(){
  7726. var me = this;
  7727. return me._serverConfigLoaded || false;
  7728. };
  7729. UE.Editor.prototype.afterConfigReady = function(handler){
  7730. if (!handler || !utils.isFunction(handler)) return;
  7731. var me = this;
  7732. var readyHandler = function(){
  7733. handler.apply(me, arguments);
  7734. me.removeListener('serverConfigLoaded', readyHandler);
  7735. };
  7736. if (me.isServerConfigLoaded()) {
  7737. handler.call(me, 'serverConfigLoaded');
  7738. } else {
  7739. me.addListener('serverConfigLoaded', readyHandler);
  7740. }
  7741. };
  7742. })();
  7743. // core/ajax.js
  7744. /**
  7745. * @file
  7746. * @module UE.ajax
  7747. * @since 1.2.6.1
  7748. */
  7749. /**
  7750. * 提供对ajax请求的支持
  7751. * @module UE.ajax
  7752. */
  7753. UE.ajax = function() {
  7754. //创建一个ajaxRequest对象
  7755. var fnStr = 'XMLHttpRequest()';
  7756. try {
  7757. new ActiveXObject("Msxml2.XMLHTTP");
  7758. fnStr = 'ActiveXObject(\'Msxml2.XMLHTTP\')';
  7759. } catch (e) {
  7760. try {
  7761. new ActiveXObject("Microsoft.XMLHTTP");
  7762. fnStr = 'ActiveXObject(\'Microsoft.XMLHTTP\')'
  7763. } catch (e) {
  7764. }
  7765. }
  7766. var creatAjaxRequest = new Function('return new ' + fnStr);
  7767. /**
  7768. * 将json参数转化成适合ajax提交的参数列表
  7769. * @param json
  7770. */
  7771. function json2str(json) {
  7772. var strArr = [];
  7773. for (var i in json) {
  7774. //忽略默认的几个参数
  7775. if(i=="method" || i=="timeout" || i=="async" || i=="dataType" || i=="callback") continue;
  7776. //忽略控制
  7777. if(json[i] == undefined || json[i] == null) continue;
  7778. //传递过来的对象和函数不在提交之列
  7779. if (!((typeof json[i]).toLowerCase() == "function" || (typeof json[i]).toLowerCase() == "object")) {
  7780. strArr.push( encodeURIComponent(i) + "="+encodeURIComponent(json[i]) );
  7781. } else if (utils.isArray(json[i])) {
  7782. //支持传数组内容
  7783. for(var j = 0; j < json[i].length; j++) {
  7784. strArr.push( encodeURIComponent(i) + "[]="+encodeURIComponent(json[i][j]) );
  7785. }
  7786. }
  7787. }
  7788. return strArr.join("&");
  7789. }
  7790. function doAjax(url, ajaxOptions) {
  7791. var xhr = creatAjaxRequest(),
  7792. //是否超时
  7793. timeIsOut = false,
  7794. //默认参数
  7795. defaultAjaxOptions = {
  7796. method:"POST",
  7797. timeout:5000,
  7798. async:true,
  7799. data:{},//需要传递对象的话只能覆盖
  7800. onsuccess:function() {
  7801. },
  7802. onerror:function() {
  7803. }
  7804. };
  7805. if (typeof url === "object") {
  7806. ajaxOptions = url;
  7807. url = ajaxOptions.url;
  7808. }
  7809. if (!xhr || !url) return;
  7810. var ajaxOpts = ajaxOptions ? utils.extend(defaultAjaxOptions,ajaxOptions) : defaultAjaxOptions;
  7811. var submitStr = json2str(ajaxOpts); // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing"
  7812. //如果用户直接通过data参数传递json对象过来,则也要将此json对象转化为字符串
  7813. if (!utils.isEmptyObject(ajaxOpts.data)){
  7814. submitStr += (submitStr? "&":"") + json2str(ajaxOpts.data);
  7815. }
  7816. //超时检测
  7817. var timerID = setTimeout(function() {
  7818. if (xhr.readyState != 4) {
  7819. timeIsOut = true;
  7820. xhr.abort();
  7821. clearTimeout(timerID);
  7822. }
  7823. }, ajaxOpts.timeout);
  7824. var method = ajaxOpts.method.toUpperCase();
  7825. var str = url + (url.indexOf("?")==-1?"?":"&") + (method=="POST"?"":submitStr+ "&noCache=" + +new Date);
  7826. xhr.open(method, str, ajaxOpts.async);
  7827. xhr.onreadystatechange = function() {
  7828. if (xhr.readyState == 4) {
  7829. if (!timeIsOut && xhr.status == 200) {
  7830. ajaxOpts.onsuccess(xhr);
  7831. } else {
  7832. ajaxOpts.onerror(xhr);
  7833. }
  7834. }
  7835. };
  7836. if (method == "POST") {
  7837. xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  7838. xhr.send(submitStr);
  7839. } else {
  7840. xhr.send(null);
  7841. }
  7842. }
  7843. function doJsonp(url, opts) {
  7844. var successhandler = opts.onsuccess || function(){},
  7845. scr = document.createElement('SCRIPT'),
  7846. options = opts || {},
  7847. charset = options['charset'],
  7848. callbackField = options['jsonp'] || 'callback',
  7849. callbackFnName,
  7850. timeOut = options['timeOut'] || 0,
  7851. timer,
  7852. reg = new RegExp('(\\?|&)' + callbackField + '=([^&]*)'),
  7853. matches;
  7854. if (utils.isFunction(successhandler)) {
  7855. callbackFnName = 'bd__editor__' + Math.floor(Math.random() * 2147483648).toString(36);
  7856. window[callbackFnName] = getCallBack(0);
  7857. } else if(utils.isString(successhandler)){
  7858. callbackFnName = successhandler;
  7859. } else {
  7860. if (matches = reg.exec(url)) {
  7861. callbackFnName = matches[2];
  7862. }
  7863. }
  7864. url = url.replace(reg, '\x241' + callbackField + '=' + callbackFnName);
  7865. if (url.search(reg) < 0) {
  7866. url += (url.indexOf('?') < 0 ? '?' : '&') + callbackField + '=' + callbackFnName;
  7867. }
  7868. var queryStr = json2str(opts); // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing"
  7869. //如果用户直接通过data参数传递json对象过来,则也要将此json对象转化为字符串
  7870. if (!utils.isEmptyObject(opts.data)){
  7871. queryStr += (queryStr? "&":"") + json2str(opts.data);
  7872. }
  7873. if (queryStr) {
  7874. url = url.replace(/\?/, '?' + queryStr + '&');
  7875. }
  7876. scr.onerror = getCallBack(1);
  7877. if( timeOut ){
  7878. timer = setTimeout(getCallBack(1), timeOut);
  7879. }
  7880. createScriptTag(scr, url, charset);
  7881. function createScriptTag(scr, url, charset) {
  7882. scr.setAttribute('type', 'text/javascript');
  7883. scr.setAttribute('defer', 'defer');
  7884. charset && scr.setAttribute('charset', charset);
  7885. scr.setAttribute('src', url);
  7886. document.getElementsByTagName('head')[0].appendChild(scr);
  7887. }
  7888. function getCallBack(onTimeOut){
  7889. return function(){
  7890. try {
  7891. if(onTimeOut){
  7892. options.onerror && options.onerror();
  7893. }else{
  7894. try{
  7895. clearTimeout(timer);
  7896. successhandler.apply(window, arguments);
  7897. } catch (e){}
  7898. }
  7899. } catch (exception) {
  7900. options.onerror && options.onerror.call(window, exception);
  7901. } finally {
  7902. options.oncomplete && options.oncomplete.apply(window, arguments);
  7903. scr.parentNode && scr.parentNode.removeChild(scr);
  7904. window[callbackFnName] = null;
  7905. try {
  7906. delete window[callbackFnName];
  7907. }catch(e){}
  7908. }
  7909. }
  7910. }
  7911. }
  7912. return {
  7913. /**
  7914. * 根据给定的参数项,向指定的url发起一个ajax请求。 ajax请求完成后,会根据请求结果调用相应回调: 如果请求
  7915. * 成功, 则调用onsuccess回调, 失败则调用 onerror 回调
  7916. * @method request
  7917. * @param { URLString } url ajax请求的url地址
  7918. * @param { Object } ajaxOptions ajax请求选项的键值对,支持的选项如下:
  7919. * @example
  7920. * ```javascript
  7921. * //向sayhello.php发起一个异步的Ajax GET请求, 请求超时时间为10s, 请求完成后执行相应的回调。
  7922. * UE.ajax.requeset( 'sayhello.php', {
  7923. *
  7924. * //请求方法。可选值: 'GET', 'POST',默认值是'POST'
  7925. * method: 'GET',
  7926. *
  7927. * //超时时间。 默认为5000, 单位是ms
  7928. * timeout: 10000,
  7929. *
  7930. * //是否是异步请求。 true为异步请求, false为同步请求
  7931. * async: true,
  7932. *
  7933. * //请求携带的数据。如果请求为GET请求, data会经过stringify后附加到请求url之后。
  7934. * data: {
  7935. * name: 'ueditor'
  7936. * },
  7937. *
  7938. * //请求成功后的回调, 该回调接受当前的XMLHttpRequest对象作为参数。
  7939. * onsuccess: function ( xhr ) {
  7940. * console.log( xhr.responseText );
  7941. * },
  7942. *
  7943. * //请求失败或者超时后的回调。
  7944. * onerror: function ( xhr ) {
  7945. * alert( 'Ajax请求失败' );
  7946. * }
  7947. *
  7948. * } );
  7949. * ```
  7950. */
  7951. /**
  7952. * 根据给定的参数项发起一个ajax请求, 参数项里必须包含一个url地址。 ajax请求完成后,会根据请求结果调用相应回调: 如果请求
  7953. * 成功, 则调用onsuccess回调, 失败则调用 onerror 回调。
  7954. * @method request
  7955. * @warning 如果在参数项里未提供一个key为“url”的地址值,则该请求将直接退出。
  7956. * @param { Object } ajaxOptions ajax请求选项的键值对,支持的选项如下:
  7957. * @example
  7958. * ```javascript
  7959. *
  7960. * //向sayhello.php发起一个异步的Ajax POST请求, 请求超时时间为5s, 请求完成后不执行任何回调。
  7961. * UE.ajax.requeset( 'sayhello.php', {
  7962. *
  7963. * //请求的地址, 该项是必须的。
  7964. * url: 'sayhello.php'
  7965. *
  7966. * } );
  7967. * ```
  7968. */
  7969. request:function(url, opts) {
  7970. if (opts && opts.dataType == 'jsonp') {
  7971. doJsonp(url, opts);
  7972. } else {
  7973. doAjax(url, opts);
  7974. }
  7975. },
  7976. getJSONP:function(url, data, fn) {
  7977. var opts = {
  7978. 'data': data,
  7979. 'oncomplete': fn
  7980. };
  7981. doJsonp(url, opts);
  7982. }
  7983. };
  7984. }();
  7985. // core/filterword.js
  7986. /**
  7987. * UE过滤word的静态方法
  7988. * @file
  7989. */
  7990. /**
  7991. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  7992. * @module UE
  7993. */
  7994. /**
  7995. * 根据传入html字符串过滤word
  7996. * @module UE
  7997. * @since 1.2.6.1
  7998. * @method filterWord
  7999. * @param { String } html html字符串
  8000. * @return { String } 已过滤后的结果字符串
  8001. * @example
  8002. * ```javascript
  8003. * UE.filterWord(html);
  8004. * ```
  8005. */
  8006. var filterWord = UE.filterWord = function () {
  8007. //是否是word过来的内容
  8008. function isWordDocument( str ) {
  8009. return /(class="?Mso|style="[^"]*\bmso\-|w:WordDocument|<(v|o):|lang=)/ig.test( str );
  8010. }
  8011. //去掉小数
  8012. function transUnit( v ) {
  8013. v = v.replace( /[\d.]+\w+/g, function ( m ) {
  8014. return utils.transUnitToPx(m);
  8015. } );
  8016. return v;
  8017. }
  8018. function filterPasteWord( str ) {
  8019. return str.replace(/[\t\r\n]+/g,' ')
  8020. .replace( /<!--[\s\S]*?-->/ig, "" )
  8021. //转换图片
  8022. .replace(/<v:shape [^>]*>[\s\S]*?.<\/v:shape>/gi,function(str){
  8023. //opera能自己解析出image所这里直接返回空
  8024. if(browser.opera){
  8025. return '';
  8026. }
  8027. try{
  8028. //有可能是bitmap占为图,无用,直接过滤掉,主要体现在粘贴excel表格中
  8029. if(/Bitmap/i.test(str)){
  8030. return '';
  8031. }
  8032. var width = str.match(/width:([ \d.]*p[tx])/i)[1],
  8033. height = str.match(/height:([ \d.]*p[tx])/i)[1],
  8034. src = str.match(/src=\s*"([^"]*)"/i)[1];
  8035. return '<img width="'+ transUnit(width) +'" height="'+transUnit(height) +'" src="' + src + '" />';
  8036. } catch(e){
  8037. return '';
  8038. }
  8039. })
  8040. //针对wps添加的多余标签处理
  8041. .replace(/<\/?div[^>]*>/g,'')
  8042. //去掉多余的属性
  8043. .replace( /v:\w+=(["']?)[^'"]+\1/g, '' )
  8044. .replace( /<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|xml|meta|link|style|\w+:\w+)(?=[\s\/>]))[^>]*>/gi, "" )
  8045. .replace( /<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi, "<p><strong>$1</strong></p>" )
  8046. //去掉多余的属性
  8047. .replace( /\s+(class|lang|align)\s*=\s*(['"]?)([\w-]+)\2/ig, function(str,name,marks,val){
  8048. //保留list的标示
  8049. return name == 'class' && val == 'MsoListParagraph' ? str : ''
  8050. })
  8051. //清除多余的font/span不能匹配&nbsp;有可能是空格
  8052. .replace( /<(font|span)[^>]*>(\s*)<\/\1>/gi, function(a,b,c){
  8053. return c.replace(/[\t\r\n ]+/g,' ')
  8054. })
  8055. //处理style的问题
  8056. .replace( /(<[a-z][^>]*)\sstyle=(["'])([^\2]*?)\2/gi, function( str, tag, tmp, style ) {
  8057. var n = [],
  8058. s = style.replace( /^\s+|\s+$/, '' )
  8059. .replace(/&#39;/g,'\'')
  8060. .replace( /&quot;/gi, "'" )
  8061. .replace(/[\d.]+(cm|pt)/g,function(str){
  8062. return utils.transUnitToPx(str)
  8063. })
  8064. .split( /;\s*/g );
  8065. for ( var i = 0,v; v = s[i];i++ ) {
  8066. var name, value,
  8067. parts = v.split( ":" );
  8068. if ( parts.length == 2 ) {
  8069. name = parts[0].toLowerCase();
  8070. value = parts[1].toLowerCase();
  8071. if(/^(background)\w*/.test(name) && value.replace(/(initial|\s)/g,'').length == 0
  8072. ||
  8073. /^(margin)\w*/.test(name) && /^0\w+$/.test(value)
  8074. ){
  8075. continue;
  8076. }
  8077. switch ( name ) {
  8078. case "mso-padding-alt":
  8079. case "mso-padding-top-alt":
  8080. case "mso-padding-right-alt":
  8081. case "mso-padding-bottom-alt":
  8082. case "mso-padding-left-alt":
  8083. case "mso-margin-alt":
  8084. case "mso-margin-top-alt":
  8085. case "mso-margin-right-alt":
  8086. case "mso-margin-bottom-alt":
  8087. case "mso-margin-left-alt":
  8088. //ie下会出现挤到一起的情况
  8089. //case "mso-table-layout-alt":
  8090. case "mso-height":
  8091. case "mso-width":
  8092. case "mso-vertical-align-alt":
  8093. //trace:1819 ff下会解析出padding在table上
  8094. if(!/<table/.test(tag))
  8095. n[i] = name.replace( /^mso-|-alt$/g, "" ) + ":" + transUnit( value );
  8096. continue;
  8097. case "horiz-align":
  8098. n[i] = "text-align:" + value;
  8099. continue;
  8100. case "vert-align":
  8101. n[i] = "vertical-align:" + value;
  8102. continue;
  8103. case "font-color":
  8104. case "mso-foreground":
  8105. n[i] = "color:" + value;
  8106. continue;
  8107. case "mso-background":
  8108. case "mso-highlight":
  8109. n[i] = "background:" + value;
  8110. continue;
  8111. case "mso-default-height":
  8112. n[i] = "min-height:" + transUnit( value );
  8113. continue;
  8114. case "mso-default-width":
  8115. n[i] = "min-width:" + transUnit( value );
  8116. continue;
  8117. case "mso-padding-between-alt":
  8118. n[i] = "border-collapse:separate;border-spacing:" + transUnit( value );
  8119. continue;
  8120. case "text-line-through":
  8121. if ( (value == "single") || (value == "double") ) {
  8122. n[i] = "text-decoration:line-through";
  8123. }
  8124. continue;
  8125. case "mso-zero-height":
  8126. if ( value == "yes" ) {
  8127. n[i] = "display:none";
  8128. }
  8129. continue;
  8130. // case 'background':
  8131. // break;
  8132. case 'margin':
  8133. if ( !/[1-9]/.test( value ) ) {
  8134. continue;
  8135. }
  8136. }
  8137. 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 )
  8138. ||
  8139. /text\-indent|padding|margin/.test(name) && /\-[\d.]+/.test(value)
  8140. ) {
  8141. continue;
  8142. }
  8143. n[i] = name + ":" + parts[1];
  8144. }
  8145. }
  8146. return tag + (n.length ? ' style="' + n.join( ';').replace(/;{2,}/g,';') + '"' : '');
  8147. })
  8148. }
  8149. return function ( html ) {
  8150. return (isWordDocument( html ) ? filterPasteWord( html ) : html);
  8151. };
  8152. }();
  8153. // core/node.js
  8154. /**
  8155. * 编辑器模拟的节点类
  8156. * @file
  8157. * @module UE
  8158. * @class uNode
  8159. * @since 1.2.6.1
  8160. */
  8161. /**
  8162. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  8163. * @unfile
  8164. * @module UE
  8165. */
  8166. (function () {
  8167. /**
  8168. * 编辑器模拟的节点类
  8169. * @unfile
  8170. * @module UE
  8171. * @class uNode
  8172. */
  8173. /**
  8174. * 通过一个键值对,创建一个uNode对象
  8175. * @constructor
  8176. * @param { Object } attr 传入要创建的uNode的初始属性
  8177. * @example
  8178. * ```javascript
  8179. * var node = new uNode({
  8180. * type:'element',
  8181. * tagName:'span',
  8182. * attrs:{style:'font-size:14px;'}
  8183. * }
  8184. * ```
  8185. */
  8186. var uNode = UE.uNode = function (obj) {
  8187. this.type = obj.type;
  8188. this.data = obj.data;
  8189. this.tagName = obj.tagName;
  8190. this.parentNode = obj.parentNode;
  8191. this.attrs = obj.attrs || {};
  8192. this.children = obj.children;
  8193. };
  8194. var notTransAttrs = {
  8195. 'href':1,
  8196. 'src':1,
  8197. '_src':1,
  8198. '_href':1,
  8199. 'cdata_data':1
  8200. };
  8201. var notTransTagName = {
  8202. style:1,
  8203. script:1
  8204. };
  8205. var indentChar = ' ',
  8206. breakChar = '\n';
  8207. function insertLine(arr, current, begin) {
  8208. arr.push(breakChar);
  8209. return current + (begin ? 1 : -1);
  8210. }
  8211. function insertIndent(arr, current) {
  8212. //插入缩进
  8213. for (var i = 0; i < current; i++) {
  8214. arr.push(indentChar);
  8215. }
  8216. }
  8217. //创建uNode的静态方法
  8218. //支持标签和html
  8219. uNode.createElement = function (html) {
  8220. if (/[<>]/.test(html)) {
  8221. return UE.htmlparser(html).children[0]
  8222. } else {
  8223. return new uNode({
  8224. type:'element',
  8225. children:[],
  8226. tagName:html
  8227. })
  8228. }
  8229. };
  8230. uNode.createText = function (data,noTrans) {
  8231. return new UE.uNode({
  8232. type:'text',
  8233. 'data':noTrans ? data : utils.unhtml(data || '')
  8234. })
  8235. };
  8236. function nodeToHtml(node, arr, formatter, current) {
  8237. switch (node.type) {
  8238. case 'root':
  8239. for (var i = 0, ci; ci = node.children[i++];) {
  8240. //插入新行
  8241. if (formatter && ci.type == 'element' && !dtd.$inlineWithA[ci.tagName] && i > 1) {
  8242. insertLine(arr, current, true);
  8243. insertIndent(arr, current)
  8244. }
  8245. nodeToHtml(ci, arr, formatter, current)
  8246. }
  8247. break;
  8248. case 'text':
  8249. isText(node, arr);
  8250. break;
  8251. case 'element':
  8252. isElement(node, arr, formatter, current);
  8253. break;
  8254. case 'comment':
  8255. isComment(node, arr, formatter);
  8256. }
  8257. return arr;
  8258. }
  8259. function isText(node, arr) {
  8260. if(node.parentNode.tagName == 'pre'){
  8261. //源码模式下输入html标签,不能做转换处理,直接输出
  8262. arr.push(node.data)
  8263. }else{
  8264. arr.push(notTransTagName[node.parentNode.tagName] ? utils.html(node.data) : node.data.replace(/[ ]{2}/g,' &nbsp;'))
  8265. }
  8266. }
  8267. function isElement(node, arr, formatter, current) {
  8268. var attrhtml = '';
  8269. if (node.attrs) {
  8270. attrhtml = [];
  8271. var attrs = node.attrs;
  8272. for (var a in attrs) {
  8273. //这里就针对
  8274. //<p>'<img src='http://nsclick.baidu.com/u.gif?&asdf=\"sdf&asdfasdfs;asdf'></p>
  8275. //这里边的\"做转换,要不用innerHTML直接被截断了,属性src
  8276. //有可能做的不够
  8277. attrhtml.push(a + (attrs[a] !== undefined ? '="' + (notTransAttrs[a] ? utils.html(attrs[a]).replace(/["]/g, function (a) {
  8278. return '&quot;'
  8279. }) : utils.unhtml(attrs[a])) + '"' : ''))
  8280. }
  8281. attrhtml = attrhtml.join(' ');
  8282. }
  8283. arr.push('<' + node.tagName +
  8284. (attrhtml ? ' ' + attrhtml : '') +
  8285. (dtd.$empty[node.tagName] ? '\/' : '' ) + '>'
  8286. );
  8287. //插入新行
  8288. if (formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != 'pre') {
  8289. if(node.children && node.children.length){
  8290. current = insertLine(arr, current, true);
  8291. insertIndent(arr, current)
  8292. }
  8293. }
  8294. if (node.children && node.children.length) {
  8295. for (var i = 0, ci; ci = node.children[i++];) {
  8296. if (formatter && ci.type == 'element' && !dtd.$inlineWithA[ci.tagName] && i > 1) {
  8297. insertLine(arr, current);
  8298. insertIndent(arr, current)
  8299. }
  8300. nodeToHtml(ci, arr, formatter, current)
  8301. }
  8302. }
  8303. if (!dtd.$empty[node.tagName]) {
  8304. if (formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != 'pre') {
  8305. if(node.children && node.children.length){
  8306. current = insertLine(arr, current);
  8307. insertIndent(arr, current)
  8308. }
  8309. }
  8310. arr.push('<\/' + node.tagName + '>');
  8311. }
  8312. }
  8313. function isComment(node, arr) {
  8314. arr.push('<!--' + node.data + '-->');
  8315. }
  8316. function getNodeById(root, id) {
  8317. var node;
  8318. if (root.type == 'element' && root.getAttr('id') == id) {
  8319. return root;
  8320. }
  8321. if (root.children && root.children.length) {
  8322. for (var i = 0, ci; ci = root.children[i++];) {
  8323. if (node = getNodeById(ci, id)) {
  8324. return node;
  8325. }
  8326. }
  8327. }
  8328. }
  8329. function getNodesByTagName(node, tagName, arr) {
  8330. if (node.type == 'element' && node.tagName == tagName) {
  8331. arr.push(node);
  8332. }
  8333. if (node.children && node.children.length) {
  8334. for (var i = 0, ci; ci = node.children[i++];) {
  8335. getNodesByTagName(ci, tagName, arr)
  8336. }
  8337. }
  8338. }
  8339. function nodeTraversal(root,fn){
  8340. if(root.children && root.children.length){
  8341. for(var i= 0,ci;ci=root.children[i];){
  8342. nodeTraversal(ci,fn);
  8343. //ci被替换的情况,这里就不再走 fn了
  8344. if(ci.parentNode ){
  8345. if(ci.children && ci.children.length){
  8346. fn(ci)
  8347. }
  8348. if(ci.parentNode) i++
  8349. }
  8350. }
  8351. }else{
  8352. fn(root)
  8353. }
  8354. }
  8355. uNode.prototype = {
  8356. /**
  8357. * 当前节点对象,转换成html文本
  8358. * @method toHtml
  8359. * @return { String } 返回转换后的html字符串
  8360. * @example
  8361. * ```javascript
  8362. * node.toHtml();
  8363. * ```
  8364. */
  8365. /**
  8366. * 当前节点对象,转换成html文本
  8367. * @method toHtml
  8368. * @param { Boolean } formatter 是否格式化返回值
  8369. * @return { String } 返回转换后的html字符串
  8370. * @example
  8371. * ```javascript
  8372. * node.toHtml( true );
  8373. * ```
  8374. */
  8375. toHtml:function (formatter) {
  8376. var arr = [];
  8377. nodeToHtml(this, arr, formatter, 0);
  8378. return arr.join('')
  8379. },
  8380. /**
  8381. * 获取节点的html内容
  8382. * @method innerHTML
  8383. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  8384. * @return { String } 返回节点的html内容
  8385. * @example
  8386. * ```javascript
  8387. * var htmlstr = node.innerHTML();
  8388. * ```
  8389. */
  8390. /**
  8391. * 设置节点的html内容
  8392. * @method innerHTML
  8393. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  8394. * @param { String } htmlstr 传入要设置的html内容
  8395. * @return { UE.uNode } 返回节点本身
  8396. * @example
  8397. * ```javascript
  8398. * node.innerHTML('<span>text</span>');
  8399. * ```
  8400. */
  8401. innerHTML:function (htmlstr) {
  8402. if (this.type != 'element' || dtd.$empty[this.tagName]) {
  8403. return this;
  8404. }
  8405. if (utils.isString(htmlstr)) {
  8406. if(this.children){
  8407. for (var i = 0, ci; ci = this.children[i++];) {
  8408. ci.parentNode = null;
  8409. }
  8410. }
  8411. this.children = [];
  8412. var tmpRoot = UE.htmlparser(htmlstr);
  8413. for (var i = 0, ci; ci = tmpRoot.children[i++];) {
  8414. this.children.push(ci);
  8415. ci.parentNode = this;
  8416. }
  8417. return this;
  8418. } else {
  8419. var tmpRoot = new UE.uNode({
  8420. type:'root',
  8421. children:this.children
  8422. });
  8423. return tmpRoot.toHtml();
  8424. }
  8425. },
  8426. /**
  8427. * 获取节点的纯文本内容
  8428. * @method innerText
  8429. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  8430. * @return { String } 返回节点的存文本内容
  8431. * @example
  8432. * ```javascript
  8433. * var textStr = node.innerText();
  8434. * ```
  8435. */
  8436. /**
  8437. * 设置节点的纯文本内容
  8438. * @method innerText
  8439. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  8440. * @param { String } textStr 传入要设置的文本内容
  8441. * @return { UE.uNode } 返回节点本身
  8442. * @example
  8443. * ```javascript
  8444. * node.innerText('<span>text</span>');
  8445. * ```
  8446. */
  8447. innerText:function (textStr,noTrans) {
  8448. if (this.type != 'element' || dtd.$empty[this.tagName]) {
  8449. return this;
  8450. }
  8451. if (textStr) {
  8452. if(this.children){
  8453. for (var i = 0, ci; ci = this.children[i++];) {
  8454. ci.parentNode = null;
  8455. }
  8456. }
  8457. this.children = [];
  8458. this.appendChild(uNode.createText(textStr,noTrans));
  8459. return this;
  8460. } else {
  8461. return this.toHtml().replace(/<[^>]+>/g, '');
  8462. }
  8463. },
  8464. /**
  8465. * 获取当前对象的data属性
  8466. * @method getData
  8467. * @return { Object } 若节点的type值是elemenet,返回空字符串,否则返回节点的data属性
  8468. * @example
  8469. * ```javascript
  8470. * node.getData();
  8471. * ```
  8472. */
  8473. getData:function () {
  8474. if (this.type == 'element')
  8475. return '';
  8476. return this.data
  8477. },
  8478. /**
  8479. * 获取当前节点下的第一个子节点
  8480. * @method firstChild
  8481. * @return { UE.uNode } 返回第一个子节点
  8482. * @example
  8483. * ```javascript
  8484. * node.firstChild(); //返回第一个子节点
  8485. * ```
  8486. */
  8487. firstChild:function () {
  8488. // if (this.type != 'element' || dtd.$empty[this.tagName]) {
  8489. // return this;
  8490. // }
  8491. return this.children ? this.children[0] : null;
  8492. },
  8493. /**
  8494. * 获取当前节点下的最后一个子节点
  8495. * @method lastChild
  8496. * @return { UE.uNode } 返回最后一个子节点
  8497. * @example
  8498. * ```javascript
  8499. * node.lastChild(); //返回最后一个子节点
  8500. * ```
  8501. */
  8502. lastChild:function () {
  8503. // if (this.type != 'element' || dtd.$empty[this.tagName] ) {
  8504. // return this;
  8505. // }
  8506. return this.children ? this.children[this.children.length - 1] : null;
  8507. },
  8508. /**
  8509. * 获取和当前节点有相同父亲节点的前一个节点
  8510. * @method previousSibling
  8511. * @return { UE.uNode } 返回前一个节点
  8512. * @example
  8513. * ```javascript
  8514. * node.children[2].previousSibling(); //返回子节点node.children[1]
  8515. * ```
  8516. */
  8517. previousSibling : function(){
  8518. var parent = this.parentNode;
  8519. for (var i = 0, ci; ci = parent.children[i]; i++) {
  8520. if (ci === this) {
  8521. return i == 0 ? null : parent.children[i-1];
  8522. }
  8523. }
  8524. },
  8525. /**
  8526. * 获取和当前节点有相同父亲节点的后一个节点
  8527. * @method nextSibling
  8528. * @return { UE.uNode } 返回后一个节点,找不到返回null
  8529. * @example
  8530. * ```javascript
  8531. * node.children[2].nextSibling(); //如果有,返回子节点node.children[3]
  8532. * ```
  8533. */
  8534. nextSibling : function(){
  8535. var parent = this.parentNode;
  8536. for (var i = 0, ci; ci = parent.children[i++];) {
  8537. if (ci === this) {
  8538. return parent.children[i];
  8539. }
  8540. }
  8541. },
  8542. /**
  8543. * 用新的节点替换当前节点
  8544. * @method replaceChild
  8545. * @param { UE.uNode } target 要替换成该节点参数
  8546. * @param { UE.uNode } source 要被替换掉的节点
  8547. * @return { UE.uNode } 返回替换之后的节点对象
  8548. * @example
  8549. * ```javascript
  8550. * node.replaceChild(newNode, childNode); //用newNode替换childNode,childNode是node的子节点
  8551. * ```
  8552. */
  8553. replaceChild:function (target, source) {
  8554. if (this.children) {
  8555. if(target.parentNode){
  8556. target.parentNode.removeChild(target);
  8557. }
  8558. for (var i = 0, ci; ci = this.children[i]; i++) {
  8559. if (ci === source) {
  8560. this.children.splice(i, 1, target);
  8561. source.parentNode = null;
  8562. target.parentNode = this;
  8563. return target;
  8564. }
  8565. }
  8566. }
  8567. },
  8568. /**
  8569. * 在节点的子节点列表最后位置插入一个节点
  8570. * @method appendChild
  8571. * @param { UE.uNode } node 要插入的节点
  8572. * @return { UE.uNode } 返回刚插入的子节点
  8573. * @example
  8574. * ```javascript
  8575. * node.appendChild( newNode ); //在node内插入子节点newNode
  8576. * ```
  8577. */
  8578. appendChild:function (node) {
  8579. if (this.type == 'root' || (this.type == 'element' && !dtd.$empty[this.tagName])) {
  8580. if (!this.children) {
  8581. this.children = []
  8582. }
  8583. if(node.parentNode){
  8584. node.parentNode.removeChild(node);
  8585. }
  8586. for (var i = 0, ci; ci = this.children[i]; i++) {
  8587. if (ci === node) {
  8588. this.children.splice(i, 1);
  8589. break;
  8590. }
  8591. }
  8592. this.children.push(node);
  8593. node.parentNode = this;
  8594. return node;
  8595. }
  8596. },
  8597. /**
  8598. * 在传入节点的前面插入一个节点
  8599. * @method insertBefore
  8600. * @param { UE.uNode } target 要插入的节点
  8601. * @param { UE.uNode } source 在该参数节点前面插入
  8602. * @return { UE.uNode } 返回刚插入的子节点
  8603. * @example
  8604. * ```javascript
  8605. * node.parentNode.insertBefore(newNode, node); //在node节点后面插入newNode
  8606. * ```
  8607. */
  8608. insertBefore:function (target, source) {
  8609. if (this.children) {
  8610. if(target.parentNode){
  8611. target.parentNode.removeChild(target);
  8612. }
  8613. for (var i = 0, ci; ci = this.children[i]; i++) {
  8614. if (ci === source) {
  8615. this.children.splice(i, 0, target);
  8616. target.parentNode = this;
  8617. return target;
  8618. }
  8619. }
  8620. }
  8621. },
  8622. /**
  8623. * 在传入节点的后面插入一个节点
  8624. * @method insertAfter
  8625. * @param { UE.uNode } target 要插入的节点
  8626. * @param { UE.uNode } source 在该参数节点后面插入
  8627. * @return { UE.uNode } 返回刚插入的子节点
  8628. * @example
  8629. * ```javascript
  8630. * node.parentNode.insertAfter(newNode, node); //在node节点后面插入newNode
  8631. * ```
  8632. */
  8633. insertAfter:function (target, source) {
  8634. if (this.children) {
  8635. if(target.parentNode){
  8636. target.parentNode.removeChild(target);
  8637. }
  8638. for (var i = 0, ci; ci = this.children[i]; i++) {
  8639. if (ci === source) {
  8640. this.children.splice(i + 1, 0, target);
  8641. target.parentNode = this;
  8642. return target;
  8643. }
  8644. }
  8645. }
  8646. },
  8647. /**
  8648. * 从当前节点的子节点列表中,移除节点
  8649. * @method removeChild
  8650. * @param { UE.uNode } node 要移除的节点引用
  8651. * @param { Boolean } keepChildren 是否保留移除节点的子节点,若传入true,自动把移除节点的子节点插入到移除的位置
  8652. * @return { * } 返回刚移除的子节点
  8653. * @example
  8654. * ```javascript
  8655. * node.removeChild(childNode,true); //在node的子节点列表中移除child节点,并且吧child的子节点插入到移除的位置
  8656. * ```
  8657. */
  8658. removeChild:function (node,keepChildren) {
  8659. if (this.children) {
  8660. for (var i = 0, ci; ci = this.children[i]; i++) {
  8661. if (ci === node) {
  8662. this.children.splice(i, 1);
  8663. ci.parentNode = null;
  8664. if(keepChildren && ci.children && ci.children.length){
  8665. for(var j= 0,cj;cj=ci.children[j];j++){
  8666. this.children.splice(i+j,0,cj);
  8667. cj.parentNode = this;
  8668. }
  8669. }
  8670. return ci;
  8671. }
  8672. }
  8673. }
  8674. },
  8675. /**
  8676. * 获取当前节点所代表的元素属性,即获取attrs对象下的属性值
  8677. * @method getAttr
  8678. * @param { String } attrName 要获取的属性名称
  8679. * @return { * } 返回attrs对象下的属性值
  8680. * @example
  8681. * ```javascript
  8682. * node.getAttr('title');
  8683. * ```
  8684. */
  8685. getAttr:function (attrName) {
  8686. return this.attrs && this.attrs[attrName.toLowerCase()]
  8687. },
  8688. /**
  8689. * 设置当前节点所代表的元素属性,即设置attrs对象下的属性值
  8690. * @method setAttr
  8691. * @param { String } attrName 要设置的属性名称
  8692. * @param { * } attrVal 要设置的属性值,类型视设置的属性而定
  8693. * @return { * } 返回attrs对象下的属性值
  8694. * @example
  8695. * ```javascript
  8696. * node.setAttr('title','标题');
  8697. * ```
  8698. */
  8699. setAttr:function (attrName, attrVal) {
  8700. if (!attrName) {
  8701. delete this.attrs;
  8702. return;
  8703. }
  8704. if(!this.attrs){
  8705. this.attrs = {};
  8706. }
  8707. if (utils.isObject(attrName)) {
  8708. for (var a in attrName) {
  8709. if (!attrName[a]) {
  8710. delete this.attrs[a]
  8711. } else {
  8712. this.attrs[a.toLowerCase()] = attrName[a];
  8713. }
  8714. }
  8715. } else {
  8716. if (!attrVal) {
  8717. delete this.attrs[attrName]
  8718. } else {
  8719. this.attrs[attrName.toLowerCase()] = attrVal;
  8720. }
  8721. }
  8722. },
  8723. /**
  8724. * 获取当前节点在父节点下的位置索引
  8725. * @method getIndex
  8726. * @return { Number } 返回索引数值,如果没有父节点,返回-1
  8727. * @example
  8728. * ```javascript
  8729. * node.getIndex();
  8730. * ```
  8731. */
  8732. getIndex:function(){
  8733. var parent = this.parentNode;
  8734. for(var i= 0,ci;ci=parent.children[i];i++){
  8735. if(ci === this){
  8736. return i;
  8737. }
  8738. }
  8739. return -1;
  8740. },
  8741. /**
  8742. * 在当前节点下,根据id查找节点
  8743. * @method getNodeById
  8744. * @param { String } id 要查找的id
  8745. * @return { UE.uNode } 返回找到的节点
  8746. * @example
  8747. * ```javascript
  8748. * node.getNodeById('textId');
  8749. * ```
  8750. */
  8751. getNodeById:function (id) {
  8752. var node;
  8753. if (this.children && this.children.length) {
  8754. for (var i = 0, ci; ci = this.children[i++];) {
  8755. if (node = getNodeById(ci, id)) {
  8756. return node;
  8757. }
  8758. }
  8759. }
  8760. },
  8761. /**
  8762. * 在当前节点下,根据元素名称查找节点列表
  8763. * @method getNodesByTagName
  8764. * @param { String } tagNames 要查找的元素名称
  8765. * @return { Array } 返回找到的节点列表
  8766. * @example
  8767. * ```javascript
  8768. * node.getNodesByTagName('span');
  8769. * ```
  8770. */
  8771. getNodesByTagName:function (tagNames) {
  8772. tagNames = utils.trim(tagNames).replace(/[ ]{2,}/g, ' ').split(' ');
  8773. var arr = [], me = this;
  8774. utils.each(tagNames, function (tagName) {
  8775. if (me.children && me.children.length) {
  8776. for (var i = 0, ci; ci = me.children[i++];) {
  8777. getNodesByTagName(ci, tagName, arr)
  8778. }
  8779. }
  8780. });
  8781. return arr;
  8782. },
  8783. /**
  8784. * 根据样式名称,获取节点的样式值
  8785. * @method getStyle
  8786. * @param { String } name 要获取的样式名称
  8787. * @return { String } 返回样式值
  8788. * @example
  8789. * ```javascript
  8790. * node.getStyle('font-size');
  8791. * ```
  8792. */
  8793. getStyle:function (name) {
  8794. var cssStyle = this.getAttr('style');
  8795. if (!cssStyle) {
  8796. return ''
  8797. }
  8798. var reg = new RegExp('(^|;)\\s*' + name + ':([^;]+)','i');
  8799. var match = cssStyle.match(reg);
  8800. if (match && match[0]) {
  8801. return match[2]
  8802. }
  8803. return '';
  8804. },
  8805. /**
  8806. * 给节点设置样式
  8807. * @method setStyle
  8808. * @param { String } name 要设置的的样式名称
  8809. * @param { String } val 要设置的的样值
  8810. * @example
  8811. * ```javascript
  8812. * node.setStyle('font-size', '12px');
  8813. * ```
  8814. */
  8815. setStyle:function (name, val) {
  8816. function exec(name, val) {
  8817. var reg = new RegExp('(^|;)\\s*' + name + ':([^;]+;?)', 'gi');
  8818. cssStyle = cssStyle.replace(reg, '$1');
  8819. if (val) {
  8820. cssStyle = name + ':' + utils.unhtml(val) + ';' + cssStyle
  8821. }
  8822. }
  8823. var cssStyle = this.getAttr('style');
  8824. if (!cssStyle) {
  8825. cssStyle = '';
  8826. }
  8827. if (utils.isObject(name)) {
  8828. for (var a in name) {
  8829. exec(a, name[a])
  8830. }
  8831. } else {
  8832. exec(name, val)
  8833. }
  8834. this.setAttr('style', utils.trim(cssStyle))
  8835. },
  8836. /**
  8837. * 传入一个函数,递归遍历当前节点下的所有节点
  8838. * @method traversal
  8839. * @param { Function } fn 遍历到节点的时,传入节点作为参数,运行此函数
  8840. * @example
  8841. * ```javascript
  8842. * traversal(node, function(){
  8843. * console.log(node.type);
  8844. * });
  8845. * ```
  8846. */
  8847. traversal:function(fn){
  8848. if(this.children && this.children.length){
  8849. nodeTraversal(this,fn);
  8850. }
  8851. return this;
  8852. }
  8853. }
  8854. })();
  8855. // core/htmlparser.js
  8856. /**
  8857. * html字符串转换成uNode节点
  8858. * @file
  8859. * @module UE
  8860. * @since 1.2.6.1
  8861. */
  8862. /**
  8863. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  8864. * @unfile
  8865. * @module UE
  8866. */
  8867. /**
  8868. * html字符串转换成uNode节点的静态方法
  8869. * @method htmlparser
  8870. * @param { String } htmlstr 要转换的html代码
  8871. * @param { Boolean } ignoreBlank 若设置为true,转换的时候忽略\n\r\t等空白字符
  8872. * @return { uNode } 给定的html片段转换形成的uNode对象
  8873. * @example
  8874. * ```javascript
  8875. * var root = UE.htmlparser('<p><b>htmlparser</b></p>', true);
  8876. * ```
  8877. */
  8878. var htmlparser = UE.htmlparser = function (htmlstr,ignoreBlank) {
  8879. //todo 原来的方式 [^"'<>\/] 有\/就不能配对上 <TD vAlign=top background=../AAA.JPG> 这样的标签了
  8880. //先去掉了,加上的原因忘了,这里先记录
  8881. var re_tag = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/<>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g,
  8882. re_attr = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g;
  8883. //ie下取得的html可能会有\n存在,要去掉,在处理replace(/[\t\r\n]*/g,'');代码高量的\n不能去除
  8884. var allowEmptyTags = {
  8885. b:1,code:1,i:1,u:1,strike:1,s:1,tt:1,strong:1,q:1,samp:1,em:1,span:1,
  8886. sub:1,img:1,sup:1,font:1,big:1,small:1,iframe:1,a:1,br:1,pre:1
  8887. };
  8888. htmlstr = htmlstr.replace(new RegExp(domUtils.fillChar, 'g'), '');
  8889. if(!ignoreBlank){
  8890. htmlstr = htmlstr.replace(new RegExp('[\\r\\t\\n'+(ignoreBlank?'':' ')+']*<\/?(\\w+)\\s*(?:[^>]*)>[\\r\\t\\n'+(ignoreBlank?'':' ')+']*','g'), function(a,b){
  8891. //br暂时单独处理
  8892. if(b && allowEmptyTags[b.toLowerCase()]){
  8893. return a.replace(/(^[\n\r]+)|([\n\r]+$)/g,'');
  8894. }
  8895. return a.replace(new RegExp('^[\\r\\n'+(ignoreBlank?'':' ')+']+'),'').replace(new RegExp('[\\r\\n'+(ignoreBlank?'':' ')+']+$'),'');
  8896. });
  8897. }
  8898. var notTransAttrs = {
  8899. 'href':1,
  8900. 'src':1
  8901. };
  8902. var uNode = UE.uNode,
  8903. needParentNode = {
  8904. 'td':'tr',
  8905. 'tr':['tbody','thead','tfoot'],
  8906. 'tbody':'table',
  8907. 'th':'tr',
  8908. 'thead':'table',
  8909. 'tfoot':'table',
  8910. 'caption':'table',
  8911. 'li':['ul', 'ol'],
  8912. 'dt':'dl',
  8913. 'dd':'dl',
  8914. 'option':'select'
  8915. },
  8916. needChild = {
  8917. 'ol':'li',
  8918. 'ul':'li'
  8919. };
  8920. function text(parent, data) {
  8921. if(needChild[parent.tagName]){
  8922. var tmpNode = uNode.createElement(needChild[parent.tagName]);
  8923. parent.appendChild(tmpNode);
  8924. tmpNode.appendChild(uNode.createText(data));
  8925. parent = tmpNode;
  8926. }else{
  8927. parent.appendChild(uNode.createText(data));
  8928. }
  8929. }
  8930. function element(parent, tagName, htmlattr) {
  8931. var needParentTag;
  8932. if (needParentTag = needParentNode[tagName]) {
  8933. var tmpParent = parent,hasParent;
  8934. while(tmpParent.type != 'root'){
  8935. if(utils.isArray(needParentTag) ? utils.indexOf(needParentTag, tmpParent.tagName) != -1 : needParentTag == tmpParent.tagName){
  8936. parent = tmpParent;
  8937. hasParent = true;
  8938. break;
  8939. }
  8940. tmpParent = tmpParent.parentNode;
  8941. }
  8942. if(!hasParent){
  8943. parent = element(parent, utils.isArray(needParentTag) ? needParentTag[0] : needParentTag)
  8944. }
  8945. }
  8946. //按dtd处理嵌套
  8947. // if(parent.type != 'root' && !dtd[parent.tagName][tagName])
  8948. // parent = parent.parentNode;
  8949. var elm = new uNode({
  8950. parentNode:parent,
  8951. type:'element',
  8952. tagName:tagName.toLowerCase(),
  8953. //是自闭合的处理一下
  8954. children:dtd.$empty[tagName] ? null : []
  8955. });
  8956. //如果属性存在,处理属性
  8957. if (htmlattr) {
  8958. var attrs = {}, match;
  8959. while (match = re_attr.exec(htmlattr)) {
  8960. attrs[match[1].toLowerCase()] = notTransAttrs[match[1].toLowerCase()] ? (match[2] || match[3] || match[4]) : utils.unhtml(match[2] || match[3] || match[4])
  8961. }
  8962. elm.attrs = attrs;
  8963. }
  8964. //trace:3970
  8965. // //如果parent下不能放elm
  8966. // if(dtd.$inline[parent.tagName] && dtd.$block[elm.tagName] && !dtd[parent.tagName][elm.tagName]){
  8967. // parent = parent.parentNode;
  8968. // elm.parentNode = parent;
  8969. // }
  8970. parent.children.push(elm);
  8971. //如果是自闭合节点返回父亲节点
  8972. return dtd.$empty[tagName] ? parent : elm
  8973. }
  8974. function comment(parent, data) {
  8975. parent.children.push(new uNode({
  8976. type:'comment',
  8977. data:data,
  8978. parentNode:parent
  8979. }));
  8980. }
  8981. var match, currentIndex = 0, nextIndex = 0;
  8982. //设置根节点
  8983. var root = new uNode({
  8984. type:'root',
  8985. children:[]
  8986. });
  8987. var currentParent = root;
  8988. while (match = re_tag.exec(htmlstr)) {
  8989. currentIndex = match.index;
  8990. try{
  8991. if (currentIndex > nextIndex) {
  8992. //text node
  8993. text(currentParent, htmlstr.slice(nextIndex, currentIndex));
  8994. }
  8995. if (match[3]) {
  8996. if(dtd.$cdata[currentParent.tagName]){
  8997. text(currentParent, match[0]);
  8998. }else{
  8999. //start tag
  9000. currentParent = element(currentParent, match[3].toLowerCase(), match[4]);
  9001. }
  9002. } else if (match[1]) {
  9003. if(currentParent.type != 'root'){
  9004. if(dtd.$cdata[currentParent.tagName] && !dtd.$cdata[match[1]]){
  9005. text(currentParent, match[0]);
  9006. }else{
  9007. var tmpParent = currentParent;
  9008. while(currentParent.type == 'element' && currentParent.tagName != match[1].toLowerCase()){
  9009. currentParent = currentParent.parentNode;
  9010. if(currentParent.type == 'root'){
  9011. currentParent = tmpParent;
  9012. throw 'break'
  9013. }
  9014. }
  9015. //end tag
  9016. currentParent = currentParent.parentNode;
  9017. }
  9018. }
  9019. } else if (match[2]) {
  9020. //comment
  9021. comment(currentParent, match[2])
  9022. }
  9023. }catch(e){}
  9024. nextIndex = re_tag.lastIndex;
  9025. }
  9026. //如果结束是文本,就有可能丢掉,所以这里手动判断一下
  9027. //例如 <li>sdfsdfsdf<li>sdfsdfsdfsdf
  9028. if (nextIndex < htmlstr.length) {
  9029. text(currentParent, htmlstr.slice(nextIndex));
  9030. }
  9031. return root;
  9032. };
  9033. // core/filternode.js
  9034. /**
  9035. * UE过滤节点的静态方法
  9036. * @file
  9037. */
  9038. /**
  9039. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  9040. * @module UE
  9041. */
  9042. /**
  9043. * 根据传入节点和过滤规则过滤相应节点
  9044. * @module UE
  9045. * @since 1.2.6.1
  9046. * @method filterNode
  9047. * @param { Object } root 指定root节点
  9048. * @param { Object } rules 过滤规则json对象
  9049. * @example
  9050. * ```javascript
  9051. * UE.filterNode(root,editor.options.filterRules);
  9052. * ```
  9053. */
  9054. var filterNode = UE.filterNode = function () {
  9055. function filterNode(node,rules){
  9056. switch (node.type) {
  9057. case 'text':
  9058. break;
  9059. case 'element':
  9060. var val;
  9061. if(val = rules[node.tagName]){
  9062. if(val === '-'){
  9063. node.parentNode.removeChild(node)
  9064. }else if(utils.isFunction(val)){
  9065. var parentNode = node.parentNode,
  9066. index = node.getIndex();
  9067. val(node);
  9068. if(node.parentNode){
  9069. if(node.children){
  9070. for(var i = 0,ci;ci=node.children[i];){
  9071. filterNode(ci,rules);
  9072. if(ci.parentNode){
  9073. i++;
  9074. }
  9075. }
  9076. }
  9077. }else{
  9078. for(var i = index,ci;ci=parentNode.children[i];){
  9079. filterNode(ci,rules);
  9080. if(ci.parentNode){
  9081. i++;
  9082. }
  9083. }
  9084. }
  9085. }else{
  9086. var attrs = val['$'];
  9087. if(attrs && node.attrs){
  9088. var tmpAttrs = {},tmpVal;
  9089. for(var a in attrs){
  9090. tmpVal = node.getAttr(a);
  9091. //todo 只先对style单独处理
  9092. if(a == 'style' && utils.isArray(attrs[a])){
  9093. var tmpCssStyle = [];
  9094. utils.each(attrs[a],function(v){
  9095. var tmp;
  9096. if(tmp = node.getStyle(v)){
  9097. tmpCssStyle.push(v + ':' + tmp);
  9098. }
  9099. });
  9100. tmpVal = tmpCssStyle.join(';')
  9101. }
  9102. if(tmpVal){
  9103. tmpAttrs[a] = tmpVal;
  9104. }
  9105. }
  9106. node.attrs = tmpAttrs;
  9107. }
  9108. if(node.children){
  9109. for(var i = 0,ci;ci=node.children[i];){
  9110. filterNode(ci,rules);
  9111. if(ci.parentNode){
  9112. i++;
  9113. }
  9114. }
  9115. }
  9116. }
  9117. }else{
  9118. //如果不在名单里扣出子节点并删除该节点,cdata除外
  9119. if(dtd.$cdata[node.tagName]){
  9120. node.parentNode.removeChild(node)
  9121. }else{
  9122. var parentNode = node.parentNode,
  9123. index = node.getIndex();
  9124. node.parentNode.removeChild(node,true);
  9125. for(var i = index,ci;ci=parentNode.children[i];){
  9126. filterNode(ci,rules);
  9127. if(ci.parentNode){
  9128. i++;
  9129. }
  9130. }
  9131. }
  9132. }
  9133. break;
  9134. case 'comment':
  9135. node.parentNode.removeChild(node)
  9136. }
  9137. }
  9138. return function(root,rules){
  9139. if(utils.isEmptyObject(rules)){
  9140. return root;
  9141. }
  9142. var val;
  9143. if(val = rules['-']){
  9144. utils.each(val.split(' '),function(k){
  9145. rules[k] = '-'
  9146. })
  9147. }
  9148. for(var i= 0,ci;ci=root.children[i];){
  9149. filterNode(ci,rules);
  9150. if(ci.parentNode){
  9151. i++;
  9152. }
  9153. }
  9154. return root;
  9155. }
  9156. }();
  9157. // core/plugin.js
  9158. /**
  9159. * Created with JetBrains PhpStorm.
  9160. * User: campaign
  9161. * Date: 10/8/13
  9162. * Time: 6:15 PM
  9163. * To change this template use File | Settings | File Templates.
  9164. */
  9165. UE.plugin = function(){
  9166. var _plugins = {};
  9167. return {
  9168. register : function(pluginName,fn,oldOptionName,afterDisabled){
  9169. if(oldOptionName && utils.isFunction(oldOptionName)){
  9170. afterDisabled = oldOptionName;
  9171. oldOptionName = null
  9172. }
  9173. _plugins[pluginName] = {
  9174. optionName : oldOptionName || pluginName,
  9175. execFn : fn,
  9176. //当插件被禁用时执行
  9177. afterDisabled : afterDisabled
  9178. }
  9179. },
  9180. load : function(editor){
  9181. utils.each(_plugins,function(plugin){
  9182. var _export = plugin.execFn.call(editor);
  9183. if(editor.options[plugin.optionName] !== false){
  9184. if(_export){
  9185. //后边需要再做扩展
  9186. utils.each(_export,function(v,k){
  9187. switch(k.toLowerCase()){
  9188. case 'shortcutkey':
  9189. editor.addshortcutkey(v);
  9190. break;
  9191. case 'bindevents':
  9192. utils.each(v,function(fn,eventName){
  9193. editor.addListener(eventName,fn);
  9194. });
  9195. break;
  9196. case 'bindmultievents':
  9197. utils.each(utils.isArray(v) ? v:[v],function(event){
  9198. var types = utils.trim(event.type).split(/\s+/);
  9199. utils.each(types,function(eventName){
  9200. editor.addListener(eventName, event.handler);
  9201. });
  9202. });
  9203. break;
  9204. case 'commands':
  9205. utils.each(v,function(execFn,execName){
  9206. editor.commands[execName] = execFn
  9207. });
  9208. break;
  9209. case 'outputrule':
  9210. editor.addOutputRule(v);
  9211. break;
  9212. case 'inputrule':
  9213. editor.addInputRule(v);
  9214. break;
  9215. case 'defaultoptions':
  9216. editor.setOpt(v)
  9217. }
  9218. })
  9219. }
  9220. }else if(plugin.afterDisabled){
  9221. plugin.afterDisabled.call(editor)
  9222. }
  9223. });
  9224. //向下兼容
  9225. utils.each(UE.plugins,function(plugin){
  9226. plugin.call(editor);
  9227. });
  9228. },
  9229. run : function(pluginName,editor){
  9230. var plugin = _plugins[pluginName];
  9231. if(plugin){
  9232. plugin.exeFn.call(editor)
  9233. }
  9234. }
  9235. }
  9236. }();
  9237. // core/keymap.js
  9238. var keymap = UE.keymap = {
  9239. 'Backspace' : 8,
  9240. 'Tab' : 9,
  9241. 'Enter' : 13,
  9242. 'Shift':16,
  9243. 'Control':17,
  9244. 'Alt':18,
  9245. 'CapsLock':20,
  9246. 'Esc':27,
  9247. 'Spacebar':32,
  9248. 'PageUp':33,
  9249. 'PageDown':34,
  9250. 'End':35,
  9251. 'Home':36,
  9252. 'Left':37,
  9253. 'Up':38,
  9254. 'Right':39,
  9255. 'Down':40,
  9256. 'Insert':45,
  9257. 'Del':46,
  9258. 'NumLock':144,
  9259. 'Cmd':91,
  9260. '=':187,
  9261. '-':189,
  9262. "b":66,
  9263. 'i':73,
  9264. //回退
  9265. 'z':90,
  9266. 'y':89,
  9267. //粘贴
  9268. 'v' : 86,
  9269. 'x' : 88,
  9270. 's' : 83,
  9271. 'n' : 78
  9272. };
  9273. // core/localstorage.js
  9274. //存储媒介封装
  9275. var LocalStorage = UE.LocalStorage = (function () {
  9276. var storage = window.localStorage || getUserData() || null,
  9277. LOCAL_FILE = 'localStorage';
  9278. return {
  9279. saveLocalData: function (key, data) {
  9280. if (storage && data) {
  9281. storage.setItem(key, data);
  9282. return true;
  9283. }
  9284. return false;
  9285. },
  9286. getLocalData: function (key) {
  9287. if (storage) {
  9288. return storage.getItem(key);
  9289. }
  9290. return null;
  9291. },
  9292. removeItem: function (key) {
  9293. storage && storage.removeItem(key);
  9294. }
  9295. };
  9296. function getUserData() {
  9297. var container = document.createElement("div");
  9298. container.style.display = "none";
  9299. if (!container.addBehavior) {
  9300. return null;
  9301. }
  9302. container.addBehavior("#default#userdata");
  9303. return {
  9304. getItem: function (key) {
  9305. var result = null;
  9306. try {
  9307. document.body.appendChild(container);
  9308. container.load(LOCAL_FILE);
  9309. result = container.getAttribute(key);
  9310. document.body.removeChild(container);
  9311. } catch (e) {
  9312. }
  9313. return result;
  9314. },
  9315. setItem: function (key, value) {
  9316. document.body.appendChild(container);
  9317. container.setAttribute(key, value);
  9318. container.save(LOCAL_FILE);
  9319. document.body.removeChild(container);
  9320. },
  9321. //// 暂时没有用到
  9322. //clear: function () {
  9323. //
  9324. // var expiresTime = new Date();
  9325. // expiresTime.setFullYear(expiresTime.getFullYear() - 1);
  9326. // document.body.appendChild(container);
  9327. // container.expires = expiresTime.toUTCString();
  9328. // container.save(LOCAL_FILE);
  9329. // document.body.removeChild(container);
  9330. //
  9331. //},
  9332. removeItem: function (key) {
  9333. document.body.appendChild(container);
  9334. container.removeAttribute(key);
  9335. container.save(LOCAL_FILE);
  9336. document.body.removeChild(container);
  9337. }
  9338. };
  9339. }
  9340. })();
  9341. (function () {
  9342. var ROOTKEY = 'ueditor_preference';
  9343. UE.Editor.prototype.setPreferences = function(key,value){
  9344. var obj = {};
  9345. if (utils.isString(key)) {
  9346. obj[ key ] = value;
  9347. } else {
  9348. obj = key;
  9349. }
  9350. var data = LocalStorage.getLocalData(ROOTKEY);
  9351. if (data && (data = utils.str2json(data))) {
  9352. utils.extend(data, obj);
  9353. } else {
  9354. data = obj;
  9355. }
  9356. data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data));
  9357. };
  9358. UE.Editor.prototype.getPreferences = function(key){
  9359. var data = LocalStorage.getLocalData(ROOTKEY);
  9360. if (data && (data = utils.str2json(data))) {
  9361. return key ? data[key] : data
  9362. }
  9363. return null;
  9364. };
  9365. UE.Editor.prototype.removePreferences = function (key) {
  9366. var data = LocalStorage.getLocalData(ROOTKEY);
  9367. if (data && (data = utils.str2json(data))) {
  9368. data[key] = undefined;
  9369. delete data[key]
  9370. }
  9371. data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data));
  9372. };
  9373. })();
  9374. // plugins/defaultfilter.js
  9375. ///import core
  9376. ///plugin 编辑器默认的过滤转换机制
  9377. UE.plugins['defaultfilter'] = function () {
  9378. var me = this;
  9379. me.setOpt({
  9380. 'allowDivTransToP':true,
  9381. 'disabledTableInTable':true
  9382. });
  9383. //默认的过滤处理
  9384. //进入编辑器的内容处理
  9385. me.addInputRule(function (root) {
  9386. var allowDivTransToP = this.options.allowDivTransToP;
  9387. var val;
  9388. function tdParent(node){
  9389. while(node && node.type == 'element'){
  9390. if(node.tagName == 'td'){
  9391. return true;
  9392. }
  9393. node = node.parentNode;
  9394. }
  9395. return false;
  9396. }
  9397. //进行默认的处理
  9398. root.traversal(function (node) {
  9399. if (node.type == 'element') {
  9400. if (!dtd.$cdata[node.tagName] && me.options.autoClearEmptyNode && dtd.$inline[node.tagName] && !dtd.$empty[node.tagName] && (!node.attrs || utils.isEmptyObject(node.attrs))) {
  9401. if (!node.firstChild()) node.parentNode.removeChild(node);
  9402. else if (node.tagName == 'span' && (!node.attrs || utils.isEmptyObject(node.attrs))) {
  9403. node.parentNode.removeChild(node, true)
  9404. }
  9405. return;
  9406. }
  9407. switch (node.tagName) {
  9408. case 'style':
  9409. case 'script':
  9410. node.setAttr({
  9411. cdata_tag: node.tagName,
  9412. cdata_data: (node.innerHTML() || ''),
  9413. '_ue_custom_node_':'true'
  9414. });
  9415. node.tagName = 'div';
  9416. node.innerHTML('');
  9417. break;
  9418. case 'a':
  9419. if (val = node.getAttr('href')) {
  9420. node.setAttr('_href', val)
  9421. }
  9422. break;
  9423. case 'img':
  9424. //todo base64暂时去掉,后边做远程图片上传后,干掉这个
  9425. if (val = node.getAttr('src')) {
  9426. if (/^data:/.test(val)) {
  9427. node.parentNode.removeChild(node);
  9428. break;
  9429. }
  9430. }
  9431. node.setAttr('_src', node.getAttr('src'));
  9432. break;
  9433. case 'span':
  9434. if (browser.webkit && (val = node.getStyle('white-space'))) {
  9435. if (/nowrap|normal/.test(val)) {
  9436. node.setStyle('white-space', '');
  9437. if (me.options.autoClearEmptyNode && utils.isEmptyObject(node.attrs)) {
  9438. node.parentNode.removeChild(node, true)
  9439. }
  9440. }
  9441. }
  9442. val = node.getAttr('id');
  9443. if(val && /^_baidu_bookmark_/i.test(val)){
  9444. node.parentNode.removeChild(node)
  9445. }
  9446. break;
  9447. case 'p':
  9448. if (val = node.getAttr('align')) {
  9449. node.setAttr('align');
  9450. node.setStyle('text-align', val)
  9451. }
  9452. //trace:3431
  9453. // var cssStyle = node.getAttr('style');
  9454. // if (cssStyle) {
  9455. // cssStyle = cssStyle.replace(/(margin|padding)[^;]+/g, '');
  9456. // node.setAttr('style', cssStyle)
  9457. //
  9458. // }
  9459. //p标签不允许嵌套
  9460. utils.each(node.children,function(n){
  9461. if(n.type == 'element' && n.tagName == 'p'){
  9462. var next = n.nextSibling();
  9463. node.parentNode.insertAfter(n,node);
  9464. var last = n;
  9465. while(next){
  9466. var tmp = next.nextSibling();
  9467. node.parentNode.insertAfter(next,last);
  9468. last = next;
  9469. next = tmp;
  9470. }
  9471. return false;
  9472. }
  9473. });
  9474. if (!node.firstChild()) {
  9475. node.innerHTML(browser.ie ? '&nbsp;' : '<br/>')
  9476. }
  9477. break;
  9478. case 'div':
  9479. if(node.getAttr('cdata_tag')){
  9480. break;
  9481. }
  9482. //针对代码这里不处理插入代码的div
  9483. val = node.getAttr('class');
  9484. if(val && /^line number\d+/.test(val)){
  9485. break;
  9486. }
  9487. if(!allowDivTransToP){
  9488. break;
  9489. }
  9490. var tmpNode, p = UE.uNode.createElement('p');
  9491. while (tmpNode = node.firstChild()) {
  9492. if (tmpNode.type == 'text' || !UE.dom.dtd.$block[tmpNode.tagName]) {
  9493. p.appendChild(tmpNode);
  9494. } else {
  9495. if (p.firstChild()) {
  9496. node.parentNode.insertBefore(p, node);
  9497. p = UE.uNode.createElement('p');
  9498. } else {
  9499. node.parentNode.insertBefore(tmpNode, node);
  9500. }
  9501. }
  9502. }
  9503. if (p.firstChild()) {
  9504. node.parentNode.insertBefore(p, node);
  9505. }
  9506. node.parentNode.removeChild(node);
  9507. break;
  9508. case 'dl':
  9509. node.tagName = 'ul';
  9510. break;
  9511. case 'dt':
  9512. case 'dd':
  9513. node.tagName = 'li';
  9514. break;
  9515. case 'li':
  9516. var className = node.getAttr('class');
  9517. if (!className || !/list\-/.test(className)) {
  9518. node.setAttr()
  9519. }
  9520. var tmpNodes = node.getNodesByTagName('ol ul');
  9521. UE.utils.each(tmpNodes, function (n) {
  9522. node.parentNode.insertAfter(n, node);
  9523. });
  9524. break;
  9525. case 'td':
  9526. case 'th':
  9527. case 'caption':
  9528. if(!node.children || !node.children.length){
  9529. node.appendChild(browser.ie11below ? UE.uNode.createText(' ') : UE.uNode.createElement('br'))
  9530. }
  9531. break;
  9532. case 'table':
  9533. if(me.options.disabledTableInTable && tdParent(node)){
  9534. node.parentNode.insertBefore(UE.uNode.createText(node.innerText()),node);
  9535. node.parentNode.removeChild(node)
  9536. }
  9537. }
  9538. }
  9539. // if(node.type == 'comment'){
  9540. // node.parentNode.removeChild(node);
  9541. // }
  9542. })
  9543. });
  9544. //从编辑器出去的内容处理
  9545. me.addOutputRule(function (root) {
  9546. var val;
  9547. root.traversal(function (node) {
  9548. if (node.type == 'element') {
  9549. if (me.options.autoClearEmptyNode && dtd.$inline[node.tagName] && !dtd.$empty[node.tagName] && (!node.attrs || utils.isEmptyObject(node.attrs))) {
  9550. if (!node.firstChild()) node.parentNode.removeChild(node);
  9551. else if (node.tagName == 'span' && (!node.attrs || utils.isEmptyObject(node.attrs))) {
  9552. node.parentNode.removeChild(node, true)
  9553. }
  9554. return;
  9555. }
  9556. switch (node.tagName) {
  9557. case 'div':
  9558. if (val = node.getAttr('cdata_tag')) {
  9559. node.tagName = val;
  9560. node.appendChild(UE.uNode.createText(node.getAttr('cdata_data')));
  9561. node.setAttr({cdata_tag: '', cdata_data: '','_ue_custom_node_':''});
  9562. }
  9563. break;
  9564. case 'a':
  9565. if (val = node.getAttr('_href')) {
  9566. node.setAttr({
  9567. 'href': utils.html(val),
  9568. '_href': ''
  9569. })
  9570. }
  9571. break;
  9572. break;
  9573. case 'span':
  9574. val = node.getAttr('id');
  9575. if(val && /^_baidu_bookmark_/i.test(val)){
  9576. node.parentNode.removeChild(node)
  9577. }
  9578. break;
  9579. case 'img':
  9580. if (val = node.getAttr('_src')) {
  9581. node.setAttr({
  9582. 'src': node.getAttr('_src'),
  9583. '_src': ''
  9584. })
  9585. }
  9586. }
  9587. }
  9588. })
  9589. });
  9590. };
  9591. // plugins/inserthtml.js
  9592. /**
  9593. * 插入html字符串插件
  9594. * @file
  9595. * @since 1.2.6.1
  9596. */
  9597. /**
  9598. * 插入html代码
  9599. * @command inserthtml
  9600. * @method execCommand
  9601. * @param { String } cmd 命令字符串
  9602. * @param { String } html 插入的html字符串
  9603. * @remaind 插入的标签内容是在当前的选区位置上插入,如果当前是闭合状态,那直接插入内容, 如果当前是选中状态,将先清除当前选中内容后,再做插入
  9604. * @warning 注意:该命令会对当前选区的位置,对插入的内容进行过滤转换处理。 过滤的规则遵循html语意化的原则。
  9605. * @example
  9606. * ```javascript
  9607. * //xxx[BB]xxx 当前选区为非闭合选区,选中BB这两个文本
  9608. * //执行命令,插入<b>CC</b>
  9609. * //插入后的效果 xxx<b>CC</b>xxx
  9610. * //<p>xx|xxx</p> 当前选区为闭合状态
  9611. * //插入<p>CC</p>
  9612. * //结果 <p>xx</p><p>CC</p><p>xxx</p>
  9613. * //<p>xxxx</p>|</p>xxx</p> 当前选区在两个p标签之间
  9614. * //插入 xxxx
  9615. * //结果 <p>xxxx</p><p>xxxx</p></p>xxx</p>
  9616. * ```
  9617. */
  9618. UE.commands['inserthtml'] = {
  9619. execCommand: function (command,html,notNeedFilter){
  9620. var me = this,
  9621. range,
  9622. div;
  9623. if(!html){
  9624. return;
  9625. }
  9626. if(me.fireEvent('beforeinserthtml',html) === true){
  9627. return;
  9628. }
  9629. range = me.selection.getRange();
  9630. div = range.document.createElement( 'div' );
  9631. div.style.display = 'inline';
  9632. if (!notNeedFilter) {
  9633. var root = UE.htmlparser(html);
  9634. //如果给了过滤规则就先进行过滤
  9635. if(me.options.filterRules){
  9636. UE.filterNode(root,me.options.filterRules);
  9637. }
  9638. //执行默认的处理
  9639. me.filterInputRule(root);
  9640. html = root.toHtml()
  9641. }
  9642. div.innerHTML = utils.trim( html );
  9643. if ( !range.collapsed ) {
  9644. var tmpNode = range.startContainer;
  9645. if(domUtils.isFillChar(tmpNode)){
  9646. range.setStartBefore(tmpNode)
  9647. }
  9648. tmpNode = range.endContainer;
  9649. if(domUtils.isFillChar(tmpNode)){
  9650. range.setEndAfter(tmpNode)
  9651. }
  9652. range.txtToElmBoundary();
  9653. //结束边界可能放到了br的前边,要把br包含进来
  9654. // x[xxx]<br/>
  9655. if(range.endContainer && range.endContainer.nodeType == 1){
  9656. tmpNode = range.endContainer.childNodes[range.endOffset];
  9657. if(tmpNode && domUtils.isBr(tmpNode)){
  9658. range.setEndAfter(tmpNode);
  9659. }
  9660. }
  9661. if(range.startOffset == 0){
  9662. tmpNode = range.startContainer;
  9663. if(domUtils.isBoundaryNode(tmpNode,'firstChild') ){
  9664. tmpNode = range.endContainer;
  9665. if(range.endOffset == (tmpNode.nodeType == 3 ? tmpNode.nodeValue.length : tmpNode.childNodes.length) && domUtils.isBoundaryNode(tmpNode,'lastChild')){
  9666. me.body.innerHTML = '<p>'+(browser.ie ? '' : '<br/>')+'</p>';
  9667. range.setStart(me.body.firstChild,0).collapse(true)
  9668. }
  9669. }
  9670. }
  9671. !range.collapsed && range.deleteContents();
  9672. if(range.startContainer.nodeType == 1){
  9673. var child = range.startContainer.childNodes[range.startOffset],pre;
  9674. if(child && domUtils.isBlockElm(child) && (pre = child.previousSibling) && domUtils.isBlockElm(pre)){
  9675. range.setEnd(pre,pre.childNodes.length).collapse();
  9676. while(child.firstChild){
  9677. pre.appendChild(child.firstChild);
  9678. }
  9679. domUtils.remove(child);
  9680. }
  9681. }
  9682. }
  9683. var child,parent,pre,tmp,hadBreak = 0, nextNode;
  9684. //如果当前位置选中了fillchar要干掉,要不会产生空行
  9685. if(range.inFillChar()){
  9686. child = range.startContainer;
  9687. if(domUtils.isFillChar(child)){
  9688. range.setStartBefore(child).collapse(true);
  9689. domUtils.remove(child);
  9690. }else if(domUtils.isFillChar(child,true)){
  9691. child.nodeValue = child.nodeValue.replace(fillCharReg,'');
  9692. range.startOffset--;
  9693. range.collapsed && range.collapse(true)
  9694. }
  9695. }
  9696. //列表单独处理
  9697. var li = domUtils.findParentByTagName(range.startContainer,'li',true);
  9698. if(li){
  9699. var next,last;
  9700. while(child = div.firstChild){
  9701. //针对hr单独处理一下先
  9702. while(child && (child.nodeType == 3 || !domUtils.isBlockElm(child) || child.tagName=='HR' )){
  9703. next = child.nextSibling;
  9704. range.insertNode( child).collapse();
  9705. last = child;
  9706. child = next;
  9707. }
  9708. if(child){
  9709. if(/^(ol|ul)$/i.test(child.tagName)){
  9710. while(child.firstChild){
  9711. last = child.firstChild;
  9712. domUtils.insertAfter(li,child.firstChild);
  9713. li = li.nextSibling;
  9714. }
  9715. domUtils.remove(child)
  9716. }else{
  9717. var tmpLi;
  9718. next = child.nextSibling;
  9719. tmpLi = me.document.createElement('li');
  9720. domUtils.insertAfter(li,tmpLi);
  9721. tmpLi.appendChild(child);
  9722. last = child;
  9723. child = next;
  9724. li = tmpLi;
  9725. }
  9726. }
  9727. }
  9728. li = domUtils.findParentByTagName(range.startContainer,'li',true);
  9729. if(domUtils.isEmptyBlock(li)){
  9730. domUtils.remove(li)
  9731. }
  9732. if(last){
  9733. range.setStartAfter(last).collapse(true).select(true)
  9734. }
  9735. }else{
  9736. while ( child = div.firstChild ) {
  9737. if(hadBreak){
  9738. var p = me.document.createElement('p');
  9739. while(child && (child.nodeType == 3 || !dtd.$block[child.tagName])){
  9740. nextNode = child.nextSibling;
  9741. p.appendChild(child);
  9742. child = nextNode;
  9743. }
  9744. if(p.firstChild){
  9745. child = p
  9746. }
  9747. }
  9748. range.insertNode( child );
  9749. nextNode = child.nextSibling;
  9750. if ( !hadBreak && child.nodeType == domUtils.NODE_ELEMENT && domUtils.isBlockElm( child ) ){
  9751. parent = domUtils.findParent( child,function ( node ){ return domUtils.isBlockElm( node ); } );
  9752. if ( parent && parent.tagName.toLowerCase() != 'body' && !(dtd[parent.tagName][child.nodeName] && child.parentNode === parent)){
  9753. if(!dtd[parent.tagName][child.nodeName]){
  9754. pre = parent;
  9755. }else{
  9756. tmp = child.parentNode;
  9757. while (tmp !== parent){
  9758. pre = tmp;
  9759. tmp = tmp.parentNode;
  9760. }
  9761. }
  9762. domUtils.breakParent( child, pre || tmp );
  9763. //去掉break后前一个多余的节点 <p>|<[p> ==> <p></p><div></div><p>|</p>
  9764. var pre = child.previousSibling;
  9765. domUtils.trimWhiteTextNode(pre);
  9766. if(!pre.childNodes.length){
  9767. domUtils.remove(pre);
  9768. }
  9769. //trace:2012,在非ie的情况,切开后剩下的节点有可能不能点入光标添加br占位
  9770. if(!browser.ie &&
  9771. (next = child.nextSibling) &&
  9772. domUtils.isBlockElm(next) &&
  9773. next.lastChild &&
  9774. !domUtils.isBr(next.lastChild)){
  9775. next.appendChild(me.document.createElement('br'));
  9776. }
  9777. hadBreak = 1;
  9778. }
  9779. }
  9780. var next = child.nextSibling;
  9781. if(!div.firstChild && next && domUtils.isBlockElm(next)){
  9782. range.setStart(next,0).collapse(true);
  9783. break;
  9784. }
  9785. range.setEndAfter( child ).collapse();
  9786. }
  9787. child = range.startContainer;
  9788. if(nextNode && domUtils.isBr(nextNode)){
  9789. domUtils.remove(nextNode)
  9790. }
  9791. //用chrome可能有空白展位符
  9792. if(domUtils.isBlockElm(child) && domUtils.isEmptyNode(child)){
  9793. if(nextNode = child.nextSibling){
  9794. domUtils.remove(child);
  9795. if(nextNode.nodeType == 1 && dtd.$block[nextNode.tagName]){
  9796. range.setStart(nextNode,0).collapse(true).shrinkBoundary()
  9797. }
  9798. }else{
  9799. try{
  9800. child.innerHTML = browser.ie ? domUtils.fillChar : '<br/>';
  9801. }catch(e){
  9802. range.setStartBefore(child);
  9803. domUtils.remove(child)
  9804. }
  9805. }
  9806. }
  9807. //加上true因为在删除表情等时会删两次,第一次是删的fillData
  9808. try{
  9809. range.select(true);
  9810. }catch(e){}
  9811. }
  9812. setTimeout(function(){
  9813. range = me.selection.getRange();
  9814. range.scrollToView(me.autoHeightEnabled,me.autoHeightEnabled ? domUtils.getXY(me.iframe).y:0);
  9815. me.fireEvent('afterinserthtml', html);
  9816. },200);
  9817. }
  9818. };
  9819. // plugins/autotypeset.js
  9820. /**
  9821. * 自动排版
  9822. * @file
  9823. * @since 1.2.6.1
  9824. */
  9825. /**
  9826. * 对当前编辑器的内容执行自动排版, 排版的行为根据config配置文件里的“autotypeset”选项进行控制。
  9827. * @command autotypeset
  9828. * @method execCommand
  9829. * @param { String } cmd 命令字符串
  9830. * @example
  9831. * ```javascript
  9832. * editor.execCommand( 'autotypeset' );
  9833. * ```
  9834. */
  9835. UE.plugins['autotypeset'] = function(){
  9836. this.setOpt({'autotypeset': {
  9837. mergeEmptyline: true, //合并空行
  9838. removeClass: true, //去掉冗余的class
  9839. removeEmptyline: false, //去掉空行
  9840. textAlign:"left", //段落的排版方式,可以是 left,right,center,justify 去掉这个属性表示不执行排版
  9841. imageBlockLine: 'center', //图片的浮动方式,独占一行剧中,左右浮动,默认: center,left,right,none 去掉这个属性表示不执行排版
  9842. pasteFilter: false, //根据规则过滤没事粘贴进来的内容
  9843. clearFontSize: false, //去掉所有的内嵌字号,使用编辑器默认的字号
  9844. clearFontFamily: false, //去掉所有的内嵌字体,使用编辑器默认的字体
  9845. removeEmptyNode: false, // 去掉空节点
  9846. //可以去掉的标签
  9847. removeTagNames: utils.extend({div:1},dtd.$removeEmpty),
  9848. indent: false, // 行首缩进
  9849. indentValue : '2em', //行首缩进的大小
  9850. bdc2sb: false,
  9851. tobdc: false
  9852. }});
  9853. var me = this,
  9854. opt = me.options.autotypeset,
  9855. remainClass = {
  9856. 'selectTdClass':1,
  9857. 'pagebreak':1,
  9858. 'anchorclass':1
  9859. },
  9860. remainTag = {
  9861. 'li':1
  9862. },
  9863. tags = {
  9864. div:1,
  9865. p:1,
  9866. //trace:2183 这些也认为是行
  9867. blockquote:1,center:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,
  9868. span:1
  9869. },
  9870. highlightCont;
  9871. //升级了版本,但配置项目里没有autotypeset
  9872. if(!opt){
  9873. return;
  9874. }
  9875. readLocalOpts();
  9876. function isLine(node,notEmpty){
  9877. if(!node || node.nodeType == 3)
  9878. return 0;
  9879. if(domUtils.isBr(node))
  9880. return 1;
  9881. if(node && node.parentNode && tags[node.tagName.toLowerCase()]){
  9882. if(highlightCont && highlightCont.contains(node)
  9883. ||
  9884. node.getAttribute('pagebreak')
  9885. ){
  9886. return 0;
  9887. }
  9888. return notEmpty ? !domUtils.isEmptyBlock(node) : domUtils.isEmptyBlock(node,new RegExp('[\\s'+domUtils.fillChar
  9889. +']','g'));
  9890. }
  9891. }
  9892. function removeNotAttributeSpan(node){
  9893. if(!node.style.cssText){
  9894. domUtils.removeAttributes(node,['style']);
  9895. if(node.tagName.toLowerCase() == 'span' && domUtils.hasNoAttributes(node)){
  9896. domUtils.remove(node,true);
  9897. }
  9898. }
  9899. }
  9900. function autotype(type,html){
  9901. var me = this,cont;
  9902. if(html){
  9903. if(!opt.pasteFilter){
  9904. return;
  9905. }
  9906. cont = me.document.createElement('div');
  9907. cont.innerHTML = html.html;
  9908. }else{
  9909. cont = me.document.body;
  9910. }
  9911. var nodes = domUtils.getElementsByTagName(cont,'*');
  9912. // 行首缩进,段落方向,段间距,段内间距
  9913. for(var i=0,ci;ci=nodes[i++];){
  9914. if(me.fireEvent('excludeNodeinautotype',ci) === true){
  9915. continue;
  9916. }
  9917. //font-size
  9918. if(opt.clearFontSize && ci.style.fontSize){
  9919. domUtils.removeStyle(ci,'font-size');
  9920. removeNotAttributeSpan(ci);
  9921. }
  9922. //font-family
  9923. if(opt.clearFontFamily && ci.style.fontFamily){
  9924. domUtils.removeStyle(ci,'font-family');
  9925. removeNotAttributeSpan(ci);
  9926. }
  9927. if(isLine(ci)){
  9928. //合并空行
  9929. if(opt.mergeEmptyline ){
  9930. var next = ci.nextSibling,tmpNode,isBr = domUtils.isBr(ci);
  9931. while(isLine(next)){
  9932. tmpNode = next;
  9933. next = tmpNode.nextSibling;
  9934. if(isBr && (!next || next && !domUtils.isBr(next))){
  9935. break;
  9936. }
  9937. domUtils.remove(tmpNode);
  9938. }
  9939. }
  9940. //去掉空行,保留占位的空行
  9941. if(opt.removeEmptyline && domUtils.inDoc(ci,cont) && !remainTag[ci.parentNode.tagName.toLowerCase()] ){
  9942. if(domUtils.isBr(ci)){
  9943. next = ci.nextSibling;
  9944. if(next && !domUtils.isBr(next)){
  9945. continue;
  9946. }
  9947. }
  9948. domUtils.remove(ci);
  9949. continue;
  9950. }
  9951. }
  9952. if(isLine(ci,true) && ci.tagName != 'SPAN'){
  9953. if(opt.indent){
  9954. ci.style.textIndent = opt.indentValue;
  9955. }
  9956. if(opt.textAlign){
  9957. ci.style.textAlign = opt.textAlign;
  9958. }
  9959. // if(opt.lineHeight)
  9960. // ci.style.lineHeight = opt.lineHeight + 'cm';
  9961. }
  9962. //去掉class,保留的class不去掉
  9963. if(opt.removeClass && ci.className && !remainClass[ci.className.toLowerCase()]){
  9964. if(highlightCont && highlightCont.contains(ci)){
  9965. continue;
  9966. }
  9967. domUtils.removeAttributes(ci,['class']);
  9968. }
  9969. //表情不处理
  9970. if(opt.imageBlockLine && ci.tagName.toLowerCase() == 'img' && !ci.getAttribute('emotion')){
  9971. if(html){
  9972. var img = ci;
  9973. switch (opt.imageBlockLine){
  9974. case 'left':
  9975. case 'right':
  9976. case 'none':
  9977. var pN = img.parentNode,tmpNode,pre,next;
  9978. while(dtd.$inline[pN.tagName] || pN.tagName == 'A'){
  9979. pN = pN.parentNode;
  9980. }
  9981. tmpNode = pN;
  9982. if(tmpNode.tagName == 'P' && domUtils.getStyle(tmpNode,'text-align') == 'center'){
  9983. if(!domUtils.isBody(tmpNode) && domUtils.getChildCount(tmpNode,function(node){return !domUtils.isBr(node) && !domUtils.isWhitespace(node)}) == 1){
  9984. pre = tmpNode.previousSibling;
  9985. next = tmpNode.nextSibling;
  9986. if(pre && next && pre.nodeType == 1 && next.nodeType == 1 && pre.tagName == next.tagName && domUtils.isBlockElm(pre)){
  9987. pre.appendChild(tmpNode.firstChild);
  9988. while(next.firstChild){
  9989. pre.appendChild(next.firstChild);
  9990. }
  9991. domUtils.remove(tmpNode);
  9992. domUtils.remove(next);
  9993. }else{
  9994. domUtils.setStyle(tmpNode,'text-align','');
  9995. }
  9996. }
  9997. }
  9998. domUtils.setStyle(img,'float', opt.imageBlockLine);
  9999. break;
  10000. case 'center':
  10001. if(me.queryCommandValue('imagefloat') != 'center'){
  10002. pN = img.parentNode;
  10003. domUtils.setStyle(img,'float','none');
  10004. tmpNode = img;
  10005. while(pN && domUtils.getChildCount(pN,function(node){return !domUtils.isBr(node) && !domUtils.isWhitespace(node)}) == 1
  10006. && (dtd.$inline[pN.tagName] || pN.tagName == 'A')){
  10007. tmpNode = pN;
  10008. pN = pN.parentNode;
  10009. }
  10010. var pNode = me.document.createElement('p');
  10011. domUtils.setAttributes(pNode,{
  10012. style:'text-align:center'
  10013. });
  10014. tmpNode.parentNode.insertBefore(pNode,tmpNode);
  10015. pNode.appendChild(tmpNode);
  10016. domUtils.setStyle(tmpNode,'float','');
  10017. }
  10018. }
  10019. } else {
  10020. var range = me.selection.getRange();
  10021. range.selectNode(ci).select();
  10022. me.execCommand('imagefloat', opt.imageBlockLine);
  10023. }
  10024. }
  10025. //去掉冗余的标签
  10026. if(opt.removeEmptyNode){
  10027. if(opt.removeTagNames[ci.tagName.toLowerCase()] && domUtils.hasNoAttributes(ci) && domUtils.isEmptyBlock(ci)){
  10028. domUtils.remove(ci);
  10029. }
  10030. }
  10031. }
  10032. if(opt.tobdc){
  10033. var root = UE.htmlparser(cont.innerHTML);
  10034. root.traversal(function(node){
  10035. if(node.type == 'text'){
  10036. node.data = ToDBC(node.data)
  10037. }
  10038. });
  10039. cont.innerHTML = root.toHtml()
  10040. }
  10041. if(opt.bdc2sb){
  10042. var root = UE.htmlparser(cont.innerHTML);
  10043. root.traversal(function(node){
  10044. if(node.type == 'text'){
  10045. node.data = DBC2SB(node.data)
  10046. }
  10047. });
  10048. cont.innerHTML = root.toHtml()
  10049. }
  10050. if(html){
  10051. html.html = cont.innerHTML;
  10052. }
  10053. }
  10054. if(opt.pasteFilter){
  10055. me.addListener('beforepaste',autotype);
  10056. }
  10057. function DBC2SB(str) {
  10058. var result = '';
  10059. for (var i = 0; i < str.length; i++) {
  10060. var code = str.charCodeAt(i); //获取当前字符的unicode编码
  10061. if (code >= 65281 && code <= 65373)//在这个unicode编码范围中的是所有的英文字母已经各种字符
  10062. {
  10063. result += String.fromCharCode(str.charCodeAt(i) - 65248); //把全角字符的unicode编码转换为对应半角字符的unicode码
  10064. } else if (code == 12288)//空格
  10065. {
  10066. result += String.fromCharCode(str.charCodeAt(i) - 12288 + 32);
  10067. } else {
  10068. result += str.charAt(i);
  10069. }
  10070. }
  10071. return result;
  10072. }
  10073. function ToDBC(txtstring) {
  10074. txtstring = utils.html(txtstring);
  10075. var tmp = "";
  10076. var mark = "";/*用于判断,如果是html尖括里的标记,则不进行全角的转换*/
  10077. for (var i = 0; i < txtstring.length; i++) {
  10078. if (txtstring.charCodeAt(i) == 32) {
  10079. tmp = tmp + String.fromCharCode(12288);
  10080. }
  10081. else if (txtstring.charCodeAt(i) < 127) {
  10082. tmp = tmp + String.fromCharCode(txtstring.charCodeAt(i) + 65248);
  10083. }
  10084. else {
  10085. tmp += txtstring.charAt(i);
  10086. }
  10087. }
  10088. return tmp;
  10089. }
  10090. function readLocalOpts() {
  10091. var cookieOpt = me.getPreferences('autotypeset');
  10092. utils.extend(me.options.autotypeset, cookieOpt);
  10093. }
  10094. me.commands['autotypeset'] = {
  10095. execCommand:function () {
  10096. me.removeListener('beforepaste',autotype);
  10097. if(opt.pasteFilter){
  10098. me.addListener('beforepaste',autotype);
  10099. }
  10100. autotype.call(me)
  10101. }
  10102. };
  10103. };
  10104. // plugins/autosubmit.js
  10105. /**
  10106. * 快捷键提交
  10107. * @file
  10108. * @since 1.2.6.1
  10109. */
  10110. /**
  10111. * 提交表单
  10112. * @command autosubmit
  10113. * @method execCommand
  10114. * @param { String } cmd 命令字符串
  10115. * @example
  10116. * ```javascript
  10117. * editor.execCommand( 'autosubmit' );
  10118. * ```
  10119. */
  10120. UE.plugin.register('autosubmit',function(){
  10121. return {
  10122. shortcutkey:{
  10123. "autosubmit":"ctrl+13" //手动提交
  10124. },
  10125. commands:{
  10126. 'autosubmit':{
  10127. execCommand:function () {
  10128. var me=this,
  10129. form = domUtils.findParentByTagName(me.iframe,"form", false);
  10130. if (form){
  10131. if(me.fireEvent("beforesubmit")===false){
  10132. return;
  10133. }
  10134. me.sync();
  10135. form.submit();
  10136. }
  10137. }
  10138. }
  10139. }
  10140. }
  10141. });
  10142. // plugins/background.js
  10143. /**
  10144. * 背景插件,为UEditor提供设置背景功能
  10145. * @file
  10146. * @since 1.2.6.1
  10147. */
  10148. UE.plugin.register('background', function () {
  10149. var me = this,
  10150. cssRuleId = 'editor_background',
  10151. isSetColored,
  10152. reg = new RegExp('body[\\s]*\\{(.+)\\}', 'i');
  10153. function stringToObj(str) {
  10154. var obj = {}, styles = str.split(';');
  10155. utils.each(styles, function (v) {
  10156. var index = v.indexOf(':'),
  10157. key = utils.trim(v.substr(0, index)).toLowerCase();
  10158. key && (obj[key] = utils.trim(v.substr(index + 1) || ''));
  10159. });
  10160. return obj;
  10161. }
  10162. function setBackground(obj) {
  10163. if (obj) {
  10164. var styles = [];
  10165. for (var name in obj) {
  10166. if (obj.hasOwnProperty(name)) {
  10167. styles.push(name + ":" + obj[name] + '; ');
  10168. }
  10169. }
  10170. utils.cssRule(cssRuleId, styles.length ? ('body{' + styles.join("") + '}') : '', me.document);
  10171. } else {
  10172. utils.cssRule(cssRuleId, '', me.document)
  10173. }
  10174. }
  10175. //重写editor.hasContent方法
  10176. var orgFn = me.hasContents;
  10177. me.hasContents = function(){
  10178. if(me.queryCommandValue('background')){
  10179. return true
  10180. }
  10181. return orgFn.apply(me,arguments);
  10182. };
  10183. return {
  10184. bindEvents: {
  10185. 'getAllHtml': function (type, headHtml) {
  10186. var body = this.body,
  10187. su = domUtils.getComputedStyle(body, "background-image"),
  10188. url = "";
  10189. if (su.indexOf(me.options.imagePath) > 0) {
  10190. url = su.substring(su.indexOf(me.options.imagePath), su.length - 1).replace(/"|\(|\)/ig, "");
  10191. } else {
  10192. url = su != "none" ? su.replace(/url\("?|"?\)/ig, "") : "";
  10193. }
  10194. var html = '<style type="text/css">body{';
  10195. var bgObj = {
  10196. "background-color": domUtils.getComputedStyle(body, "background-color") || "#ffffff",
  10197. 'background-image': url ? 'url(' + url + ')' : '',
  10198. 'background-repeat': domUtils.getComputedStyle(body, "background-repeat") || "",
  10199. 'background-position': browser.ie ? (domUtils.getComputedStyle(body, "background-position-x") + " " + domUtils.getComputedStyle(body, "background-position-y")) : domUtils.getComputedStyle(body, "background-position"),
  10200. 'height': domUtils.getComputedStyle(body, "height")
  10201. };
  10202. for (var name in bgObj) {
  10203. if (bgObj.hasOwnProperty(name)) {
  10204. html += name + ":" + bgObj[name] + "; ";
  10205. }
  10206. }
  10207. html += '}</style> ';
  10208. headHtml.push(html);
  10209. },
  10210. 'aftersetcontent': function () {
  10211. if(isSetColored == false) setBackground();
  10212. }
  10213. },
  10214. inputRule: function (root) {
  10215. isSetColored = false;
  10216. utils.each(root.getNodesByTagName('p'), function (p) {
  10217. var styles = p.getAttr('data-background');
  10218. if (styles) {
  10219. isSetColored = true;
  10220. setBackground(stringToObj(styles));
  10221. p.parentNode.removeChild(p);
  10222. }
  10223. })
  10224. },
  10225. outputRule: function (root) {
  10226. var me = this,
  10227. styles = (utils.cssRule(cssRuleId, me.document) || '').replace(/[\n\r]+/g, '').match(reg);
  10228. if (styles) {
  10229. root.appendChild(UE.uNode.createElement('<p style="display:none;" data-background="' + utils.trim(styles[1].replace(/"/g, '').replace(/[\s]+/g, ' ')) + '"><br/></p>'));
  10230. }
  10231. },
  10232. commands: {
  10233. 'background': {
  10234. execCommand: function (cmd, obj) {
  10235. setBackground(obj);
  10236. },
  10237. queryCommandValue: function () {
  10238. var me = this,
  10239. styles = (utils.cssRule(cssRuleId, me.document) || '').replace(/[\n\r]+/g, '').match(reg);
  10240. return styles ? stringToObj(styles[1]) : null;
  10241. },
  10242. notNeedUndo: true
  10243. }
  10244. }
  10245. }
  10246. });
  10247. // plugins/image.js
  10248. /**
  10249. * 图片插入、排版插件
  10250. * @file
  10251. * @since 1.2.6.1
  10252. */
  10253. /**
  10254. * 图片对齐方式
  10255. * @command imagefloat
  10256. * @method execCommand
  10257. * @remind 值center为独占一行居中
  10258. * @param { String } cmd 命令字符串
  10259. * @param { String } align 对齐方式,可传left、right、none、center
  10260. * @remaind center表示图片独占一行
  10261. * @example
  10262. * ```javascript
  10263. * editor.execCommand( 'imagefloat', 'center' );
  10264. * ```
  10265. */
  10266. /**
  10267. * 如果选区所在位置是图片区域
  10268. * @command imagefloat
  10269. * @method queryCommandValue
  10270. * @param { String } cmd 命令字符串
  10271. * @return { String } 返回图片对齐方式
  10272. * @example
  10273. * ```javascript
  10274. * editor.queryCommandValue( 'imagefloat' );
  10275. * ```
  10276. */
  10277. UE.commands['imagefloat'] = {
  10278. execCommand:function (cmd, align) {
  10279. var me = this,
  10280. range = me.selection.getRange();
  10281. if (!range.collapsed) {
  10282. var img = range.getClosedNode();
  10283. if (img && img.tagName == 'IMG') {
  10284. switch (align) {
  10285. case 'left':
  10286. case 'right':
  10287. case 'none':
  10288. var pN = img.parentNode, tmpNode, pre, next;
  10289. while (dtd.$inline[pN.tagName] || pN.tagName == 'A') {
  10290. pN = pN.parentNode;
  10291. }
  10292. tmpNode = pN;
  10293. if (tmpNode.tagName == 'P' && domUtils.getStyle(tmpNode, 'text-align') == 'center') {
  10294. if (!domUtils.isBody(tmpNode) && domUtils.getChildCount(tmpNode, function (node) {
  10295. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  10296. }) == 1) {
  10297. pre = tmpNode.previousSibling;
  10298. next = tmpNode.nextSibling;
  10299. if (pre && next && pre.nodeType == 1 && next.nodeType == 1 && pre.tagName == next.tagName && domUtils.isBlockElm(pre)) {
  10300. pre.appendChild(tmpNode.firstChild);
  10301. while (next.firstChild) {
  10302. pre.appendChild(next.firstChild);
  10303. }
  10304. domUtils.remove(tmpNode);
  10305. domUtils.remove(next);
  10306. } else {
  10307. domUtils.setStyle(tmpNode, 'text-align', '');
  10308. }
  10309. }
  10310. range.selectNode(img).select();
  10311. }
  10312. domUtils.setStyle(img, 'float', align == 'none' ? '' : align);
  10313. if(align == 'none'){
  10314. domUtils.removeAttributes(img,'align');
  10315. }
  10316. break;
  10317. case 'center':
  10318. if (me.queryCommandValue('imagefloat') != 'center') {
  10319. pN = img.parentNode;
  10320. domUtils.setStyle(img, 'float', '');
  10321. domUtils.removeAttributes(img,'align');
  10322. tmpNode = img;
  10323. while (pN && domUtils.getChildCount(pN, function (node) {
  10324. return !domUtils.isBr(node) && !domUtils.isWhitespace(node);
  10325. }) == 1
  10326. && (dtd.$inline[pN.tagName] || pN.tagName == 'A')) {
  10327. tmpNode = pN;
  10328. pN = pN.parentNode;
  10329. }
  10330. range.setStartBefore(tmpNode).setCursor(false);
  10331. pN = me.document.createElement('div');
  10332. pN.appendChild(tmpNode);
  10333. domUtils.setStyle(tmpNode, 'float', '');
  10334. me.execCommand('insertHtml', '<p id="_img_parent_tmp" style="text-align:center">' + pN.innerHTML + '</p>');
  10335. tmpNode = me.document.getElementById('_img_parent_tmp');
  10336. tmpNode.removeAttribute('id');
  10337. tmpNode = tmpNode.firstChild;
  10338. range.selectNode(tmpNode).select();
  10339. //去掉后边多余的元素
  10340. next = tmpNode.parentNode.nextSibling;
  10341. if (next && domUtils.isEmptyNode(next)) {
  10342. domUtils.remove(next);
  10343. }
  10344. }
  10345. break;
  10346. }
  10347. }
  10348. }
  10349. },
  10350. queryCommandValue:function () {
  10351. var range = this.selection.getRange(),
  10352. startNode, floatStyle;
  10353. if (range.collapsed) {
  10354. return 'none';
  10355. }
  10356. startNode = range.getClosedNode();
  10357. if (startNode && startNode.nodeType == 1 && startNode.tagName == 'IMG') {
  10358. floatStyle = domUtils.getComputedStyle(startNode, 'float') || startNode.getAttribute('align');
  10359. if (floatStyle == 'none') {
  10360. floatStyle = domUtils.getComputedStyle(startNode.parentNode, 'text-align') == 'center' ? 'center' : floatStyle;
  10361. }
  10362. return {
  10363. left:1,
  10364. right:1,
  10365. center:1
  10366. }[floatStyle] ? floatStyle : 'none';
  10367. }
  10368. return 'none';
  10369. },
  10370. queryCommandState:function () {
  10371. var range = this.selection.getRange(),
  10372. startNode;
  10373. if (range.collapsed) return -1;
  10374. startNode = range.getClosedNode();
  10375. if (startNode && startNode.nodeType == 1 && startNode.tagName == 'IMG') {
  10376. return 0;
  10377. }
  10378. return -1;
  10379. }
  10380. };
  10381. /**
  10382. * 插入图片
  10383. * @command insertimage
  10384. * @method execCommand
  10385. * @param { String } cmd 命令字符串
  10386. * @param { Object } opt 属性键值对,这些属性都将被复制到当前插入图片
  10387. * @remind 该命令第二个参数可接受一个图片配置项对象的数组,可以插入多张图片,
  10388. * 此时数组的每一个元素都是一个Object类型的图片属性集合。
  10389. * @example
  10390. * ```javascript
  10391. * editor.execCommand( 'insertimage', {
  10392. * src:'a/b/c.jpg',
  10393. * width:'100',
  10394. * height:'100'
  10395. * } );
  10396. * ```
  10397. * @example
  10398. * ```javascript
  10399. * editor.execCommand( 'insertimage', [{
  10400. * src:'a/b/c.jpg',
  10401. * width:'100',
  10402. * height:'100'
  10403. * },{
  10404. * src:'a/b/d.jpg',
  10405. * width:'100',
  10406. * height:'100'
  10407. * }] );
  10408. * ```
  10409. */
  10410. UE.commands['insertimage'] = {
  10411. execCommand:function (cmd, opt) {
  10412. opt = utils.isArray(opt) ? opt : [opt];
  10413. if (!opt.length) {
  10414. return;
  10415. }
  10416. var me = this,
  10417. range = me.selection.getRange(),
  10418. img = range.getClosedNode();
  10419. if(me.fireEvent('beforeinsertimage', opt) === true){
  10420. return;
  10421. }
  10422. function unhtmlData(imgCi) {
  10423. utils.each('width,height,border,hspace,vspace'.split(','), function (item) {
  10424. if (imgCi[item]) {
  10425. imgCi[item] = parseInt(imgCi[item], 10) || 0;
  10426. }
  10427. });
  10428. utils.each('src,_src'.split(','), function (item) {
  10429. if (imgCi[item]) {
  10430. imgCi[item] = utils.unhtmlForUrl(imgCi[item]);
  10431. }
  10432. });
  10433. utils.each('title,alt'.split(','), function (item) {
  10434. if (imgCi[item]) {
  10435. imgCi[item] = utils.unhtml(imgCi[item]);
  10436. }
  10437. });
  10438. }
  10439. if (img && /img/i.test(img.tagName) && (img.className != "edui-faked-video" || img.className.indexOf("edui-upload-video")!=-1) && !img.getAttribute("word_img")) {
  10440. var first = opt.shift();
  10441. var floatStyle = first['floatStyle'];
  10442. delete first['floatStyle'];
  10443. //// img.style.border = (first.border||0) +"px solid #000";
  10444. //// img.style.margin = (first.margin||0) +"px";
  10445. // img.style.cssText += ';margin:' + (first.margin||0) +"px;" + 'border:' + (first.border||0) +"px solid #000";
  10446. domUtils.setAttributes(img, first);
  10447. me.execCommand('imagefloat', floatStyle);
  10448. if (opt.length > 0) {
  10449. range.setStartAfter(img).setCursor(false, true);
  10450. me.execCommand('insertimage', opt);
  10451. }
  10452. } else {
  10453. var html = [], str = '', ci;
  10454. ci = opt[0];
  10455. if (opt.length == 1) {
  10456. unhtmlData(ci);
  10457. str = '<img src="' + ci.src + '" ' + (ci._src ? ' _src="' + ci._src + '" ' : '') +
  10458. (ci.width ? 'width="' + ci.width + '" ' : '') +
  10459. (ci.height ? ' height="' + ci.height + '" ' : '') +
  10460. (ci['floatStyle'] == 'left' || ci['floatStyle'] == 'right' ? ' style="float:' + ci['floatStyle'] + ';"' : '') +
  10461. (ci.title && ci.title != "" ? ' title="' + ci.title + '"' : '') +
  10462. (ci.border && ci.border != "0" ? ' border="' + ci.border + '"' : '') +
  10463. (ci.alt && ci.alt != "" ? ' alt="' + ci.alt + '"' : '') +
  10464. (ci.hspace && ci.hspace != "0" ? ' hspace = "' + ci.hspace + '"' : '') +
  10465. (ci.vspace && ci.vspace != "0" ? ' vspace = "' + ci.vspace + '"' : '') + '/>';
  10466. if (ci['floatStyle'] == 'center') {
  10467. str = '<p style="text-align: center">' + str + '</p>';
  10468. }
  10469. html.push(str);
  10470. } else {
  10471. for (var i = 0; ci = opt[i++];) {
  10472. unhtmlData(ci);
  10473. str = '<p ' + (ci['floatStyle'] == 'center' ? 'style="text-align: center" ' : '') + '><img src="' + ci.src + '" ' +
  10474. (ci.width ? 'width="' + ci.width + '" ' : '') + (ci._src ? ' _src="' + ci._src + '" ' : '') +
  10475. (ci.height ? ' height="' + ci.height + '" ' : '') +
  10476. ' style="' + (ci['floatStyle'] && ci['floatStyle'] != 'center' ? 'float:' + ci['floatStyle'] + ';' : '') +
  10477. (ci.border || '') + '" ' +
  10478. (ci.title ? ' title="' + ci.title + '"' : '') + ' /></p>';
  10479. html.push(str);
  10480. }
  10481. }
  10482. me.execCommand('insertHtml', html.join(''));
  10483. }
  10484. me.fireEvent('afterinsertimage', opt)
  10485. }
  10486. };
  10487. // plugins/justify.js
  10488. /**
  10489. * 段落格式
  10490. * @file
  10491. * @since 1.2.6.1
  10492. */
  10493. /**
  10494. * 段落对齐方式
  10495. * @command justify
  10496. * @method execCommand
  10497. * @param { String } cmd 命令字符串
  10498. * @param { String } align 对齐方式:left => 居左,right => 居右,center => 居中,justify => 两端对齐
  10499. * @example
  10500. * ```javascript
  10501. * editor.execCommand( 'justify', 'center' );
  10502. * ```
  10503. */
  10504. /**
  10505. * 如果选区所在位置是段落区域,返回当前段落对齐方式
  10506. * @command justify
  10507. * @method queryCommandValue
  10508. * @param { String } cmd 命令字符串
  10509. * @return { String } 返回段落对齐方式
  10510. * @example
  10511. * ```javascript
  10512. * editor.queryCommandValue( 'justify' );
  10513. * ```
  10514. */
  10515. UE.plugins['justify']=function(){
  10516. var me=this,
  10517. block = domUtils.isBlockElm,
  10518. defaultValue = {
  10519. left:1,
  10520. right:1,
  10521. center:1,
  10522. justify:1
  10523. },
  10524. doJustify = function (range, style) {
  10525. var bookmark = range.createBookmark(),
  10526. filterFn = function (node) {
  10527. return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' && !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node);
  10528. };
  10529. range.enlarge(true);
  10530. var bookmark2 = range.createBookmark(),
  10531. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
  10532. tmpRange = range.cloneRange(),
  10533. tmpNode;
  10534. while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) {
  10535. if (current.nodeType == 3 || !block(current)) {
  10536. tmpRange.setStartBefore(current);
  10537. while (current && current !== bookmark2.end && !block(current)) {
  10538. tmpNode = current;
  10539. current = domUtils.getNextDomNode(current, false, null, function (node) {
  10540. return !block(node);
  10541. });
  10542. }
  10543. tmpRange.setEndAfter(tmpNode);
  10544. var common = tmpRange.getCommonAncestor();
  10545. if (!domUtils.isBody(common) && block(common)) {
  10546. domUtils.setStyles(common, utils.isString(style) ? {'text-align':style} : style);
  10547. current = common;
  10548. } else {
  10549. var p = range.document.createElement('p');
  10550. domUtils.setStyles(p, utils.isString(style) ? {'text-align':style} : style);
  10551. var frag = tmpRange.extractContents();
  10552. p.appendChild(frag);
  10553. tmpRange.insertNode(p);
  10554. current = p;
  10555. }
  10556. current = domUtils.getNextDomNode(current, false, filterFn);
  10557. } else {
  10558. current = domUtils.getNextDomNode(current, true, filterFn);
  10559. }
  10560. }
  10561. return range.moveToBookmark(bookmark2).moveToBookmark(bookmark);
  10562. };
  10563. UE.commands['justify'] = {
  10564. execCommand:function (cmdName, align) {
  10565. var range = this.selection.getRange(),
  10566. txt;
  10567. //闭合时单独处理
  10568. if (range.collapsed) {
  10569. txt = this.document.createTextNode('p');
  10570. range.insertNode(txt);
  10571. }
  10572. doJustify(range, align);
  10573. if (txt) {
  10574. range.setStartBefore(txt).collapse(true);
  10575. domUtils.remove(txt);
  10576. }
  10577. range.select();
  10578. return true;
  10579. },
  10580. queryCommandValue:function () {
  10581. var startNode = this.selection.getStart(),
  10582. value = domUtils.getComputedStyle(startNode, 'text-align');
  10583. return defaultValue[value] ? value : 'left';
  10584. },
  10585. queryCommandState:function () {
  10586. var start = this.selection.getStart(),
  10587. cell = start && domUtils.findParentByTagName(start, ["td", "th","caption"], true);
  10588. return cell? -1:0;
  10589. }
  10590. };
  10591. };
  10592. // plugins/font.js
  10593. /**
  10594. * 字体颜色,背景色,字号,字体,下划线,删除线
  10595. * @file
  10596. * @since 1.2.6.1
  10597. */
  10598. /**
  10599. * 字体颜色
  10600. * @command forecolor
  10601. * @method execCommand
  10602. * @param { String } cmd 命令字符串
  10603. * @param { String } value 色值(必须十六进制)
  10604. * @example
  10605. * ```javascript
  10606. * editor.execCommand( 'forecolor', '#000' );
  10607. * ```
  10608. */
  10609. /**
  10610. * 返回选区字体颜色
  10611. * @command forecolor
  10612. * @method queryCommandValue
  10613. * @param { String } cmd 命令字符串
  10614. * @return { String } 返回字体颜色
  10615. * @example
  10616. * ```javascript
  10617. * editor.queryCommandValue( 'forecolor' );
  10618. * ```
  10619. */
  10620. /**
  10621. * 字体背景颜色
  10622. * @command backcolor
  10623. * @method execCommand
  10624. * @param { String } cmd 命令字符串
  10625. * @param { String } value 色值(必须十六进制)
  10626. * @example
  10627. * ```javascript
  10628. * editor.execCommand( 'backcolor', '#000' );
  10629. * ```
  10630. */
  10631. /**
  10632. * 返回选区字体颜色
  10633. * @command backcolor
  10634. * @method queryCommandValue
  10635. * @param { String } cmd 命令字符串
  10636. * @return { String } 返回字体背景颜色
  10637. * @example
  10638. * ```javascript
  10639. * editor.queryCommandValue( 'backcolor' );
  10640. * ```
  10641. */
  10642. /**
  10643. * 字体大小
  10644. * @command fontsize
  10645. * @method execCommand
  10646. * @param { String } cmd 命令字符串
  10647. * @param { String } value 字体大小
  10648. * @example
  10649. * ```javascript
  10650. * editor.execCommand( 'fontsize', '14px' );
  10651. * ```
  10652. */
  10653. /**
  10654. * 返回选区字体大小
  10655. * @command fontsize
  10656. * @method queryCommandValue
  10657. * @param { String } cmd 命令字符串
  10658. * @return { String } 返回字体大小
  10659. * @example
  10660. * ```javascript
  10661. * editor.queryCommandValue( 'fontsize' );
  10662. * ```
  10663. */
  10664. /**
  10665. * 字体样式
  10666. * @command fontfamily
  10667. * @method execCommand
  10668. * @param { String } cmd 命令字符串
  10669. * @param { String } value 字体样式
  10670. * @example
  10671. * ```javascript
  10672. * editor.execCommand( 'fontfamily', '微软雅黑' );
  10673. * ```
  10674. */
  10675. /**
  10676. * 返回选区字体样式
  10677. * @command fontfamily
  10678. * @method queryCommandValue
  10679. * @param { String } cmd 命令字符串
  10680. * @return { String } 返回字体样式
  10681. * @example
  10682. * ```javascript
  10683. * editor.queryCommandValue( 'fontfamily' );
  10684. * ```
  10685. */
  10686. /**
  10687. * 字体下划线,与删除线互斥
  10688. * @command underline
  10689. * @method execCommand
  10690. * @param { String } cmd 命令字符串
  10691. * @example
  10692. * ```javascript
  10693. * editor.execCommand( 'underline' );
  10694. * ```
  10695. */
  10696. /**
  10697. * 字体删除线,与下划线互斥
  10698. * @command strikethrough
  10699. * @method execCommand
  10700. * @param { String } cmd 命令字符串
  10701. * @example
  10702. * ```javascript
  10703. * editor.execCommand( 'strikethrough' );
  10704. * ```
  10705. */
  10706. /**
  10707. * 字体边框
  10708. * @command fontborder
  10709. * @method execCommand
  10710. * @param { String } cmd 命令字符串
  10711. * @example
  10712. * ```javascript
  10713. * editor.execCommand( 'fontborder' );
  10714. * ```
  10715. */
  10716. UE.plugins['font'] = function () {
  10717. var me = this,
  10718. fonts = {
  10719. 'forecolor': 'color',
  10720. 'backcolor': 'background-color',
  10721. 'fontsize': 'font-size',
  10722. 'fontfamily': 'font-family',
  10723. 'underline': 'text-decoration',
  10724. 'strikethrough': 'text-decoration',
  10725. 'fontborder': 'border'
  10726. },
  10727. needCmd = {'underline': 1, 'strikethrough': 1, 'fontborder': 1},
  10728. needSetChild = {
  10729. 'forecolor': 'color',
  10730. 'backcolor': 'background-color',
  10731. 'fontsize': 'font-size',
  10732. 'fontfamily': 'font-family'
  10733. };
  10734. me.setOpt({
  10735. 'fontfamily': [
  10736. { name: 'songti', val: '宋体,SimSun'},
  10737. { name: 'yahei', val: '微软雅黑,Microsoft YaHei'},
  10738. { name: 'kaiti', val: '楷体,楷体_GB2312, SimKai'},
  10739. { name: 'heiti', val: '黑体, SimHei'},
  10740. { name: 'lishu', val: '隶书, SimLi'},
  10741. { name: 'andaleMono', val: 'andale mono'},
  10742. { name: 'arial', val: 'arial, helvetica,sans-serif'},
  10743. { name: 'arialBlack', val: 'arial black,avant garde'},
  10744. { name: 'comicSansMs', val: 'comic sans ms'},
  10745. { name: 'impact', val: 'impact,chicago'},
  10746. { name: 'timesNewRoman', val: 'times new roman'}
  10747. ],
  10748. 'fontsize': [10, 11, 12, 14, 16, 18, 20, 24, 36]
  10749. });
  10750. function mergeWithParent(node){
  10751. var parent;
  10752. while(parent = node.parentNode){
  10753. if(parent.tagName == 'SPAN' && domUtils.getChildCount(parent,function(child){
  10754. return !domUtils.isBookmarkNode(child) && !domUtils.isBr(child)
  10755. }) == 1) {
  10756. parent.style.cssText += node.style.cssText;
  10757. domUtils.remove(node,true);
  10758. node = parent;
  10759. }else{
  10760. break;
  10761. }
  10762. }
  10763. }
  10764. function mergeChild(rng,cmdName,value){
  10765. if(needSetChild[cmdName]){
  10766. rng.adjustmentBoundary();
  10767. if(!rng.collapsed && rng.startContainer.nodeType == 1){
  10768. var start = rng.startContainer.childNodes[rng.startOffset];
  10769. if(start && domUtils.isTagNode(start,'span')){
  10770. var bk = rng.createBookmark();
  10771. utils.each(domUtils.getElementsByTagName(start, 'span'), function (span) {
  10772. if (!span.parentNode || domUtils.isBookmarkNode(span))return;
  10773. if(cmdName == 'backcolor' && domUtils.getComputedStyle(span,'background-color').toLowerCase() === value){
  10774. return;
  10775. }
  10776. domUtils.removeStyle(span,needSetChild[cmdName]);
  10777. if(span.style.cssText.replace(/^\s+$/,'').length == 0){
  10778. domUtils.remove(span,true)
  10779. }
  10780. });
  10781. rng.moveToBookmark(bk)
  10782. }
  10783. }
  10784. }
  10785. }
  10786. function mergesibling(rng,cmdName,value) {
  10787. var collapsed = rng.collapsed,
  10788. bk = rng.createBookmark(), common;
  10789. if (collapsed) {
  10790. common = bk.start.parentNode;
  10791. while (dtd.$inline[common.tagName]) {
  10792. common = common.parentNode;
  10793. }
  10794. } else {
  10795. common = domUtils.getCommonAncestor(bk.start, bk.end);
  10796. }
  10797. utils.each(domUtils.getElementsByTagName(common, 'span'), function (span) {
  10798. if (!span.parentNode || domUtils.isBookmarkNode(span))return;
  10799. if (/\s*border\s*:\s*none;?\s*/i.test(span.style.cssText)) {
  10800. if(/^\s*border\s*:\s*none;?\s*$/.test(span.style.cssText)){
  10801. domUtils.remove(span, true);
  10802. }else{
  10803. domUtils.removeStyle(span,'border');
  10804. }
  10805. return
  10806. }
  10807. if (/border/i.test(span.style.cssText) && span.parentNode.tagName == 'SPAN' && /border/i.test(span.parentNode.style.cssText)) {
  10808. span.style.cssText = span.style.cssText.replace(/border[^:]*:[^;]+;?/gi, '');
  10809. }
  10810. if(!(cmdName=='fontborder' && value=='none')){
  10811. var next = span.nextSibling;
  10812. while (next && next.nodeType == 1 && next.tagName == 'SPAN' ) {
  10813. if(domUtils.isBookmarkNode(next) && cmdName == 'fontborder') {
  10814. span.appendChild(next);
  10815. next = span.nextSibling;
  10816. continue;
  10817. }
  10818. if (next.style.cssText == span.style.cssText) {
  10819. domUtils.moveChild(next, span);
  10820. domUtils.remove(next);
  10821. }
  10822. if (span.nextSibling === next)
  10823. break;
  10824. next = span.nextSibling;
  10825. }
  10826. }
  10827. mergeWithParent(span);
  10828. if(browser.ie && browser.version > 8 ){
  10829. //拷贝父亲们的特别的属性,这里只做背景颜色的处理
  10830. var parent = domUtils.findParent(span,function(n){return n.tagName == 'SPAN' && /background-color/.test(n.style.cssText)});
  10831. if(parent && !/background-color/.test(span.style.cssText)){
  10832. span.style.backgroundColor = parent.style.backgroundColor;
  10833. }
  10834. }
  10835. });
  10836. rng.moveToBookmark(bk);
  10837. mergeChild(rng,cmdName,value)
  10838. }
  10839. me.addInputRule(function (root) {
  10840. utils.each(root.getNodesByTagName('u s del font strike'), function (node) {
  10841. if (node.tagName == 'font') {
  10842. var cssStyle = [];
  10843. for (var p in node.attrs) {
  10844. switch (p) {
  10845. case 'size':
  10846. cssStyle.push('font-size:' +
  10847. ({
  10848. '1':'10',
  10849. '2':'12',
  10850. '3':'16',
  10851. '4':'18',
  10852. '5':'24',
  10853. '6':'32',
  10854. '7':'48'
  10855. }[node.attrs[p]] || node.attrs[p]) + 'px');
  10856. break;
  10857. case 'color':
  10858. cssStyle.push('color:' + node.attrs[p]);
  10859. break;
  10860. case 'face':
  10861. cssStyle.push('font-family:' + node.attrs[p]);
  10862. break;
  10863. case 'style':
  10864. cssStyle.push(node.attrs[p]);
  10865. }
  10866. }
  10867. node.attrs = {
  10868. 'style': cssStyle.join(';')
  10869. };
  10870. } else {
  10871. var val = node.tagName == 'u' ? 'underline' : 'line-through';
  10872. node.attrs = {
  10873. 'style': (node.getAttr('style') || '') + 'text-decoration:' + val + ';'
  10874. }
  10875. }
  10876. node.tagName = 'span';
  10877. });
  10878. // utils.each(root.getNodesByTagName('span'), function (node) {
  10879. // var val;
  10880. // if(val = node.getAttr('class')){
  10881. // if(/fontstrikethrough/.test(val)){
  10882. // node.setStyle('text-decoration','line-through');
  10883. // if(node.attrs['class']){
  10884. // node.attrs['class'] = node.attrs['class'].replace(/fontstrikethrough/,'');
  10885. // }else{
  10886. // node.setAttr('class')
  10887. // }
  10888. // }
  10889. // if(/fontborder/.test(val)){
  10890. // node.setStyle('border','1px solid #000');
  10891. // if(node.attrs['class']){
  10892. // node.attrs['class'] = node.attrs['class'].replace(/fontborder/,'');
  10893. // }else{
  10894. // node.setAttr('class')
  10895. // }
  10896. // }
  10897. // }
  10898. // });
  10899. });
  10900. // me.addOutputRule(function(root){
  10901. // utils.each(root.getNodesByTagName('span'), function (node) {
  10902. // var val;
  10903. // if(val = node.getStyle('text-decoration')){
  10904. // if(/line-through/.test(val)){
  10905. // if(node.attrs['class']){
  10906. // node.attrs['class'] += ' fontstrikethrough';
  10907. // }else{
  10908. // node.setAttr('class','fontstrikethrough')
  10909. // }
  10910. // }
  10911. //
  10912. // node.setStyle('text-decoration')
  10913. // }
  10914. // if(val = node.getStyle('border')){
  10915. // if(/1px/.test(val) && /solid/.test(val)){
  10916. // if(node.attrs['class']){
  10917. // node.attrs['class'] += ' fontborder';
  10918. //
  10919. // }else{
  10920. // node.setAttr('class','fontborder')
  10921. // }
  10922. // }
  10923. // node.setStyle('border')
  10924. //
  10925. // }
  10926. // });
  10927. // });
  10928. for (var p in fonts) {
  10929. (function (cmd, style) {
  10930. UE.commands[cmd] = {
  10931. execCommand: function (cmdName, value) {
  10932. value = value || (this.queryCommandState(cmdName) ? 'none' : cmdName == 'underline' ? 'underline' :
  10933. cmdName == 'fontborder' ? '1px solid #000' :
  10934. 'line-through');
  10935. var me = this,
  10936. range = this.selection.getRange(),
  10937. text;
  10938. if (value == 'default') {
  10939. if (range.collapsed) {
  10940. text = me.document.createTextNode('font');
  10941. range.insertNode(text).select();
  10942. }
  10943. me.execCommand('removeFormat', 'span,a', style);
  10944. if (text) {
  10945. range.setStartBefore(text).collapse(true);
  10946. domUtils.remove(text);
  10947. }
  10948. mergesibling(range,cmdName,value);
  10949. range.select()
  10950. } else {
  10951. if (!range.collapsed) {
  10952. if (needCmd[cmd] && me.queryCommandValue(cmd)) {
  10953. me.execCommand('removeFormat', 'span,a', style);
  10954. }
  10955. range = me.selection.getRange();
  10956. range.applyInlineStyle('span', {'style': style + ':' + value});
  10957. mergesibling(range, cmdName,value);
  10958. range.select();
  10959. } else {
  10960. var span = domUtils.findParentByTagName(range.startContainer, 'span', true);
  10961. text = me.document.createTextNode('font');
  10962. if (span && !span.children.length && !span[browser.ie ? 'innerText' : 'textContent'].replace(fillCharReg, '').length) {
  10963. //for ie hack when enter
  10964. range.insertNode(text);
  10965. if (needCmd[cmd]) {
  10966. range.selectNode(text).select();
  10967. me.execCommand('removeFormat', 'span,a', style, null);
  10968. span = domUtils.findParentByTagName(text, 'span', true);
  10969. range.setStartBefore(text);
  10970. }
  10971. span && (span.style.cssText += ';' + style + ':' + value);
  10972. range.collapse(true).select();
  10973. } else {
  10974. range.insertNode(text);
  10975. range.selectNode(text).select();
  10976. span = range.document.createElement('span');
  10977. if (needCmd[cmd]) {
  10978. //a标签内的不处理跳过
  10979. if (domUtils.findParentByTagName(text, 'a', true)) {
  10980. range.setStartBefore(text).setCursor();
  10981. domUtils.remove(text);
  10982. return;
  10983. }
  10984. me.execCommand('removeFormat', 'span,a', style);
  10985. }
  10986. span.style.cssText = style + ':' + value;
  10987. text.parentNode.insertBefore(span, text);
  10988. //修复,span套span 但样式不继承的问题
  10989. if (!browser.ie || browser.ie && browser.version == 9) {
  10990. var spanParent = span.parentNode;
  10991. while (!domUtils.isBlockElm(spanParent)) {
  10992. if (spanParent.tagName == 'SPAN') {
  10993. //opera合并style不会加入";"
  10994. span.style.cssText = spanParent.style.cssText + ";" + span.style.cssText;
  10995. }
  10996. spanParent = spanParent.parentNode;
  10997. }
  10998. }
  10999. if (opera) {
  11000. setTimeout(function () {
  11001. range.setStart(span, 0).collapse(true);
  11002. mergesibling(range, cmdName,value);
  11003. range.select();
  11004. });
  11005. } else {
  11006. range.setStart(span, 0).collapse(true);
  11007. mergesibling(range,cmdName,value);
  11008. range.select();
  11009. }
  11010. //trace:981
  11011. //domUtils.mergeToParent(span)
  11012. }
  11013. domUtils.remove(text);
  11014. }
  11015. }
  11016. return true;
  11017. },
  11018. queryCommandValue: function (cmdName) {
  11019. var startNode = this.selection.getStart();
  11020. //trace:946
  11021. if (cmdName == 'underline' || cmdName == 'strikethrough') {
  11022. var tmpNode = startNode, value;
  11023. while (tmpNode && !domUtils.isBlockElm(tmpNode) && !domUtils.isBody(tmpNode)) {
  11024. if (tmpNode.nodeType == 1) {
  11025. value = domUtils.getComputedStyle(tmpNode, style);
  11026. if (value != 'none') {
  11027. return value;
  11028. }
  11029. }
  11030. tmpNode = tmpNode.parentNode;
  11031. }
  11032. return 'none';
  11033. }
  11034. if (cmdName == 'fontborder') {
  11035. var tmp = startNode, val;
  11036. while (tmp && dtd.$inline[tmp.tagName]) {
  11037. if (val = domUtils.getComputedStyle(tmp, 'border')) {
  11038. if (/1px/.test(val) && /solid/.test(val)) {
  11039. return val;
  11040. }
  11041. }
  11042. tmp = tmp.parentNode;
  11043. }
  11044. return ''
  11045. }
  11046. if( cmdName == 'FontSize' ) {
  11047. var styleVal = domUtils.getComputedStyle(startNode, style),
  11048. tmp = /^([\d\.]+)(\w+)$/.exec( styleVal );
  11049. if( tmp ) {
  11050. return Math.floor( tmp[1] ) + tmp[2];
  11051. }
  11052. return styleVal;
  11053. }
  11054. return domUtils.getComputedStyle(startNode, style);
  11055. },
  11056. queryCommandState: function (cmdName) {
  11057. if (!needCmd[cmdName])
  11058. return 0;
  11059. var val = this.queryCommandValue(cmdName);
  11060. if (cmdName == 'fontborder') {
  11061. return /1px/.test(val) && /solid/.test(val)
  11062. } else {
  11063. return cmdName == 'underline' ? /underline/.test(val) : /line\-through/.test(val);
  11064. }
  11065. }
  11066. };
  11067. })(p, fonts[p]);
  11068. }
  11069. };
  11070. // plugins/link.js
  11071. /**
  11072. * 超链接
  11073. * @file
  11074. * @since 1.2.6.1
  11075. */
  11076. /**
  11077. * 插入超链接
  11078. * @command link
  11079. * @method execCommand
  11080. * @param { String } cmd 命令字符串
  11081. * @param { Object } options 设置自定义属性,例如:url、title、target
  11082. * @example
  11083. * ```javascript
  11084. * editor.execCommand( 'link', '{
  11085. * url:'ueditor.baidu.com',
  11086. * title:'ueditor',
  11087. * target:'_blank'
  11088. * }' );
  11089. * ```
  11090. */
  11091. /**
  11092. * 返回当前选中的第一个超链接节点
  11093. * @command link
  11094. * @method queryCommandValue
  11095. * @param { String } cmd 命令字符串
  11096. * @return { Element } 超链接节点
  11097. * @example
  11098. * ```javascript
  11099. * editor.queryCommandValue( 'link' );
  11100. * ```
  11101. */
  11102. /**
  11103. * 取消超链接
  11104. * @command unlink
  11105. * @method execCommand
  11106. * @param { String } cmd 命令字符串
  11107. * @example
  11108. * ```javascript
  11109. * editor.execCommand( 'unlink');
  11110. * ```
  11111. */
  11112. UE.plugins['link'] = function(){
  11113. function optimize( range ) {
  11114. var start = range.startContainer,end = range.endContainer;
  11115. if ( start = domUtils.findParentByTagName( start, 'a', true ) ) {
  11116. range.setStartBefore( start );
  11117. }
  11118. if ( end = domUtils.findParentByTagName( end, 'a', true ) ) {
  11119. range.setEndAfter( end );
  11120. }
  11121. }
  11122. UE.commands['unlink'] = {
  11123. execCommand : function() {
  11124. var range = this.selection.getRange(),
  11125. bookmark;
  11126. if(range.collapsed && !domUtils.findParentByTagName( range.startContainer, 'a', true )){
  11127. return;
  11128. }
  11129. bookmark = range.createBookmark();
  11130. optimize( range );
  11131. range.removeInlineStyle( 'a' ).moveToBookmark( bookmark ).select();
  11132. },
  11133. queryCommandState : function(){
  11134. return !this.highlight && this.queryCommandValue('link') ? 0 : -1;
  11135. }
  11136. };
  11137. function doLink(range,opt,me){
  11138. var rngClone = range.cloneRange(),
  11139. link = me.queryCommandValue('link');
  11140. optimize( range = range.adjustmentBoundary() );
  11141. var start = range.startContainer;
  11142. if(start.nodeType == 1 && link){
  11143. start = start.childNodes[range.startOffset];
  11144. if(start && start.nodeType == 1 && start.tagName == 'A' && /^(?:https?|ftp|file)\s*:\s*\/\//.test(start[browser.ie?'innerText':'textContent'])){
  11145. start[browser.ie ? 'innerText' : 'textContent'] = utils.html(opt.textValue||opt.href);
  11146. }
  11147. }
  11148. if( !rngClone.collapsed || link){
  11149. range.removeInlineStyle( 'a' );
  11150. rngClone = range.cloneRange();
  11151. }
  11152. if ( rngClone.collapsed ) {
  11153. var a = range.document.createElement( 'a'),
  11154. text = '';
  11155. if(opt.textValue){
  11156. text = utils.html(opt.textValue);
  11157. delete opt.textValue;
  11158. }else{
  11159. text = utils.html(opt.href);
  11160. }
  11161. domUtils.setAttributes( a, opt );
  11162. start = domUtils.findParentByTagName( rngClone.startContainer, 'a', true );
  11163. if(start && domUtils.isInNodeEndBoundary(rngClone,start)){
  11164. range.setStartAfter(start).collapse(true);
  11165. }
  11166. a[browser.ie ? 'innerText' : 'textContent'] = text;
  11167. range.insertNode(a).selectNode( a );
  11168. } else {
  11169. range.applyInlineStyle( 'a', opt );
  11170. }
  11171. }
  11172. UE.commands['link'] = {
  11173. execCommand : function( cmdName, opt ) {
  11174. var range;
  11175. opt._href && (opt._href = utils.unhtml(opt._href,/[<">]/g));
  11176. opt.href && (opt.href = utils.unhtml(opt.href,/[<">]/g));
  11177. opt.textValue && (opt.textValue = utils.unhtml(opt.textValue,/[<">]/g));
  11178. doLink(range=this.selection.getRange(),opt,this);
  11179. //闭合都不加占位符,如果加了会在a后边多个占位符节点,导致a是图片背景组成的列表,出现空白问题
  11180. range.collapse().select(true);
  11181. },
  11182. queryCommandValue : function() {
  11183. var range = this.selection.getRange(),
  11184. node;
  11185. if ( range.collapsed ) {
  11186. // node = this.selection.getStart();
  11187. //在ie下getstart()取值偏上了
  11188. node = range.startContainer;
  11189. node = node.nodeType == 1 ? node : node.parentNode;
  11190. if ( node && (node = domUtils.findParentByTagName( node, 'a', true )) && ! domUtils.isInNodeEndBoundary(range,node)) {
  11191. return node;
  11192. }
  11193. } else {
  11194. //trace:1111 如果是<p><a>xx</a></p> startContainer是p就会找不到a
  11195. range.shrinkBoundary();
  11196. var start = range.startContainer.nodeType == 3 || !range.startContainer.childNodes[range.startOffset] ? range.startContainer : range.startContainer.childNodes[range.startOffset],
  11197. end = range.endContainer.nodeType == 3 || range.endOffset == 0 ? range.endContainer : range.endContainer.childNodes[range.endOffset-1],
  11198. common = range.getCommonAncestor();
  11199. node = domUtils.findParentByTagName( common, 'a', true );
  11200. if ( !node && common.nodeType == 1){
  11201. var as = common.getElementsByTagName( 'a' ),
  11202. ps,pe;
  11203. for ( var i = 0,ci; ci = as[i++]; ) {
  11204. ps = domUtils.getPosition( ci, start ),pe = domUtils.getPosition( ci,end);
  11205. if ( (ps & domUtils.POSITION_FOLLOWING || ps & domUtils.POSITION_CONTAINS)
  11206. &&
  11207. (pe & domUtils.POSITION_PRECEDING || pe & domUtils.POSITION_CONTAINS)
  11208. ) {
  11209. node = ci;
  11210. break;
  11211. }
  11212. }
  11213. }
  11214. return node;
  11215. }
  11216. },
  11217. queryCommandState : function() {
  11218. //判断如果是视频的话连接不可用
  11219. //fix 853
  11220. var img = this.selection.getRange().getClosedNode(),
  11221. flag = img && (img.className == "edui-faked-video" || img.className.indexOf("edui-upload-video")!=-1);
  11222. return flag ? -1 : 0;
  11223. }
  11224. };
  11225. };
  11226. // plugins/iframe.js
  11227. ///import core
  11228. ///import plugins\inserthtml.js
  11229. ///commands 插入框架
  11230. ///commandsName InsertFrame
  11231. ///commandsTitle 插入Iframe
  11232. ///commandsDialog dialogs\insertframe
  11233. UE.plugins['insertframe'] = function() {
  11234. var me =this;
  11235. function deleteIframe(){
  11236. me._iframe && delete me._iframe;
  11237. }
  11238. me.addListener("selectionchange",function(){
  11239. deleteIframe();
  11240. });
  11241. };
  11242. // plugins/scrawl.js
  11243. ///import core
  11244. ///commands 涂鸦
  11245. ///commandsName Scrawl
  11246. ///commandsTitle 涂鸦
  11247. ///commandsDialog dialogs\scrawl
  11248. UE.commands['scrawl'] = {
  11249. queryCommandState : function(){
  11250. return ( browser.ie && browser.version <= 8 ) ? -1 :0;
  11251. }
  11252. };
  11253. // plugins/removeformat.js
  11254. /**
  11255. * 清除格式
  11256. * @file
  11257. * @since 1.2.6.1
  11258. */
  11259. /**
  11260. * 清除文字样式
  11261. * @command removeformat
  11262. * @method execCommand
  11263. * @param { String } cmd 命令字符串
  11264. * @param {String} tags 以逗号隔开的标签。如:strong
  11265. * @param {String} style 样式如:color
  11266. * @param {String} attrs 属性如:width
  11267. * @example
  11268. * ```javascript
  11269. * editor.execCommand( 'removeformat', 'strong','color','width' );
  11270. * ```
  11271. */
  11272. UE.plugins['removeformat'] = function(){
  11273. var me = this;
  11274. me.setOpt({
  11275. 'removeFormatTags': 'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var',
  11276. 'removeFormatAttributes':'class,style,lang,width,height,align,hspace,valign'
  11277. });
  11278. me.commands['removeformat'] = {
  11279. execCommand : function( cmdName, tags, style, attrs,notIncludeA ) {
  11280. var tagReg = new RegExp( '^(?:' + (tags || this.options.removeFormatTags).replace( /,/g, '|' ) + ')$', 'i' ) ,
  11281. removeFormatAttributes = style ? [] : (attrs || this.options.removeFormatAttributes).split( ',' ),
  11282. range = new dom.Range( this.document ),
  11283. bookmark,node,parent,
  11284. filter = function( node ) {
  11285. return node.nodeType == 1;
  11286. };
  11287. function isRedundantSpan (node) {
  11288. if (node.nodeType == 3 || node.tagName.toLowerCase() != 'span'){
  11289. return 0;
  11290. }
  11291. if (browser.ie) {
  11292. //ie 下判断实效,所以只能简单用style来判断
  11293. //return node.style.cssText == '' ? 1 : 0;
  11294. var attrs = node.attributes;
  11295. if ( attrs.length ) {
  11296. for ( var i = 0,l = attrs.length; i<l; i++ ) {
  11297. if ( attrs[i].specified ) {
  11298. return 0;
  11299. }
  11300. }
  11301. return 1;
  11302. }
  11303. }
  11304. return !node.attributes.length;
  11305. }
  11306. function doRemove( range ) {
  11307. var bookmark1 = range.createBookmark();
  11308. if ( range.collapsed ) {
  11309. range.enlarge( true );
  11310. }
  11311. //不能把a标签切了
  11312. if(!notIncludeA){
  11313. var aNode = domUtils.findParentByTagName(range.startContainer,'a',true);
  11314. if(aNode){
  11315. range.setStartBefore(aNode);
  11316. }
  11317. aNode = domUtils.findParentByTagName(range.endContainer,'a',true);
  11318. if(aNode){
  11319. range.setEndAfter(aNode);
  11320. }
  11321. }
  11322. bookmark = range.createBookmark();
  11323. node = bookmark.start;
  11324. //切开始
  11325. while ( (parent = node.parentNode) && !domUtils.isBlockElm( parent ) ) {
  11326. domUtils.breakParent( node, parent );
  11327. domUtils.clearEmptySibling( node );
  11328. }
  11329. if ( bookmark.end ) {
  11330. //切结束
  11331. node = bookmark.end;
  11332. while ( (parent = node.parentNode) && !domUtils.isBlockElm( parent ) ) {
  11333. domUtils.breakParent( node, parent );
  11334. domUtils.clearEmptySibling( node );
  11335. }
  11336. //开始去除样式
  11337. var current = domUtils.getNextDomNode( bookmark.start, false, filter ),
  11338. next;
  11339. while ( current ) {
  11340. if ( current == bookmark.end ) {
  11341. break;
  11342. }
  11343. next = domUtils.getNextDomNode( current, true, filter );
  11344. if ( !dtd.$empty[current.tagName.toLowerCase()] && !domUtils.isBookmarkNode( current ) ) {
  11345. if ( tagReg.test( current.tagName ) ) {
  11346. if ( style ) {
  11347. domUtils.removeStyle( current, style );
  11348. if ( isRedundantSpan( current ) && style != 'text-decoration'){
  11349. domUtils.remove( current, true );
  11350. }
  11351. } else {
  11352. domUtils.remove( current, true );
  11353. }
  11354. } else {
  11355. //trace:939 不能把list上的样式去掉
  11356. if(!dtd.$tableContent[current.tagName] && !dtd.$list[current.tagName]){
  11357. domUtils.removeAttributes( current, removeFormatAttributes );
  11358. if ( isRedundantSpan( current ) ){
  11359. domUtils.remove( current, true );
  11360. }
  11361. }
  11362. }
  11363. }
  11364. current = next;
  11365. }
  11366. }
  11367. //trace:1035
  11368. //trace:1096 不能把td上的样式去掉,比如边框
  11369. var pN = bookmark.start.parentNode;
  11370. if(domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName] && !dtd.$list[pN.tagName]){
  11371. domUtils.removeAttributes( pN,removeFormatAttributes );
  11372. }
  11373. pN = bookmark.end.parentNode;
  11374. if(bookmark.end && domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName]&& !dtd.$list[pN.tagName]){
  11375. domUtils.removeAttributes( pN,removeFormatAttributes );
  11376. }
  11377. range.moveToBookmark( bookmark ).moveToBookmark(bookmark1);
  11378. //清除冗余的代码 <b><bookmark></b>
  11379. var node = range.startContainer,
  11380. tmp,
  11381. collapsed = range.collapsed;
  11382. while(node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]){
  11383. tmp = node.parentNode;
  11384. range.setStartBefore(node);
  11385. //trace:937
  11386. //更新结束边界
  11387. if(range.startContainer === range.endContainer){
  11388. range.endOffset--;
  11389. }
  11390. domUtils.remove(node);
  11391. node = tmp;
  11392. }
  11393. if(!collapsed){
  11394. node = range.endContainer;
  11395. while(node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]){
  11396. tmp = node.parentNode;
  11397. range.setEndBefore(node);
  11398. domUtils.remove(node);
  11399. node = tmp;
  11400. }
  11401. }
  11402. }
  11403. range = this.selection.getRange();
  11404. doRemove( range );
  11405. range.select();
  11406. }
  11407. };
  11408. };
  11409. // plugins/blockquote.js
  11410. /**
  11411. * 添加引用
  11412. * @file
  11413. * @since 1.2.6.1
  11414. */
  11415. /**
  11416. * 添加引用
  11417. * @command blockquote
  11418. * @method execCommand
  11419. * @param { String } cmd 命令字符串
  11420. * @example
  11421. * ```javascript
  11422. * editor.execCommand( 'blockquote' );
  11423. * ```
  11424. */
  11425. /**
  11426. * 添加引用
  11427. * @command blockquote
  11428. * @method execCommand
  11429. * @param { String } cmd 命令字符串
  11430. * @param { Object } attrs 节点属性
  11431. * @example
  11432. * ```javascript
  11433. * editor.execCommand( 'blockquote',{
  11434. * style: "color: red;"
  11435. * } );
  11436. * ```
  11437. */
  11438. UE.plugins['blockquote'] = function(){
  11439. var me = this;
  11440. function getObj(editor){
  11441. return domUtils.filterNodeList(editor.selection.getStartElementPath(),'blockquote');
  11442. }
  11443. me.commands['blockquote'] = {
  11444. execCommand : function( cmdName, attrs ) {
  11445. var range = this.selection.getRange(),
  11446. obj = getObj(this),
  11447. blockquote = dtd.blockquote,
  11448. bookmark = range.createBookmark();
  11449. if ( obj ) {
  11450. var start = range.startContainer,
  11451. startBlock = domUtils.isBlockElm(start) ? start : domUtils.findParent(start,function(node){return domUtils.isBlockElm(node)}),
  11452. end = range.endContainer,
  11453. endBlock = domUtils.isBlockElm(end) ? end : domUtils.findParent(end,function(node){return domUtils.isBlockElm(node)});
  11454. //处理一下li
  11455. startBlock = domUtils.findParentByTagName(startBlock,'li',true) || startBlock;
  11456. endBlock = domUtils.findParentByTagName(endBlock,'li',true) || endBlock;
  11457. if(startBlock.tagName == 'LI' || startBlock.tagName == 'TD' || startBlock === obj || domUtils.isBody(startBlock)){
  11458. domUtils.remove(obj,true);
  11459. }else{
  11460. domUtils.breakParent(startBlock,obj);
  11461. }
  11462. if(startBlock !== endBlock){
  11463. obj = domUtils.findParentByTagName(endBlock,'blockquote');
  11464. if(obj){
  11465. if(endBlock.tagName == 'LI' || endBlock.tagName == 'TD'|| domUtils.isBody(endBlock)){
  11466. obj.parentNode && domUtils.remove(obj,true);
  11467. }else{
  11468. domUtils.breakParent(endBlock,obj);
  11469. }
  11470. }
  11471. }
  11472. var blockquotes = domUtils.getElementsByTagName(this.document,'blockquote');
  11473. for(var i=0,bi;bi=blockquotes[i++];){
  11474. if(!bi.childNodes.length){
  11475. domUtils.remove(bi);
  11476. }else if(domUtils.getPosition(bi,startBlock)&domUtils.POSITION_FOLLOWING && domUtils.getPosition(bi,endBlock)&domUtils.POSITION_PRECEDING){
  11477. domUtils.remove(bi,true);
  11478. }
  11479. }
  11480. } else {
  11481. var tmpRange = range.cloneRange(),
  11482. node = tmpRange.startContainer.nodeType == 1 ? tmpRange.startContainer : tmpRange.startContainer.parentNode,
  11483. preNode = node,
  11484. doEnd = 1;
  11485. //调整开始
  11486. while ( 1 ) {
  11487. if ( domUtils.isBody(node) ) {
  11488. if ( preNode !== node ) {
  11489. if ( range.collapsed ) {
  11490. tmpRange.selectNode( preNode );
  11491. doEnd = 0;
  11492. } else {
  11493. tmpRange.setStartBefore( preNode );
  11494. }
  11495. }else{
  11496. tmpRange.setStart(node,0);
  11497. }
  11498. break;
  11499. }
  11500. if ( !blockquote[node.tagName] ) {
  11501. if ( range.collapsed ) {
  11502. tmpRange.selectNode( preNode );
  11503. } else{
  11504. tmpRange.setStartBefore( preNode);
  11505. }
  11506. break;
  11507. }
  11508. preNode = node;
  11509. node = node.parentNode;
  11510. }
  11511. //调整结束
  11512. if ( doEnd ) {
  11513. preNode = node = node = tmpRange.endContainer.nodeType == 1 ? tmpRange.endContainer : tmpRange.endContainer.parentNode;
  11514. while ( 1 ) {
  11515. if ( domUtils.isBody( node ) ) {
  11516. if ( preNode !== node ) {
  11517. tmpRange.setEndAfter( preNode );
  11518. } else {
  11519. tmpRange.setEnd( node, node.childNodes.length );
  11520. }
  11521. break;
  11522. }
  11523. if ( !blockquote[node.tagName] ) {
  11524. tmpRange.setEndAfter( preNode );
  11525. break;
  11526. }
  11527. preNode = node;
  11528. node = node.parentNode;
  11529. }
  11530. }
  11531. node = range.document.createElement( 'blockquote' );
  11532. domUtils.setAttributes( node, attrs );
  11533. node.appendChild( tmpRange.extractContents() );
  11534. tmpRange.insertNode( node );
  11535. //去除重复的
  11536. var childs = domUtils.getElementsByTagName(node,'blockquote');
  11537. for(var i=0,ci;ci=childs[i++];){
  11538. if(ci.parentNode){
  11539. domUtils.remove(ci,true);
  11540. }
  11541. }
  11542. }
  11543. range.moveToBookmark( bookmark ).select();
  11544. },
  11545. queryCommandState : function() {
  11546. return getObj(this) ? 1 : 0;
  11547. }
  11548. };
  11549. };
  11550. // plugins/convertcase.js
  11551. /**
  11552. * 大小写转换
  11553. * @file
  11554. * @since 1.2.6.1
  11555. */
  11556. /**
  11557. * 把选区内文本变大写,与“tolowercase”命令互斥
  11558. * @command touppercase
  11559. * @method execCommand
  11560. * @param { String } cmd 命令字符串
  11561. * @example
  11562. * ```javascript
  11563. * editor.execCommand( 'touppercase' );
  11564. * ```
  11565. */
  11566. /**
  11567. * 把选区内文本变小写,与“touppercase”命令互斥
  11568. * @command tolowercase
  11569. * @method execCommand
  11570. * @param { String } cmd 命令字符串
  11571. * @example
  11572. * ```javascript
  11573. * editor.execCommand( 'tolowercase' );
  11574. * ```
  11575. */
  11576. UE.commands['touppercase'] =
  11577. UE.commands['tolowercase'] = {
  11578. execCommand:function (cmd) {
  11579. var me = this;
  11580. var rng = me.selection.getRange();
  11581. if(rng.collapsed){
  11582. return rng;
  11583. }
  11584. var bk = rng.createBookmark(),
  11585. bkEnd = bk.end,
  11586. filterFn = function( node ) {
  11587. return !domUtils.isBr(node) && !domUtils.isWhitespace( node );
  11588. },
  11589. curNode = domUtils.getNextDomNode( bk.start, false, filterFn );
  11590. while ( curNode && (domUtils.getPosition( curNode, bkEnd ) & domUtils.POSITION_PRECEDING) ) {
  11591. if ( curNode.nodeType == 3 ) {
  11592. curNode.nodeValue = curNode.nodeValue[cmd == 'touppercase' ? 'toUpperCase' : 'toLowerCase']();
  11593. }
  11594. curNode = domUtils.getNextDomNode( curNode, true, filterFn );
  11595. if(curNode === bkEnd){
  11596. break;
  11597. }
  11598. }
  11599. rng.moveToBookmark(bk).select();
  11600. }
  11601. };
  11602. // plugins/indent.js
  11603. /**
  11604. * 首行缩进
  11605. * @file
  11606. * @since 1.2.6.1
  11607. */
  11608. /**
  11609. * 缩进
  11610. * @command indent
  11611. * @method execCommand
  11612. * @param { String } cmd 命令字符串
  11613. * @example
  11614. * ```javascript
  11615. * editor.execCommand( 'indent' );
  11616. * ```
  11617. */
  11618. UE.commands['indent'] = {
  11619. execCommand : function() {
  11620. var me = this,value = me.queryCommandState("indent") ? "0em" : (me.options.indentValue || '2em');
  11621. me.execCommand('Paragraph','p',{style:'text-indent:'+ value});
  11622. },
  11623. queryCommandState : function() {
  11624. var pN = domUtils.filterNodeList(this.selection.getStartElementPath(),'p h1 h2 h3 h4 h5 h6');
  11625. return pN && pN.style.textIndent && parseInt(pN.style.textIndent) ? 1 : 0;
  11626. }
  11627. };
  11628. // plugins/print.js
  11629. /**
  11630. * 打印
  11631. * @file
  11632. * @since 1.2.6.1
  11633. */
  11634. /**
  11635. * 打印
  11636. * @command print
  11637. * @method execCommand
  11638. * @param { String } cmd 命令字符串
  11639. * @example
  11640. * ```javascript
  11641. * editor.execCommand( 'print' );
  11642. * ```
  11643. */
  11644. UE.commands['print'] = {
  11645. execCommand : function(){
  11646. this.window.print();
  11647. },
  11648. notNeedUndo : 1
  11649. };
  11650. // plugins/preview.js
  11651. /**
  11652. * 预览
  11653. * @file
  11654. * @since 1.2.6.1
  11655. */
  11656. /**
  11657. * 预览
  11658. * @command preview
  11659. * @method execCommand
  11660. * @param { String } cmd 命令字符串
  11661. * @example
  11662. * ```javascript
  11663. * editor.execCommand( 'preview' );
  11664. * ```
  11665. */
  11666. UE.commands['preview'] = {
  11667. execCommand : function(){
  11668. var w = window.open('', '_blank', ''),
  11669. d = w.document;
  11670. d.open();
  11671. d.write('<!DOCTYPE html><html><head><meta charset="utf-8"/><script src="'+this.options.UEDITOR_HOME_URL+'ueditor.parse.js"></script><script>' +
  11672. "setTimeout(function(){uParse('div',{rootPath: '"+ this.options.UEDITOR_HOME_URL +"'})},300)" +
  11673. '</script></head><body><div>'+this.getContent(null,null,true)+'</div></body></html>');
  11674. d.close();
  11675. },
  11676. notNeedUndo : 1
  11677. };
  11678. // plugins/selectall.js
  11679. /**
  11680. * 全选
  11681. * @file
  11682. * @since 1.2.6.1
  11683. */
  11684. /**
  11685. * 选中所有内容
  11686. * @command selectall
  11687. * @method execCommand
  11688. * @param { String } cmd 命令字符串
  11689. * @example
  11690. * ```javascript
  11691. * editor.execCommand( 'selectall' );
  11692. * ```
  11693. */
  11694. UE.plugins['selectall'] = function(){
  11695. var me = this;
  11696. me.commands['selectall'] = {
  11697. execCommand : function(){
  11698. //去掉了原生的selectAll,因为会出现报错和当内容为空时,不能出现闭合状态的光标
  11699. var me = this,body = me.body,
  11700. range = me.selection.getRange();
  11701. range.selectNodeContents(body);
  11702. if(domUtils.isEmptyBlock(body)){
  11703. //opera不能自动合并到元素的里边,要手动处理一下
  11704. if(browser.opera && body.firstChild && body.firstChild.nodeType == 1){
  11705. range.setStartAtFirst(body.firstChild);
  11706. }
  11707. range.collapse(true);
  11708. }
  11709. range.select(true);
  11710. },
  11711. notNeedUndo : 1
  11712. };
  11713. //快捷键
  11714. me.addshortcutkey({
  11715. "selectAll" : "ctrl+65"
  11716. });
  11717. };
  11718. // plugins/paragraph.js
  11719. /**
  11720. * 段落样式
  11721. * @file
  11722. * @since 1.2.6.1
  11723. */
  11724. /**
  11725. * 段落格式
  11726. * @command paragraph
  11727. * @method execCommand
  11728. * @param { String } cmd 命令字符串
  11729. * @param {String} style 标签值为:'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
  11730. * @param {Object} attrs 标签的属性
  11731. * @example
  11732. * ```javascript
  11733. * editor.execCommand( 'Paragraph','h1','{
  11734. * class:'test'
  11735. * }' );
  11736. * ```
  11737. */
  11738. /**
  11739. * 返回选区内节点标签名
  11740. * @command paragraph
  11741. * @method queryCommandValue
  11742. * @param { String } cmd 命令字符串
  11743. * @return { String } 节点标签名
  11744. * @example
  11745. * ```javascript
  11746. * editor.queryCommandValue( 'Paragraph' );
  11747. * ```
  11748. */
  11749. UE.plugins['paragraph'] = function() {
  11750. var me = this,
  11751. block = domUtils.isBlockElm,
  11752. notExchange = ['TD','LI','PRE'],
  11753. doParagraph = function(range,style,attrs,sourceCmdName){
  11754. var bookmark = range.createBookmark(),
  11755. filterFn = function( node ) {
  11756. return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' && !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace( node );
  11757. },
  11758. para;
  11759. range.enlarge( true );
  11760. var bookmark2 = range.createBookmark(),
  11761. current = domUtils.getNextDomNode( bookmark2.start, false, filterFn ),
  11762. tmpRange = range.cloneRange(),
  11763. tmpNode;
  11764. while ( current && !(domUtils.getPosition( current, bookmark2.end ) & domUtils.POSITION_FOLLOWING) ) {
  11765. if ( current.nodeType == 3 || !block( current ) ) {
  11766. tmpRange.setStartBefore( current );
  11767. while ( current && current !== bookmark2.end && !block( current ) ) {
  11768. tmpNode = current;
  11769. current = domUtils.getNextDomNode( current, false, null, function( node ) {
  11770. return !block( node );
  11771. } );
  11772. }
  11773. tmpRange.setEndAfter( tmpNode );
  11774. para = range.document.createElement( style );
  11775. if(attrs){
  11776. domUtils.setAttributes(para,attrs);
  11777. if(sourceCmdName && sourceCmdName == 'customstyle' && attrs.style){
  11778. para.style.cssText = attrs.style;
  11779. }
  11780. }
  11781. para.appendChild( tmpRange.extractContents() );
  11782. //需要内容占位
  11783. if(domUtils.isEmptyNode(para)){
  11784. domUtils.fillChar(range.document,para);
  11785. }
  11786. tmpRange.insertNode( para );
  11787. var parent = para.parentNode;
  11788. //如果para上一级是一个block元素且不是body,td就删除它
  11789. if ( block( parent ) && !domUtils.isBody( para.parentNode ) && utils.indexOf(notExchange,parent.tagName)==-1) {
  11790. //存储dir,style
  11791. if(!(sourceCmdName && sourceCmdName == 'customstyle')){
  11792. parent.getAttribute('dir') && para.setAttribute('dir',parent.getAttribute('dir'));
  11793. //trace:1070
  11794. parent.style.cssText && (para.style.cssText = parent.style.cssText + ';' + para.style.cssText);
  11795. //trace:1030
  11796. parent.style.textAlign && !para.style.textAlign && (para.style.textAlign = parent.style.textAlign);
  11797. parent.style.textIndent && !para.style.textIndent && (para.style.textIndent = parent.style.textIndent);
  11798. parent.style.padding && !para.style.padding && (para.style.padding = parent.style.padding);
  11799. }
  11800. //trace:1706 选择的就是h1-6要删除
  11801. if(attrs && /h\d/i.test(parent.tagName) && !/h\d/i.test(para.tagName) ){
  11802. domUtils.setAttributes(parent,attrs);
  11803. if(sourceCmdName && sourceCmdName == 'customstyle' && attrs.style){
  11804. parent.style.cssText = attrs.style;
  11805. }
  11806. domUtils.remove(para,true);
  11807. para = parent;
  11808. }else{
  11809. domUtils.remove( para.parentNode, true );
  11810. }
  11811. }
  11812. if( utils.indexOf(notExchange,parent.tagName)!=-1){
  11813. current = parent;
  11814. }else{
  11815. current = para;
  11816. }
  11817. current = domUtils.getNextDomNode( current, false, filterFn );
  11818. } else {
  11819. current = domUtils.getNextDomNode( current, true, filterFn );
  11820. }
  11821. }
  11822. return range.moveToBookmark( bookmark2 ).moveToBookmark( bookmark );
  11823. };
  11824. me.setOpt('paragraph',{'p':'', 'h1':'', 'h2':'', 'h3':'', 'h4':'', 'h5':'', 'h6':''});
  11825. me.commands['paragraph'] = {
  11826. execCommand : function( cmdName, style,attrs,sourceCmdName ) {
  11827. var range = this.selection.getRange();
  11828. //闭合时单独处理
  11829. if(range.collapsed){
  11830. var txt = this.document.createTextNode('p');
  11831. range.insertNode(txt);
  11832. //去掉冗余的fillchar
  11833. if(browser.ie){
  11834. var node = txt.previousSibling;
  11835. if(node && domUtils.isWhitespace(node)){
  11836. domUtils.remove(node);
  11837. }
  11838. node = txt.nextSibling;
  11839. if(node && domUtils.isWhitespace(node)){
  11840. domUtils.remove(node);
  11841. }
  11842. }
  11843. }
  11844. range = doParagraph(range,style,attrs,sourceCmdName);
  11845. if(txt){
  11846. range.setStartBefore(txt).collapse(true);
  11847. var pN = txt.parentNode;
  11848. domUtils.remove(txt);
  11849. if(domUtils.isBlockElm(pN)&&domUtils.isEmptyNode(pN)){
  11850. domUtils.fillNode(this.document,pN);
  11851. }
  11852. }
  11853. if(browser.gecko && range.collapsed && range.startContainer.nodeType == 1){
  11854. var child = range.startContainer.childNodes[range.startOffset];
  11855. if(child && child.nodeType == 1 && child.tagName.toLowerCase() == style){
  11856. range.setStart(child,0).collapse(true);
  11857. }
  11858. }
  11859. //trace:1097 原来有true,原因忘了,但去了就不能清除多余的占位符了
  11860. range.select();
  11861. return true;
  11862. },
  11863. queryCommandValue : function() {
  11864. var node = domUtils.filterNodeList(this.selection.getStartElementPath(),'p h1 h2 h3 h4 h5 h6');
  11865. return node ? node.tagName.toLowerCase() : '';
  11866. }
  11867. };
  11868. };
  11869. // plugins/directionality.js
  11870. /**
  11871. * 设置文字输入的方向的插件
  11872. * @file
  11873. * @since 1.2.6.1
  11874. */
  11875. (function() {
  11876. var block = domUtils.isBlockElm ,
  11877. getObj = function(editor){
  11878. // var startNode = editor.selection.getStart(),
  11879. // parents;
  11880. // if ( startNode ) {
  11881. // //查找所有的是block的父亲节点
  11882. // parents = domUtils.findParents( startNode, true, block, true );
  11883. // for ( var i = 0,ci; ci = parents[i++]; ) {
  11884. // if ( ci.getAttribute( 'dir' ) ) {
  11885. // return ci;
  11886. // }
  11887. // }
  11888. // }
  11889. return domUtils.filterNodeList(editor.selection.getStartElementPath(),function(n){return n && n.nodeType == 1 && n.getAttribute('dir')});
  11890. },
  11891. doDirectionality = function(range,editor,forward){
  11892. var bookmark,
  11893. filterFn = function( node ) {
  11894. return node.nodeType == 1 ? !domUtils.isBookmarkNode(node) : !domUtils.isWhitespace(node);
  11895. },
  11896. obj = getObj( editor );
  11897. if ( obj && range.collapsed ) {
  11898. obj.setAttribute( 'dir', forward );
  11899. return range;
  11900. }
  11901. bookmark = range.createBookmark();
  11902. range.enlarge( true );
  11903. var bookmark2 = range.createBookmark(),
  11904. current = domUtils.getNextDomNode( bookmark2.start, false, filterFn ),
  11905. tmpRange = range.cloneRange(),
  11906. tmpNode;
  11907. while ( current && !(domUtils.getPosition( current, bookmark2.end ) & domUtils.POSITION_FOLLOWING) ) {
  11908. if ( current.nodeType == 3 || !block( current ) ) {
  11909. tmpRange.setStartBefore( current );
  11910. while ( current && current !== bookmark2.end && !block( current ) ) {
  11911. tmpNode = current;
  11912. current = domUtils.getNextDomNode( current, false, null, function( node ) {
  11913. return !block( node );
  11914. } );
  11915. }
  11916. tmpRange.setEndAfter( tmpNode );
  11917. var common = tmpRange.getCommonAncestor();
  11918. if ( !domUtils.isBody( common ) && block( common ) ) {
  11919. //遍历到了block节点
  11920. common.setAttribute( 'dir', forward );
  11921. current = common;
  11922. } else {
  11923. //没有遍历到,添加一个block节点
  11924. var p = range.document.createElement( 'p' );
  11925. p.setAttribute( 'dir', forward );
  11926. var frag = tmpRange.extractContents();
  11927. p.appendChild( frag );
  11928. tmpRange.insertNode( p );
  11929. current = p;
  11930. }
  11931. current = domUtils.getNextDomNode( current, false, filterFn );
  11932. } else {
  11933. current = domUtils.getNextDomNode( current, true, filterFn );
  11934. }
  11935. }
  11936. return range.moveToBookmark( bookmark2 ).moveToBookmark( bookmark );
  11937. };
  11938. /**
  11939. * 文字输入方向
  11940. * @command directionality
  11941. * @method execCommand
  11942. * @param { String } cmdName 命令字符串
  11943. * @param { String } forward 传入'ltr'表示从左向右输入,传入'rtl'表示从右向左输入
  11944. * @example
  11945. * ```javascript
  11946. * editor.execCommand( 'directionality', 'ltr');
  11947. * ```
  11948. */
  11949. /**
  11950. * 查询当前选区的文字输入方向
  11951. * @command directionality
  11952. * @method queryCommandValue
  11953. * @param { String } cmdName 命令字符串
  11954. * @return { String } 返回'ltr'表示从左向右输入,返回'rtl'表示从右向左输入
  11955. * @example
  11956. * ```javascript
  11957. * editor.queryCommandValue( 'directionality');
  11958. * ```
  11959. */
  11960. UE.commands['directionality'] = {
  11961. execCommand : function( cmdName,forward ) {
  11962. var range = this.selection.getRange();
  11963. //闭合时单独处理
  11964. if(range.collapsed){
  11965. var txt = this.document.createTextNode('d');
  11966. range.insertNode(txt);
  11967. }
  11968. doDirectionality(range,this,forward);
  11969. if(txt){
  11970. range.setStartBefore(txt).collapse(true);
  11971. domUtils.remove(txt);
  11972. }
  11973. range.select();
  11974. return true;
  11975. },
  11976. queryCommandValue : function() {
  11977. var node = getObj(this);
  11978. return node ? node.getAttribute('dir') : 'ltr';
  11979. }
  11980. };
  11981. })();
  11982. // plugins/horizontal.js
  11983. /**
  11984. * 插入分割线插件
  11985. * @file
  11986. * @since 1.2.6.1
  11987. */
  11988. /**
  11989. * 插入分割线
  11990. * @command horizontal
  11991. * @method execCommand
  11992. * @param { String } cmdName 命令字符串
  11993. * @example
  11994. * ```javascript
  11995. * editor.execCommand( 'horizontal' );
  11996. * ```
  11997. */
  11998. UE.plugins['horizontal'] = function(){
  11999. var me = this;
  12000. me.commands['horizontal'] = {
  12001. execCommand : function( cmdName ) {
  12002. var me = this;
  12003. if(me.queryCommandState(cmdName)!==-1){
  12004. me.execCommand('insertHtml','<hr>');
  12005. var range = me.selection.getRange(),
  12006. start = range.startContainer;
  12007. if(start.nodeType == 1 && !start.childNodes[range.startOffset] ){
  12008. var tmp;
  12009. if(tmp = start.childNodes[range.startOffset - 1]){
  12010. if(tmp.nodeType == 1 && tmp.tagName == 'HR'){
  12011. if(me.options.enterTag == 'p'){
  12012. tmp = me.document.createElement('p');
  12013. range.insertNode(tmp);
  12014. range.setStart(tmp,0).setCursor();
  12015. }else{
  12016. tmp = me.document.createElement('br');
  12017. range.insertNode(tmp);
  12018. range.setStartBefore(tmp).setCursor();
  12019. }
  12020. }
  12021. }
  12022. }
  12023. return true;
  12024. }
  12025. },
  12026. //边界在table里不能加分隔线
  12027. queryCommandState : function() {
  12028. return domUtils.filterNodeList(this.selection.getStartElementPath(),'table') ? -1 : 0;
  12029. }
  12030. };
  12031. // me.addListener('delkeyup',function(){
  12032. // var rng = this.selection.getRange();
  12033. // if(browser.ie && browser.version > 8){
  12034. // rng.txtToElmBoundary(true);
  12035. // if(domUtils.isStartInblock(rng)){
  12036. // var tmpNode = rng.startContainer;
  12037. // var pre = tmpNode.previousSibling;
  12038. // if(pre && domUtils.isTagNode(pre,'hr')){
  12039. // domUtils.remove(pre);
  12040. // rng.select();
  12041. // return;
  12042. // }
  12043. // }
  12044. // }
  12045. // if(domUtils.isBody(rng.startContainer)){
  12046. // var hr = rng.startContainer.childNodes[rng.startOffset -1];
  12047. // if(hr && hr.nodeName == 'HR'){
  12048. // var next = hr.nextSibling;
  12049. // if(next){
  12050. // rng.setStart(next,0)
  12051. // }else if(hr.previousSibling){
  12052. // rng.setStartAtLast(hr.previousSibling)
  12053. // }else{
  12054. // var p = this.document.createElement('p');
  12055. // hr.parentNode.insertBefore(p,hr);
  12056. // domUtils.fillNode(this.document,p);
  12057. // rng.setStart(p,0);
  12058. // }
  12059. // domUtils.remove(hr);
  12060. // rng.setCursor(false,true);
  12061. // }
  12062. // }
  12063. // })
  12064. me.addListener('delkeydown',function(name,evt){
  12065. var rng = this.selection.getRange();
  12066. rng.txtToElmBoundary(true);
  12067. if(domUtils.isStartInblock(rng)){
  12068. var tmpNode = rng.startContainer;
  12069. var pre = tmpNode.previousSibling;
  12070. if(pre && domUtils.isTagNode(pre,'hr')){
  12071. domUtils.remove(pre);
  12072. rng.select();
  12073. domUtils.preventDefault(evt);
  12074. return true;
  12075. }
  12076. }
  12077. })
  12078. };
  12079. // plugins/time.js
  12080. /**
  12081. * 插入时间和日期
  12082. * @file
  12083. * @since 1.2.6.1
  12084. */
  12085. /**
  12086. * 插入时间,默认格式:12:59:59
  12087. * @command time
  12088. * @method execCommand
  12089. * @param { String } cmd 命令字符串
  12090. * @example
  12091. * ```javascript
  12092. * editor.execCommand( 'time');
  12093. * ```
  12094. */
  12095. /**
  12096. * 插入日期,默认格式:2013-08-30
  12097. * @command date
  12098. * @method execCommand
  12099. * @param { String } cmd 命令字符串
  12100. * @example
  12101. * ```javascript
  12102. * editor.execCommand( 'date');
  12103. * ```
  12104. */
  12105. UE.commands['time'] = UE.commands["date"] = {
  12106. execCommand : function(cmd, format){
  12107. var date = new Date;
  12108. function formatTime(date, format) {
  12109. var hh = ('0' + date.getHours()).slice(-2),
  12110. ii = ('0' + date.getMinutes()).slice(-2),
  12111. ss = ('0' + date.getSeconds()).slice(-2);
  12112. format = format || 'hh:ii:ss';
  12113. return format.replace(/hh/ig, hh).replace(/ii/ig, ii).replace(/ss/ig, ss);
  12114. }
  12115. function formatDate(date, format) {
  12116. var yyyy = ('000' + date.getFullYear()).slice(-4),
  12117. yy = yyyy.slice(-2),
  12118. mm = ('0' + (date.getMonth()+1)).slice(-2),
  12119. dd = ('0' + date.getDate()).slice(-2);
  12120. format = format || 'yyyy-mm-dd';
  12121. return format.replace(/yyyy/ig, yyyy).replace(/yy/ig, yy).replace(/mm/ig, mm).replace(/dd/ig, dd);
  12122. }
  12123. this.execCommand('insertHtml',cmd == "time" ? formatTime(date, format):formatDate(date, format) );
  12124. }
  12125. };
  12126. // plugins/rowspacing.js
  12127. /**
  12128. * 段前段后间距插件
  12129. * @file
  12130. * @since 1.2.6.1
  12131. */
  12132. /**
  12133. * 设置段间距
  12134. * @command rowspacing
  12135. * @method execCommand
  12136. * @param { String } cmd 命令字符串
  12137. * @param { String } value 段间距的值,以px为单位
  12138. * @param { String } dir 间距位置,top或bottom,分别表示段前和段后
  12139. * @example
  12140. * ```javascript
  12141. * editor.execCommand( 'rowspacing', '10', 'top' );
  12142. * ```
  12143. */
  12144. UE.plugins['rowspacing'] = function(){
  12145. var me = this;
  12146. me.setOpt({
  12147. 'rowspacingtop':['5', '10', '15', '20', '25'],
  12148. 'rowspacingbottom':['5', '10', '15', '20', '25']
  12149. });
  12150. me.commands['rowspacing'] = {
  12151. execCommand : function( cmdName,value,dir ) {
  12152. this.execCommand('paragraph','p',{style:'margin-'+dir+':'+value + 'px'});
  12153. return true;
  12154. },
  12155. queryCommandValue : function(cmdName,dir) {
  12156. var pN = domUtils.filterNodeList(this.selection.getStartElementPath(),function(node){return domUtils.isBlockElm(node) }),
  12157. value;
  12158. //trace:1026
  12159. if(pN){
  12160. value = domUtils.getComputedStyle(pN,'margin-'+dir).replace(/[^\d]/g,'');
  12161. return !value ? 0 : value;
  12162. }
  12163. return 0;
  12164. }
  12165. };
  12166. };
  12167. // plugins/lineheight.js
  12168. /**
  12169. * 设置行内间距
  12170. * @file
  12171. * @since 1.2.6.1
  12172. */
  12173. UE.plugins['lineheight'] = function(){
  12174. var me = this;
  12175. me.setOpt({'lineheight':['1', '1.5','1.75','2', '3', '4', '5']});
  12176. /**
  12177. * 行距
  12178. * @command lineheight
  12179. * @method execCommand
  12180. * @param { String } cmdName 命令字符串
  12181. * @param { String } value 传入的行高值, 该值是当前字体的倍数, 例如: 1.5, 1.75
  12182. * @example
  12183. * ```javascript
  12184. * editor.execCommand( 'lineheight', 1.5);
  12185. * ```
  12186. */
  12187. /**
  12188. * 查询当前选区内容的行高大小
  12189. * @command lineheight
  12190. * @method queryCommandValue
  12191. * @param { String } cmd 命令字符串
  12192. * @return { String } 返回当前行高大小
  12193. * @example
  12194. * ```javascript
  12195. * editor.queryCommandValue( 'lineheight' );
  12196. * ```
  12197. */
  12198. me.commands['lineheight'] = {
  12199. execCommand : function( cmdName,value ) {
  12200. this.execCommand('paragraph','p',{style:'line-height:'+ (value == "1" ? "normal" : value + 'em') });
  12201. return true;
  12202. },
  12203. queryCommandValue : function() {
  12204. var pN = domUtils.filterNodeList(this.selection.getStartElementPath(),function(node){return domUtils.isBlockElm(node)});
  12205. if(pN){
  12206. var value = domUtils.getComputedStyle(pN,'line-height');
  12207. return value == 'normal' ? 1 : value.replace(/[^\d.]*/ig,"");
  12208. }
  12209. }
  12210. };
  12211. };
  12212. // plugins/insertcode.js
  12213. /**
  12214. * 插入代码插件
  12215. * @file
  12216. * @since 1.2.6.1
  12217. */
  12218. UE.plugins['insertcode'] = function() {
  12219. var me = this;
  12220. me.ready(function(){
  12221. utils.cssRule('pre','pre{margin:.5em 0;padding:.4em .6em;border-radius:8px;background:#f8f8f8;}',
  12222. me.document)
  12223. });
  12224. me.setOpt('insertcode',{
  12225. 'as3':'ActionScript3',
  12226. 'bash':'Bash/Shell',
  12227. 'cpp':'C/C++',
  12228. 'css':'Css',
  12229. 'cf':'CodeFunction',
  12230. 'c#':'C#',
  12231. 'delphi':'Delphi',
  12232. 'diff':'Diff',
  12233. 'erlang':'Erlang',
  12234. 'groovy':'Groovy',
  12235. 'html':'Html',
  12236. 'java':'Java',
  12237. 'jfx':'JavaFx',
  12238. 'js':'Javascript',
  12239. 'pl':'Perl',
  12240. 'php':'Php',
  12241. 'plain':'Plain Text',
  12242. 'ps':'PowerShell',
  12243. 'python':'Python',
  12244. 'ruby':'Ruby',
  12245. 'scala':'Scala',
  12246. 'sql':'Sql',
  12247. 'vb':'Vb',
  12248. 'xml':'Xml'
  12249. });
  12250. /**
  12251. * 插入代码
  12252. * @command insertcode
  12253. * @method execCommand
  12254. * @param { String } cmd 命令字符串
  12255. * @param { String } lang 插入代码的语言
  12256. * @example
  12257. * ```javascript
  12258. * editor.execCommand( 'insertcode', 'javascript' );
  12259. * ```
  12260. */
  12261. /**
  12262. * 如果选区所在位置是插入插入代码区域,返回代码的语言
  12263. * @command insertcode
  12264. * @method queryCommandValue
  12265. * @param { String } cmd 命令字符串
  12266. * @return { String } 返回代码的语言
  12267. * @example
  12268. * ```javascript
  12269. * editor.queryCommandValue( 'insertcode' );
  12270. * ```
  12271. */
  12272. me.commands['insertcode'] = {
  12273. execCommand : function(cmd,lang){
  12274. var me = this,
  12275. rng = me.selection.getRange(),
  12276. pre = domUtils.findParentByTagName(rng.startContainer,'pre',true);
  12277. if(pre){
  12278. pre.className = 'brush:'+lang+';toolbar:false;';
  12279. }else{
  12280. var code = '';
  12281. if(rng.collapsed){
  12282. code = browser.ie && browser.ie11below ? (browser.version <= 8 ? '&nbsp;':''):'<br/>';
  12283. }else{
  12284. var frag = rng.extractContents();
  12285. var div = me.document.createElement('div');
  12286. div.appendChild(frag);
  12287. utils.each(UE.filterNode(UE.htmlparser(div.innerHTML.replace(/[\r\t]/g,'')),me.options.filterTxtRules).children,function(node){
  12288. if(browser.ie && browser.ie11below && browser.version > 8){
  12289. if(node.type =='element'){
  12290. if(node.tagName == 'br'){
  12291. code += '\n'
  12292. }else if(!dtd.$empty[node.tagName]){
  12293. utils.each(node.children,function(cn){
  12294. if(cn.type =='element'){
  12295. if(cn.tagName == 'br'){
  12296. code += '\n'
  12297. }else if(!dtd.$empty[node.tagName]){
  12298. code += cn.innerText();
  12299. }
  12300. }else{
  12301. code += cn.data
  12302. }
  12303. })
  12304. if(!/\n$/.test(code)){
  12305. code += '\n';
  12306. }
  12307. }
  12308. }else{
  12309. code += node.data + '\n'
  12310. }
  12311. if(!node.nextSibling() && /\n$/.test(code)){
  12312. code = code.replace(/\n$/,'');
  12313. }
  12314. }else{
  12315. if(browser.ie && browser.ie11below){
  12316. if(node.type =='element'){
  12317. if(node.tagName == 'br'){
  12318. code += '<br>'
  12319. }else if(!dtd.$empty[node.tagName]){
  12320. utils.each(node.children,function(cn){
  12321. if(cn.type =='element'){
  12322. if(cn.tagName == 'br'){
  12323. code += '<br>'
  12324. }else if(!dtd.$empty[node.tagName]){
  12325. code += cn.innerText();
  12326. }
  12327. }else{
  12328. code += cn.data
  12329. }
  12330. });
  12331. if(!/br>$/.test(code)){
  12332. code += '<br>';
  12333. }
  12334. }
  12335. }else{
  12336. code += node.data + '<br>'
  12337. }
  12338. if(!node.nextSibling() && /<br>$/.test(code)){
  12339. code = code.replace(/<br>$/,'');
  12340. }
  12341. }else{
  12342. code += (node.type == 'element' ? (dtd.$empty[node.tagName] ? '' : node.innerText()) : node.data);
  12343. if(!/br\/?\s*>$/.test(code)){
  12344. if(!node.nextSibling())
  12345. return;
  12346. code += '<br>'
  12347. }
  12348. }
  12349. }
  12350. });
  12351. }
  12352. me.execCommand('inserthtml','<pre id="coder"class="brush:'+lang+';toolbar:false">'+code+'</pre>',true);
  12353. pre = me.document.getElementById('coder');
  12354. domUtils.removeAttributes(pre,'id');
  12355. var tmpNode = pre.previousSibling;
  12356. if(tmpNode && (tmpNode.nodeType == 3 && tmpNode.nodeValue.length == 1 && browser.ie && browser.version == 6 || domUtils.isEmptyBlock(tmpNode))){
  12357. domUtils.remove(tmpNode)
  12358. }
  12359. var rng = me.selection.getRange();
  12360. if(domUtils.isEmptyBlock(pre)){
  12361. rng.setStart(pre,0).setCursor(false,true)
  12362. }else{
  12363. rng.selectNodeContents(pre).select()
  12364. }
  12365. }
  12366. },
  12367. queryCommandValue : function(){
  12368. var path = this.selection.getStartElementPath();
  12369. var lang = '';
  12370. utils.each(path,function(node){
  12371. if(node.nodeName =='PRE'){
  12372. var match = node.className.match(/brush:([^;]+)/);
  12373. lang = match && match[1] ? match[1] : '';
  12374. return false;
  12375. }
  12376. });
  12377. return lang;
  12378. }
  12379. };
  12380. me.addInputRule(function(root){
  12381. utils.each(root.getNodesByTagName('pre'),function(pre){
  12382. var brs = pre.getNodesByTagName('br');
  12383. if(brs.length){
  12384. browser.ie && browser.ie11below && browser.version > 8 && utils.each(brs,function(br){
  12385. var txt = UE.uNode.createText('\n');
  12386. br.parentNode.insertBefore(txt,br);
  12387. br.parentNode.removeChild(br);
  12388. });
  12389. return;
  12390. }
  12391. if(browser.ie && browser.ie11below && browser.version > 8)
  12392. return;
  12393. var code = pre.innerText().split(/\n/);
  12394. pre.innerHTML('');
  12395. utils.each(code,function(c){
  12396. if(c.length){
  12397. pre.appendChild(UE.uNode.createText(c));
  12398. }
  12399. pre.appendChild(UE.uNode.createElement('br'))
  12400. })
  12401. })
  12402. });
  12403. me.addOutputRule(function(root){
  12404. utils.each(root.getNodesByTagName('pre'),function(pre){
  12405. var code = '';
  12406. utils.each(pre.children,function(n){
  12407. if(n.type == 'text'){
  12408. //在ie下文本内容有可能末尾带有\n要去掉
  12409. //trace:3396
  12410. code += n.data.replace(/[ ]/g,'&nbsp;').replace(/\n$/,'');
  12411. }else{
  12412. if(n.tagName == 'br'){
  12413. code += '\n'
  12414. }else{
  12415. code += (!dtd.$empty[n.tagName] ? '' : n.innerText());
  12416. }
  12417. }
  12418. });
  12419. pre.innerText(code.replace(/(&nbsp;|\n)+$/,''))
  12420. })
  12421. });
  12422. //不需要判断highlight的command列表
  12423. me.notNeedCodeQuery ={
  12424. help:1,
  12425. undo:1,
  12426. redo:1,
  12427. source:1,
  12428. print:1,
  12429. searchreplace:1,
  12430. fullscreen:1,
  12431. preview:1,
  12432. insertparagraph:1,
  12433. elementpath:1,
  12434. insertcode:1,
  12435. inserthtml:1,
  12436. selectall:1
  12437. };
  12438. //将queyCommamndState重置
  12439. var orgQuery = me.queryCommandState;
  12440. me.queryCommandState = function(cmd){
  12441. var me = this;
  12442. if(!me.notNeedCodeQuery[cmd.toLowerCase()] && me.selection && me.queryCommandValue('insertcode')){
  12443. return -1;
  12444. }
  12445. return UE.Editor.prototype.queryCommandState.apply(this,arguments)
  12446. };
  12447. me.addListener('beforeenterkeydown',function(){
  12448. var rng = me.selection.getRange();
  12449. var pre = domUtils.findParentByTagName(rng.startContainer,'pre',true);
  12450. if(pre){
  12451. me.fireEvent('saveScene');
  12452. if(!rng.collapsed){
  12453. rng.deleteContents();
  12454. }
  12455. if(!browser.ie || browser.ie9above){
  12456. var tmpNode = me.document.createElement('br'),pre;
  12457. rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true);
  12458. var next = tmpNode.nextSibling;
  12459. if(!next && (!browser.ie || browser.version > 10)){
  12460. rng.insertNode(tmpNode.cloneNode(false));
  12461. }else{
  12462. rng.setStartAfter(tmpNode);
  12463. }
  12464. pre = tmpNode.previousSibling;
  12465. var tmp;
  12466. while(pre ){
  12467. tmp = pre;
  12468. pre = pre.previousSibling;
  12469. if(!pre || pre.nodeName == 'BR'){
  12470. pre = tmp;
  12471. break;
  12472. }
  12473. }
  12474. if(pre){
  12475. var str = '';
  12476. while(pre && pre.nodeName != 'BR' && new RegExp('^[\\s'+domUtils.fillChar+']*$').test(pre.nodeValue)){
  12477. str += pre.nodeValue;
  12478. pre = pre.nextSibling;
  12479. }
  12480. if(pre.nodeName != 'BR'){
  12481. var match = pre.nodeValue.match(new RegExp('^([\\s'+domUtils.fillChar+']+)'));
  12482. if(match && match[1]){
  12483. str += match[1]
  12484. }
  12485. }
  12486. if(str){
  12487. str = me.document.createTextNode(str);
  12488. rng.insertNode(str).setStartAfter(str);
  12489. }
  12490. }
  12491. rng.collapse(true).select(true);
  12492. }else{
  12493. if(browser.version > 8){
  12494. var txt = me.document.createTextNode('\n');
  12495. var start = rng.startContainer;
  12496. if(rng.startOffset == 0){
  12497. var preNode = start.previousSibling;
  12498. if(preNode){
  12499. rng.insertNode(txt);
  12500. var fillchar = me.document.createTextNode(' ');
  12501. rng.setStartAfter(txt).insertNode(fillchar).setStart(fillchar,0).collapse(true).select(true)
  12502. }
  12503. }else{
  12504. rng.insertNode(txt).setStartAfter(txt);
  12505. var fillchar = me.document.createTextNode(' ');
  12506. start = rng.startContainer.childNodes[rng.startOffset];
  12507. if(start && !/^\n/.test(start.nodeValue)){
  12508. rng.setStartBefore(txt)
  12509. }
  12510. rng.insertNode(fillchar).setStart(fillchar,0).collapse(true).select(true)
  12511. }
  12512. }else{
  12513. var tmpNode = me.document.createElement('br');
  12514. rng.insertNode(tmpNode);
  12515. rng.insertNode(me.document.createTextNode(domUtils.fillChar));
  12516. rng.setStartAfter(tmpNode);
  12517. pre = tmpNode.previousSibling;
  12518. var tmp;
  12519. while(pre ){
  12520. tmp = pre;
  12521. pre = pre.previousSibling;
  12522. if(!pre || pre.nodeName == 'BR'){
  12523. pre = tmp;
  12524. break;
  12525. }
  12526. }
  12527. if(pre){
  12528. var str = '';
  12529. while(pre && pre.nodeName != 'BR' && new RegExp('^[ '+domUtils.fillChar+']*$').test(pre.nodeValue)){
  12530. str += pre.nodeValue;
  12531. pre = pre.nextSibling;
  12532. }
  12533. if(pre.nodeName != 'BR'){
  12534. var match = pre.nodeValue.match(new RegExp('^([ '+domUtils.fillChar+']+)'));
  12535. if(match && match[1]){
  12536. str += match[1]
  12537. }
  12538. }
  12539. str = me.document.createTextNode(str);
  12540. rng.insertNode(str).setStartAfter(str);
  12541. }
  12542. rng.collapse(true).select();
  12543. }
  12544. }
  12545. me.fireEvent('saveScene');
  12546. return true;
  12547. }
  12548. });
  12549. me.addListener('tabkeydown',function(cmd,evt){
  12550. var rng = me.selection.getRange();
  12551. var pre = domUtils.findParentByTagName(rng.startContainer,'pre',true);
  12552. if(pre){
  12553. me.fireEvent('saveScene');
  12554. if(evt.shiftKey){
  12555. }else{
  12556. if(!rng.collapsed){
  12557. var bk = rng.createBookmark();
  12558. var start = bk.start.previousSibling;
  12559. while(start){
  12560. if(pre.firstChild === start && !domUtils.isBr(start)){
  12561. pre.insertBefore(me.document.createTextNode(' '),start);
  12562. break;
  12563. }
  12564. if(domUtils.isBr(start)){
  12565. pre.insertBefore(me.document.createTextNode(' '),start.nextSibling);
  12566. break;
  12567. }
  12568. start = start.previousSibling;
  12569. }
  12570. var end = bk.end;
  12571. start = bk.start.nextSibling;
  12572. if(pre.firstChild === bk.start){
  12573. pre.insertBefore(me.document.createTextNode(' '),start.nextSibling)
  12574. }
  12575. while(start && start !== end){
  12576. if(domUtils.isBr(start) && start.nextSibling){
  12577. if(start.nextSibling === end){
  12578. break;
  12579. }
  12580. pre.insertBefore(me.document.createTextNode(' '),start.nextSibling)
  12581. }
  12582. start = start.nextSibling;
  12583. }
  12584. rng.moveToBookmark(bk).select();
  12585. }else{
  12586. var tmpNode = me.document.createTextNode(' ');
  12587. rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true).select(true);
  12588. }
  12589. }
  12590. me.fireEvent('saveScene');
  12591. return true;
  12592. }
  12593. });
  12594. me.addListener('beforeinserthtml',function(evtName,html){
  12595. var me = this,
  12596. rng = me.selection.getRange(),
  12597. pre = domUtils.findParentByTagName(rng.startContainer,'pre',true);
  12598. if(pre){
  12599. if(!rng.collapsed){
  12600. rng.deleteContents()
  12601. }
  12602. var htmlstr = '';
  12603. if(browser.ie && browser.version > 8){
  12604. utils.each(UE.filterNode(UE.htmlparser(html),me.options.filterTxtRules).children,function(node){
  12605. if(node.type =='element'){
  12606. if(node.tagName == 'br'){
  12607. htmlstr += '\n'
  12608. }else if(!dtd.$empty[node.tagName]){
  12609. utils.each(node.children,function(cn){
  12610. if(cn.type =='element'){
  12611. if(cn.tagName == 'br'){
  12612. htmlstr += '\n'
  12613. }else if(!dtd.$empty[node.tagName]){
  12614. htmlstr += cn.innerText();
  12615. }
  12616. }else{
  12617. htmlstr += cn.data
  12618. }
  12619. })
  12620. if(!/\n$/.test(htmlstr)){
  12621. htmlstr += '\n';
  12622. }
  12623. }
  12624. }else{
  12625. htmlstr += node.data + '\n'
  12626. }
  12627. if(!node.nextSibling() && /\n$/.test(htmlstr)){
  12628. htmlstr = htmlstr.replace(/\n$/,'');
  12629. }
  12630. });
  12631. var tmpNode = me.document.createTextNode(utils.html(htmlstr.replace(/&nbsp;/g,' ')));
  12632. rng.insertNode(tmpNode).selectNode(tmpNode).select();
  12633. }else{
  12634. var frag = me.document.createDocumentFragment();
  12635. utils.each(UE.filterNode(UE.htmlparser(html),me.options.filterTxtRules).children,function(node){
  12636. if(node.type =='element'){
  12637. if(node.tagName == 'br'){
  12638. frag.appendChild(me.document.createElement('br'))
  12639. }else if(!dtd.$empty[node.tagName]){
  12640. utils.each(node.children,function(cn){
  12641. if(cn.type =='element'){
  12642. if(cn.tagName == 'br'){
  12643. frag.appendChild(me.document.createElement('br'))
  12644. }else if(!dtd.$empty[node.tagName]){
  12645. frag.appendChild(me.document.createTextNode(utils.html(cn.innerText().replace(/&nbsp;/g,' '))));
  12646. }
  12647. }else{
  12648. frag.appendChild(me.document.createTextNode(utils.html( cn.data.replace(/&nbsp;/g,' '))));
  12649. }
  12650. })
  12651. if(frag.lastChild.nodeName != 'BR'){
  12652. frag.appendChild(me.document.createElement('br'))
  12653. }
  12654. }
  12655. }else{
  12656. frag.appendChild(me.document.createTextNode(utils.html( node.data.replace(/&nbsp;/g,' '))));
  12657. }
  12658. if(!node.nextSibling() && frag.lastChild.nodeName == 'BR'){
  12659. frag.removeChild(frag.lastChild)
  12660. }
  12661. });
  12662. rng.insertNode(frag).select();
  12663. }
  12664. return true;
  12665. }
  12666. });
  12667. //方向键的处理
  12668. me.addListener('keydown',function(cmd,evt){
  12669. var me = this,keyCode = evt.keyCode || evt.which;
  12670. if(keyCode == 40){
  12671. var rng = me.selection.getRange(),pre,start = rng.startContainer;
  12672. if(rng.collapsed && (pre = domUtils.findParentByTagName(rng.startContainer,'pre',true)) && !pre.nextSibling){
  12673. var last = pre.lastChild
  12674. while(last && last.nodeName == 'BR'){
  12675. last = last.previousSibling;
  12676. }
  12677. if(last === start || rng.startContainer === pre && rng.startOffset == pre.childNodes.length){
  12678. me.execCommand('insertparagraph');
  12679. domUtils.preventDefault(evt)
  12680. }
  12681. }
  12682. }
  12683. });
  12684. //trace:3395
  12685. me.addListener('delkeydown',function(type,evt){
  12686. var rng = this.selection.getRange();
  12687. rng.txtToElmBoundary(true);
  12688. var start = rng.startContainer;
  12689. if(domUtils.isTagNode(start,'pre') && rng.collapsed && domUtils.isStartInblock(rng)){
  12690. var p = me.document.createElement('p');
  12691. domUtils.fillNode(me.document,p);
  12692. start.parentNode.insertBefore(p,start);
  12693. domUtils.remove(start);
  12694. rng.setStart(p,0).setCursor(false,true);
  12695. domUtils.preventDefault(evt);
  12696. return true;
  12697. }
  12698. })
  12699. };
  12700. // plugins/cleardoc.js
  12701. /**
  12702. * 清空文档插件
  12703. * @file
  12704. * @since 1.2.6.1
  12705. */
  12706. /**
  12707. * 清空文档
  12708. * @command cleardoc
  12709. * @method execCommand
  12710. * @param { String } cmd 命令字符串
  12711. * @example
  12712. * ```javascript
  12713. * //editor 是编辑器实例
  12714. * editor.execCommand('cleardoc');
  12715. * ```
  12716. */
  12717. UE.commands['cleardoc'] = {
  12718. execCommand : function( cmdName) {
  12719. var me = this,
  12720. enterTag = me.options.enterTag,
  12721. range = me.selection.getRange();
  12722. if(enterTag == "br"){
  12723. me.body.innerHTML = "<br/>";
  12724. range.setStart(me.body,0).setCursor();
  12725. }else{
  12726. me.body.innerHTML = "<p>"+(ie ? "" : "<br/>")+"</p>";
  12727. range.setStart(me.body.firstChild,0).setCursor(false,true);
  12728. }
  12729. setTimeout(function(){
  12730. me.fireEvent("clearDoc");
  12731. },0);
  12732. }
  12733. };
  12734. // plugins/anchor.js
  12735. /**
  12736. * 锚点插件,为UEditor提供插入锚点支持
  12737. * @file
  12738. * @since 1.2.6.1
  12739. */
  12740. UE.plugin.register('anchor', function (){
  12741. return {
  12742. bindEvents:{
  12743. 'ready':function(){
  12744. utils.cssRule('anchor',
  12745. '.anchorclass{background: url(\''
  12746. + this.options.themePath
  12747. + this.options.theme +'/images/anchor.gif\') no-repeat scroll left center transparent;cursor: auto;display: inline-block;height: 16px;width: 15px;}',
  12748. this.document);
  12749. }
  12750. },
  12751. outputRule: function(root){
  12752. utils.each(root.getNodesByTagName('img'),function(a){
  12753. var val;
  12754. if(val = a.getAttr('anchorname')){
  12755. a.tagName = 'a';
  12756. a.setAttr({
  12757. anchorname : '',
  12758. name : val,
  12759. 'class' : ''
  12760. })
  12761. }
  12762. })
  12763. },
  12764. inputRule:function(root){
  12765. utils.each(root.getNodesByTagName('a'),function(a){
  12766. var val;
  12767. if((val = a.getAttr('name')) && !a.getAttr('href')){
  12768. a.tagName = 'img';
  12769. a.setAttr({
  12770. anchorname :a.getAttr('name'),
  12771. 'class' : 'anchorclass'
  12772. });
  12773. a.setAttr('name')
  12774. }
  12775. })
  12776. },
  12777. commands:{
  12778. /**
  12779. * 插入锚点
  12780. * @command anchor
  12781. * @method execCommand
  12782. * @param { String } cmd 命令字符串
  12783. * @param { String } name 锚点名称字符串
  12784. * @example
  12785. * ```javascript
  12786. * //editor 是编辑器实例
  12787. * editor.execCommand('anchor', 'anchor1');
  12788. * ```
  12789. */
  12790. 'anchor':{
  12791. execCommand:function (cmd, name) {
  12792. var range = this.selection.getRange(),img = range.getClosedNode();
  12793. if (img && img.getAttribute('anchorname')) {
  12794. if (name) {
  12795. img.setAttribute('anchorname', name);
  12796. } else {
  12797. range.setStartBefore(img).setCursor();
  12798. domUtils.remove(img);
  12799. }
  12800. } else {
  12801. if (name) {
  12802. //只在选区的开始插入
  12803. var anchor = this.document.createElement('img');
  12804. range.collapse(true);
  12805. domUtils.setAttributes(anchor,{
  12806. 'anchorname':name,
  12807. 'class':'anchorclass'
  12808. });
  12809. range.insertNode(anchor).setStartAfter(anchor).setCursor(false,true);
  12810. }
  12811. }
  12812. }
  12813. }
  12814. }
  12815. }
  12816. });
  12817. // plugins/wordcount.js
  12818. ///import core
  12819. ///commands 字数统计
  12820. ///commandsName WordCount,wordCount
  12821. ///commandsTitle 字数统计
  12822. /*
  12823. * Created by JetBrains WebStorm.
  12824. * User: taoqili
  12825. * Date: 11-9-7
  12826. * Time: 下午8:18
  12827. * To change this template use File | Settings | File Templates.
  12828. */
  12829. UE.plugins['wordcount'] = function(){
  12830. var me = this;
  12831. me.setOpt('wordCount',true);
  12832. me.addListener('contentchange',function(){
  12833. me.fireEvent('wordcount');
  12834. });
  12835. var timer;
  12836. me.addListener('ready',function(){
  12837. var me = this;
  12838. domUtils.on(me.body,"keyup",function(evt){
  12839. var code = evt.keyCode||evt.which,
  12840. //忽略的按键,ctr,alt,shift,方向键
  12841. ignores = {"16":1,"18":1,"20":1,"37":1,"38":1,"39":1,"40":1};
  12842. if(code in ignores) return;
  12843. clearTimeout(timer);
  12844. timer = setTimeout(function(){
  12845. me.fireEvent('wordcount');
  12846. },200)
  12847. })
  12848. });
  12849. };
  12850. // plugins/pagebreak.js
  12851. /**
  12852. * 分页功能插件
  12853. * @file
  12854. * @since 1.2.6.1
  12855. */
  12856. UE.plugins['pagebreak'] = function () {
  12857. var me = this,
  12858. notBreakTags = ['td'];
  12859. me.setOpt('pageBreakTag','_ueditor_page_break_tag_');
  12860. function fillNode(node){
  12861. if(domUtils.isEmptyBlock(node)){
  12862. var firstChild = node.firstChild,tmpNode;
  12863. while(firstChild && firstChild.nodeType == 1 && domUtils.isEmptyBlock(firstChild)){
  12864. tmpNode = firstChild;
  12865. firstChild = firstChild.firstChild;
  12866. }
  12867. !tmpNode && (tmpNode = node);
  12868. domUtils.fillNode(me.document,tmpNode);
  12869. }
  12870. }
  12871. //分页符样式添加
  12872. me.ready(function(){
  12873. utils.cssRule('pagebreak','.pagebreak{display:block;clear:both !important;cursor:default !important;width: 100% !important;margin:0;}',me.document);
  12874. });
  12875. function isHr(node){
  12876. return node && node.nodeType == 1 && node.tagName == 'HR' && node.className == 'pagebreak';
  12877. }
  12878. me.addInputRule(function(root){
  12879. root.traversal(function(node){
  12880. if(node.type == 'text' && node.data == me.options.pageBreakTag){
  12881. var hr = UE.uNode.createElement('<hr class="pagebreak" noshade="noshade" size="5" style="-webkit-user-select: none;">');
  12882. node.parentNode.insertBefore(hr,node);
  12883. node.parentNode.removeChild(node)
  12884. }
  12885. })
  12886. });
  12887. me.addOutputRule(function(node){
  12888. utils.each(node.getNodesByTagName('hr'),function(n){
  12889. if(n.getAttr('class') == 'pagebreak'){
  12890. var txt = UE.uNode.createText(me.options.pageBreakTag);
  12891. n.parentNode.insertBefore(txt,n);
  12892. n.parentNode.removeChild(n);
  12893. }
  12894. })
  12895. });
  12896. /**
  12897. * 插入分页符
  12898. * @command pagebreak
  12899. * @method execCommand
  12900. * @param { String } cmd 命令字符串
  12901. * @remind 在表格中插入分页符会把表格切分成两部分
  12902. * @remind 获取编辑器内的数据时, 编辑器会把分页符转换成“_ueditor_page_break_tag_”字符串,
  12903. * 以便于提交数据到服务器端后处理分页。
  12904. * @example
  12905. * ```javascript
  12906. * editor.execCommand( 'pagebreak'); //插入一个hr标签,带有样式类名pagebreak
  12907. * ```
  12908. */
  12909. me.commands['pagebreak'] = {
  12910. execCommand:function () {
  12911. var range = me.selection.getRange(),hr = me.document.createElement('hr');
  12912. domUtils.setAttributes(hr,{
  12913. 'class' : 'pagebreak',
  12914. noshade:"noshade",
  12915. size:"5"
  12916. });
  12917. domUtils.unSelectable(hr);
  12918. //table单独处理
  12919. var node = domUtils.findParentByTagName(range.startContainer, notBreakTags, true),
  12920. parents = [], pN;
  12921. if (node) {
  12922. switch (node.tagName) {
  12923. case 'TD':
  12924. pN = node.parentNode;
  12925. if (!pN.previousSibling) {
  12926. var table = domUtils.findParentByTagName(pN, 'table');
  12927. // var tableWrapDiv = table.parentNode;
  12928. // if(tableWrapDiv && tableWrapDiv.nodeType == 1
  12929. // && tableWrapDiv.tagName == 'DIV'
  12930. // && tableWrapDiv.getAttribute('dropdrag')
  12931. // ){
  12932. // domUtils.remove(tableWrapDiv,true);
  12933. // }
  12934. table.parentNode.insertBefore(hr, table);
  12935. parents = domUtils.findParents(hr, true);
  12936. } else {
  12937. pN.parentNode.insertBefore(hr, pN);
  12938. parents = domUtils.findParents(hr);
  12939. }
  12940. pN = parents[1];
  12941. if (hr !== pN) {
  12942. domUtils.breakParent(hr, pN);
  12943. }
  12944. //table要重写绑定一下拖拽
  12945. me.fireEvent('afteradjusttable',me.document);
  12946. }
  12947. } else {
  12948. if (!range.collapsed) {
  12949. range.deleteContents();
  12950. var start = range.startContainer;
  12951. while ( !domUtils.isBody(start) && domUtils.isBlockElm(start) && domUtils.isEmptyNode(start)) {
  12952. range.setStartBefore(start).collapse(true);
  12953. domUtils.remove(start);
  12954. start = range.startContainer;
  12955. }
  12956. }
  12957. range.insertNode(hr);
  12958. var pN = hr.parentNode, nextNode;
  12959. while (!domUtils.isBody(pN)) {
  12960. domUtils.breakParent(hr, pN);
  12961. nextNode = hr.nextSibling;
  12962. if (nextNode && domUtils.isEmptyBlock(nextNode)) {
  12963. domUtils.remove(nextNode);
  12964. }
  12965. pN = hr.parentNode;
  12966. }
  12967. nextNode = hr.nextSibling;
  12968. var pre = hr.previousSibling;
  12969. if(isHr(pre)){
  12970. domUtils.remove(pre);
  12971. }else{
  12972. pre && fillNode(pre);
  12973. }
  12974. if(!nextNode){
  12975. var p = me.document.createElement('p');
  12976. hr.parentNode.appendChild(p);
  12977. domUtils.fillNode(me.document,p);
  12978. range.setStart(p,0).collapse(true);
  12979. }else{
  12980. if(isHr(nextNode)){
  12981. domUtils.remove(nextNode);
  12982. }else{
  12983. fillNode(nextNode);
  12984. }
  12985. range.setEndAfter(hr).collapse(false);
  12986. }
  12987. range.select(true);
  12988. }
  12989. }
  12990. };
  12991. };
  12992. // plugins/wordimage.js
  12993. ///import core
  12994. ///commands 本地图片引导上传
  12995. ///commandsName WordImage
  12996. ///commandsTitle 本地图片引导上传
  12997. ///commandsDialog dialogs\wordimage
  12998. UE.plugin.register('wordimage',function(){
  12999. var me = this,
  13000. images = [];
  13001. return {
  13002. commands : {
  13003. 'wordimage':{
  13004. execCommand:function () {
  13005. var images = domUtils.getElementsByTagName(me.body, "img");
  13006. var urlList = [];
  13007. for (var i = 0, ci; ci = images[i++];) {
  13008. var url = ci.getAttribute("word_img");
  13009. url && urlList.push(url);
  13010. }
  13011. return urlList;
  13012. },
  13013. queryCommandState:function () {
  13014. images = domUtils.getElementsByTagName(me.body, "img");
  13015. for (var i = 0, ci; ci = images[i++];) {
  13016. if (ci.getAttribute("word_img")) {
  13017. return 1;
  13018. }
  13019. }
  13020. return -1;
  13021. },
  13022. notNeedUndo:true
  13023. }
  13024. },
  13025. inputRule : function (root) {
  13026. utils.each(root.getNodesByTagName('img'), function (img) {
  13027. var attrs = img.attrs,
  13028. flag = parseInt(attrs.width) < 128 || parseInt(attrs.height) < 43,
  13029. opt = me.options,
  13030. src = opt.UEDITOR_HOME_URL + 'themes/default/images/spacer.gif';
  13031. if (attrs['src'] && /^(?:(file:\/+))/.test(attrs['src'])) {
  13032. img.setAttr({
  13033. width:attrs.width,
  13034. height:attrs.height,
  13035. alt:attrs.alt,
  13036. word_img: attrs.src,
  13037. src:src,
  13038. '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'
  13039. })
  13040. }
  13041. })
  13042. }
  13043. }
  13044. });
  13045. // plugins/dragdrop.js
  13046. UE.plugins['dragdrop'] = function (){
  13047. var me = this;
  13048. me.ready(function(){
  13049. domUtils.on(this.body,'dragend',function(){
  13050. var rng = me.selection.getRange();
  13051. var node = rng.getClosedNode()||me.selection.getStart();
  13052. if(node && node.tagName == 'IMG'){
  13053. var pre = node.previousSibling,next;
  13054. while(next = node.nextSibling){
  13055. if(next.nodeType == 1 && next.tagName == 'SPAN' && !next.firstChild){
  13056. domUtils.remove(next)
  13057. }else{
  13058. break;
  13059. }
  13060. }
  13061. if((pre && pre.nodeType == 1 && !domUtils.isEmptyBlock(pre) || !pre) && (!next || next && !domUtils.isEmptyBlock(next))){
  13062. if(pre && pre.tagName == 'P' && !domUtils.isEmptyBlock(pre)){
  13063. pre.appendChild(node);
  13064. domUtils.moveChild(next,pre);
  13065. domUtils.remove(next);
  13066. }else if(next && next.tagName == 'P' && !domUtils.isEmptyBlock(next)){
  13067. next.insertBefore(node,next.firstChild);
  13068. }
  13069. if(pre && pre.tagName == 'P' && domUtils.isEmptyBlock(pre)){
  13070. domUtils.remove(pre)
  13071. }
  13072. if(next && next.tagName == 'P' && domUtils.isEmptyBlock(next)){
  13073. domUtils.remove(next)
  13074. }
  13075. rng.selectNode(node).select();
  13076. me.fireEvent('saveScene');
  13077. }
  13078. }
  13079. })
  13080. });
  13081. me.addListener('keyup', function(type, evt) {
  13082. var keyCode = evt.keyCode || evt.which;
  13083. if (keyCode == 13) {
  13084. var rng = me.selection.getRange(),node;
  13085. if(node = domUtils.findParentByTagName(rng.startContainer,'p',true)){
  13086. if(domUtils.getComputedStyle(node,'text-align') == 'center'){
  13087. domUtils.removeStyle(node,'text-align')
  13088. }
  13089. }
  13090. }
  13091. })
  13092. };
  13093. // plugins/undo.js
  13094. /**
  13095. * undo redo
  13096. * @file
  13097. * @since 1.2.6.1
  13098. */
  13099. /**
  13100. * 撤销上一次执行的命令
  13101. * @command undo
  13102. * @method execCommand
  13103. * @param { String } cmd 命令字符串
  13104. * @example
  13105. * ```javascript
  13106. * editor.execCommand( 'undo' );
  13107. * ```
  13108. */
  13109. /**
  13110. * 重做上一次执行的命令
  13111. * @command redo
  13112. * @method execCommand
  13113. * @param { String } cmd 命令字符串
  13114. * @example
  13115. * ```javascript
  13116. * editor.execCommand( 'redo' );
  13117. * ```
  13118. */
  13119. UE.plugins['undo'] = function () {
  13120. var saveSceneTimer;
  13121. var me = this,
  13122. maxUndoCount = me.options.maxUndoCount || 20,
  13123. maxInputCount = me.options.maxInputCount || 20,
  13124. fillchar = new RegExp(domUtils.fillChar + '|<\/hr>', 'gi');// ie会产生多余的</hr>
  13125. var noNeedFillCharTags = {
  13126. ol:1,ul:1,table:1,tbody:1,tr:1,body:1
  13127. };
  13128. var orgState = me.options.autoClearEmptyNode;
  13129. function compareAddr(indexA, indexB) {
  13130. if (indexA.length != indexB.length)
  13131. return 0;
  13132. for (var i = 0, l = indexA.length; i < l; i++) {
  13133. if (indexA[i] != indexB[i])
  13134. return 0
  13135. }
  13136. return 1;
  13137. }
  13138. function compareRangeAddress(rngAddrA, rngAddrB) {
  13139. if (rngAddrA.collapsed != rngAddrB.collapsed) {
  13140. return 0;
  13141. }
  13142. if (!compareAddr(rngAddrA.startAddress, rngAddrB.startAddress) || !compareAddr(rngAddrA.endAddress, rngAddrB.endAddress)) {
  13143. return 0;
  13144. }
  13145. return 1;
  13146. }
  13147. function UndoManager() {
  13148. this.list = [];
  13149. this.index = 0;
  13150. this.hasUndo = false;
  13151. this.hasRedo = false;
  13152. this.undo = function () {
  13153. if (this.hasUndo) {
  13154. if (!this.list[this.index - 1] && this.list.length == 1) {
  13155. this.reset();
  13156. return;
  13157. }
  13158. while (this.list[this.index].content == this.list[this.index - 1].content) {
  13159. this.index--;
  13160. if (this.index == 0) {
  13161. return this.restore(0);
  13162. }
  13163. }
  13164. this.restore(--this.index);
  13165. }
  13166. };
  13167. this.redo = function () {
  13168. if (this.hasRedo) {
  13169. while (this.list[this.index].content == this.list[this.index + 1].content) {
  13170. this.index++;
  13171. if (this.index == this.list.length - 1) {
  13172. return this.restore(this.index);
  13173. }
  13174. }
  13175. this.restore(++this.index);
  13176. }
  13177. };
  13178. this.restore = function () {
  13179. var me = this.editor;
  13180. var scene = this.list[this.index];
  13181. var root = UE.htmlparser(scene.content.replace(fillchar, ''));
  13182. me.options.autoClearEmptyNode = false;
  13183. me.filterInputRule(root);
  13184. me.options.autoClearEmptyNode = orgState;
  13185. //trace:873
  13186. //去掉展位符
  13187. me.document.body.innerHTML = root.toHtml();
  13188. me.fireEvent('afterscencerestore');
  13189. //处理undo后空格不展位的问题
  13190. if (browser.ie) {
  13191. utils.each(domUtils.getElementsByTagName(me.document,'td th caption p'),function(node){
  13192. if(domUtils.isEmptyNode(node)){
  13193. domUtils.fillNode(me.document, node);
  13194. }
  13195. })
  13196. }
  13197. try{
  13198. var rng = new dom.Range(me.document).moveToAddress(scene.address);
  13199. rng.select(noNeedFillCharTags[rng.startContainer.nodeName.toLowerCase()]);
  13200. }catch(e){}
  13201. this.update();
  13202. this.clearKey();
  13203. //不能把自己reset了
  13204. me.fireEvent('reset', true);
  13205. };
  13206. this.getScene = function () {
  13207. var me = this.editor;
  13208. var rng = me.selection.getRange(),
  13209. rngAddress = rng.createAddress(false,true);
  13210. me.fireEvent('beforegetscene');
  13211. var root = UE.htmlparser(me.body.innerHTML);
  13212. me.options.autoClearEmptyNode = false;
  13213. me.filterOutputRule(root);
  13214. me.options.autoClearEmptyNode = orgState;
  13215. var cont = root.toHtml();
  13216. //trace:3461
  13217. //这个会引起回退时导致空格丢失的情况
  13218. // browser.ie && (cont = cont.replace(/>&nbsp;</g, '><').replace(/\s*</g, '<').replace(/>\s*/g, '>'));
  13219. me.fireEvent('aftergetscene');
  13220. return {
  13221. address:rngAddress,
  13222. content:cont
  13223. }
  13224. };
  13225. this.save = function (notCompareRange,notSetCursor) {
  13226. clearTimeout(saveSceneTimer);
  13227. var currentScene = this.getScene(notSetCursor),
  13228. lastScene = this.list[this.index];
  13229. if(lastScene && lastScene.content != currentScene.content){
  13230. me.trigger('contentchange')
  13231. }
  13232. //内容相同位置相同不存
  13233. if (lastScene && lastScene.content == currentScene.content &&
  13234. ( notCompareRange ? 1 : compareRangeAddress(lastScene.address, currentScene.address) )
  13235. ) {
  13236. return;
  13237. }
  13238. this.list = this.list.slice(0, this.index + 1);
  13239. this.list.push(currentScene);
  13240. //如果大于最大数量了,就把最前的剔除
  13241. if (this.list.length > maxUndoCount) {
  13242. this.list.shift();
  13243. }
  13244. this.index = this.list.length - 1;
  13245. this.clearKey();
  13246. //跟新undo/redo状态
  13247. this.update();
  13248. };
  13249. this.update = function () {
  13250. this.hasRedo = !!this.list[this.index + 1];
  13251. this.hasUndo = !!this.list[this.index - 1];
  13252. };
  13253. this.reset = function () {
  13254. this.list = [];
  13255. this.index = 0;
  13256. this.hasUndo = false;
  13257. this.hasRedo = false;
  13258. this.clearKey();
  13259. };
  13260. this.clearKey = function () {
  13261. keycont = 0;
  13262. lastKeyCode = null;
  13263. };
  13264. }
  13265. me.undoManger = new UndoManager();
  13266. me.undoManger.editor = me;
  13267. function saveScene() {
  13268. this.undoManger.save();
  13269. }
  13270. me.addListener('saveScene', function () {
  13271. var args = Array.prototype.splice.call(arguments,1);
  13272. this.undoManger.save.apply(this.undoManger,args);
  13273. });
  13274. // me.addListener('beforeexeccommand', saveScene);
  13275. // me.addListener('afterexeccommand', saveScene);
  13276. me.addListener('reset', function (type, exclude) {
  13277. if (!exclude) {
  13278. this.undoManger.reset();
  13279. }
  13280. });
  13281. me.commands['redo'] = me.commands['undo'] = {
  13282. execCommand:function (cmdName) {
  13283. this.undoManger[cmdName]();
  13284. },
  13285. queryCommandState:function (cmdName) {
  13286. return this.undoManger['has' + (cmdName.toLowerCase() == 'undo' ? 'Undo' : 'Redo')] ? 0 : -1;
  13287. },
  13288. notNeedUndo:1
  13289. };
  13290. var keys = {
  13291. // /*Backspace*/ 8:1, /*Delete*/ 46:1,
  13292. /*Shift*/ 16:1, /*Ctrl*/ 17:1, /*Alt*/ 18:1,
  13293. 37:1, 38:1, 39:1, 40:1
  13294. },
  13295. keycont = 0,
  13296. lastKeyCode;
  13297. //输入法状态下不计算字符数
  13298. var inputType = false;
  13299. me.addListener('ready', function () {
  13300. domUtils.on(this.body, 'compositionstart', function () {
  13301. inputType = true;
  13302. });
  13303. domUtils.on(this.body, 'compositionend', function () {
  13304. inputType = false;
  13305. })
  13306. });
  13307. //快捷键
  13308. me.addshortcutkey({
  13309. "Undo":"ctrl+90", //undo
  13310. "Redo":"ctrl+89" //redo
  13311. });
  13312. var isCollapsed = true;
  13313. me.addListener('keydown', function (type, evt) {
  13314. var me = this;
  13315. var keyCode = evt.keyCode || evt.which;
  13316. if (!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
  13317. if (inputType)
  13318. return;
  13319. if(!me.selection.getRange().collapsed){
  13320. me.undoManger.save(false,true);
  13321. isCollapsed = false;
  13322. return;
  13323. }
  13324. if (me.undoManger.list.length == 0) {
  13325. me.undoManger.save(true);
  13326. }
  13327. clearTimeout(saveSceneTimer);
  13328. function save(cont){
  13329. cont.undoManger.save(false,true);
  13330. cont.fireEvent('selectionchange');
  13331. }
  13332. saveSceneTimer = setTimeout(function(){
  13333. if(inputType){
  13334. var interalTimer = setInterval(function(){
  13335. if(!inputType){
  13336. save(me);
  13337. clearInterval(interalTimer)
  13338. }
  13339. },300)
  13340. return;
  13341. }
  13342. save(me);
  13343. },200);
  13344. lastKeyCode = keyCode;
  13345. keycont++;
  13346. if (keycont >= maxInputCount ) {
  13347. save(me)
  13348. }
  13349. }
  13350. });
  13351. me.addListener('keyup', function (type, evt) {
  13352. var keyCode = evt.keyCode || evt.which;
  13353. if (!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
  13354. if (inputType)
  13355. return;
  13356. if(!isCollapsed){
  13357. this.undoManger.save(false,true);
  13358. isCollapsed = true;
  13359. }
  13360. }
  13361. });
  13362. //扩展实例,添加关闭和开启命令undo
  13363. me.stopCmdUndo = function(){
  13364. me.__hasEnterExecCommand = true;
  13365. };
  13366. me.startCmdUndo = function(){
  13367. me.__hasEnterExecCommand = false;
  13368. }
  13369. };
  13370. // plugins/copy.js
  13371. UE.plugin.register('copy', function () {
  13372. var me = this;
  13373. function initZeroClipboard() {
  13374. ZeroClipboard.config({
  13375. debug: false,
  13376. swfPath: me.options.UEDITOR_HOME_URL + 'third-party/zeroclipboard/ZeroClipboard.swf'
  13377. });
  13378. var client = me.zeroclipboard = new ZeroClipboard();
  13379. // 复制内容
  13380. client.on('copy', function (e) {
  13381. var client = e.client,
  13382. rng = me.selection.getRange(),
  13383. div = document.createElement('div');
  13384. div.appendChild(rng.cloneContents());
  13385. client.setText(div.innerText || div.textContent);
  13386. client.setHtml(div.innerHTML);
  13387. rng.select();
  13388. });
  13389. // hover事件传递到target
  13390. client.on('mouseover mouseout', function (e) {
  13391. var target = e.target;
  13392. if (e.type == 'mouseover') {
  13393. domUtils.addClass(target, 'edui-state-hover');
  13394. } else if (e.type == 'mouseout') {
  13395. domUtils.removeClasses(target, 'edui-state-hover');
  13396. }
  13397. });
  13398. // flash加载不成功
  13399. client.on('wrongflash noflash', function () {
  13400. ZeroClipboard.destroy();
  13401. });
  13402. }
  13403. return {
  13404. bindEvents: {
  13405. 'ready': function () {
  13406. if (!browser.ie) {
  13407. if (window.ZeroClipboard) {
  13408. initZeroClipboard();
  13409. } else {
  13410. utils.loadFile(document, {
  13411. src: me.options.UEDITOR_HOME_URL + "third-party/zeroclipboard/ZeroClipboard.js",
  13412. tag: "script",
  13413. type: "text/javascript",
  13414. defer: "defer"
  13415. }, function () {
  13416. initZeroClipboard();
  13417. });
  13418. }
  13419. }
  13420. }
  13421. },
  13422. commands: {
  13423. 'copy': {
  13424. execCommand: function (cmd) {
  13425. if (!me.document.execCommand('copy')) {
  13426. alert(me.getLang('copymsg'));
  13427. }
  13428. }
  13429. }
  13430. }
  13431. }
  13432. });
  13433. // plugins/paste.js
  13434. ///import core
  13435. ///import plugins/inserthtml.js
  13436. ///import plugins/undo.js
  13437. ///import plugins/serialize.js
  13438. ///commands 粘贴
  13439. ///commandsName PastePlain
  13440. ///commandsTitle 纯文本粘贴模式
  13441. /**
  13442. * @description 粘贴
  13443. * @author zhanyi
  13444. */
  13445. UE.plugins['paste'] = function () {
  13446. function getClipboardData(callback) {
  13447. var doc = this.document;
  13448. if (doc.getElementById('baidu_pastebin')) {
  13449. return;
  13450. }
  13451. var range = this.selection.getRange(),
  13452. bk = range.createBookmark(),
  13453. //创建剪贴的容器div
  13454. pastebin = doc.createElement('div');
  13455. pastebin.id = 'baidu_pastebin';
  13456. // Safari 要求div必须有内容,才能粘贴内容进来
  13457. browser.webkit && pastebin.appendChild(doc.createTextNode(domUtils.fillChar + domUtils.fillChar));
  13458. doc.body.appendChild(pastebin);
  13459. //trace:717 隐藏的span不能得到top
  13460. //bk.start.innerHTML = '&nbsp;';
  13461. bk.start.style.display = '';
  13462. pastebin.style.cssText = "position:absolute;width:1px;height:1px;overflow:hidden;left:-1000px;white-space:nowrap;top:" +
  13463. //要在现在光标平行的位置加入,否则会出现跳动的问题
  13464. domUtils.getXY(bk.start).y + 'px';
  13465. range.selectNodeContents(pastebin).select(true);
  13466. setTimeout(function () {
  13467. if (browser.webkit) {
  13468. for (var i = 0, pastebins = doc.querySelectorAll('#baidu_pastebin'), pi; pi = pastebins[i++];) {
  13469. if (domUtils.isEmptyNode(pi)) {
  13470. domUtils.remove(pi);
  13471. } else {
  13472. pastebin = pi;
  13473. break;
  13474. }
  13475. }
  13476. }
  13477. try {
  13478. pastebin.parentNode.removeChild(pastebin);
  13479. } catch (e) {
  13480. }
  13481. range.moveToBookmark(bk).select(true);
  13482. callback(pastebin);
  13483. }, 0);
  13484. }
  13485. var me = this;
  13486. me.setOpt({
  13487. retainOnlyLabelPasted : false
  13488. });
  13489. var txtContent, htmlContent, address;
  13490. function getPureHtml(html){
  13491. return html.replace(/<(\/?)([\w\-]+)([^>]*)>/gi, function (a, b, tagName, attrs) {
  13492. tagName = tagName.toLowerCase();
  13493. if ({img: 1}[tagName]) {
  13494. return a;
  13495. }
  13496. attrs = attrs.replace(/([\w\-]*?)\s*=\s*(("([^"]*)")|('([^']*)')|([^\s>]+))/gi, function (str, atr, val) {
  13497. if ({
  13498. 'src': 1,
  13499. 'href': 1,
  13500. 'name': 1
  13501. }[atr.toLowerCase()]) {
  13502. return atr + '=' + val + ' '
  13503. }
  13504. return ''
  13505. });
  13506. if ({
  13507. 'span': 1,
  13508. 'div': 1
  13509. }[tagName]) {
  13510. return ''
  13511. } else {
  13512. return '<' + b + tagName + ' ' + utils.trim(attrs) + '>'
  13513. }
  13514. });
  13515. }
  13516. function filter(div) {
  13517. var html;
  13518. if (div.firstChild) {
  13519. //去掉cut中添加的边界值
  13520. var nodes = domUtils.getElementsByTagName(div, 'span');
  13521. for (var i = 0, ni; ni = nodes[i++];) {
  13522. if (ni.id == '_baidu_cut_start' || ni.id == '_baidu_cut_end') {
  13523. domUtils.remove(ni);
  13524. }
  13525. }
  13526. if (browser.webkit) {
  13527. var brs = div.querySelectorAll('div br');
  13528. for (var i = 0, bi; bi = brs[i++];) {
  13529. var pN = bi.parentNode;
  13530. if (pN.tagName == 'DIV' && pN.childNodes.length == 1) {
  13531. pN.innerHTML = '<p><br/></p>';
  13532. domUtils.remove(pN);
  13533. }
  13534. }
  13535. var divs = div.querySelectorAll('#baidu_pastebin');
  13536. for (var i = 0, di; di = divs[i++];) {
  13537. var tmpP = me.document.createElement('p');
  13538. di.parentNode.insertBefore(tmpP, di);
  13539. while (di.firstChild) {
  13540. tmpP.appendChild(di.firstChild);
  13541. }
  13542. domUtils.remove(di);
  13543. }
  13544. var metas = div.querySelectorAll('meta');
  13545. for (var i = 0, ci; ci = metas[i++];) {
  13546. domUtils.remove(ci);
  13547. }
  13548. var brs = div.querySelectorAll('br');
  13549. for (i = 0; ci = brs[i++];) {
  13550. if (/^apple-/i.test(ci.className)) {
  13551. domUtils.remove(ci);
  13552. }
  13553. }
  13554. }
  13555. if (browser.gecko) {
  13556. var dirtyNodes = div.querySelectorAll('[_moz_dirty]');
  13557. for (i = 0; ci = dirtyNodes[i++];) {
  13558. ci.removeAttribute('_moz_dirty');
  13559. }
  13560. }
  13561. if (!browser.ie) {
  13562. var spans = div.querySelectorAll('span.Apple-style-span');
  13563. for (var i = 0, ci; ci = spans[i++];) {
  13564. domUtils.remove(ci, true);
  13565. }
  13566. }
  13567. //ie下使用innerHTML会产生多余的\r\n字符,也会产生&nbsp;这里过滤掉
  13568. html = div.innerHTML;//.replace(/>(?:(\s|&nbsp;)*?)</g,'><');
  13569. //过滤word粘贴过来的冗余属性
  13570. html = UE.filterWord(html);
  13571. //取消了忽略空白的第二个参数,粘贴过来的有些是有空白的,会被套上相关的标签
  13572. var root = UE.htmlparser(html);
  13573. //如果给了过滤规则就先进行过滤
  13574. if (me.options.filterRules) {
  13575. UE.filterNode(root, me.options.filterRules);
  13576. }
  13577. //执行默认的处理
  13578. me.filterInputRule(root);
  13579. //针对chrome的处理
  13580. if (browser.webkit) {
  13581. var br = root.lastChild();
  13582. if (br && br.type == 'element' && br.tagName == 'br') {
  13583. root.removeChild(br)
  13584. }
  13585. utils.each(me.body.querySelectorAll('div'), function (node) {
  13586. if (domUtils.isEmptyBlock(node)) {
  13587. domUtils.remove(node,true)
  13588. }
  13589. })
  13590. }
  13591. html = {'html': root.toHtml()};
  13592. me.fireEvent('beforepaste', html, root);
  13593. //抢了默认的粘贴,那后边的内容就不执行了,比如表格粘贴
  13594. if(!html.html){
  13595. return;
  13596. }
  13597. root = UE.htmlparser(html.html,true);
  13598. //如果开启了纯文本模式
  13599. if (me.queryCommandState('pasteplain') === 1) {
  13600. me.execCommand('insertHtml', UE.filterNode(root, me.options.filterTxtRules).toHtml(), true);
  13601. } else {
  13602. //文本模式
  13603. UE.filterNode(root, me.options.filterTxtRules);
  13604. txtContent = root.toHtml();
  13605. //完全模式
  13606. htmlContent = html.html;
  13607. address = me.selection.getRange().createAddress(true);
  13608. me.execCommand('insertHtml', me.getOpt('retainOnlyLabelPasted') === true ? getPureHtml(htmlContent) : htmlContent, true);
  13609. }
  13610. me.fireEvent("afterpaste", html);
  13611. }
  13612. }
  13613. me.addListener('pasteTransfer', function (cmd, plainType) {
  13614. if (address && txtContent && htmlContent && txtContent != htmlContent) {
  13615. var range = me.selection.getRange();
  13616. range.moveToAddress(address, true);
  13617. if (!range.collapsed) {
  13618. while (!domUtils.isBody(range.startContainer)
  13619. ) {
  13620. var start = range.startContainer;
  13621. if(start.nodeType == 1){
  13622. start = start.childNodes[range.startOffset];
  13623. if(!start){
  13624. range.setStartBefore(range.startContainer);
  13625. continue;
  13626. }
  13627. var pre = start.previousSibling;
  13628. if(pre && pre.nodeType == 3 && new RegExp('^[\n\r\t '+domUtils.fillChar+']*$').test(pre.nodeValue)){
  13629. range.setStartBefore(pre)
  13630. }
  13631. }
  13632. if(range.startOffset == 0){
  13633. range.setStartBefore(range.startContainer);
  13634. }else{
  13635. break;
  13636. }
  13637. }
  13638. while (!domUtils.isBody(range.endContainer)
  13639. ) {
  13640. var end = range.endContainer;
  13641. if(end.nodeType == 1){
  13642. end = end.childNodes[range.endOffset];
  13643. if(!end){
  13644. range.setEndAfter(range.endContainer);
  13645. continue;
  13646. }
  13647. var next = end.nextSibling;
  13648. if(next && next.nodeType == 3 && new RegExp('^[\n\r\t'+domUtils.fillChar+']*$').test(next.nodeValue)){
  13649. range.setEndAfter(next)
  13650. }
  13651. }
  13652. if(range.endOffset == range.endContainer[range.endContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length){
  13653. range.setEndAfter(range.endContainer);
  13654. }else{
  13655. break;
  13656. }
  13657. }
  13658. }
  13659. range.deleteContents();
  13660. range.select(true);
  13661. me.__hasEnterExecCommand = true;
  13662. var html = htmlContent;
  13663. if (plainType === 2 ) {
  13664. html = getPureHtml(html);
  13665. } else if (plainType) {
  13666. html = txtContent;
  13667. }
  13668. me.execCommand('inserthtml', html, true);
  13669. me.__hasEnterExecCommand = false;
  13670. var rng = me.selection.getRange();
  13671. while (!domUtils.isBody(rng.startContainer) && !rng.startOffset &&
  13672. rng.startContainer[rng.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length
  13673. ) {
  13674. rng.setStartBefore(rng.startContainer);
  13675. }
  13676. var tmpAddress = rng.createAddress(true);
  13677. address.endAddress = tmpAddress.startAddress;
  13678. }
  13679. });
  13680. me.addListener('ready', function () {
  13681. domUtils.on(me.body, 'cut', function () {
  13682. var range = me.selection.getRange();
  13683. if (!range.collapsed && me.undoManger) {
  13684. me.undoManger.save();
  13685. }
  13686. });
  13687. //ie下beforepaste在点击右键时也会触发,所以用监控键盘才处理
  13688. domUtils.on(me.body, browser.ie || browser.opera ? 'keydown' : 'paste', function (e) {
  13689. if ((browser.ie || browser.opera) && ((!e.ctrlKey && !e.metaKey) || e.keyCode != '86')) {
  13690. return;
  13691. }
  13692. getClipboardData.call(me, function (div) {
  13693. filter(div);
  13694. });
  13695. });
  13696. });
  13697. me.commands['paste'] = {
  13698. execCommand: function (cmd) {
  13699. if (browser.ie) {
  13700. getClipboardData.call(me, function (div) {
  13701. filter(div);
  13702. });
  13703. me.document.execCommand('paste');
  13704. } else {
  13705. alert(me.getLang('pastemsg'));
  13706. }
  13707. }
  13708. }
  13709. };
  13710. // plugins/puretxtpaste.js
  13711. /**
  13712. * 纯文本粘贴插件
  13713. * @file
  13714. * @since 1.2.6.1
  13715. */
  13716. UE.plugins['pasteplain'] = function(){
  13717. var me = this;
  13718. me.setOpt({
  13719. 'pasteplain':false,
  13720. 'filterTxtRules' : function(){
  13721. function transP(node){
  13722. node.tagName = 'p';
  13723. node.setStyle();
  13724. }
  13725. function removeNode(node){
  13726. node.parentNode.removeChild(node,true)
  13727. }
  13728. return {
  13729. //直接删除及其字节点内容
  13730. '-' : 'script style object iframe embed input select',
  13731. 'p': {$:{}},
  13732. 'br':{$:{}},
  13733. div: function (node) {
  13734. var tmpNode, p = UE.uNode.createElement('p');
  13735. while (tmpNode = node.firstChild()) {
  13736. if (tmpNode.type == 'text' || !UE.dom.dtd.$block[tmpNode.tagName]) {
  13737. p.appendChild(tmpNode);
  13738. } else {
  13739. if (p.firstChild()) {
  13740. node.parentNode.insertBefore(p, node);
  13741. p = UE.uNode.createElement('p');
  13742. } else {
  13743. node.parentNode.insertBefore(tmpNode, node);
  13744. }
  13745. }
  13746. }
  13747. if (p.firstChild()) {
  13748. node.parentNode.insertBefore(p, node);
  13749. }
  13750. node.parentNode.removeChild(node);
  13751. },
  13752. ol: removeNode,
  13753. ul: removeNode,
  13754. dl:removeNode,
  13755. dt:removeNode,
  13756. dd:removeNode,
  13757. 'li':removeNode,
  13758. 'caption':transP,
  13759. 'th':transP,
  13760. 'tr':transP,
  13761. 'h1':transP,'h2':transP,'h3':transP,'h4':transP,'h5':transP,'h6':transP,
  13762. 'td':function(node){
  13763. //没有内容的td直接删掉
  13764. var txt = !!node.innerText();
  13765. if(txt){
  13766. node.parentNode.insertAfter(UE.uNode.createText(' &nbsp; &nbsp;'),node);
  13767. }
  13768. node.parentNode.removeChild(node,node.innerText())
  13769. }
  13770. }
  13771. }()
  13772. });
  13773. //暂时这里支持一下老版本的属性
  13774. var pasteplain = me.options.pasteplain;
  13775. /**
  13776. * 启用或取消纯文本粘贴模式
  13777. * @command pasteplain
  13778. * @method execCommand
  13779. * @param { String } cmd 命令字符串
  13780. * @example
  13781. * ```javascript
  13782. * editor.queryCommandState( 'pasteplain' );
  13783. * ```
  13784. */
  13785. /**
  13786. * 查询当前是否处于纯文本粘贴模式
  13787. * @command pasteplain
  13788. * @method queryCommandState
  13789. * @param { String } cmd 命令字符串
  13790. * @return { int } 如果处于纯文本模式,返回1,否则,返回0
  13791. * @example
  13792. * ```javascript
  13793. * editor.queryCommandState( 'pasteplain' );
  13794. * ```
  13795. */
  13796. me.commands['pasteplain'] = {
  13797. queryCommandState: function (){
  13798. return pasteplain ? 1 : 0;
  13799. },
  13800. execCommand: function (){
  13801. pasteplain = !pasteplain|0;
  13802. },
  13803. notNeedUndo : 1
  13804. };
  13805. };
  13806. // plugins/list.js
  13807. /**
  13808. * 有序列表,无序列表插件
  13809. * @file
  13810. * @since 1.2.6.1
  13811. */
  13812. UE.plugins['list'] = function () {
  13813. var me = this,
  13814. notExchange = {
  13815. 'TD':1,
  13816. 'PRE':1,
  13817. 'BLOCKQUOTE':1
  13818. };
  13819. var customStyle = {
  13820. 'cn' : 'cn-1-',
  13821. 'cn1' : 'cn-2-',
  13822. 'cn2' : 'cn-3-',
  13823. 'num': 'num-1-',
  13824. 'num1' : 'num-2-',
  13825. 'num2' : 'num-3-',
  13826. 'dash' : 'dash',
  13827. 'dot':'dot'
  13828. };
  13829. me.setOpt( {
  13830. 'autoTransWordToList':false,
  13831. 'insertorderedlist':{
  13832. 'num':'',
  13833. 'num1':'',
  13834. 'num2':'',
  13835. 'cn':'',
  13836. 'cn1':'',
  13837. 'cn2':'',
  13838. 'decimal':'',
  13839. 'lower-alpha':'',
  13840. 'lower-roman':'',
  13841. 'upper-alpha':'',
  13842. 'upper-roman':''
  13843. },
  13844. 'insertunorderedlist':{
  13845. 'circle':'',
  13846. 'disc':'',
  13847. 'square':'',
  13848. 'dash' : '',
  13849. 'dot':''
  13850. },
  13851. listDefaultPaddingLeft : '30',
  13852. listiconpath : 'http://bs.baidu.com/listicon/',
  13853. maxListLevel : -1,//-1不限制
  13854. disablePInList:false
  13855. } );
  13856. function listToArray(list){
  13857. var arr = [];
  13858. for(var p in list){
  13859. arr.push(p)
  13860. }
  13861. return arr;
  13862. }
  13863. var listStyle = {
  13864. 'OL':listToArray(me.options.insertorderedlist),
  13865. 'UL':listToArray(me.options.insertunorderedlist)
  13866. };
  13867. var liiconpath = me.options.listiconpath;
  13868. //根据用户配置,调整customStyle
  13869. for(var s in customStyle){
  13870. if(!me.options.insertorderedlist.hasOwnProperty(s) && !me.options.insertunorderedlist.hasOwnProperty(s)){
  13871. delete customStyle[s];
  13872. }
  13873. }
  13874. me.ready(function () {
  13875. var customCss = [];
  13876. for(var p in customStyle){
  13877. if(p == 'dash' || p == 'dot'){
  13878. customCss.push('li.list-' + customStyle[p] + '{background-image:url(' + liiconpath +customStyle[p]+'.gif)}');
  13879. customCss.push('ul.custom_'+p+'{list-style:none;}ul.custom_'+p+' li{background-position:0 3px;background-repeat:no-repeat}');
  13880. }else{
  13881. for(var i= 0;i<99;i++){
  13882. customCss.push('li.list-' + customStyle[p] + i + '{background-image:url(' + liiconpath + 'list-'+customStyle[p] + i + '.gif)}')
  13883. }
  13884. customCss.push('ol.custom_'+p+'{list-style:none;}ol.custom_'+p+' li{background-position:0 3px;background-repeat:no-repeat}');
  13885. }
  13886. switch(p){
  13887. case 'cn':
  13888. customCss.push('li.list-'+p+'-paddingleft-1{padding-left:25px}');
  13889. customCss.push('li.list-'+p+'-paddingleft-2{padding-left:40px}');
  13890. customCss.push('li.list-'+p+'-paddingleft-3{padding-left:55px}');
  13891. break;
  13892. case 'cn1':
  13893. customCss.push('li.list-'+p+'-paddingleft-1{padding-left:30px}');
  13894. customCss.push('li.list-'+p+'-paddingleft-2{padding-left:40px}');
  13895. customCss.push('li.list-'+p+'-paddingleft-3{padding-left:55px}');
  13896. break;
  13897. case 'cn2':
  13898. customCss.push('li.list-'+p+'-paddingleft-1{padding-left:40px}');
  13899. customCss.push('li.list-'+p+'-paddingleft-2{padding-left:55px}');
  13900. customCss.push('li.list-'+p+'-paddingleft-3{padding-left:68px}');
  13901. break;
  13902. case 'num':
  13903. case 'num1':
  13904. customCss.push('li.list-'+p+'-paddingleft-1{padding-left:25px}');
  13905. break;
  13906. case 'num2':
  13907. customCss.push('li.list-'+p+'-paddingleft-1{padding-left:35px}');
  13908. customCss.push('li.list-'+p+'-paddingleft-2{padding-left:40px}');
  13909. break;
  13910. case 'dash':
  13911. customCss.push('li.list-'+p+'-paddingleft{padding-left:35px}');
  13912. break;
  13913. case 'dot':
  13914. customCss.push('li.list-'+p+'-paddingleft{padding-left:20px}');
  13915. }
  13916. }
  13917. customCss.push('.list-paddingleft-1{padding-left:0}');
  13918. customCss.push('.list-paddingleft-2{padding-left:'+me.options.listDefaultPaddingLeft+'px}');
  13919. customCss.push('.list-paddingleft-3{padding-left:'+me.options.listDefaultPaddingLeft*2+'px}');
  13920. //如果不给宽度会在自定应样式里出现滚动条
  13921. utils.cssRule('list', 'ol,ul{margin:0;pading:0;'+(browser.ie ? '' : 'width:95%')+'}li{clear:both;}'+customCss.join('\n'), me.document);
  13922. });
  13923. //单独处理剪切的问题
  13924. me.ready(function(){
  13925. domUtils.on(me.body,'cut',function(){
  13926. setTimeout(function(){
  13927. var rng = me.selection.getRange(),li;
  13928. //trace:3416
  13929. if(!rng.collapsed){
  13930. if(li = domUtils.findParentByTagName(rng.startContainer,'li',true)){
  13931. if(!li.nextSibling && domUtils.isEmptyBlock(li)){
  13932. var pn = li.parentNode,node;
  13933. if(node = pn.previousSibling){
  13934. domUtils.remove(pn);
  13935. rng.setStartAtLast(node).collapse(true);
  13936. rng.select(true);
  13937. }else if(node = pn.nextSibling){
  13938. domUtils.remove(pn);
  13939. rng.setStartAtFirst(node).collapse(true);
  13940. rng.select(true);
  13941. }else{
  13942. var tmpNode = me.document.createElement('p');
  13943. domUtils.fillNode(me.document,tmpNode);
  13944. pn.parentNode.insertBefore(tmpNode,pn);
  13945. domUtils.remove(pn);
  13946. rng.setStart(tmpNode,0).collapse(true);
  13947. rng.select(true);
  13948. }
  13949. }
  13950. }
  13951. }
  13952. })
  13953. })
  13954. });
  13955. function getStyle(node){
  13956. var cls = node.className;
  13957. if(domUtils.hasClass(node,/custom_/)){
  13958. return cls.match(/custom_(\w+)/)[1]
  13959. }
  13960. return domUtils.getStyle(node, 'list-style-type')
  13961. }
  13962. me.addListener('beforepaste',function(type,html){
  13963. var me = this,
  13964. rng = me.selection.getRange(),li;
  13965. var root = UE.htmlparser(html.html,true);
  13966. if(li = domUtils.findParentByTagName(rng.startContainer,'li',true)){
  13967. var list = li.parentNode,tagName = list.tagName == 'OL' ? 'ul':'ol';
  13968. utils.each(root.getNodesByTagName(tagName),function(n){
  13969. n.tagName = list.tagName;
  13970. n.setAttr();
  13971. if(n.parentNode === root){
  13972. type = getStyle(list) || (list.tagName == 'OL' ? 'decimal' : 'disc')
  13973. }else{
  13974. var className = n.parentNode.getAttr('class');
  13975. if(className && /custom_/.test(className)){
  13976. type = className.match(/custom_(\w+)/)[1]
  13977. }else{
  13978. type = n.parentNode.getStyle('list-style-type');
  13979. }
  13980. if(!type){
  13981. type = list.tagName == 'OL' ? 'decimal' : 'disc';
  13982. }
  13983. }
  13984. var index = utils.indexOf(listStyle[list.tagName], type);
  13985. if(n.parentNode !== root)
  13986. index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
  13987. var currentStyle = listStyle[list.tagName][index];
  13988. if(customStyle[currentStyle]){
  13989. n.setAttr('class', 'custom_' + currentStyle)
  13990. }else{
  13991. n.setStyle('list-style-type',currentStyle)
  13992. }
  13993. })
  13994. }
  13995. html.html = root.toHtml();
  13996. });
  13997. //导出时,去掉p标签
  13998. me.getOpt('disablePInList') === true && me.addOutputRule(function(root){
  13999. utils.each(root.getNodesByTagName('li'),function(li){
  14000. var newChildrens = [],index=0;
  14001. utils.each(li.children,function(n){
  14002. if(n.tagName == 'p'){
  14003. var tmpNode;
  14004. while(tmpNode = n.children.pop()) {
  14005. newChildrens.splice(index,0,tmpNode);
  14006. tmpNode.parentNode = li;
  14007. lastNode = tmpNode;
  14008. }
  14009. tmpNode = newChildrens[newChildrens.length-1];
  14010. if(!tmpNode || tmpNode.type != 'element' || tmpNode.tagName != 'br'){
  14011. var br = UE.uNode.createElement('br');
  14012. br.parentNode = li;
  14013. newChildrens.push(br);
  14014. }
  14015. index = newChildrens.length;
  14016. }
  14017. });
  14018. if(newChildrens.length){
  14019. li.children = newChildrens;
  14020. }
  14021. });
  14022. });
  14023. //进入编辑器的li要套p标签
  14024. me.addInputRule(function(root){
  14025. utils.each(root.getNodesByTagName('li'),function(li){
  14026. var tmpP = UE.uNode.createElement('p');
  14027. for(var i= 0,ci;ci=li.children[i];){
  14028. if(ci.type == 'text' || dtd.p[ci.tagName]){
  14029. tmpP.appendChild(ci);
  14030. }else{
  14031. if(tmpP.firstChild()){
  14032. li.insertBefore(tmpP,ci);
  14033. tmpP = UE.uNode.createElement('p');
  14034. i = i + 2;
  14035. }else{
  14036. i++;
  14037. }
  14038. }
  14039. }
  14040. if(tmpP.firstChild() && !tmpP.parentNode || !li.firstChild()){
  14041. li.appendChild(tmpP);
  14042. }
  14043. //trace:3357
  14044. //p不能为空
  14045. if (!tmpP.firstChild()) {
  14046. tmpP.innerHTML(browser.ie ? '&nbsp;' : '<br/>')
  14047. }
  14048. //去掉末尾的空白
  14049. var p = li.firstChild();
  14050. var lastChild = p.lastChild();
  14051. if(lastChild && lastChild.type == 'text' && /^\s*$/.test(lastChild.data)){
  14052. p.removeChild(lastChild)
  14053. }
  14054. });
  14055. if(me.options.autoTransWordToList){
  14056. var orderlisttype = {
  14057. 'num1':/^\d+\)/,
  14058. 'decimal':/^\d+\./,
  14059. 'lower-alpha':/^[a-z]+\)/,
  14060. 'upper-alpha':/^[A-Z]+\./,
  14061. 'cn':/^[\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+[\u3001]/,
  14062. 'cn2':/^\([\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+\)/
  14063. },
  14064. unorderlisttype = {
  14065. 'square':'n'
  14066. };
  14067. function checkListType(content,container){
  14068. var span = container.firstChild();
  14069. if(span && span.type == 'element' && span.tagName == 'span' && /Wingdings|Symbol/.test(span.getStyle('font-family'))){
  14070. for(var p in unorderlisttype){
  14071. if(unorderlisttype[p] == span.data){
  14072. return p
  14073. }
  14074. }
  14075. return 'disc'
  14076. }
  14077. for(var p in orderlisttype){
  14078. if(orderlisttype[p].test(content)){
  14079. return p;
  14080. }
  14081. }
  14082. }
  14083. utils.each(root.getNodesByTagName('p'),function(node){
  14084. if(node.getAttr('class') != 'MsoListParagraph'){
  14085. return
  14086. }
  14087. //word粘贴过来的会带有margin要去掉,但这样也可能会误命中一些央视
  14088. node.setStyle('margin','');
  14089. node.setStyle('margin-left','');
  14090. node.setAttr('class','');
  14091. function appendLi(list,p,type){
  14092. if(list.tagName == 'ol'){
  14093. if(browser.ie){
  14094. var first = p.firstChild();
  14095. if(first.type =='element' && first.tagName == 'span' && orderlisttype[type].test(first.innerText())){
  14096. p.removeChild(first);
  14097. }
  14098. }else{
  14099. p.innerHTML(p.innerHTML().replace(orderlisttype[type],''));
  14100. }
  14101. }else{
  14102. p.removeChild(p.firstChild())
  14103. }
  14104. var li = UE.uNode.createElement('li');
  14105. li.appendChild(p);
  14106. list.appendChild(li);
  14107. }
  14108. var tmp = node,type,cacheNode = node;
  14109. if(node.parentNode.tagName != 'li' && (type = checkListType(node.innerText(),node))){
  14110. var list = UE.uNode.createElement(me.options.insertorderedlist.hasOwnProperty(type) ? 'ol' : 'ul');
  14111. if(customStyle[type]){
  14112. list.setAttr('class','custom_'+type)
  14113. }else{
  14114. list.setStyle('list-style-type',type)
  14115. }
  14116. while(node && node.parentNode.tagName != 'li' && checkListType(node.innerText(),node)){
  14117. tmp = node.nextSibling();
  14118. if(!tmp){
  14119. node.parentNode.insertBefore(list,node)
  14120. }
  14121. appendLi(list,node,type);
  14122. node = tmp;
  14123. }
  14124. if(!list.parentNode && node && node.parentNode){
  14125. node.parentNode.insertBefore(list,node)
  14126. }
  14127. }
  14128. var span = cacheNode.firstChild();
  14129. if(span && span.type == 'element' && span.tagName == 'span' && /^\s*(&nbsp;)+\s*$/.test(span.innerText())){
  14130. span.parentNode.removeChild(span)
  14131. }
  14132. })
  14133. }
  14134. });
  14135. //调整索引标签
  14136. me.addListener('contentchange',function(){
  14137. adjustListStyle(me.document)
  14138. });
  14139. function adjustListStyle(doc,ignore){
  14140. utils.each(domUtils.getElementsByTagName(doc,'ol ul'),function(node){
  14141. if(!domUtils.inDoc(node,doc))
  14142. return;
  14143. var parent = node.parentNode;
  14144. if(parent.tagName == node.tagName){
  14145. var nodeStyleType = getStyle(node) || (node.tagName == 'OL' ? 'decimal' : 'disc'),
  14146. parentStyleType = getStyle(parent) || (parent.tagName == 'OL' ? 'decimal' : 'disc');
  14147. if(nodeStyleType == parentStyleType){
  14148. var styleIndex = utils.indexOf(listStyle[node.tagName], nodeStyleType);
  14149. styleIndex = styleIndex + 1 == listStyle[node.tagName].length ? 0 : styleIndex + 1;
  14150. setListStyle(node,listStyle[node.tagName][styleIndex])
  14151. }
  14152. }
  14153. var index = 0,type = 2;
  14154. if( domUtils.hasClass(node,/custom_/)){
  14155. if(!(/[ou]l/i.test(parent.tagName) && domUtils.hasClass(parent,/custom_/))){
  14156. type = 1;
  14157. }
  14158. }else{
  14159. if(/[ou]l/i.test(parent.tagName) && domUtils.hasClass(parent,/custom_/)){
  14160. type = 3;
  14161. }
  14162. }
  14163. var style = domUtils.getStyle(node, 'list-style-type');
  14164. style && (node.style.cssText = 'list-style-type:' + style);
  14165. node.className = utils.trim(node.className.replace(/list-paddingleft-\w+/,'')) + ' list-paddingleft-' + type;
  14166. utils.each(domUtils.getElementsByTagName(node,'li'),function(li){
  14167. li.style.cssText && (li.style.cssText = '');
  14168. if(!li.firstChild){
  14169. domUtils.remove(li);
  14170. return;
  14171. }
  14172. if(li.parentNode !== node){
  14173. return;
  14174. }
  14175. index++;
  14176. if(domUtils.hasClass(node,/custom_/) ){
  14177. var paddingLeft = 1,currentStyle = getStyle(node);
  14178. if(node.tagName == 'OL'){
  14179. if(currentStyle){
  14180. switch(currentStyle){
  14181. case 'cn' :
  14182. case 'cn1':
  14183. case 'cn2':
  14184. if(index > 10 && (index % 10 == 0 || index > 10 && index < 20)){
  14185. paddingLeft = 2
  14186. }else if(index > 20){
  14187. paddingLeft = 3
  14188. }
  14189. break;
  14190. case 'num2' :
  14191. if(index > 9){
  14192. paddingLeft = 2
  14193. }
  14194. }
  14195. }
  14196. li.className = 'list-'+customStyle[currentStyle]+ index + ' ' + 'list-'+currentStyle+'-paddingleft-' + paddingLeft;
  14197. }else{
  14198. li.className = 'list-'+customStyle[currentStyle] + ' ' + 'list-'+currentStyle+'-paddingleft';
  14199. }
  14200. }else{
  14201. li.className = li.className.replace(/list-[\w\-]+/gi,'');
  14202. }
  14203. var className = li.getAttribute('class');
  14204. if(className !== null && !className.replace(/\s/g,'')){
  14205. domUtils.removeAttributes(li,'class')
  14206. }
  14207. });
  14208. !ignore && adjustList(node,node.tagName.toLowerCase(),getStyle(node)||domUtils.getStyle(node, 'list-style-type'),true);
  14209. })
  14210. }
  14211. function adjustList(list, tag, style,ignoreEmpty) {
  14212. var nextList = list.nextSibling;
  14213. if (nextList && nextList.nodeType == 1 && nextList.tagName.toLowerCase() == tag && (getStyle(nextList) || domUtils.getStyle(nextList, 'list-style-type') || (tag == 'ol' ? 'decimal' : 'disc')) == style) {
  14214. domUtils.moveChild(nextList, list);
  14215. if (nextList.childNodes.length == 0) {
  14216. domUtils.remove(nextList);
  14217. }
  14218. }
  14219. if(nextList && domUtils.isFillChar(nextList)){
  14220. domUtils.remove(nextList);
  14221. }
  14222. var preList = list.previousSibling;
  14223. if (preList && preList.nodeType == 1 && preList.tagName.toLowerCase() == tag && (getStyle(preList) || domUtils.getStyle(preList, 'list-style-type') || (tag == 'ol' ? 'decimal' : 'disc')) == style) {
  14224. domUtils.moveChild(list, preList);
  14225. }
  14226. if(preList && domUtils.isFillChar(preList)){
  14227. domUtils.remove(preList);
  14228. }
  14229. !ignoreEmpty && domUtils.isEmptyBlock(list) && domUtils.remove(list);
  14230. if(getStyle(list)){
  14231. adjustListStyle(list.ownerDocument,true)
  14232. }
  14233. }
  14234. function setListStyle(list,style){
  14235. if(customStyle[style]){
  14236. list.className = 'custom_' + style;
  14237. }
  14238. try{
  14239. domUtils.setStyle(list, 'list-style-type', style);
  14240. }catch(e){}
  14241. }
  14242. function clearEmptySibling(node) {
  14243. var tmpNode = node.previousSibling;
  14244. if (tmpNode && domUtils.isEmptyBlock(tmpNode)) {
  14245. domUtils.remove(tmpNode);
  14246. }
  14247. tmpNode = node.nextSibling;
  14248. if (tmpNode && domUtils.isEmptyBlock(tmpNode)) {
  14249. domUtils.remove(tmpNode);
  14250. }
  14251. }
  14252. me.addListener('keydown', function (type, evt) {
  14253. function preventAndSave() {
  14254. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  14255. me.fireEvent('contentchange');
  14256. me.undoManger && me.undoManger.save();
  14257. }
  14258. function findList(node,filterFn){
  14259. while(node && !domUtils.isBody(node)){
  14260. if(filterFn(node)){
  14261. return null
  14262. }
  14263. if(node.nodeType == 1 && /[ou]l/i.test(node.tagName)){
  14264. return node;
  14265. }
  14266. node = node.parentNode;
  14267. }
  14268. return null;
  14269. }
  14270. var keyCode = evt.keyCode || evt.which;
  14271. if (keyCode == 13 && !evt.shiftKey) {//回车
  14272. var rng = me.selection.getRange(),
  14273. parent = domUtils.findParent(rng.startContainer,function(node){return domUtils.isBlockElm(node)},true),
  14274. li = domUtils.findParentByTagName(rng.startContainer,'li',true);
  14275. if(parent && parent.tagName != 'PRE' && !li){
  14276. var html = parent.innerHTML.replace(new RegExp(domUtils.fillChar, 'g'),'');
  14277. if(/^\s*1\s*\.[^\d]/.test(html)){
  14278. parent.innerHTML = html.replace(/^\s*1\s*\./,'');
  14279. rng.setStartAtLast(parent).collapse(true).select();
  14280. me.__hasEnterExecCommand = true;
  14281. me.execCommand('insertorderedlist');
  14282. me.__hasEnterExecCommand = false;
  14283. }
  14284. }
  14285. var range = me.selection.getRange(),
  14286. start = findList(range.startContainer,function (node) {
  14287. return node.tagName == 'TABLE';
  14288. }),
  14289. end = range.collapsed ? start : findList(range.endContainer,function (node) {
  14290. return node.tagName == 'TABLE';
  14291. });
  14292. if (start && end && start === end) {
  14293. if (!range.collapsed) {
  14294. start = domUtils.findParentByTagName(range.startContainer, 'li', true);
  14295. end = domUtils.findParentByTagName(range.endContainer, 'li', true);
  14296. if (start && end && start === end) {
  14297. range.deleteContents();
  14298. li = domUtils.findParentByTagName(range.startContainer, 'li', true);
  14299. if (li && domUtils.isEmptyBlock(li)) {
  14300. pre = li.previousSibling;
  14301. next = li.nextSibling;
  14302. p = me.document.createElement('p');
  14303. domUtils.fillNode(me.document, p);
  14304. parentList = li.parentNode;
  14305. if (pre && next) {
  14306. range.setStart(next, 0).collapse(true).select(true);
  14307. domUtils.remove(li);
  14308. } else {
  14309. if (!pre && !next || !pre) {
  14310. parentList.parentNode.insertBefore(p, parentList);
  14311. } else {
  14312. li.parentNode.parentNode.insertBefore(p, parentList.nextSibling);
  14313. }
  14314. domUtils.remove(li);
  14315. if (!parentList.firstChild) {
  14316. domUtils.remove(parentList);
  14317. }
  14318. range.setStart(p, 0).setCursor();
  14319. }
  14320. preventAndSave();
  14321. return;
  14322. }
  14323. } else {
  14324. var tmpRange = range.cloneRange(),
  14325. bk = tmpRange.collapse(false).createBookmark();
  14326. range.deleteContents();
  14327. tmpRange.moveToBookmark(bk);
  14328. var li = domUtils.findParentByTagName(tmpRange.startContainer, 'li', true);
  14329. clearEmptySibling(li);
  14330. tmpRange.select();
  14331. preventAndSave();
  14332. return;
  14333. }
  14334. }
  14335. li = domUtils.findParentByTagName(range.startContainer, 'li', true);
  14336. if (li) {
  14337. if (domUtils.isEmptyBlock(li)) {
  14338. bk = range.createBookmark();
  14339. var parentList = li.parentNode;
  14340. if (li !== parentList.lastChild) {
  14341. domUtils.breakParent(li, parentList);
  14342. clearEmptySibling(li);
  14343. } else {
  14344. parentList.parentNode.insertBefore(li, parentList.nextSibling);
  14345. if (domUtils.isEmptyNode(parentList)) {
  14346. domUtils.remove(parentList);
  14347. }
  14348. }
  14349. //嵌套不处理
  14350. if (!dtd.$list[li.parentNode.tagName]) {
  14351. if (!domUtils.isBlockElm(li.firstChild)) {
  14352. p = me.document.createElement('p');
  14353. li.parentNode.insertBefore(p, li);
  14354. while (li.firstChild) {
  14355. p.appendChild(li.firstChild);
  14356. }
  14357. domUtils.remove(li);
  14358. } else {
  14359. domUtils.remove(li, true);
  14360. }
  14361. }
  14362. range.moveToBookmark(bk).select();
  14363. } else {
  14364. var first = li.firstChild;
  14365. if (!first || !domUtils.isBlockElm(first)) {
  14366. var p = me.document.createElement('p');
  14367. !li.firstChild && domUtils.fillNode(me.document, p);
  14368. while (li.firstChild) {
  14369. p.appendChild(li.firstChild);
  14370. }
  14371. li.appendChild(p);
  14372. first = p;
  14373. }
  14374. var span = me.document.createElement('span');
  14375. range.insertNode(span);
  14376. domUtils.breakParent(span, li);
  14377. var nextLi = span.nextSibling;
  14378. first = nextLi.firstChild;
  14379. if (!first) {
  14380. p = me.document.createElement('p');
  14381. domUtils.fillNode(me.document, p);
  14382. nextLi.appendChild(p);
  14383. first = p;
  14384. }
  14385. if (domUtils.isEmptyNode(first)) {
  14386. first.innerHTML = '';
  14387. domUtils.fillNode(me.document, first);
  14388. }
  14389. range.setStart(first, 0).collapse(true).shrinkBoundary().select();
  14390. domUtils.remove(span);
  14391. var pre = nextLi.previousSibling;
  14392. if (pre && domUtils.isEmptyBlock(pre)) {
  14393. pre.innerHTML = '<p></p>';
  14394. domUtils.fillNode(me.document, pre.firstChild);
  14395. }
  14396. }
  14397. // }
  14398. preventAndSave();
  14399. }
  14400. }
  14401. }
  14402. if (keyCode == 8) {
  14403. //修中ie中li下的问题
  14404. range = me.selection.getRange();
  14405. if (range.collapsed && domUtils.isStartInblock(range)) {
  14406. tmpRange = range.cloneRange().trimBoundary();
  14407. li = domUtils.findParentByTagName(range.startContainer, 'li', true);
  14408. //要在li的最左边,才能处理
  14409. if (li && domUtils.isStartInblock(tmpRange)) {
  14410. start = domUtils.findParentByTagName(range.startContainer, 'p', true);
  14411. if (start && start !== li.firstChild) {
  14412. var parentList = domUtils.findParentByTagName(start,['ol','ul']);
  14413. domUtils.breakParent(start,parentList);
  14414. clearEmptySibling(start);
  14415. me.fireEvent('contentchange');
  14416. range.setStart(start,0).setCursor(false,true);
  14417. me.fireEvent('saveScene');
  14418. domUtils.preventDefault(evt);
  14419. return;
  14420. }
  14421. if (li && (pre = li.previousSibling)) {
  14422. if (keyCode == 46 && li.childNodes.length) {
  14423. return;
  14424. }
  14425. //有可能上边的兄弟节点是个2级菜单,要追加到2级菜单的最后的li
  14426. if (dtd.$list[pre.tagName]) {
  14427. pre = pre.lastChild;
  14428. }
  14429. me.undoManger && me.undoManger.save();
  14430. first = li.firstChild;
  14431. if (domUtils.isBlockElm(first)) {
  14432. if (domUtils.isEmptyNode(first)) {
  14433. // range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
  14434. pre.appendChild(first);
  14435. range.setStart(first, 0).setCursor(false, true);
  14436. //first不是唯一的节点
  14437. while (li.firstChild) {
  14438. pre.appendChild(li.firstChild);
  14439. }
  14440. } else {
  14441. span = me.document.createElement('span');
  14442. range.insertNode(span);
  14443. //判断pre是否是空的节点,如果是<p><br/></p>类型的空节点,干掉p标签防止它占位
  14444. if (domUtils.isEmptyBlock(pre)) {
  14445. pre.innerHTML = '';
  14446. }
  14447. domUtils.moveChild(li, pre);
  14448. range.setStartBefore(span).collapse(true).select(true);
  14449. domUtils.remove(span);
  14450. }
  14451. } else {
  14452. if (domUtils.isEmptyNode(li)) {
  14453. var p = me.document.createElement('p');
  14454. pre.appendChild(p);
  14455. range.setStart(p, 0).setCursor();
  14456. // range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
  14457. } else {
  14458. range.setEnd(pre, pre.childNodes.length).collapse().select(true);
  14459. while (li.firstChild) {
  14460. pre.appendChild(li.firstChild);
  14461. }
  14462. }
  14463. }
  14464. domUtils.remove(li);
  14465. me.fireEvent('contentchange');
  14466. me.fireEvent('saveScene');
  14467. domUtils.preventDefault(evt);
  14468. return;
  14469. }
  14470. //trace:980
  14471. if (li && !li.previousSibling) {
  14472. var parentList = li.parentNode;
  14473. var bk = range.createBookmark();
  14474. if(domUtils.isTagNode(parentList.parentNode,'ol ul')){
  14475. parentList.parentNode.insertBefore(li,parentList);
  14476. if(domUtils.isEmptyNode(parentList)){
  14477. domUtils.remove(parentList)
  14478. }
  14479. }else{
  14480. while(li.firstChild){
  14481. parentList.parentNode.insertBefore(li.firstChild,parentList);
  14482. }
  14483. domUtils.remove(li);
  14484. if(domUtils.isEmptyNode(parentList)){
  14485. domUtils.remove(parentList)
  14486. }
  14487. }
  14488. range.moveToBookmark(bk).setCursor(false,true);
  14489. me.fireEvent('contentchange');
  14490. me.fireEvent('saveScene');
  14491. domUtils.preventDefault(evt);
  14492. return;
  14493. }
  14494. }
  14495. }
  14496. }
  14497. });
  14498. me.addListener('keyup',function(type, evt){
  14499. var keyCode = evt.keyCode || evt.which;
  14500. if (keyCode == 8) {
  14501. var rng = me.selection.getRange(),list;
  14502. if(list = domUtils.findParentByTagName(rng.startContainer,['ol', 'ul'],true)){
  14503. adjustList(list,list.tagName.toLowerCase(),getStyle(list)||domUtils.getComputedStyle(list,'list-style-type'),true)
  14504. }
  14505. }
  14506. });
  14507. //处理tab键
  14508. me.addListener('tabkeydown',function(){
  14509. var range = me.selection.getRange();
  14510. //控制级数
  14511. function checkLevel(li){
  14512. if(me.options.maxListLevel != -1){
  14513. var level = li.parentNode,levelNum = 0;
  14514. while(/[ou]l/i.test(level.tagName)){
  14515. levelNum++;
  14516. level = level.parentNode;
  14517. }
  14518. if(levelNum >= me.options.maxListLevel){
  14519. return true;
  14520. }
  14521. }
  14522. }
  14523. //只以开始为准
  14524. //todo 后续改进
  14525. var li = domUtils.findParentByTagName(range.startContainer, 'li', true);
  14526. if(li){
  14527. var bk;
  14528. if(range.collapsed){
  14529. if(checkLevel(li))
  14530. return true;
  14531. var parentLi = li.parentNode,
  14532. list = me.document.createElement(parentLi.tagName),
  14533. index = utils.indexOf(listStyle[list.tagName], getStyle(parentLi)||domUtils.getComputedStyle(parentLi, 'list-style-type'));
  14534. index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
  14535. var currentStyle = listStyle[list.tagName][index];
  14536. setListStyle(list,currentStyle);
  14537. if(domUtils.isStartInblock(range)){
  14538. me.fireEvent('saveScene');
  14539. bk = range.createBookmark();
  14540. parentLi.insertBefore(list, li);
  14541. list.appendChild(li);
  14542. adjustList(list,list.tagName.toLowerCase(),currentStyle);
  14543. me.fireEvent('contentchange');
  14544. range.moveToBookmark(bk).select(true);
  14545. return true;
  14546. }
  14547. }else{
  14548. me.fireEvent('saveScene');
  14549. bk = range.createBookmark();
  14550. for(var i= 0,closeList,parents = domUtils.findParents(li),ci;ci=parents[i++];){
  14551. if(domUtils.isTagNode(ci,'ol ul')){
  14552. closeList = ci;
  14553. break;
  14554. }
  14555. }
  14556. var current = li;
  14557. if(bk.end){
  14558. while(current && !(domUtils.getPosition(current, bk.end) & domUtils.POSITION_FOLLOWING)){
  14559. if(checkLevel(current)){
  14560. current = domUtils.getNextDomNode(current,false,null,function(node){return node !== closeList});
  14561. continue;
  14562. }
  14563. var parentLi = current.parentNode,
  14564. list = me.document.createElement(parentLi.tagName),
  14565. index = utils.indexOf(listStyle[list.tagName], getStyle(parentLi)||domUtils.getComputedStyle(parentLi, 'list-style-type'));
  14566. var currentIndex = index + 1 == listStyle[list.tagName].length ? 0 : index + 1;
  14567. var currentStyle = listStyle[list.tagName][currentIndex];
  14568. setListStyle(list,currentStyle);
  14569. parentLi.insertBefore(list, current);
  14570. while(current && !(domUtils.getPosition(current, bk.end) & domUtils.POSITION_FOLLOWING)){
  14571. li = current.nextSibling;
  14572. list.appendChild(current);
  14573. if(!li || domUtils.isTagNode(li,'ol ul')){
  14574. if(li){
  14575. while(li = li.firstChild){
  14576. if(li.tagName == 'LI'){
  14577. break;
  14578. }
  14579. }
  14580. }else{
  14581. li = domUtils.getNextDomNode(current,false,null,function(node){return node !== closeList});
  14582. }
  14583. break;
  14584. }
  14585. current = li;
  14586. }
  14587. adjustList(list,list.tagName.toLowerCase(),currentStyle);
  14588. current = li;
  14589. }
  14590. }
  14591. me.fireEvent('contentchange');
  14592. range.moveToBookmark(bk).select();
  14593. return true;
  14594. }
  14595. }
  14596. });
  14597. function getLi(start){
  14598. while(start && !domUtils.isBody(start)){
  14599. if(start.nodeName == 'TABLE'){
  14600. return null;
  14601. }
  14602. if(start.nodeName == 'LI'){
  14603. return start
  14604. }
  14605. start = start.parentNode;
  14606. }
  14607. }
  14608. /**
  14609. * 有序列表,与“insertunorderedlist”命令互斥
  14610. * @command insertorderedlist
  14611. * @method execCommand
  14612. * @param { String } command 命令字符串
  14613. * @param { String } style 插入的有序列表类型,值为:decimal,lower-alpha,lower-roman,upper-alpha,upper-roman,cn,cn1,cn2,num,num1,num2
  14614. * @example
  14615. * ```javascript
  14616. * editor.execCommand( 'insertorderedlist','decimal');
  14617. * ```
  14618. */
  14619. /**
  14620. * 查询当前选区内容是否有序列表
  14621. * @command insertorderedlist
  14622. * @method queryCommandState
  14623. * @param { String } cmd 命令字符串
  14624. * @return { int } 如果当前选区是有序列表返回1,否则返回0
  14625. * @example
  14626. * ```javascript
  14627. * editor.queryCommandState( 'insertorderedlist' );
  14628. * ```
  14629. */
  14630. /**
  14631. * 查询当前选区内容是否有序列表
  14632. * @command insertorderedlist
  14633. * @method queryCommandValue
  14634. * @param { String } cmd 命令字符串
  14635. * @return { String } 返回当前有序列表的类型,值为null或decimal,lower-alpha,lower-roman,upper-alpha,upper-roman,cn,cn1,cn2,num,num1,num2
  14636. * @example
  14637. * ```javascript
  14638. * editor.queryCommandValue( 'insertorderedlist' );
  14639. * ```
  14640. */
  14641. /**
  14642. * 无序列表,与“insertorderedlist”命令互斥
  14643. * @command insertunorderedlist
  14644. * @method execCommand
  14645. * @param { String } command 命令字符串
  14646. * @param { String } style 插入的无序列表类型,值为:circle,disc,square,dash,dot
  14647. * @example
  14648. * ```javascript
  14649. * editor.execCommand( 'insertunorderedlist','circle');
  14650. * ```
  14651. */
  14652. /**
  14653. * 查询当前是否有word文档粘贴进来的图片
  14654. * @command insertunorderedlist
  14655. * @method insertunorderedlist
  14656. * @param { String } command 命令字符串
  14657. * @return { int } 如果当前选区是无序列表返回1,否则返回0
  14658. * @example
  14659. * ```javascript
  14660. * editor.queryCommandState( 'insertunorderedlist' );
  14661. * ```
  14662. */
  14663. /**
  14664. * 查询当前选区内容是否有序列表
  14665. * @command insertunorderedlist
  14666. * @method queryCommandValue
  14667. * @param { String } command 命令字符串
  14668. * @return { String } 返回当前无序列表的类型,值为null或circle,disc,square,dash,dot
  14669. * @example
  14670. * ```javascript
  14671. * editor.queryCommandValue( 'insertunorderedlist' );
  14672. * ```
  14673. */
  14674. me.commands['insertorderedlist'] =
  14675. me.commands['insertunorderedlist'] = {
  14676. execCommand:function (command, style) {
  14677. if (!style) {
  14678. style = command.toLowerCase() == 'insertorderedlist' ? 'decimal' : 'disc';
  14679. }
  14680. var me = this,
  14681. range = this.selection.getRange(),
  14682. filterFn = function (node) {
  14683. return node.nodeType == 1 ? node.tagName.toLowerCase() != 'br' : !domUtils.isWhitespace(node);
  14684. },
  14685. tag = command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul',
  14686. frag = me.document.createDocumentFragment();
  14687. //去掉是因为会出现选到末尾,导致adjustmentBoundary缩到ol/ul的位置
  14688. //range.shrinkBoundary();//.adjustmentBoundary();
  14689. range.adjustmentBoundary().shrinkBoundary();
  14690. var bko = range.createBookmark(true),
  14691. start = getLi(me.document.getElementById(bko.start)),
  14692. modifyStart = 0,
  14693. end = getLi(me.document.getElementById(bko.end)),
  14694. modifyEnd = 0,
  14695. startParent, endParent,
  14696. list, tmp;
  14697. if (start || end) {
  14698. start && (startParent = start.parentNode);
  14699. if (!bko.end) {
  14700. end = start;
  14701. }
  14702. end && (endParent = end.parentNode);
  14703. if (startParent === endParent) {
  14704. while (start !== end) {
  14705. tmp = start;
  14706. start = start.nextSibling;
  14707. if (!domUtils.isBlockElm(tmp.firstChild)) {
  14708. var p = me.document.createElement('p');
  14709. while (tmp.firstChild) {
  14710. p.appendChild(tmp.firstChild);
  14711. }
  14712. tmp.appendChild(p);
  14713. }
  14714. frag.appendChild(tmp);
  14715. }
  14716. tmp = me.document.createElement('span');
  14717. startParent.insertBefore(tmp, end);
  14718. if (!domUtils.isBlockElm(end.firstChild)) {
  14719. p = me.document.createElement('p');
  14720. while (end.firstChild) {
  14721. p.appendChild(end.firstChild);
  14722. }
  14723. end.appendChild(p);
  14724. }
  14725. frag.appendChild(end);
  14726. domUtils.breakParent(tmp, startParent);
  14727. if (domUtils.isEmptyNode(tmp.previousSibling)) {
  14728. domUtils.remove(tmp.previousSibling);
  14729. }
  14730. if (domUtils.isEmptyNode(tmp.nextSibling)) {
  14731. domUtils.remove(tmp.nextSibling)
  14732. }
  14733. var nodeStyle = getStyle(startParent) || domUtils.getComputedStyle(startParent, 'list-style-type') || (command.toLowerCase() == 'insertorderedlist' ? 'decimal' : 'disc');
  14734. if (startParent.tagName.toLowerCase() == tag && nodeStyle == style) {
  14735. for (var i = 0, ci, tmpFrag = me.document.createDocumentFragment(); ci = frag.firstChild;) {
  14736. if(domUtils.isTagNode(ci,'ol ul')){
  14737. // 删除时,子列表不处理
  14738. // utils.each(domUtils.getElementsByTagName(ci,'li'),function(li){
  14739. // while(li.firstChild){
  14740. // tmpFrag.appendChild(li.firstChild);
  14741. // }
  14742. //
  14743. // });
  14744. tmpFrag.appendChild(ci);
  14745. }else{
  14746. while (ci.firstChild) {
  14747. tmpFrag.appendChild(ci.firstChild);
  14748. domUtils.remove(ci);
  14749. }
  14750. }
  14751. }
  14752. tmp.parentNode.insertBefore(tmpFrag, tmp);
  14753. } else {
  14754. list = me.document.createElement(tag);
  14755. setListStyle(list,style);
  14756. list.appendChild(frag);
  14757. tmp.parentNode.insertBefore(list, tmp);
  14758. }
  14759. domUtils.remove(tmp);
  14760. list && adjustList(list, tag, style);
  14761. range.moveToBookmark(bko).select();
  14762. return;
  14763. }
  14764. //开始
  14765. if (start) {
  14766. while (start) {
  14767. tmp = start.nextSibling;
  14768. if (domUtils.isTagNode(start, 'ol ul')) {
  14769. frag.appendChild(start);
  14770. } else {
  14771. var tmpfrag = me.document.createDocumentFragment(),
  14772. hasBlock = 0;
  14773. while (start.firstChild) {
  14774. if (domUtils.isBlockElm(start.firstChild)) {
  14775. hasBlock = 1;
  14776. }
  14777. tmpfrag.appendChild(start.firstChild);
  14778. }
  14779. if (!hasBlock) {
  14780. var tmpP = me.document.createElement('p');
  14781. tmpP.appendChild(tmpfrag);
  14782. frag.appendChild(tmpP);
  14783. } else {
  14784. frag.appendChild(tmpfrag);
  14785. }
  14786. domUtils.remove(start);
  14787. }
  14788. start = tmp;
  14789. }
  14790. startParent.parentNode.insertBefore(frag, startParent.nextSibling);
  14791. if (domUtils.isEmptyNode(startParent)) {
  14792. range.setStartBefore(startParent);
  14793. domUtils.remove(startParent);
  14794. } else {
  14795. range.setStartAfter(startParent);
  14796. }
  14797. modifyStart = 1;
  14798. }
  14799. if (end && domUtils.inDoc(endParent, me.document)) {
  14800. //结束
  14801. start = endParent.firstChild;
  14802. while (start && start !== end) {
  14803. tmp = start.nextSibling;
  14804. if (domUtils.isTagNode(start, 'ol ul')) {
  14805. frag.appendChild(start);
  14806. } else {
  14807. tmpfrag = me.document.createDocumentFragment();
  14808. hasBlock = 0;
  14809. while (start.firstChild) {
  14810. if (domUtils.isBlockElm(start.firstChild)) {
  14811. hasBlock = 1;
  14812. }
  14813. tmpfrag.appendChild(start.firstChild);
  14814. }
  14815. if (!hasBlock) {
  14816. tmpP = me.document.createElement('p');
  14817. tmpP.appendChild(tmpfrag);
  14818. frag.appendChild(tmpP);
  14819. } else {
  14820. frag.appendChild(tmpfrag);
  14821. }
  14822. domUtils.remove(start);
  14823. }
  14824. start = tmp;
  14825. }
  14826. var tmpDiv = domUtils.createElement(me.document, 'div', {
  14827. 'tmpDiv':1
  14828. });
  14829. domUtils.moveChild(end, tmpDiv);
  14830. frag.appendChild(tmpDiv);
  14831. domUtils.remove(end);
  14832. endParent.parentNode.insertBefore(frag, endParent);
  14833. range.setEndBefore(endParent);
  14834. if (domUtils.isEmptyNode(endParent)) {
  14835. domUtils.remove(endParent);
  14836. }
  14837. modifyEnd = 1;
  14838. }
  14839. }
  14840. if (!modifyStart) {
  14841. range.setStartBefore(me.document.getElementById(bko.start));
  14842. }
  14843. if (bko.end && !modifyEnd) {
  14844. range.setEndAfter(me.document.getElementById(bko.end));
  14845. }
  14846. range.enlarge(true, function (node) {
  14847. return notExchange[node.tagName];
  14848. });
  14849. frag = me.document.createDocumentFragment();
  14850. var bk = range.createBookmark(),
  14851. current = domUtils.getNextDomNode(bk.start, false, filterFn),
  14852. tmpRange = range.cloneRange(),
  14853. tmpNode,
  14854. block = domUtils.isBlockElm;
  14855. while (current && current !== bk.end && (domUtils.getPosition(current, bk.end) & domUtils.POSITION_PRECEDING)) {
  14856. if (current.nodeType == 3 || dtd.li[current.tagName]) {
  14857. if (current.nodeType == 1 && dtd.$list[current.tagName]) {
  14858. while (current.firstChild) {
  14859. frag.appendChild(current.firstChild);
  14860. }
  14861. tmpNode = domUtils.getNextDomNode(current, false, filterFn);
  14862. domUtils.remove(current);
  14863. current = tmpNode;
  14864. continue;
  14865. }
  14866. tmpNode = current;
  14867. tmpRange.setStartBefore(current);
  14868. while (current && current !== bk.end && (!block(current) || domUtils.isBookmarkNode(current) )) {
  14869. tmpNode = current;
  14870. current = domUtils.getNextDomNode(current, false, null, function (node) {
  14871. return !notExchange[node.tagName];
  14872. });
  14873. }
  14874. if (current && block(current)) {
  14875. tmp = domUtils.getNextDomNode(tmpNode, false, filterFn);
  14876. if (tmp && domUtils.isBookmarkNode(tmp)) {
  14877. current = domUtils.getNextDomNode(tmp, false, filterFn);
  14878. tmpNode = tmp;
  14879. }
  14880. }
  14881. tmpRange.setEndAfter(tmpNode);
  14882. current = domUtils.getNextDomNode(tmpNode, false, filterFn);
  14883. var li = range.document.createElement('li');
  14884. li.appendChild(tmpRange.extractContents());
  14885. if(domUtils.isEmptyNode(li)){
  14886. var tmpNode = range.document.createElement('p');
  14887. while(li.firstChild){
  14888. tmpNode.appendChild(li.firstChild)
  14889. }
  14890. li.appendChild(tmpNode);
  14891. }
  14892. frag.appendChild(li);
  14893. } else {
  14894. current = domUtils.getNextDomNode(current, true, filterFn);
  14895. }
  14896. }
  14897. range.moveToBookmark(bk).collapse(true);
  14898. list = me.document.createElement(tag);
  14899. setListStyle(list,style);
  14900. list.appendChild(frag);
  14901. range.insertNode(list);
  14902. //当前list上下看能否合并
  14903. adjustList(list, tag, style);
  14904. //去掉冗余的tmpDiv
  14905. for (var i = 0, ci, tmpDivs = domUtils.getElementsByTagName(list, 'div'); ci = tmpDivs[i++];) {
  14906. if (ci.getAttribute('tmpDiv')) {
  14907. domUtils.remove(ci, true)
  14908. }
  14909. }
  14910. range.moveToBookmark(bko).select();
  14911. },
  14912. queryCommandState:function (command) {
  14913. var tag = command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul';
  14914. var path = this.selection.getStartElementPath();
  14915. for(var i= 0,ci;ci = path[i++];){
  14916. if(ci.nodeName == 'TABLE'){
  14917. return 0
  14918. }
  14919. if(tag == ci.nodeName.toLowerCase()){
  14920. return 1
  14921. };
  14922. }
  14923. return 0;
  14924. },
  14925. queryCommandValue:function (command) {
  14926. var tag = command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul';
  14927. var path = this.selection.getStartElementPath(),
  14928. node;
  14929. for(var i= 0,ci;ci = path[i++];){
  14930. if(ci.nodeName == 'TABLE'){
  14931. node = null;
  14932. break;
  14933. }
  14934. if(tag == ci.nodeName.toLowerCase()){
  14935. node = ci;
  14936. break;
  14937. };
  14938. }
  14939. return node ? getStyle(node) || domUtils.getComputedStyle(node, 'list-style-type') : null;
  14940. }
  14941. };
  14942. };
  14943. // plugins/source.js
  14944. /**
  14945. * 源码编辑插件
  14946. * @file
  14947. * @since 1.2.6.1
  14948. */
  14949. (function (){
  14950. var sourceEditors = {
  14951. textarea: function (editor, holder){
  14952. var textarea = holder.ownerDocument.createElement('textarea');
  14953. textarea.style.cssText = 'position:absolute;resize:none;width:100%;height:100%;border:0;padding:0;margin:0;overflow-y:auto;';
  14954. // todo: IE下只有onresize属性可用... 很纠结
  14955. if (browser.ie && browser.version < 8) {
  14956. textarea.style.width = holder.offsetWidth + 'px';
  14957. textarea.style.height = holder.offsetHeight + 'px';
  14958. holder.onresize = function (){
  14959. textarea.style.width = holder.offsetWidth + 'px';
  14960. textarea.style.height = holder.offsetHeight + 'px';
  14961. };
  14962. }
  14963. holder.appendChild(textarea);
  14964. return {
  14965. setContent: function (content){
  14966. textarea.value = content;
  14967. },
  14968. getContent: function (){
  14969. return textarea.value;
  14970. },
  14971. select: function (){
  14972. var range;
  14973. if (browser.ie) {
  14974. range = textarea.createTextRange();
  14975. range.collapse(true);
  14976. range.select();
  14977. } else {
  14978. //todo: chrome下无法设置焦点
  14979. textarea.setSelectionRange(0, 0);
  14980. textarea.focus();
  14981. }
  14982. },
  14983. dispose: function (){
  14984. holder.removeChild(textarea);
  14985. // todo
  14986. holder.onresize = null;
  14987. textarea = null;
  14988. holder = null;
  14989. }
  14990. };
  14991. },
  14992. codemirror: function (editor, holder){
  14993. var codeEditor = window.CodeMirror(holder, {
  14994. mode: "text/html",
  14995. tabMode: "indent",
  14996. lineNumbers: true,
  14997. lineWrapping:true
  14998. });
  14999. var dom = codeEditor.getWrapperElement();
  15000. dom.style.cssText = 'position:absolute;left:0;top:0;width:100%;height:100%;font-family:consolas,"Courier new",monospace;font-size:13px;';
  15001. codeEditor.getScrollerElement().style.cssText = 'position:absolute;left:0;top:0;width:100%;height:100%;';
  15002. codeEditor.refresh();
  15003. return {
  15004. getCodeMirror:function(){
  15005. return codeEditor;
  15006. },
  15007. setContent: function (content){
  15008. codeEditor.setValue(content);
  15009. },
  15010. getContent: function (){
  15011. return codeEditor.getValue();
  15012. },
  15013. select: function (){
  15014. codeEditor.focus();
  15015. },
  15016. dispose: function (){
  15017. holder.removeChild(dom);
  15018. dom = null;
  15019. codeEditor = null;
  15020. }
  15021. };
  15022. }
  15023. };
  15024. UE.plugins['source'] = function (){
  15025. var me = this;
  15026. var opt = this.options;
  15027. var sourceMode = false;
  15028. var sourceEditor;
  15029. var orgSetContent;
  15030. opt.sourceEditor = browser.ie ? 'textarea' : (opt.sourceEditor || 'codemirror');
  15031. me.setOpt({
  15032. sourceEditorFirst:false
  15033. });
  15034. function createSourceEditor(holder){
  15035. return sourceEditors[opt.sourceEditor == 'codemirror' && window.CodeMirror ? 'codemirror' : 'textarea'](me, holder);
  15036. }
  15037. var bakCssText;
  15038. //解决在源码模式下getContent不能得到最新的内容问题
  15039. var oldGetContent,
  15040. bakAddress;
  15041. /**
  15042. * 切换源码模式和编辑模式
  15043. * @command source
  15044. * @method execCommand
  15045. * @param { String } cmd 命令字符串
  15046. * @example
  15047. * ```javascript
  15048. * editor.execCommand( 'source');
  15049. * ```
  15050. */
  15051. /**
  15052. * 查询当前编辑区域的状态是源码模式还是可视化模式
  15053. * @command source
  15054. * @method queryCommandState
  15055. * @param { String } cmd 命令字符串
  15056. * @return { int } 如果当前是源码编辑模式,返回1,否则返回0
  15057. * @example
  15058. * ```javascript
  15059. * editor.queryCommandState( 'source' );
  15060. * ```
  15061. */
  15062. me.commands['source'] = {
  15063. execCommand: function (){
  15064. sourceMode = !sourceMode;
  15065. if (sourceMode) {
  15066. bakAddress = me.selection.getRange().createAddress(false,true);
  15067. me.undoManger && me.undoManger.save(true);
  15068. if(browser.gecko){
  15069. me.body.contentEditable = false;
  15070. }
  15071. bakCssText = me.iframe.style.cssText;
  15072. me.iframe.style.cssText += 'position:absolute;left:-32768px;top:-32768px;';
  15073. me.fireEvent('beforegetcontent');
  15074. var root = UE.htmlparser(me.body.innerHTML);
  15075. me.filterOutputRule(root);
  15076. root.traversal(function (node) {
  15077. if (node.type == 'element') {
  15078. switch (node.tagName) {
  15079. case 'td':
  15080. case 'th':
  15081. case 'caption':
  15082. if(node.children && node.children.length == 1){
  15083. if(node.firstChild().tagName == 'br' ){
  15084. node.removeChild(node.firstChild())
  15085. }
  15086. };
  15087. break;
  15088. case 'pre':
  15089. node.innerText(node.innerText().replace(/&nbsp;/g,' '))
  15090. }
  15091. }
  15092. });
  15093. me.fireEvent('aftergetcontent');
  15094. var content = root.toHtml(true);
  15095. sourceEditor = createSourceEditor(me.iframe.parentNode);
  15096. sourceEditor.setContent(content);
  15097. orgSetContent = me.setContent;
  15098. me.setContent = function(html){
  15099. //这里暂时不触发事件,防止报错
  15100. var root = UE.htmlparser(html);
  15101. me.filterInputRule(root);
  15102. html = root.toHtml();
  15103. sourceEditor.setContent(html);
  15104. };
  15105. setTimeout(function (){
  15106. sourceEditor.select();
  15107. me.addListener('fullscreenchanged', function(){
  15108. try{
  15109. sourceEditor.getCodeMirror().refresh()
  15110. }catch(e){}
  15111. });
  15112. });
  15113. //重置getContent,源码模式下取值也能是最新的数据
  15114. oldGetContent = me.getContent;
  15115. me.getContent = function (){
  15116. return sourceEditor.getContent() || '<p>' + (browser.ie ? '' : '<br/>')+'</p>';
  15117. };
  15118. } else {
  15119. me.iframe.style.cssText = bakCssText;
  15120. var cont = sourceEditor.getContent() || '<p>' + (browser.ie ? '' : '<br/>')+'</p>';
  15121. //处理掉block节点前后的空格,有可能会误命中,暂时不考虑
  15122. cont = cont.replace(new RegExp('[\\r\\t\\n ]*<\/?(\\w+)\\s*(?:[^>]*)>','g'), function(a,b){
  15123. if(b && !dtd.$inlineWithA[b.toLowerCase()]){
  15124. return a.replace(/(^[\n\r\t ]*)|([\n\r\t ]*$)/g,'');
  15125. }
  15126. return a.replace(/(^[\n\r\t]*)|([\n\r\t]*$)/g,'')
  15127. });
  15128. me.setContent = orgSetContent;
  15129. me.setContent(cont);
  15130. sourceEditor.dispose();
  15131. sourceEditor = null;
  15132. //还原getContent方法
  15133. me.getContent = oldGetContent;
  15134. var first = me.body.firstChild;
  15135. //trace:1106 都删除空了,下边会报错,所以补充一个p占位
  15136. if(!first){
  15137. me.body.innerHTML = '<p>'+(browser.ie?'':'<br/>')+'</p>';
  15138. first = me.body.firstChild;
  15139. }
  15140. //要在ifm为显示时ff才能取到selection,否则报错
  15141. //这里不能比较位置了
  15142. me.undoManger && me.undoManger.save(true);
  15143. if(browser.gecko){
  15144. var input = document.createElement('input');
  15145. input.style.cssText = 'position:absolute;left:0;top:-32768px';
  15146. document.body.appendChild(input);
  15147. me.body.contentEditable = false;
  15148. setTimeout(function(){
  15149. domUtils.setViewportOffset(input, { left: -32768, top: 0 });
  15150. input.focus();
  15151. setTimeout(function(){
  15152. me.body.contentEditable = true;
  15153. me.selection.getRange().moveToAddress(bakAddress).select(true);
  15154. domUtils.remove(input);
  15155. });
  15156. });
  15157. }else{
  15158. //ie下有可能报错,比如在代码顶头的情况
  15159. try{
  15160. me.selection.getRange().moveToAddress(bakAddress).select(true);
  15161. }catch(e){}
  15162. }
  15163. }
  15164. this.fireEvent('sourcemodechanged', sourceMode);
  15165. },
  15166. queryCommandState: function (){
  15167. return sourceMode|0;
  15168. },
  15169. notNeedUndo : 1
  15170. };
  15171. var oldQueryCommandState = me.queryCommandState;
  15172. me.queryCommandState = function (cmdName){
  15173. cmdName = cmdName.toLowerCase();
  15174. if (sourceMode) {
  15175. //源码模式下可以开启的命令
  15176. return cmdName in {
  15177. 'source' : 1,
  15178. 'fullscreen' : 1
  15179. } ? 1 : -1
  15180. }
  15181. return oldQueryCommandState.apply(this, arguments);
  15182. };
  15183. if(opt.sourceEditor == "codemirror"){
  15184. me.addListener("ready",function(){
  15185. utils.loadFile(document,{
  15186. src : opt.codeMirrorJsUrl || opt.UEDITOR_HOME_URL + "third-party/codemirror/codemirror.js",
  15187. tag : "script",
  15188. type : "text/javascript",
  15189. defer : "defer"
  15190. },function(){
  15191. if(opt.sourceEditorFirst){
  15192. setTimeout(function(){
  15193. me.execCommand("source");
  15194. },0);
  15195. }
  15196. });
  15197. utils.loadFile(document,{
  15198. tag : "link",
  15199. rel : "stylesheet",
  15200. type : "text/css",
  15201. href : opt.codeMirrorCssUrl || opt.UEDITOR_HOME_URL + "third-party/codemirror/codemirror.css"
  15202. });
  15203. });
  15204. }
  15205. };
  15206. })();
  15207. // plugins/enterkey.js
  15208. ///import core
  15209. ///import plugins/undo.js
  15210. ///commands 设置回车标签p或br
  15211. ///commandsName EnterKey
  15212. ///commandsTitle 设置回车标签p或br
  15213. /**
  15214. * @description 处理回车
  15215. * @author zhanyi
  15216. */
  15217. UE.plugins['enterkey'] = function() {
  15218. var hTag,
  15219. me = this,
  15220. tag = me.options.enterTag;
  15221. me.addListener('keyup', function(type, evt) {
  15222. var keyCode = evt.keyCode || evt.which;
  15223. if (keyCode == 13) {
  15224. var range = me.selection.getRange(),
  15225. start = range.startContainer,
  15226. doSave;
  15227. //修正在h1-h6里边回车后不能嵌套p的问题
  15228. if (!browser.ie) {
  15229. if (/h\d/i.test(hTag)) {
  15230. if (browser.gecko) {
  15231. var h = domUtils.findParentByTagName(start, [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6','blockquote','caption','table'], true);
  15232. if (!h) {
  15233. me.document.execCommand('formatBlock', false, '<p>');
  15234. doSave = 1;
  15235. }
  15236. } else {
  15237. //chrome remove div
  15238. if (start.nodeType == 1) {
  15239. var tmp = me.document.createTextNode(''),div;
  15240. range.insertNode(tmp);
  15241. div = domUtils.findParentByTagName(tmp, 'div', true);
  15242. if (div) {
  15243. var p = me.document.createElement('p');
  15244. while (div.firstChild) {
  15245. p.appendChild(div.firstChild);
  15246. }
  15247. div.parentNode.insertBefore(p, div);
  15248. domUtils.remove(div);
  15249. range.setStartBefore(tmp).setCursor();
  15250. doSave = 1;
  15251. }
  15252. domUtils.remove(tmp);
  15253. }
  15254. }
  15255. if (me.undoManger && doSave) {
  15256. me.undoManger.save();
  15257. }
  15258. }
  15259. //没有站位符,会出现多行的问题
  15260. browser.opera && range.select();
  15261. }else{
  15262. me.fireEvent('saveScene',true,true)
  15263. }
  15264. }
  15265. });
  15266. me.addListener('keydown', function(type, evt) {
  15267. var keyCode = evt.keyCode || evt.which;
  15268. if (keyCode == 13) {//回车
  15269. if(me.fireEvent('beforeenterkeydown')){
  15270. domUtils.preventDefault(evt);
  15271. return;
  15272. }
  15273. me.fireEvent('saveScene',true,true);
  15274. hTag = '';
  15275. var range = me.selection.getRange();
  15276. if (!range.collapsed) {
  15277. //跨td不能删
  15278. var start = range.startContainer,
  15279. end = range.endContainer,
  15280. startTd = domUtils.findParentByTagName(start, 'td', true),
  15281. endTd = domUtils.findParentByTagName(end, 'td', true);
  15282. if (startTd && endTd && startTd !== endTd || !startTd && endTd || startTd && !endTd) {
  15283. evt.preventDefault ? evt.preventDefault() : ( evt.returnValue = false);
  15284. return;
  15285. }
  15286. }
  15287. if (tag == 'p') {
  15288. if (!browser.ie) {
  15289. start = domUtils.findParentByTagName(range.startContainer, ['ol','ul','p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6','blockquote','caption'], true);
  15290. //opera下执行formatblock会在table的场景下有问题,回车在opera原生支持很好,所以暂时在opera去掉调用这个原生的command
  15291. //trace:2431
  15292. if (!start && !browser.opera) {
  15293. me.document.execCommand('formatBlock', false, '<p>');
  15294. if (browser.gecko) {
  15295. range = me.selection.getRange();
  15296. start = domUtils.findParentByTagName(range.startContainer, 'p', true);
  15297. start && domUtils.removeDirtyAttr(start);
  15298. }
  15299. } else {
  15300. hTag = start.tagName;
  15301. start.tagName.toLowerCase() == 'p' && browser.gecko && domUtils.removeDirtyAttr(start);
  15302. }
  15303. }
  15304. } else {
  15305. evt.preventDefault ? evt.preventDefault() : ( evt.returnValue = false);
  15306. if (!range.collapsed) {
  15307. range.deleteContents();
  15308. start = range.startContainer;
  15309. if (start.nodeType == 1 && (start = start.childNodes[range.startOffset])) {
  15310. while (start.nodeType == 1) {
  15311. if (dtd.$empty[start.tagName]) {
  15312. range.setStartBefore(start).setCursor();
  15313. if (me.undoManger) {
  15314. me.undoManger.save();
  15315. }
  15316. return false;
  15317. }
  15318. if (!start.firstChild) {
  15319. var br = range.document.createElement('br');
  15320. start.appendChild(br);
  15321. range.setStart(start, 0).setCursor();
  15322. if (me.undoManger) {
  15323. me.undoManger.save();
  15324. }
  15325. return false;
  15326. }
  15327. start = start.firstChild;
  15328. }
  15329. if (start === range.startContainer.childNodes[range.startOffset]) {
  15330. br = range.document.createElement('br');
  15331. range.insertNode(br).setCursor();
  15332. } else {
  15333. range.setStart(start, 0).setCursor();
  15334. }
  15335. } else {
  15336. br = range.document.createElement('br');
  15337. range.insertNode(br).setStartAfter(br).setCursor();
  15338. }
  15339. } else {
  15340. br = range.document.createElement('br');
  15341. range.insertNode(br);
  15342. var parent = br.parentNode;
  15343. if (parent.lastChild === br) {
  15344. br.parentNode.insertBefore(br.cloneNode(true), br);
  15345. range.setStartBefore(br);
  15346. } else {
  15347. range.setStartAfter(br);
  15348. }
  15349. range.setCursor();
  15350. }
  15351. }
  15352. }
  15353. });
  15354. };
  15355. // plugins/keystrokes.js
  15356. /* 处理特殊键的兼容性问题 */
  15357. UE.plugins['keystrokes'] = function() {
  15358. var me = this;
  15359. var collapsed = true;
  15360. me.addListener('keydown', function(type, evt) {
  15361. var keyCode = evt.keyCode || evt.which,
  15362. rng = me.selection.getRange();
  15363. //处理全选的情况
  15364. if(!rng.collapsed && !(evt.ctrlKey || evt.shiftKey || evt.altKey || evt.metaKey) && (keyCode >= 65 && keyCode <=90
  15365. || keyCode >= 48 && keyCode <= 57 ||
  15366. keyCode >= 96 && keyCode <= 111 || {
  15367. 13:1,
  15368. 8:1,
  15369. 46:1
  15370. }[keyCode])
  15371. ){
  15372. var tmpNode = rng.startContainer;
  15373. if(domUtils.isFillChar(tmpNode)){
  15374. rng.setStartBefore(tmpNode)
  15375. }
  15376. tmpNode = rng.endContainer;
  15377. if(domUtils.isFillChar(tmpNode)){
  15378. rng.setEndAfter(tmpNode)
  15379. }
  15380. rng.txtToElmBoundary();
  15381. //结束边界可能放到了br的前边,要把br包含进来
  15382. // x[xxx]<br/>
  15383. if(rng.endContainer && rng.endContainer.nodeType == 1){
  15384. tmpNode = rng.endContainer.childNodes[rng.endOffset];
  15385. if(tmpNode && domUtils.isBr(tmpNode)){
  15386. rng.setEndAfter(tmpNode);
  15387. }
  15388. }
  15389. if(rng.startOffset == 0){
  15390. tmpNode = rng.startContainer;
  15391. if(domUtils.isBoundaryNode(tmpNode,'firstChild') ){
  15392. tmpNode = rng.endContainer;
  15393. if(rng.endOffset == (tmpNode.nodeType == 3 ? tmpNode.nodeValue.length : tmpNode.childNodes.length) && domUtils.isBoundaryNode(tmpNode,'lastChild')){
  15394. me.fireEvent('saveScene');
  15395. me.body.innerHTML = '<p>'+(browser.ie ? '' : '<br/>')+'</p>';
  15396. rng.setStart(me.body.firstChild,0).setCursor(false,true);
  15397. me._selectionChange();
  15398. return;
  15399. }
  15400. }
  15401. }
  15402. }
  15403. //处理backspace
  15404. if (keyCode == keymap.Backspace) {
  15405. rng = me.selection.getRange();
  15406. collapsed = rng.collapsed;
  15407. if(me.fireEvent('delkeydown',evt)){
  15408. return;
  15409. }
  15410. var start,end;
  15411. //避免按两次删除才能生效的问题
  15412. if(rng.collapsed && rng.inFillChar()){
  15413. start = rng.startContainer;
  15414. if(domUtils.isFillChar(start)){
  15415. rng.setStartBefore(start).shrinkBoundary(true).collapse(true);
  15416. domUtils.remove(start)
  15417. }else{
  15418. start.nodeValue = start.nodeValue.replace(new RegExp('^' + domUtils.fillChar ),'');
  15419. rng.startOffset--;
  15420. rng.collapse(true).select(true)
  15421. }
  15422. }
  15423. //解决选中control元素不能删除的问题
  15424. if (start = rng.getClosedNode()) {
  15425. me.fireEvent('saveScene');
  15426. rng.setStartBefore(start);
  15427. domUtils.remove(start);
  15428. rng.setCursor();
  15429. me.fireEvent('saveScene');
  15430. domUtils.preventDefault(evt);
  15431. return;
  15432. }
  15433. //阻止在table上的删除
  15434. if (!browser.ie) {
  15435. start = domUtils.findParentByTagName(rng.startContainer, 'table', true);
  15436. end = domUtils.findParentByTagName(rng.endContainer, 'table', true);
  15437. if (start && !end || !start && end || start !== end) {
  15438. evt.preventDefault();
  15439. return;
  15440. }
  15441. }
  15442. }
  15443. //处理tab键的逻辑
  15444. if (keyCode == keymap.Tab) {
  15445. //不处理以下标签
  15446. var excludeTagNameForTabKey = {
  15447. 'ol' : 1,
  15448. 'ul' : 1,
  15449. 'table':1
  15450. };
  15451. //处理组件里的tab按下事件
  15452. if(me.fireEvent('tabkeydown',evt)){
  15453. domUtils.preventDefault(evt);
  15454. return;
  15455. }
  15456. var range = me.selection.getRange();
  15457. me.fireEvent('saveScene');
  15458. for (var i = 0,txt = '',tabSize = me.options.tabSize|| 4,tabNode = me.options.tabNode || '&nbsp;'; i < tabSize; i++) {
  15459. txt += tabNode;
  15460. }
  15461. var span = me.document.createElement('span');
  15462. span.innerHTML = txt + domUtils.fillChar;
  15463. if (range.collapsed) {
  15464. range.insertNode(span.cloneNode(true).firstChild).setCursor(true);
  15465. } else {
  15466. var filterFn = function(node) {
  15467. return domUtils.isBlockElm(node) && !excludeTagNameForTabKey[node.tagName.toLowerCase()]
  15468. };
  15469. //普通的情况
  15470. start = domUtils.findParent(range.startContainer, filterFn,true);
  15471. end = domUtils.findParent(range.endContainer, filterFn,true);
  15472. if (start && end && start === end) {
  15473. range.deleteContents();
  15474. range.insertNode(span.cloneNode(true).firstChild).setCursor(true);
  15475. } else {
  15476. var bookmark = range.createBookmark();
  15477. range.enlarge(true);
  15478. var bookmark2 = range.createBookmark(),
  15479. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn);
  15480. while (current && !(domUtils.getPosition(current, bookmark2.end) & domUtils.POSITION_FOLLOWING)) {
  15481. current.insertBefore(span.cloneNode(true).firstChild, current.firstChild);
  15482. current = domUtils.getNextDomNode(current, false, filterFn);
  15483. }
  15484. range.moveToBookmark(bookmark2).moveToBookmark(bookmark).select();
  15485. }
  15486. }
  15487. domUtils.preventDefault(evt)
  15488. }
  15489. //trace:1634
  15490. //ff的del键在容器空的时候,也会删除
  15491. if(browser.gecko && keyCode == 46){
  15492. range = me.selection.getRange();
  15493. if(range.collapsed){
  15494. start = range.startContainer;
  15495. if(domUtils.isEmptyBlock(start)){
  15496. var parent = start.parentNode;
  15497. while(domUtils.getChildCount(parent) == 1 && !domUtils.isBody(parent)){
  15498. start = parent;
  15499. parent = parent.parentNode;
  15500. }
  15501. if(start === parent.lastChild)
  15502. evt.preventDefault();
  15503. return;
  15504. }
  15505. }
  15506. }
  15507. });
  15508. me.addListener('keyup', function(type, evt) {
  15509. var keyCode = evt.keyCode || evt.which,
  15510. rng,me = this;
  15511. if(keyCode == keymap.Backspace){
  15512. if(me.fireEvent('delkeyup')){
  15513. return;
  15514. }
  15515. rng = me.selection.getRange();
  15516. if(rng.collapsed){
  15517. var tmpNode,
  15518. autoClearTagName = ['h1','h2','h3','h4','h5','h6'];
  15519. if(tmpNode = domUtils.findParentByTagName(rng.startContainer,autoClearTagName,true)){
  15520. if(domUtils.isEmptyBlock(tmpNode)){
  15521. var pre = tmpNode.previousSibling;
  15522. if(pre && pre.nodeName != 'TABLE'){
  15523. domUtils.remove(tmpNode);
  15524. rng.setStartAtLast(pre).setCursor(false,true);
  15525. return;
  15526. }else{
  15527. var next = tmpNode.nextSibling;
  15528. if(next && next.nodeName != 'TABLE'){
  15529. domUtils.remove(tmpNode);
  15530. rng.setStartAtFirst(next).setCursor(false,true);
  15531. return;
  15532. }
  15533. }
  15534. }
  15535. }
  15536. //处理当删除到body时,要重新给p标签展位
  15537. if(domUtils.isBody(rng.startContainer)){
  15538. var tmpNode = domUtils.createElement(me.document,'p',{
  15539. 'innerHTML' : browser.ie ? domUtils.fillChar : '<br/>'
  15540. });
  15541. rng.insertNode(tmpNode).setStart(tmpNode,0).setCursor(false,true);
  15542. }
  15543. }
  15544. //chrome下如果删除了inline标签,浏览器会有记忆,在输入文字还是会套上刚才删除的标签,所以这里再选一次就不会了
  15545. if( !collapsed && (rng.startContainer.nodeType == 3 || rng.startContainer.nodeType == 1 && domUtils.isEmptyBlock(rng.startContainer))){
  15546. if(browser.ie){
  15547. var span = rng.document.createElement('span');
  15548. rng.insertNode(span).setStartBefore(span).collapse(true);
  15549. rng.select();
  15550. domUtils.remove(span)
  15551. }else{
  15552. rng.select()
  15553. }
  15554. }
  15555. }
  15556. })
  15557. };
  15558. // plugins/fiximgclick.js
  15559. ///import core
  15560. ///commands 修复chrome下图片不能点击的问题,出现八个角可改变大小
  15561. ///commandsName FixImgClick
  15562. ///commandsTitle 修复chrome下图片不能点击的问题,出现八个角可改变大小
  15563. //修复chrome下图片不能点击的问题,出现八个角可改变大小
  15564. UE.plugins['fiximgclick'] = (function () {
  15565. var elementUpdated = false;
  15566. function Scale() {
  15567. this.editor = null;
  15568. this.resizer = null;
  15569. this.cover = null;
  15570. this.doc = document;
  15571. this.prePos = {x: 0, y: 0};
  15572. this.startPos = {x: 0, y: 0};
  15573. }
  15574. (function () {
  15575. var rect = [
  15576. //[left, top, width, height]
  15577. [0, 0, -1, -1],
  15578. [0, 0, 0, -1],
  15579. [0, 0, 1, -1],
  15580. [0, 0, -1, 0],
  15581. [0, 0, 1, 0],
  15582. [0, 0, -1, 1],
  15583. [0, 0, 0, 1],
  15584. [0, 0, 1, 1]
  15585. ];
  15586. Scale.prototype = {
  15587. init: function (editor) {
  15588. var me = this;
  15589. me.editor = editor;
  15590. me.startPos = this.prePos = {x: 0, y: 0};
  15591. me.dragId = -1;
  15592. var hands = [],
  15593. cover = me.cover = document.createElement('div'),
  15594. resizer = me.resizer = document.createElement('div');
  15595. cover.id = me.editor.ui.id + '_imagescale_cover';
  15596. cover.style.cssText = 'position:absolute;display:none;z-index:' + (me.editor.options.zIndex) + ';filter:alpha(opacity=0); opacity:0;background:#CCC;';
  15597. domUtils.on(cover, 'mousedown click', function () {
  15598. me.hide();
  15599. });
  15600. for (var i = 0; i < 8; i++) {
  15601. hands.push('<span class="edui-editor-imagescale-hand' + i + '"></span>');
  15602. }
  15603. resizer.id = me.editor.ui.id + '_imagescale';
  15604. resizer.className = 'edui-editor-imagescale';
  15605. resizer.innerHTML = hands.join('');
  15606. resizer.style.cssText += ';display:none;border:1px solid #3b77ff;z-index:' + (me.editor.options.zIndex) + ';';
  15607. me.editor.ui.getDom().appendChild(cover);
  15608. me.editor.ui.getDom().appendChild(resizer);
  15609. me.initStyle();
  15610. me.initEvents();
  15611. },
  15612. initStyle: function () {
  15613. utils.cssRule('imagescale', '.edui-editor-imagescale{display:none;position:absolute;border:1px solid #38B2CE;cursor:hand;-webkit-box-sizing: content-box;-moz-box-sizing: content-box;box-sizing: content-box;}' +
  15614. '.edui-editor-imagescale span{position:absolute;width:6px;height:6px;overflow:hidden;font-size:0px;display:block;background-color:#3C9DD0;}'
  15615. + '.edui-editor-imagescale .edui-editor-imagescale-hand0{cursor:nw-resize;top:0;margin-top:-4px;left:0;margin-left:-4px;}'
  15616. + '.edui-editor-imagescale .edui-editor-imagescale-hand1{cursor:n-resize;top:0;margin-top:-4px;left:50%;margin-left:-4px;}'
  15617. + '.edui-editor-imagescale .edui-editor-imagescale-hand2{cursor:ne-resize;top:0;margin-top:-4px;left:100%;margin-left:-3px;}'
  15618. + '.edui-editor-imagescale .edui-editor-imagescale-hand3{cursor:w-resize;top:50%;margin-top:-4px;left:0;margin-left:-4px;}'
  15619. + '.edui-editor-imagescale .edui-editor-imagescale-hand4{cursor:e-resize;top:50%;margin-top:-4px;left:100%;margin-left:-3px;}'
  15620. + '.edui-editor-imagescale .edui-editor-imagescale-hand5{cursor:sw-resize;top:100%;margin-top:-3px;left:0;margin-left:-4px;}'
  15621. + '.edui-editor-imagescale .edui-editor-imagescale-hand6{cursor:s-resize;top:100%;margin-top:-3px;left:50%;margin-left:-4px;}'
  15622. + '.edui-editor-imagescale .edui-editor-imagescale-hand7{cursor:se-resize;top:100%;margin-top:-3px;left:100%;margin-left:-3px;}');
  15623. },
  15624. initEvents: function () {
  15625. var me = this;
  15626. me.startPos.x = me.startPos.y = 0;
  15627. me.isDraging = false;
  15628. },
  15629. _eventHandler: function (e) {
  15630. var me = this;
  15631. switch (e.type) {
  15632. case 'mousedown':
  15633. var hand = e.target || e.srcElement, hand;
  15634. if (hand.className.indexOf('edui-editor-imagescale-hand') != -1 && me.dragId == -1) {
  15635. me.dragId = hand.className.slice(-1);
  15636. me.startPos.x = me.prePos.x = e.clientX;
  15637. me.startPos.y = me.prePos.y = e.clientY;
  15638. domUtils.on(me.doc,'mousemove', me.proxy(me._eventHandler, me));
  15639. }
  15640. break;
  15641. case 'mousemove':
  15642. if (me.dragId != -1) {
  15643. me.updateContainerStyle(me.dragId, {x: e.clientX - me.prePos.x, y: e.clientY - me.prePos.y});
  15644. me.prePos.x = e.clientX;
  15645. me.prePos.y = e.clientY;
  15646. elementUpdated = true;
  15647. me.updateTargetElement();
  15648. }
  15649. break;
  15650. case 'mouseup':
  15651. if (me.dragId != -1) {
  15652. me.updateContainerStyle(me.dragId, {x: e.clientX - me.prePos.x, y: e.clientY - me.prePos.y});
  15653. me.updateTargetElement();
  15654. if (me.target.parentNode) me.attachTo(me.target);
  15655. me.dragId = -1;
  15656. }
  15657. domUtils.un(me.doc,'mousemove', me.proxy(me._eventHandler, me));
  15658. //修复只是点击挪动点,但没有改变大小,不应该触发contentchange
  15659. if(elementUpdated){
  15660. elementUpdated = false;
  15661. me.editor.fireEvent('contentchange');
  15662. }
  15663. break;
  15664. default:
  15665. break;
  15666. }
  15667. },
  15668. updateTargetElement: function () {
  15669. var me = this;
  15670. domUtils.setStyles(me.target, {
  15671. 'width': me.resizer.style.width,
  15672. 'height': me.resizer.style.height
  15673. });
  15674. me.target.width = parseInt(me.resizer.style.width);
  15675. me.target.height = parseInt(me.resizer.style.height);
  15676. me.attachTo(me.target);
  15677. },
  15678. updateContainerStyle: function (dir, offset) {
  15679. var me = this,
  15680. dom = me.resizer, tmp;
  15681. if (rect[dir][0] != 0) {
  15682. tmp = parseInt(dom.style.left) + offset.x;
  15683. dom.style.left = me._validScaledProp('left', tmp) + 'px';
  15684. }
  15685. if (rect[dir][1] != 0) {
  15686. tmp = parseInt(dom.style.top) + offset.y;
  15687. dom.style.top = me._validScaledProp('top', tmp) + 'px';
  15688. }
  15689. if (rect[dir][2] != 0) {
  15690. tmp = dom.clientWidth + rect[dir][2] * offset.x;
  15691. dom.style.width = me._validScaledProp('width', tmp) + 'px';
  15692. }
  15693. if (rect[dir][3] != 0) {
  15694. tmp = dom.clientHeight + rect[dir][3] * offset.y;
  15695. dom.style.height = me._validScaledProp('height', tmp) + 'px';
  15696. }
  15697. },
  15698. _validScaledProp: function (prop, value) {
  15699. var ele = this.resizer,
  15700. wrap = document;
  15701. value = isNaN(value) ? 0 : value;
  15702. switch (prop) {
  15703. case 'left':
  15704. return value < 0 ? 0 : (value + ele.clientWidth) > wrap.clientWidth ? wrap.clientWidth - ele.clientWidth : value;
  15705. case 'top':
  15706. return value < 0 ? 0 : (value + ele.clientHeight) > wrap.clientHeight ? wrap.clientHeight - ele.clientHeight : value;
  15707. case 'width':
  15708. return value <= 0 ? 1 : (value + ele.offsetLeft) > wrap.clientWidth ? wrap.clientWidth - ele.offsetLeft : value;
  15709. case 'height':
  15710. return value <= 0 ? 1 : (value + ele.offsetTop) > wrap.clientHeight ? wrap.clientHeight - ele.offsetTop : value;
  15711. }
  15712. },
  15713. hideCover: function () {
  15714. this.cover.style.display = 'none';
  15715. },
  15716. showCover: function () {
  15717. var me = this,
  15718. editorPos = domUtils.getXY(me.editor.ui.getDom()),
  15719. iframePos = domUtils.getXY(me.editor.iframe);
  15720. domUtils.setStyles(me.cover, {
  15721. 'width': me.editor.iframe.offsetWidth + 'px',
  15722. 'height': me.editor.iframe.offsetHeight + 'px',
  15723. 'top': iframePos.y - editorPos.y + 'px',
  15724. 'left': iframePos.x - editorPos.x + 'px',
  15725. 'position': 'absolute',
  15726. 'display': ''
  15727. })
  15728. },
  15729. show: function (targetObj) {
  15730. var me = this;
  15731. me.resizer.style.display = 'block';
  15732. if(targetObj) me.attachTo(targetObj);
  15733. domUtils.on(this.resizer, 'mousedown', me.proxy(me._eventHandler, me));
  15734. domUtils.on(me.doc, 'mouseup', me.proxy(me._eventHandler, me));
  15735. me.showCover();
  15736. me.editor.fireEvent('afterscaleshow', me);
  15737. me.editor.fireEvent('saveScene');
  15738. },
  15739. hide: function () {
  15740. var me = this;
  15741. me.hideCover();
  15742. me.resizer.style.display = 'none';
  15743. domUtils.un(me.resizer, 'mousedown', me.proxy(me._eventHandler, me));
  15744. domUtils.un(me.doc, 'mouseup', me.proxy(me._eventHandler, me));
  15745. me.editor.fireEvent('afterscalehide', me);
  15746. },
  15747. proxy: function( fn, context ) {
  15748. return function(e) {
  15749. return fn.apply( context || this, arguments);
  15750. };
  15751. },
  15752. attachTo: function (targetObj) {
  15753. var me = this,
  15754. target = me.target = targetObj,
  15755. resizer = this.resizer,
  15756. imgPos = domUtils.getXY(target),
  15757. iframePos = domUtils.getXY(me.editor.iframe),
  15758. editorPos = domUtils.getXY(resizer.parentNode);
  15759. domUtils.setStyles(resizer, {
  15760. 'width': target.width + 'px',
  15761. 'height': target.height + 'px',
  15762. 'left': iframePos.x + imgPos.x - me.editor.document.body.scrollLeft - editorPos.x - parseInt(resizer.style.borderLeftWidth) + 'px',
  15763. 'top': iframePos.y + imgPos.y - me.editor.document.body.scrollTop - editorPos.y - parseInt(resizer.style.borderTopWidth) + 'px'
  15764. });
  15765. }
  15766. }
  15767. })();
  15768. return function () {
  15769. var me = this,
  15770. imageScale;
  15771. me.setOpt('imageScaleEnabled', true);
  15772. if ( !browser.ie && me.options.imageScaleEnabled) {
  15773. me.addListener('click', function (type, e) {
  15774. var range = me.selection.getRange(),
  15775. img = range.getClosedNode();
  15776. if (img && img.tagName == 'IMG' && me.body.contentEditable!="false") {
  15777. if (img.className.indexOf("edui-faked-music") != -1 ||
  15778. img.getAttribute("anchorname") ||
  15779. domUtils.hasClass(img, 'loadingclass') ||
  15780. domUtils.hasClass(img, 'loaderrorclass')) { return }
  15781. if (!imageScale) {
  15782. imageScale = new Scale();
  15783. imageScale.init(me);
  15784. me.ui.getDom().appendChild(imageScale.resizer);
  15785. var _keyDownHandler = function (e) {
  15786. imageScale.hide();
  15787. if(imageScale.target) me.selection.getRange().selectNode(imageScale.target).select();
  15788. }, _mouseDownHandler = function (e) {
  15789. var ele = e.target || e.srcElement;
  15790. if (ele && (ele.className===undefined || ele.className.indexOf('edui-editor-imagescale') == -1)) {
  15791. _keyDownHandler(e);
  15792. }
  15793. }, timer;
  15794. me.addListener('afterscaleshow', function (e) {
  15795. me.addListener('beforekeydown', _keyDownHandler);
  15796. me.addListener('beforemousedown', _mouseDownHandler);
  15797. domUtils.on(document, 'keydown', _keyDownHandler);
  15798. domUtils.on(document,'mousedown', _mouseDownHandler);
  15799. me.selection.getNative().removeAllRanges();
  15800. });
  15801. me.addListener('afterscalehide', function (e) {
  15802. me.removeListener('beforekeydown', _keyDownHandler);
  15803. me.removeListener('beforemousedown', _mouseDownHandler);
  15804. domUtils.un(document, 'keydown', _keyDownHandler);
  15805. domUtils.un(document,'mousedown', _mouseDownHandler);
  15806. var target = imageScale.target;
  15807. if (target.parentNode) {
  15808. me.selection.getRange().selectNode(target).select();
  15809. }
  15810. });
  15811. //TODO 有iframe的情况,mousedown不能往下传。。
  15812. domUtils.on(imageScale.resizer, 'mousedown', function (e) {
  15813. me.selection.getNative().removeAllRanges();
  15814. var ele = e.target || e.srcElement;
  15815. if (ele && ele.className.indexOf('edui-editor-imagescale-hand') == -1) {
  15816. timer = setTimeout(function () {
  15817. imageScale.hide();
  15818. if(imageScale.target) me.selection.getRange().selectNode(ele).select();
  15819. }, 200);
  15820. }
  15821. });
  15822. domUtils.on(imageScale.resizer, 'mouseup', function (e) {
  15823. var ele = e.target || e.srcElement;
  15824. if (ele && ele.className.indexOf('edui-editor-imagescale-hand') == -1) {
  15825. clearTimeout(timer);
  15826. }
  15827. });
  15828. }
  15829. imageScale.show(img);
  15830. } else {
  15831. if (imageScale && imageScale.resizer.style.display != 'none') imageScale.hide();
  15832. }
  15833. });
  15834. }
  15835. if (browser.webkit) {
  15836. me.addListener('click', function (type, e) {
  15837. if (e.target.tagName == 'IMG' && me.body.contentEditable!="false") {
  15838. var range = new dom.Range(me.document);
  15839. range.selectNode(e.target).select();
  15840. }
  15841. });
  15842. }
  15843. }
  15844. })();
  15845. // plugins/autolink.js
  15846. ///import core
  15847. ///commands 为非ie浏览器自动添加a标签
  15848. ///commandsName AutoLink
  15849. ///commandsTitle 自动增加链接
  15850. /**
  15851. * @description 为非ie浏览器自动添加a标签
  15852. * @author zhanyi
  15853. */
  15854. UE.plugin.register('autolink',function(){
  15855. var cont = 0;
  15856. return !browser.ie ? {
  15857. bindEvents:{
  15858. 'reset' : function(){
  15859. cont = 0;
  15860. },
  15861. 'keydown':function(type, evt) {
  15862. var me = this;
  15863. var keyCode = evt.keyCode || evt.which;
  15864. if (keyCode == 32 || keyCode == 13) {
  15865. var sel = me.selection.getNative(),
  15866. range = sel.getRangeAt(0).cloneRange(),
  15867. offset,
  15868. charCode;
  15869. var start = range.startContainer;
  15870. while (start.nodeType == 1 && range.startOffset > 0) {
  15871. start = range.startContainer.childNodes[range.startOffset - 1];
  15872. if (!start){
  15873. break;
  15874. }
  15875. range.setStart(start, start.nodeType == 1 ? start.childNodes.length : start.nodeValue.length);
  15876. range.collapse(true);
  15877. start = range.startContainer;
  15878. }
  15879. do{
  15880. if (range.startOffset == 0) {
  15881. start = range.startContainer.previousSibling;
  15882. while (start && start.nodeType == 1) {
  15883. start = start.lastChild;
  15884. }
  15885. if (!start || domUtils.isFillChar(start)){
  15886. break;
  15887. }
  15888. offset = start.nodeValue.length;
  15889. } else {
  15890. start = range.startContainer;
  15891. offset = range.startOffset;
  15892. }
  15893. range.setStart(start, offset - 1);
  15894. charCode = range.toString().charCodeAt(0);
  15895. } while (charCode != 160 && charCode != 32);
  15896. if (range.toString().replace(new RegExp(domUtils.fillChar, 'g'), '').match(/(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i)) {
  15897. while(range.toString().length){
  15898. if(/^(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i.test(range.toString())){
  15899. break;
  15900. }
  15901. try{
  15902. range.setStart(range.startContainer,range.startOffset+1);
  15903. }catch(e){
  15904. //trace:2121
  15905. var start = range.startContainer;
  15906. while(!(next = start.nextSibling)){
  15907. if(domUtils.isBody(start)){
  15908. return;
  15909. }
  15910. start = start.parentNode;
  15911. }
  15912. range.setStart(next,0);
  15913. }
  15914. }
  15915. //range的开始边界已经在a标签里的不再处理
  15916. if(domUtils.findParentByTagName(range.startContainer,'a',true)){
  15917. return;
  15918. }
  15919. var a = me.document.createElement('a'),text = me.document.createTextNode(' '),href;
  15920. me.undoManger && me.undoManger.save();
  15921. a.appendChild(range.extractContents());
  15922. a.href = a.innerHTML = a.innerHTML.replace(/<[^>]+>/g,'');
  15923. href = a.getAttribute("href").replace(new RegExp(domUtils.fillChar,'g'),'');
  15924. href = /^(?:https?:\/\/)/ig.test(href) ? href : "http://"+ href;
  15925. a.setAttribute('_src',utils.html(href));
  15926. a.href = utils.html(href);
  15927. range.insertNode(a);
  15928. a.parentNode.insertBefore(text, a.nextSibling);
  15929. range.setStart(text, 0);
  15930. range.collapse(true);
  15931. sel.removeAllRanges();
  15932. sel.addRange(range);
  15933. me.undoManger && me.undoManger.save();
  15934. }
  15935. }
  15936. }
  15937. }
  15938. }:{}
  15939. },function(){
  15940. var keyCodes = {
  15941. 37:1, 38:1, 39:1, 40:1,
  15942. 13:1,32:1
  15943. };
  15944. function checkIsCludeLink(node){
  15945. if(node.nodeType == 3){
  15946. return null
  15947. }
  15948. if(node.nodeName == 'A'){
  15949. return node;
  15950. }
  15951. var lastChild = node.lastChild;
  15952. while(lastChild){
  15953. if(lastChild.nodeName == 'A'){
  15954. return lastChild;
  15955. }
  15956. if(lastChild.nodeType == 3){
  15957. if(domUtils.isWhitespace(lastChild)){
  15958. lastChild = lastChild.previousSibling;
  15959. continue;
  15960. }
  15961. return null
  15962. }
  15963. lastChild = lastChild.lastChild;
  15964. }
  15965. }
  15966. browser.ie && this.addListener('keyup',function(cmd,evt){
  15967. var me = this,keyCode = evt.keyCode;
  15968. if(keyCodes[keyCode]){
  15969. var rng = me.selection.getRange();
  15970. var start = rng.startContainer;
  15971. if(keyCode == 13){
  15972. while(start && !domUtils.isBody(start) && !domUtils.isBlockElm(start)){
  15973. start = start.parentNode;
  15974. }
  15975. if(start && !domUtils.isBody(start) && start.nodeName == 'P'){
  15976. var pre = start.previousSibling;
  15977. if(pre && pre.nodeType == 1){
  15978. var pre = checkIsCludeLink(pre);
  15979. if(pre && !pre.getAttribute('_href')){
  15980. domUtils.remove(pre,true);
  15981. }
  15982. }
  15983. }
  15984. }else if(keyCode == 32 ){
  15985. if(start.nodeType == 3 && /^\s$/.test(start.nodeValue)){
  15986. start = start.previousSibling;
  15987. if(start && start.nodeName == 'A' && !start.getAttribute('_href')){
  15988. domUtils.remove(start,true);
  15989. }
  15990. }
  15991. }else {
  15992. start = domUtils.findParentByTagName(start,'a',true);
  15993. if(start && !start.getAttribute('_href')){
  15994. var bk = rng.createBookmark();
  15995. domUtils.remove(start,true);
  15996. rng.moveToBookmark(bk).select(true)
  15997. }
  15998. }
  15999. }
  16000. });
  16001. }
  16002. );
  16003. // plugins/autoheight.js
  16004. ///import core
  16005. ///commands 当输入内容超过编辑器高度时,编辑器自动增高
  16006. ///commandsName AutoHeight,autoHeightEnabled
  16007. ///commandsTitle 自动增高
  16008. /**
  16009. * @description 自动伸展
  16010. * @author zhanyi
  16011. */
  16012. UE.plugins['autoheight'] = function () {
  16013. var me = this;
  16014. //提供开关,就算加载也可以关闭
  16015. me.autoHeightEnabled = me.options.autoHeightEnabled !== false;
  16016. if (!me.autoHeightEnabled) {
  16017. return;
  16018. }
  16019. var bakOverflow,
  16020. lastHeight = 0,
  16021. options = me.options,
  16022. currentHeight,
  16023. timer;
  16024. function adjustHeight() {
  16025. var me = this;
  16026. clearTimeout(timer);
  16027. if(isFullscreen)return;
  16028. if (!me.queryCommandState || me.queryCommandState && me.queryCommandState('source') != 1) {
  16029. timer = setTimeout(function(){
  16030. var node = me.body.lastChild;
  16031. while(node && node.nodeType != 1){
  16032. node = node.previousSibling;
  16033. }
  16034. if(node && node.nodeType == 1){
  16035. node.style.clear = 'both';
  16036. currentHeight = Math.max(domUtils.getXY(node).y + node.offsetHeight + 25 ,Math.max(options.minFrameHeight, options.initialFrameHeight)) ;
  16037. if (currentHeight != lastHeight) {
  16038. if (currentHeight !== parseInt(me.iframe.parentNode.style.height)) {
  16039. me.iframe.parentNode.style.height = currentHeight + 'px';
  16040. }
  16041. me.body.style.height = currentHeight + 'px';
  16042. lastHeight = currentHeight;
  16043. }
  16044. domUtils.removeStyle(node,'clear');
  16045. }
  16046. },50)
  16047. }
  16048. }
  16049. var isFullscreen;
  16050. me.addListener('fullscreenchanged',function(cmd,f){
  16051. isFullscreen = f
  16052. });
  16053. me.addListener('destroy', function () {
  16054. me.removeListener('contentchange afterinserthtml keyup mouseup',adjustHeight)
  16055. });
  16056. me.enableAutoHeight = function () {
  16057. var me = this;
  16058. if (!me.autoHeightEnabled) {
  16059. return;
  16060. }
  16061. var doc = me.document;
  16062. me.autoHeightEnabled = true;
  16063. bakOverflow = doc.body.style.overflowY;
  16064. doc.body.style.overflowY = 'hidden';
  16065. me.addListener('contentchange afterinserthtml keyup mouseup',adjustHeight);
  16066. //ff不给事件算得不对
  16067. setTimeout(function () {
  16068. adjustHeight.call(me);
  16069. }, browser.gecko ? 100 : 0);
  16070. me.fireEvent('autoheightchanged', me.autoHeightEnabled);
  16071. };
  16072. me.disableAutoHeight = function () {
  16073. me.body.style.overflowY = bakOverflow || '';
  16074. me.removeListener('contentchange', adjustHeight);
  16075. me.removeListener('keyup', adjustHeight);
  16076. me.removeListener('mouseup', adjustHeight);
  16077. me.autoHeightEnabled = false;
  16078. me.fireEvent('autoheightchanged', me.autoHeightEnabled);
  16079. };
  16080. me.on('setHeight',function(){
  16081. me.disableAutoHeight()
  16082. });
  16083. me.addListener('ready', function () {
  16084. me.enableAutoHeight();
  16085. //trace:1764
  16086. var timer;
  16087. domUtils.on(browser.ie ? me.body : me.document, browser.webkit ? 'dragover' : 'drop', function () {
  16088. clearTimeout(timer);
  16089. timer = setTimeout(function () {
  16090. //trace:3681
  16091. adjustHeight.call(me);
  16092. }, 100);
  16093. });
  16094. //修复内容过多时,回到顶部,顶部内容被工具栏遮挡问题
  16095. var lastScrollY;
  16096. window.onscroll = function(){
  16097. if(lastScrollY === null){
  16098. lastScrollY = this.scrollY
  16099. }else if(this.scrollY == 0 && lastScrollY != 0){
  16100. me.window.scrollTo(0,0);
  16101. lastScrollY = null;
  16102. }
  16103. }
  16104. });
  16105. };
  16106. // plugins/autofloat.js
  16107. ///import core
  16108. ///commands 悬浮工具栏
  16109. ///commandsName AutoFloat,autoFloatEnabled
  16110. ///commandsTitle 悬浮工具栏
  16111. /**
  16112. * modified by chengchao01
  16113. * 注意: 引入此功能后,在IE6下会将body的背景图片覆盖掉!
  16114. */
  16115. UE.plugins['autofloat'] = function() {
  16116. var me = this,
  16117. lang = me.getLang();
  16118. me.setOpt({
  16119. topOffset:0
  16120. });
  16121. var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false,
  16122. topOffset = me.options.topOffset;
  16123. //如果不固定toolbar的位置,则直接退出
  16124. if(!optsAutoFloatEnabled){
  16125. return;
  16126. }
  16127. var uiUtils = UE.ui.uiUtils,
  16128. LteIE6 = browser.ie && browser.version <= 6,
  16129. quirks = browser.quirks;
  16130. function checkHasUI(){
  16131. if(!UE.ui){
  16132. alert(lang.autofloatMsg);
  16133. return 0;
  16134. }
  16135. return 1;
  16136. }
  16137. function fixIE6FixedPos(){
  16138. var docStyle = document.body.style;
  16139. docStyle.backgroundImage = 'url("about:blank")';
  16140. docStyle.backgroundAttachment = 'fixed';
  16141. }
  16142. var bakCssText,
  16143. placeHolder = document.createElement('div'),
  16144. toolbarBox,orgTop,
  16145. getPosition,
  16146. flag =true; //ie7模式下需要偏移
  16147. function setFloating(){
  16148. var toobarBoxPos = domUtils.getXY(toolbarBox),
  16149. origalFloat = domUtils.getComputedStyle(toolbarBox,'position'),
  16150. origalLeft = domUtils.getComputedStyle(toolbarBox,'left');
  16151. toolbarBox.style.width = toolbarBox.offsetWidth + 'px';
  16152. toolbarBox.style.zIndex = me.options.zIndex * 1 + 1;
  16153. toolbarBox.parentNode.insertBefore(placeHolder, toolbarBox);
  16154. if (LteIE6 || (quirks && browser.ie)) {
  16155. if(toolbarBox.style.position != 'absolute'){
  16156. toolbarBox.style.position = 'absolute';
  16157. }
  16158. toolbarBox.style.top = (document.body.scrollTop||document.documentElement.scrollTop) - orgTop + topOffset + 'px';
  16159. } else {
  16160. if (browser.ie7Compat && flag) {
  16161. flag = false;
  16162. toolbarBox.style.left = domUtils.getXY(toolbarBox).x - document.documentElement.getBoundingClientRect().left+2 + 'px';
  16163. }
  16164. if(toolbarBox.style.position != 'fixed'){
  16165. toolbarBox.style.position = 'fixed';
  16166. toolbarBox.style.top = topOffset +"px";
  16167. ((origalFloat == 'absolute' || origalFloat == 'relative') && parseFloat(origalLeft)) && (toolbarBox.style.left = toobarBoxPos.x + 'px');
  16168. }
  16169. }
  16170. }
  16171. function unsetFloating(){
  16172. flag = true;
  16173. if(placeHolder.parentNode){
  16174. placeHolder.parentNode.removeChild(placeHolder);
  16175. }
  16176. toolbarBox.style.cssText = bakCssText;
  16177. }
  16178. function updateFloating(){
  16179. var rect3 = getPosition(me.container);
  16180. var offset=me.options.toolbarTopOffset||0;
  16181. if (rect3.top < 0 && rect3.bottom - toolbarBox.offsetHeight > offset) {
  16182. setFloating();
  16183. }else{
  16184. unsetFloating();
  16185. }
  16186. }
  16187. var defer_updateFloating = utils.defer(function(){
  16188. updateFloating();
  16189. },browser.ie ? 200 : 100,true);
  16190. me.addListener('destroy',function(){
  16191. domUtils.un(window, ['scroll','resize'], updateFloating);
  16192. me.removeListener('keydown', defer_updateFloating);
  16193. });
  16194. me.addListener('ready', function(){
  16195. if(checkHasUI(me)){
  16196. //加载了ui组件,但在new时,没有加载ui,导致编辑器实例上没有ui类,所以这里做判断
  16197. if(!me.ui){
  16198. return;
  16199. }
  16200. getPosition = uiUtils.getClientRect;
  16201. toolbarBox = me.ui.getDom('toolbarbox');
  16202. orgTop = getPosition(toolbarBox).top;
  16203. bakCssText = toolbarBox.style.cssText;
  16204. placeHolder.style.height = toolbarBox.offsetHeight + 'px';
  16205. if(LteIE6){
  16206. fixIE6FixedPos();
  16207. }
  16208. domUtils.on(window, ['scroll','resize'], updateFloating);
  16209. me.addListener('keydown', defer_updateFloating);
  16210. me.addListener('beforefullscreenchange', function (t, enabled){
  16211. if (enabled) {
  16212. unsetFloating();
  16213. }
  16214. });
  16215. me.addListener('fullscreenchanged', function (t, enabled){
  16216. if (!enabled) {
  16217. updateFloating();
  16218. }
  16219. });
  16220. me.addListener('sourcemodechanged', function (t, enabled){
  16221. setTimeout(function (){
  16222. updateFloating();
  16223. },0);
  16224. });
  16225. me.addListener("clearDoc",function(){
  16226. setTimeout(function(){
  16227. updateFloating();
  16228. },0);
  16229. })
  16230. }
  16231. });
  16232. };
  16233. // plugins/video.js
  16234. /**
  16235. * video插件, 为UEditor提供视频插入支持
  16236. * @file
  16237. * @since 1.2.6.1
  16238. */
  16239. UE.plugins['video'] = function (){
  16240. var me =this;
  16241. /**
  16242. * 创建插入视频字符窜
  16243. * @param url 视频地址
  16244. * @param width 视频宽度
  16245. * @param height 视频高度
  16246. * @param align 视频对齐
  16247. * @param toEmbed 是否以flash代替显示
  16248. * @param addParagraph 是否需要添加P 标签
  16249. */
  16250. function creatInsertStr(url,width,height,id,align,classname,type){
  16251. url = utils.unhtmlForUrl(url);
  16252. align = utils.unhtml(align);
  16253. classname = utils.unhtml(classname).trim();
  16254. width = parseInt(width, 10) || 0;
  16255. height = parseInt(height, 10) || 0;
  16256. var str;
  16257. switch (type){
  16258. case 'image':
  16259. str = '<img ' + (id ? 'id="' + id+'"' : '') + ' width="'+ width +'" height="' + height + '" _url="'+url+'" class="' + classname.replace(/\bvideo-js\b/, '') + '"' +
  16260. ' 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 + ';': '')+'" />'
  16261. break;
  16262. case 'embed':
  16263. str = '<embed type="application/x-shockwave-flash" class="' + classname + '" pluginspage="http://www.macromedia.com/go/getflashplayer"' +
  16264. ' src="' + utils.html(url) + '" width="' + width + '" height="' + height + '"' + (align ? ' style="float:' + align + '"': '') +
  16265. ' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >';
  16266. break;
  16267. case 'video':
  16268. var ext = url.substr(url.lastIndexOf('.') + 1);
  16269. if(ext == 'ogv') ext = 'ogg';
  16270. str = '<video' + (id ? ' id="' + id + '"' : '') + ' class="' + classname + ' video-js" ' + (align ? ' style="float:' + align + '"': '') +
  16271. ' controls preload="none" width="' + width + '" height="' + height + '" src="' + url + '" data-setup="{}">' +
  16272. '<source src="' + url + '" type="video/' + ext + '" /></video>';
  16273. break;
  16274. }
  16275. return str;
  16276. }
  16277. function switchImgAndVideo(root,img2video){
  16278. utils.each(root.getNodesByTagName(img2video ? 'img' : 'embed video'),function(node){
  16279. var className = node.getAttr('class');
  16280. if(className && className.indexOf('edui-faked-video') != -1){
  16281. var html = creatInsertStr( img2video ? node.getAttr('_url') : node.getAttr('src'),node.getAttr('width'),node.getAttr('height'),null,node.getStyle('float') || '',className,img2video ? 'embed':'image');
  16282. node.parentNode.replaceChild(UE.uNode.createElement(html),node);
  16283. }
  16284. if(className && className.indexOf('edui-upload-video') != -1){
  16285. var html = creatInsertStr( img2video ? node.getAttr('_url') : node.getAttr('src'),node.getAttr('width'),node.getAttr('height'),null,node.getStyle('float') || '',className,img2video ? 'video':'image');
  16286. node.parentNode.replaceChild(UE.uNode.createElement(html),node);
  16287. }
  16288. })
  16289. }
  16290. me.addOutputRule(function(root){
  16291. switchImgAndVideo(root,true)
  16292. });
  16293. me.addInputRule(function(root){
  16294. switchImgAndVideo(root)
  16295. });
  16296. /**
  16297. * 插入视频
  16298. * @command insertvideo
  16299. * @method execCommand
  16300. * @param { String } cmd 命令字符串
  16301. * @param { Object } videoAttr 键值对对象, 描述一个视频的所有属性
  16302. * @example
  16303. * ```javascript
  16304. *
  16305. * var videoAttr = {
  16306. * //视频地址
  16307. * url: 'http://www.youku.com/xxx',
  16308. * //视频宽高值, 单位px
  16309. * width: 200,
  16310. * height: 100
  16311. * };
  16312. *
  16313. * //editor 是编辑器实例
  16314. * //向编辑器插入单个视频
  16315. * editor.execCommand( 'insertvideo', videoAttr );
  16316. * ```
  16317. */
  16318. /**
  16319. * 插入视频
  16320. * @command insertvideo
  16321. * @method execCommand
  16322. * @param { String } cmd 命令字符串
  16323. * @param { Array } videoArr 需要插入的视频的数组, 其中的每一个元素都是一个键值对对象, 描述了一个视频的所有属性
  16324. * @example
  16325. * ```javascript
  16326. *
  16327. * var videoAttr1 = {
  16328. * //视频地址
  16329. * url: 'http://www.youku.com/xxx',
  16330. * //视频宽高值, 单位px
  16331. * width: 200,
  16332. * height: 100
  16333. * },
  16334. * videoAttr2 = {
  16335. * //视频地址
  16336. * url: 'http://www.youku.com/xxx',
  16337. * //视频宽高值, 单位px
  16338. * width: 200,
  16339. * height: 100
  16340. * }
  16341. *
  16342. * //editor 是编辑器实例
  16343. * //该方法将会向编辑器内插入两个视频
  16344. * editor.execCommand( 'insertvideo', [ videoAttr1, videoAttr2 ] );
  16345. * ```
  16346. */
  16347. /**
  16348. * 查询当前光标所在处是否是一个视频
  16349. * @command insertvideo
  16350. * @method queryCommandState
  16351. * @param { String } cmd 需要查询的命令字符串
  16352. * @return { int } 如果当前光标所在处的元素是一个视频对象, 则返回1,否则返回0
  16353. * @example
  16354. * ```javascript
  16355. *
  16356. * //editor 是编辑器实例
  16357. * editor.queryCommandState( 'insertvideo' );
  16358. * ```
  16359. */
  16360. me.commands["insertvideo"] = {
  16361. execCommand: function (cmd, videoObjs, type){
  16362. videoObjs = utils.isArray(videoObjs)?videoObjs:[videoObjs];
  16363. var html = [],id = 'tmpVedio', cl;
  16364. for(var i=0,vi,len = videoObjs.length;i<len;i++){
  16365. vi = videoObjs[i];
  16366. cl = (type == 'upload' ? 'edui-upload-video video-js vjs-default-skin':'edui-faked-video');
  16367. html.push(creatInsertStr( vi.url, vi.width || 420, vi.height || 280, id + i, null, cl, 'image'));
  16368. }
  16369. me.execCommand("inserthtml",html.join(""),true);
  16370. var rng = this.selection.getRange();
  16371. for(var i= 0,len=videoObjs.length;i<len;i++){
  16372. var img = this.document.getElementById('tmpVedio'+i);
  16373. domUtils.removeAttributes(img,'id');
  16374. rng.selectNode(img).select();
  16375. me.execCommand('imagefloat',videoObjs[i].align)
  16376. }
  16377. },
  16378. queryCommandState : function(){
  16379. var img = me.selection.getRange().getClosedNode(),
  16380. flag = img && (img.className == "edui-faked-video" || img.className.indexOf("edui-upload-video")!=-1);
  16381. return flag ? 1 : 0;
  16382. }
  16383. };
  16384. };
  16385. // plugins/table.core.js
  16386. /**
  16387. * Created with JetBrains WebStorm.
  16388. * User: taoqili
  16389. * Date: 13-1-18
  16390. * Time: 上午11:09
  16391. * To change this template use File | Settings | File Templates.
  16392. */
  16393. /**
  16394. * UE表格操作类
  16395. * @param table
  16396. * @constructor
  16397. */
  16398. (function () {
  16399. var UETable = UE.UETable = function (table) {
  16400. this.table = table;
  16401. this.indexTable = [];
  16402. this.selectedTds = [];
  16403. this.cellsRange = {};
  16404. this.update(table);
  16405. };
  16406. //===以下为静态工具方法===
  16407. UETable.removeSelectedClass = function (cells) {
  16408. utils.each(cells, function (cell) {
  16409. domUtils.removeClasses(cell, "selectTdClass");
  16410. })
  16411. };
  16412. UETable.addSelectedClass = function (cells) {
  16413. utils.each(cells, function (cell) {
  16414. domUtils.addClass(cell, "selectTdClass");
  16415. })
  16416. };
  16417. UETable.isEmptyBlock = function (node) {
  16418. var reg = new RegExp(domUtils.fillChar, 'g');
  16419. if (node[browser.ie ? 'innerText' : 'textContent'].replace(/^\s*$/, '').replace(reg, '').length > 0) {
  16420. return 0;
  16421. }
  16422. for (var i in dtd.$isNotEmpty) if (dtd.$isNotEmpty.hasOwnProperty(i)) {
  16423. if (node.getElementsByTagName(i).length) {
  16424. return 0;
  16425. }
  16426. }
  16427. return 1;
  16428. };
  16429. UETable.getWidth = function (cell) {
  16430. if (!cell)return 0;
  16431. return parseInt(domUtils.getComputedStyle(cell, "width"), 10);
  16432. };
  16433. /**
  16434. * 获取单元格或者单元格组的“对齐”状态。 如果当前的检测对象是一个单元格组, 只有在满足所有单元格的 水平和竖直 对齐属性都相同的
  16435. * 条件时才会返回其状态值,否则将返回null; 如果当前只检测了一个单元格, 则直接返回当前单元格的对齐状态;
  16436. * @param table cell or table cells , 支持单个单元格dom对象 或者 单元格dom对象数组
  16437. * @return { align: 'left' || 'right' || 'center', valign: 'top' || 'middle' || 'bottom' } 或者 null
  16438. */
  16439. UETable.getTableCellAlignState = function ( cells ) {
  16440. !utils.isArray( cells ) && ( cells = [cells] );
  16441. var result = {},
  16442. status = ['align', 'valign'],
  16443. tempStatus = null,
  16444. isSame = true;//状态是否相同
  16445. utils.each( cells, function( cellNode ){
  16446. utils.each( status, function( currentState ){
  16447. tempStatus = cellNode.getAttribute( currentState );
  16448. if( !result[ currentState ] && tempStatus ) {
  16449. result[ currentState ] = tempStatus;
  16450. } else if( !result[ currentState ] || ( tempStatus !== result[ currentState ] ) ) {
  16451. isSame = false;
  16452. return false;
  16453. }
  16454. } );
  16455. return isSame;
  16456. });
  16457. return isSame ? result : null;
  16458. };
  16459. /**
  16460. * 根据当前选区获取相关的table信息
  16461. * @return {Object}
  16462. */
  16463. UETable.getTableItemsByRange = function (editor) {
  16464. var start = editor.selection.getStart();
  16465. //ff下会选中bookmark
  16466. if( start && start.id && start.id.indexOf('_baidu_bookmark_start_') === 0 && start.nextSibling) {
  16467. start = start.nextSibling;
  16468. }
  16469. //在table或者td边缘有可能存在选中tr的情况
  16470. var cell = start && domUtils.findParentByTagName(start, ["td", "th"], true),
  16471. tr = cell && cell.parentNode,
  16472. caption = start && domUtils.findParentByTagName(start, 'caption', true),
  16473. table = caption ? caption.parentNode : tr && tr.parentNode.parentNode;
  16474. return {
  16475. cell:cell,
  16476. tr:tr,
  16477. table:table,
  16478. caption:caption
  16479. }
  16480. };
  16481. UETable.getUETableBySelected = function (editor) {
  16482. var table = UETable.getTableItemsByRange(editor).table;
  16483. if (table && table.ueTable && table.ueTable.selectedTds.length) {
  16484. return table.ueTable;
  16485. }
  16486. return null;
  16487. };
  16488. UETable.getDefaultValue = function (editor, table) {
  16489. var borderMap = {
  16490. thin:'0px',
  16491. medium:'1px',
  16492. thick:'2px'
  16493. },
  16494. tableBorder, tdPadding, tdBorder, tmpValue;
  16495. if (!table) {
  16496. table = editor.document.createElement('table');
  16497. table.insertRow(0).insertCell(0).innerHTML = 'xxx';
  16498. editor.body.appendChild(table);
  16499. var td = table.getElementsByTagName('td')[0];
  16500. tmpValue = domUtils.getComputedStyle(table, 'border-left-width');
  16501. tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  16502. tmpValue = domUtils.getComputedStyle(td, 'padding-left');
  16503. tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10);
  16504. tmpValue = domUtils.getComputedStyle(td, 'border-left-width');
  16505. tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  16506. domUtils.remove(table);
  16507. return {
  16508. tableBorder:tableBorder,
  16509. tdPadding:tdPadding,
  16510. tdBorder:tdBorder
  16511. };
  16512. } else {
  16513. td = table.getElementsByTagName('td')[0];
  16514. tmpValue = domUtils.getComputedStyle(table, 'border-left-width');
  16515. tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  16516. tmpValue = domUtils.getComputedStyle(td, 'padding-left');
  16517. tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10);
  16518. tmpValue = domUtils.getComputedStyle(td, 'border-left-width');
  16519. tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10);
  16520. return {
  16521. tableBorder:tableBorder,
  16522. tdPadding:tdPadding,
  16523. tdBorder:tdBorder
  16524. };
  16525. }
  16526. };
  16527. /**
  16528. * 根据当前点击的td或者table获取索引对象
  16529. * @param tdOrTable
  16530. */
  16531. UETable.getUETable = function (tdOrTable) {
  16532. var tag = tdOrTable.tagName.toLowerCase();
  16533. tdOrTable = (tag == "td" || tag == "th" || tag == 'caption') ? domUtils.findParentByTagName(tdOrTable, "table", true) : tdOrTable;
  16534. if (!tdOrTable.ueTable) {
  16535. tdOrTable.ueTable = new UETable(tdOrTable);
  16536. }
  16537. return tdOrTable.ueTable;
  16538. };
  16539. UETable.cloneCell = function(cell,ignoreMerge,keepPro){
  16540. if (!cell || utils.isString(cell)) {
  16541. return this.table.ownerDocument.createElement(cell || 'td');
  16542. }
  16543. var flag = domUtils.hasClass(cell, "selectTdClass");
  16544. flag && domUtils.removeClasses(cell, "selectTdClass");
  16545. var tmpCell = cell.cloneNode(true);
  16546. if (ignoreMerge) {
  16547. tmpCell.rowSpan = tmpCell.colSpan = 1;
  16548. }
  16549. //去掉宽高
  16550. !keepPro && domUtils.removeAttributes(tmpCell,'width height');
  16551. !keepPro && domUtils.removeAttributes(tmpCell,'style');
  16552. tmpCell.style.borderLeftStyle = "";
  16553. tmpCell.style.borderTopStyle = "";
  16554. tmpCell.style.borderLeftColor = cell.style.borderRightColor;
  16555. tmpCell.style.borderLeftWidth = cell.style.borderRightWidth;
  16556. tmpCell.style.borderTopColor = cell.style.borderBottomColor;
  16557. tmpCell.style.borderTopWidth = cell.style.borderBottomWidth;
  16558. flag && domUtils.addClass(cell, "selectTdClass");
  16559. return tmpCell;
  16560. }
  16561. UETable.prototype = {
  16562. getMaxRows:function () {
  16563. var rows = this.table.rows, maxLen = 1;
  16564. for (var i = 0, row; row = rows[i]; i++) {
  16565. var currentMax = 1;
  16566. for (var j = 0, cj; cj = row.cells[j++];) {
  16567. currentMax = Math.max(cj.rowSpan || 1, currentMax);
  16568. }
  16569. maxLen = Math.max(currentMax + i, maxLen);
  16570. }
  16571. return maxLen;
  16572. },
  16573. /**
  16574. * 获取当前表格的最大列数
  16575. */
  16576. getMaxCols:function () {
  16577. var rows = this.table.rows, maxLen = 0, cellRows = {};
  16578. for (var i = 0, row; row = rows[i]; i++) {
  16579. var cellsNum = 0;
  16580. for (var j = 0, cj; cj = row.cells[j++];) {
  16581. cellsNum += (cj.colSpan || 1);
  16582. if (cj.rowSpan && cj.rowSpan > 1) {
  16583. for (var k = 1; k < cj.rowSpan; k++) {
  16584. if (!cellRows['row_' + (i + k)]) {
  16585. cellRows['row_' + (i + k)] = (cj.colSpan || 1);
  16586. } else {
  16587. cellRows['row_' + (i + k)]++
  16588. }
  16589. }
  16590. }
  16591. }
  16592. cellsNum += cellRows['row_' + i] || 0;
  16593. maxLen = Math.max(cellsNum, maxLen);
  16594. }
  16595. return maxLen;
  16596. },
  16597. getCellColIndex:function (cell) {
  16598. },
  16599. /**
  16600. * 获取当前cell旁边的单元格,
  16601. * @param cell
  16602. * @param right
  16603. */
  16604. getHSideCell:function (cell, right) {
  16605. try {
  16606. var cellInfo = this.getCellInfo(cell),
  16607. previewRowIndex, previewColIndex;
  16608. var len = this.selectedTds.length,
  16609. range = this.cellsRange;
  16610. //首行或者首列没有前置单元格
  16611. if ((!right && (!len ? !cellInfo.colIndex : !range.beginColIndex)) || (right && (!len ? (cellInfo.colIndex == (this.colsNum - 1)) : (range.endColIndex == this.colsNum - 1)))) return null;
  16612. previewRowIndex = !len ? cellInfo.rowIndex : range.beginRowIndex;
  16613. previewColIndex = !right ? ( !len ? (cellInfo.colIndex < 1 ? 0 : (cellInfo.colIndex - 1)) : range.beginColIndex - 1)
  16614. : ( !len ? cellInfo.colIndex + 1 : range.endColIndex + 1);
  16615. return this.getCell(this.indexTable[previewRowIndex][previewColIndex].rowIndex, this.indexTable[previewRowIndex][previewColIndex].cellIndex);
  16616. } catch (e) {
  16617. showError(e);
  16618. }
  16619. },
  16620. getTabNextCell:function (cell, preRowIndex) {
  16621. var cellInfo = this.getCellInfo(cell),
  16622. rowIndex = preRowIndex || cellInfo.rowIndex,
  16623. colIndex = cellInfo.colIndex + 1 + (cellInfo.colSpan - 1),
  16624. nextCell;
  16625. try {
  16626. nextCell = this.getCell(this.indexTable[rowIndex][colIndex].rowIndex, this.indexTable[rowIndex][colIndex].cellIndex);
  16627. } catch (e) {
  16628. try {
  16629. rowIndex = rowIndex * 1 + 1;
  16630. colIndex = 0;
  16631. nextCell = this.getCell(this.indexTable[rowIndex][colIndex].rowIndex, this.indexTable[rowIndex][colIndex].cellIndex);
  16632. } catch (e) {
  16633. }
  16634. }
  16635. return nextCell;
  16636. },
  16637. /**
  16638. * 获取视觉上的后置单元格
  16639. * @param cell
  16640. * @param bottom
  16641. */
  16642. getVSideCell:function (cell, bottom, ignoreRange) {
  16643. try {
  16644. var cellInfo = this.getCellInfo(cell),
  16645. nextRowIndex, nextColIndex;
  16646. var len = this.selectedTds.length && !ignoreRange,
  16647. range = this.cellsRange;
  16648. //末行或者末列没有后置单元格
  16649. if ((!bottom && (cellInfo.rowIndex == 0)) || (bottom && (!len ? (cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1) : (range.endRowIndex == this.rowsNum - 1)))) return null;
  16650. nextRowIndex = !bottom ? ( !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1)
  16651. : ( !len ? (cellInfo.rowIndex + cellInfo.rowSpan) : range.endRowIndex + 1);
  16652. nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex;
  16653. return this.getCell(this.indexTable[nextRowIndex][nextColIndex].rowIndex, this.indexTable[nextRowIndex][nextColIndex].cellIndex);
  16654. } catch (e) {
  16655. showError(e);
  16656. }
  16657. },
  16658. /**
  16659. * 获取相同结束位置的单元格,xOrY指代了是获取x轴相同还是y轴相同
  16660. */
  16661. getSameEndPosCells:function (cell, xOrY) {
  16662. try {
  16663. var flag = (xOrY.toLowerCase() === "x"),
  16664. end = domUtils.getXY(cell)[flag ? 'x' : 'y'] + cell["offset" + (flag ? 'Width' : 'Height')],
  16665. rows = this.table.rows,
  16666. cells = null, returns = [];
  16667. for (var i = 0; i < this.rowsNum; i++) {
  16668. cells = rows[i].cells;
  16669. for (var j = 0, tmpCell; tmpCell = cells[j++];) {
  16670. var tmpEnd = domUtils.getXY(tmpCell)[flag ? 'x' : 'y'] + tmpCell["offset" + (flag ? 'Width' : 'Height')];
  16671. //对应行的td已经被上面行rowSpan了
  16672. if (tmpEnd > end && flag) break;
  16673. if (cell == tmpCell || end == tmpEnd) {
  16674. //只获取单一的单元格
  16675. //todo 仅获取单一单元格在特定情况下会造成returns为空,从而影响后续的拖拽实现,修正这个。需考虑性能
  16676. if (tmpCell[flag ? "colSpan" : "rowSpan"] == 1) {
  16677. returns.push(tmpCell);
  16678. }
  16679. if (flag) break;
  16680. }
  16681. }
  16682. }
  16683. return returns;
  16684. } catch (e) {
  16685. showError(e);
  16686. }
  16687. },
  16688. setCellContent:function (cell, content) {
  16689. cell.innerHTML = content || (browser.ie ? domUtils.fillChar : "<br />");
  16690. },
  16691. cloneCell:UETable.cloneCell,
  16692. /**
  16693. * 获取跟当前单元格的右边竖线为左边的所有未合并单元格
  16694. */
  16695. getSameStartPosXCells:function (cell) {
  16696. try {
  16697. var start = domUtils.getXY(cell).x + cell.offsetWidth,
  16698. rows = this.table.rows, cells , returns = [];
  16699. for (var i = 0; i < this.rowsNum; i++) {
  16700. cells = rows[i].cells;
  16701. for (var j = 0, tmpCell; tmpCell = cells[j++];) {
  16702. var tmpStart = domUtils.getXY(tmpCell).x;
  16703. if (tmpStart > start) break;
  16704. if (tmpStart == start && tmpCell.colSpan == 1) {
  16705. returns.push(tmpCell);
  16706. break;
  16707. }
  16708. }
  16709. }
  16710. return returns;
  16711. } catch (e) {
  16712. showError(e);
  16713. }
  16714. },
  16715. /**
  16716. * 更新table对应的索引表
  16717. */
  16718. update:function (table) {
  16719. this.table = table || this.table;
  16720. this.selectedTds = [];
  16721. this.cellsRange = {};
  16722. this.indexTable = [];
  16723. var rows = this.table.rows,
  16724. rowsNum = this.getMaxRows(),
  16725. dNum = rowsNum - rows.length,
  16726. colsNum = this.getMaxCols();
  16727. while (dNum--) {
  16728. this.table.insertRow(rows.length);
  16729. }
  16730. this.rowsNum = rowsNum;
  16731. this.colsNum = colsNum;
  16732. for (var i = 0, len = rows.length; i < len; i++) {
  16733. this.indexTable[i] = new Array(colsNum);
  16734. }
  16735. //填充索引表
  16736. for (var rowIndex = 0, row; row = rows[rowIndex]; rowIndex++) {
  16737. for (var cellIndex = 0, cell, cells = row.cells; cell = cells[cellIndex]; cellIndex++) {
  16738. //修正整行被rowSpan时导致的行数计算错误
  16739. if (cell.rowSpan > rowsNum) {
  16740. cell.rowSpan = rowsNum;
  16741. }
  16742. var colIndex = cellIndex,
  16743. rowSpan = cell.rowSpan || 1,
  16744. colSpan = cell.colSpan || 1;
  16745. //当已经被上一行rowSpan或者被前一列colSpan了,则跳到下一个单元格进行
  16746. while (this.indexTable[rowIndex][colIndex]) colIndex++;
  16747. for (var j = 0; j < rowSpan; j++) {
  16748. for (var k = 0; k < colSpan; k++) {
  16749. this.indexTable[rowIndex + j][colIndex + k] = {
  16750. rowIndex:rowIndex,
  16751. cellIndex:cellIndex,
  16752. colIndex:colIndex,
  16753. rowSpan:rowSpan,
  16754. colSpan:colSpan
  16755. }
  16756. }
  16757. }
  16758. }
  16759. }
  16760. //修复残缺td
  16761. for (j = 0; j < rowsNum; j++) {
  16762. for (k = 0; k < colsNum; k++) {
  16763. if (this.indexTable[j][k] === undefined) {
  16764. row = rows[j];
  16765. cell = row.cells[row.cells.length - 1];
  16766. cell = cell ? cell.cloneNode(true) : this.table.ownerDocument.createElement("td");
  16767. this.setCellContent(cell);
  16768. if (cell.colSpan !== 1)cell.colSpan = 1;
  16769. if (cell.rowSpan !== 1)cell.rowSpan = 1;
  16770. row.appendChild(cell);
  16771. this.indexTable[j][k] = {
  16772. rowIndex:j,
  16773. cellIndex:cell.cellIndex,
  16774. colIndex:k,
  16775. rowSpan:1,
  16776. colSpan:1
  16777. }
  16778. }
  16779. }
  16780. }
  16781. //当框选后删除行或者列后撤销,需要重建选区。
  16782. var tds = domUtils.getElementsByTagName(this.table, "td"),
  16783. selectTds = [];
  16784. utils.each(tds, function (td) {
  16785. if (domUtils.hasClass(td, "selectTdClass")) {
  16786. selectTds.push(td);
  16787. }
  16788. });
  16789. if (selectTds.length) {
  16790. var start = selectTds[0],
  16791. end = selectTds[selectTds.length - 1],
  16792. startInfo = this.getCellInfo(start),
  16793. endInfo = this.getCellInfo(end);
  16794. this.selectedTds = selectTds;
  16795. this.cellsRange = {
  16796. beginRowIndex:startInfo.rowIndex,
  16797. beginColIndex:startInfo.colIndex,
  16798. endRowIndex:endInfo.rowIndex + endInfo.rowSpan - 1,
  16799. endColIndex:endInfo.colIndex + endInfo.colSpan - 1
  16800. };
  16801. }
  16802. //给第一行设置firstRow的样式名称,在排序图标的样式上使用到
  16803. if(!domUtils.hasClass(this.table.rows[0], "firstRow")) {
  16804. domUtils.addClass(this.table.rows[0], "firstRow");
  16805. for(var i = 1; i< this.table.rows.length; i++) {
  16806. domUtils.removeClasses(this.table.rows[i], "firstRow");
  16807. }
  16808. }
  16809. },
  16810. /**
  16811. * 获取单元格的索引信息
  16812. */
  16813. getCellInfo:function (cell) {
  16814. if (!cell) return;
  16815. var cellIndex = cell.cellIndex,
  16816. rowIndex = cell.parentNode.rowIndex,
  16817. rowInfo = this.indexTable[rowIndex],
  16818. numCols = this.colsNum;
  16819. for (var colIndex = cellIndex; colIndex < numCols; colIndex++) {
  16820. var cellInfo = rowInfo[colIndex];
  16821. if (cellInfo.rowIndex === rowIndex && cellInfo.cellIndex === cellIndex) {
  16822. return cellInfo;
  16823. }
  16824. }
  16825. },
  16826. /**
  16827. * 根据行列号获取单元格
  16828. */
  16829. getCell:function (rowIndex, cellIndex) {
  16830. return rowIndex < this.rowsNum && this.table.rows[rowIndex].cells[cellIndex] || null;
  16831. },
  16832. /**
  16833. * 删除单元格
  16834. */
  16835. deleteCell:function (cell, rowIndex) {
  16836. rowIndex = typeof rowIndex == 'number' ? rowIndex : cell.parentNode.rowIndex;
  16837. var row = this.table.rows[rowIndex];
  16838. row.deleteCell(cell.cellIndex);
  16839. },
  16840. /**
  16841. * 根据始末两个单元格获取被框选的所有单元格范围
  16842. */
  16843. getCellsRange:function (cellA, cellB) {
  16844. function checkRange(beginRowIndex, beginColIndex, endRowIndex, endColIndex) {
  16845. var tmpBeginRowIndex = beginRowIndex,
  16846. tmpBeginColIndex = beginColIndex,
  16847. tmpEndRowIndex = endRowIndex,
  16848. tmpEndColIndex = endColIndex,
  16849. cellInfo, colIndex, rowIndex;
  16850. // 通过indexTable检查是否存在超出TableRange上边界的情况
  16851. if (beginRowIndex > 0) {
  16852. for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
  16853. cellInfo = me.indexTable[beginRowIndex][colIndex];
  16854. rowIndex = cellInfo.rowIndex;
  16855. if (rowIndex < beginRowIndex) {
  16856. tmpBeginRowIndex = Math.min(rowIndex, tmpBeginRowIndex);
  16857. }
  16858. }
  16859. }
  16860. // 通过indexTable检查是否存在超出TableRange右边界的情况
  16861. if (endColIndex < me.colsNum) {
  16862. for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
  16863. cellInfo = me.indexTable[rowIndex][endColIndex];
  16864. colIndex = cellInfo.colIndex + cellInfo.colSpan - 1;
  16865. if (colIndex > endColIndex) {
  16866. tmpEndColIndex = Math.max(colIndex, tmpEndColIndex);
  16867. }
  16868. }
  16869. }
  16870. // 检查是否有超出TableRange下边界的情况
  16871. if (endRowIndex < me.rowsNum) {
  16872. for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
  16873. cellInfo = me.indexTable[endRowIndex][colIndex];
  16874. rowIndex = cellInfo.rowIndex + cellInfo.rowSpan - 1;
  16875. if (rowIndex > endRowIndex) {
  16876. tmpEndRowIndex = Math.max(rowIndex, tmpEndRowIndex);
  16877. }
  16878. }
  16879. }
  16880. // 检查是否有超出TableRange左边界的情况
  16881. if (beginColIndex > 0) {
  16882. for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
  16883. cellInfo = me.indexTable[rowIndex][beginColIndex];
  16884. colIndex = cellInfo.colIndex;
  16885. if (colIndex < beginColIndex) {
  16886. tmpBeginColIndex = Math.min(cellInfo.colIndex, tmpBeginColIndex);
  16887. }
  16888. }
  16889. }
  16890. //递归调用直至所有完成所有框选单元格的扩展
  16891. if (tmpBeginRowIndex != beginRowIndex || tmpBeginColIndex != beginColIndex || tmpEndRowIndex != endRowIndex || tmpEndColIndex != endColIndex) {
  16892. return checkRange(tmpBeginRowIndex, tmpBeginColIndex, tmpEndRowIndex, tmpEndColIndex);
  16893. } else {
  16894. // 不需要扩展TableRange的情况
  16895. return {
  16896. beginRowIndex:beginRowIndex,
  16897. beginColIndex:beginColIndex,
  16898. endRowIndex:endRowIndex,
  16899. endColIndex:endColIndex
  16900. };
  16901. }
  16902. }
  16903. try {
  16904. var me = this,
  16905. cellAInfo = me.getCellInfo(cellA);
  16906. if (cellA === cellB) {
  16907. return {
  16908. beginRowIndex:cellAInfo.rowIndex,
  16909. beginColIndex:cellAInfo.colIndex,
  16910. endRowIndex:cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
  16911. endColIndex:cellAInfo.colIndex + cellAInfo.colSpan - 1
  16912. };
  16913. }
  16914. var cellBInfo = me.getCellInfo(cellB);
  16915. // 计算TableRange的四个边
  16916. var beginRowIndex = Math.min(cellAInfo.rowIndex, cellBInfo.rowIndex),
  16917. beginColIndex = Math.min(cellAInfo.colIndex, cellBInfo.colIndex),
  16918. endRowIndex = Math.max(cellAInfo.rowIndex + cellAInfo.rowSpan - 1, cellBInfo.rowIndex + cellBInfo.rowSpan - 1),
  16919. endColIndex = Math.max(cellAInfo.colIndex + cellAInfo.colSpan - 1, cellBInfo.colIndex + cellBInfo.colSpan - 1);
  16920. return checkRange(beginRowIndex, beginColIndex, endRowIndex, endColIndex);
  16921. } catch (e) {
  16922. //throw e;
  16923. }
  16924. },
  16925. /**
  16926. * 依据cellsRange获取对应的单元格集合
  16927. */
  16928. getCells:function (range) {
  16929. //每次获取cells之前必须先清除上次的选择,否则会对后续获取操作造成影响
  16930. this.clearSelected();
  16931. var beginRowIndex = range.beginRowIndex,
  16932. beginColIndex = range.beginColIndex,
  16933. endRowIndex = range.endRowIndex,
  16934. endColIndex = range.endColIndex,
  16935. cellInfo, rowIndex, colIndex, tdHash = {}, returnTds = [];
  16936. for (var i = beginRowIndex; i <= endRowIndex; i++) {
  16937. for (var j = beginColIndex; j <= endColIndex; j++) {
  16938. cellInfo = this.indexTable[i][j];
  16939. rowIndex = cellInfo.rowIndex;
  16940. colIndex = cellInfo.colIndex;
  16941. // 如果Cells里已经包含了此Cell则跳过
  16942. var key = rowIndex + '|' + colIndex;
  16943. if (tdHash[key]) continue;
  16944. tdHash[key] = 1;
  16945. if (rowIndex < i || colIndex < j || rowIndex + cellInfo.rowSpan - 1 > endRowIndex || colIndex + cellInfo.colSpan - 1 > endColIndex) {
  16946. return null;
  16947. }
  16948. returnTds.push(this.getCell(rowIndex, cellInfo.cellIndex));
  16949. }
  16950. }
  16951. return returnTds;
  16952. },
  16953. /**
  16954. * 清理已经选中的单元格
  16955. */
  16956. clearSelected:function () {
  16957. UETable.removeSelectedClass(this.selectedTds);
  16958. this.selectedTds = [];
  16959. this.cellsRange = {};
  16960. },
  16961. /**
  16962. * 根据range设置已经选中的单元格
  16963. */
  16964. setSelected:function (range) {
  16965. var cells = this.getCells(range);
  16966. UETable.addSelectedClass(cells);
  16967. this.selectedTds = cells;
  16968. this.cellsRange = range;
  16969. },
  16970. isFullRow:function () {
  16971. var range = this.cellsRange;
  16972. return (range.endColIndex - range.beginColIndex + 1) == this.colsNum;
  16973. },
  16974. isFullCol:function () {
  16975. var range = this.cellsRange,
  16976. table = this.table,
  16977. ths = table.getElementsByTagName("th"),
  16978. rows = range.endRowIndex - range.beginRowIndex + 1;
  16979. return !ths.length ? rows == this.rowsNum : rows == this.rowsNum || (rows == this.rowsNum - 1);
  16980. },
  16981. /**
  16982. * 获取视觉上的前置单元格,默认是左边,top传入时
  16983. * @param cell
  16984. * @param top
  16985. */
  16986. getNextCell:function (cell, bottom, ignoreRange) {
  16987. try {
  16988. var cellInfo = this.getCellInfo(cell),
  16989. nextRowIndex, nextColIndex;
  16990. var len = this.selectedTds.length && !ignoreRange,
  16991. range = this.cellsRange;
  16992. //末行或者末列没有后置单元格
  16993. if ((!bottom && (cellInfo.rowIndex == 0)) || (bottom && (!len ? (cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1) : (range.endRowIndex == this.rowsNum - 1)))) return null;
  16994. nextRowIndex = !bottom ? ( !len ? cellInfo.rowIndex - 1 : range.beginRowIndex - 1)
  16995. : ( !len ? (cellInfo.rowIndex + cellInfo.rowSpan) : range.endRowIndex + 1);
  16996. nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex;
  16997. return this.getCell(this.indexTable[nextRowIndex][nextColIndex].rowIndex, this.indexTable[nextRowIndex][nextColIndex].cellIndex);
  16998. } catch (e) {
  16999. showError(e);
  17000. }
  17001. },
  17002. getPreviewCell:function (cell, top) {
  17003. try {
  17004. var cellInfo = this.getCellInfo(cell),
  17005. previewRowIndex, previewColIndex;
  17006. var len = this.selectedTds.length,
  17007. range = this.cellsRange;
  17008. //首行或者首列没有前置单元格
  17009. if ((!top && (!len ? !cellInfo.colIndex : !range.beginColIndex)) || (top && (!len ? (cellInfo.rowIndex > (this.colsNum - 1)) : (range.endColIndex == this.colsNum - 1)))) return null;
  17010. previewRowIndex = !top ? ( !len ? cellInfo.rowIndex : range.beginRowIndex )
  17011. : ( !len ? (cellInfo.rowIndex < 1 ? 0 : (cellInfo.rowIndex - 1)) : range.beginRowIndex);
  17012. previewColIndex = !top ? ( !len ? (cellInfo.colIndex < 1 ? 0 : (cellInfo.colIndex - 1)) : range.beginColIndex - 1)
  17013. : ( !len ? cellInfo.colIndex : range.endColIndex + 1);
  17014. return this.getCell(this.indexTable[previewRowIndex][previewColIndex].rowIndex, this.indexTable[previewRowIndex][previewColIndex].cellIndex);
  17015. } catch (e) {
  17016. showError(e);
  17017. }
  17018. },
  17019. /**
  17020. * 移动单元格中的内容
  17021. */
  17022. moveContent:function (cellTo, cellFrom) {
  17023. if (UETable.isEmptyBlock(cellFrom)) return;
  17024. if (UETable.isEmptyBlock(cellTo)) {
  17025. cellTo.innerHTML = cellFrom.innerHTML;
  17026. return;
  17027. }
  17028. var child = cellTo.lastChild;
  17029. if (child.nodeType == 3 || !dtd.$block[child.tagName]) {
  17030. cellTo.appendChild(cellTo.ownerDocument.createElement('br'))
  17031. }
  17032. while (child = cellFrom.firstChild) {
  17033. cellTo.appendChild(child);
  17034. }
  17035. },
  17036. /**
  17037. * 向右合并单元格
  17038. */
  17039. mergeRight:function (cell) {
  17040. var cellInfo = this.getCellInfo(cell),
  17041. rightColIndex = cellInfo.colIndex + cellInfo.colSpan,
  17042. rightCellInfo = this.indexTable[cellInfo.rowIndex][rightColIndex],
  17043. rightCell = this.getCell(rightCellInfo.rowIndex, rightCellInfo.cellIndex);
  17044. //合并
  17045. cell.colSpan = cellInfo.colSpan + rightCellInfo.colSpan;
  17046. //被合并的单元格不应存在宽度属性
  17047. cell.removeAttribute("width");
  17048. //移动内容
  17049. this.moveContent(cell, rightCell);
  17050. //删掉被合并的Cell
  17051. this.deleteCell(rightCell, rightCellInfo.rowIndex);
  17052. this.update();
  17053. },
  17054. /**
  17055. * 向下合并单元格
  17056. */
  17057. mergeDown:function (cell) {
  17058. var cellInfo = this.getCellInfo(cell),
  17059. downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan,
  17060. downCellInfo = this.indexTable[downRowIndex][cellInfo.colIndex],
  17061. downCell = this.getCell(downCellInfo.rowIndex, downCellInfo.cellIndex);
  17062. cell.rowSpan = cellInfo.rowSpan + downCellInfo.rowSpan;
  17063. cell.removeAttribute("height");
  17064. this.moveContent(cell, downCell);
  17065. this.deleteCell(downCell, downCellInfo.rowIndex);
  17066. this.update();
  17067. },
  17068. /**
  17069. * 合并整个range中的内容
  17070. */
  17071. mergeRange:function () {
  17072. //由于合并操作可以在任意时刻进行,所以无法通过鼠标位置等信息实时生成range,只能通过缓存实例中的cellsRange对象来访问
  17073. var range = this.cellsRange,
  17074. leftTopCell = this.getCell(range.beginRowIndex, this.indexTable[range.beginRowIndex][range.beginColIndex].cellIndex);
  17075. if (leftTopCell.tagName == "TH" && range.endRowIndex !== range.beginRowIndex) {
  17076. var index = this.indexTable,
  17077. info = this.getCellInfo(leftTopCell);
  17078. leftTopCell = this.getCell(1, index[1][info.colIndex].cellIndex);
  17079. range = this.getCellsRange(leftTopCell, this.getCell(index[this.rowsNum - 1][info.colIndex].rowIndex, index[this.rowsNum - 1][info.colIndex].cellIndex));
  17080. }
  17081. // 删除剩余的Cells
  17082. var cells = this.getCells(range);
  17083. for(var i= 0,ci;ci=cells[i++];){
  17084. if (ci !== leftTopCell) {
  17085. this.moveContent(leftTopCell, ci);
  17086. this.deleteCell(ci);
  17087. }
  17088. }
  17089. // 修改左上角Cell的rowSpan和colSpan,并调整宽度属性设置
  17090. leftTopCell.rowSpan = range.endRowIndex - range.beginRowIndex + 1;
  17091. leftTopCell.rowSpan > 1 && leftTopCell.removeAttribute("height");
  17092. leftTopCell.colSpan = range.endColIndex - range.beginColIndex + 1;
  17093. leftTopCell.colSpan > 1 && leftTopCell.removeAttribute("width");
  17094. if (leftTopCell.rowSpan == this.rowsNum && leftTopCell.colSpan != 1) {
  17095. leftTopCell.colSpan = 1;
  17096. }
  17097. if (leftTopCell.colSpan == this.colsNum && leftTopCell.rowSpan != 1) {
  17098. var rowIndex = leftTopCell.parentNode.rowIndex;
  17099. //解决IE下的表格操作问题
  17100. if( this.table.deleteRow ) {
  17101. for (var i = rowIndex+ 1, curIndex=rowIndex+ 1, len=leftTopCell.rowSpan; i < len; i++) {
  17102. this.table.deleteRow(curIndex);
  17103. }
  17104. } else {
  17105. for (var i = 0, len=leftTopCell.rowSpan - 1; i < len; i++) {
  17106. var row = this.table.rows[rowIndex + 1];
  17107. row.parentNode.removeChild(row);
  17108. }
  17109. }
  17110. leftTopCell.rowSpan = 1;
  17111. }
  17112. this.update();
  17113. },
  17114. /**
  17115. * 插入一行单元格
  17116. */
  17117. insertRow:function (rowIndex, sourceCell) {
  17118. var numCols = this.colsNum,
  17119. table = this.table,
  17120. row = table.insertRow(rowIndex), cell,
  17121. isInsertTitle = typeof sourceCell == 'string' && sourceCell.toUpperCase() == 'TH';
  17122. function replaceTdToTh(colIndex, cell, tableRow) {
  17123. if (colIndex == 0) {
  17124. var tr = tableRow.nextSibling || tableRow.previousSibling,
  17125. th = tr.cells[colIndex];
  17126. if (th.tagName == 'TH') {
  17127. th = cell.ownerDocument.createElement("th");
  17128. th.appendChild(cell.firstChild);
  17129. tableRow.insertBefore(th, cell);
  17130. domUtils.remove(cell)
  17131. }
  17132. }else{
  17133. if (cell.tagName == 'TH') {
  17134. var td = cell.ownerDocument.createElement("td");
  17135. td.appendChild(cell.firstChild);
  17136. tableRow.insertBefore(td, cell);
  17137. domUtils.remove(cell)
  17138. }
  17139. }
  17140. }
  17141. //首行直接插入,无需考虑部分单元格被rowspan的情况
  17142. if (rowIndex == 0 || rowIndex == this.rowsNum) {
  17143. for (var colIndex = 0; colIndex < numCols; colIndex++) {
  17144. cell = this.cloneCell(sourceCell, true);
  17145. this.setCellContent(cell);
  17146. cell.getAttribute('vAlign') && cell.setAttribute('vAlign', cell.getAttribute('vAlign'));
  17147. row.appendChild(cell);
  17148. if(!isInsertTitle) replaceTdToTh(colIndex, cell, row);
  17149. }
  17150. } else {
  17151. var infoRow = this.indexTable[rowIndex],
  17152. cellIndex = 0;
  17153. for (colIndex = 0; colIndex < numCols; colIndex++) {
  17154. var cellInfo = infoRow[colIndex];
  17155. //如果存在某个单元格的rowspan穿过待插入行的位置,则修改该单元格的rowspan即可,无需插入单元格
  17156. if (cellInfo.rowIndex < rowIndex) {
  17157. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  17158. cell.rowSpan = cellInfo.rowSpan + 1;
  17159. } else {
  17160. cell = this.cloneCell(sourceCell, true);
  17161. this.setCellContent(cell);
  17162. row.appendChild(cell);
  17163. }
  17164. if(!isInsertTitle) replaceTdToTh(colIndex, cell, row);
  17165. }
  17166. }
  17167. //框选时插入不触发contentchange,需要手动更新索引。
  17168. this.update();
  17169. return row;
  17170. },
  17171. /**
  17172. * 删除一行单元格
  17173. * @param rowIndex
  17174. */
  17175. deleteRow:function (rowIndex) {
  17176. var row = this.table.rows[rowIndex],
  17177. infoRow = this.indexTable[rowIndex],
  17178. colsNum = this.colsNum,
  17179. count = 0; //处理计数
  17180. for (var colIndex = 0; colIndex < colsNum;) {
  17181. var cellInfo = infoRow[colIndex],
  17182. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  17183. if (cell.rowSpan > 1) {
  17184. if (cellInfo.rowIndex == rowIndex) {
  17185. var clone = cell.cloneNode(true);
  17186. clone.rowSpan = cell.rowSpan - 1;
  17187. clone.innerHTML = "";
  17188. cell.rowSpan = 1;
  17189. var nextRowIndex = rowIndex + 1,
  17190. nextRow = this.table.rows[nextRowIndex],
  17191. insertCellIndex,
  17192. preMerged = this.getPreviewMergedCellsNum(nextRowIndex, colIndex) - count;
  17193. if (preMerged < colIndex) {
  17194. insertCellIndex = colIndex - preMerged - 1;
  17195. //nextRow.insertCell(insertCellIndex);
  17196. domUtils.insertAfter(nextRow.cells[insertCellIndex], clone);
  17197. } else {
  17198. if (nextRow.cells.length) nextRow.insertBefore(clone, nextRow.cells[0])
  17199. }
  17200. count += 1;
  17201. //cell.parentNode.removeChild(cell);
  17202. }
  17203. }
  17204. colIndex += cell.colSpan || 1;
  17205. }
  17206. var deleteTds = [], cacheMap = {};
  17207. for (colIndex = 0; colIndex < colsNum; colIndex++) {
  17208. var tmpRowIndex = infoRow[colIndex].rowIndex,
  17209. tmpCellIndex = infoRow[colIndex].cellIndex,
  17210. key = tmpRowIndex + "_" + tmpCellIndex;
  17211. if (cacheMap[key])continue;
  17212. cacheMap[key] = 1;
  17213. cell = this.getCell(tmpRowIndex, tmpCellIndex);
  17214. deleteTds.push(cell);
  17215. }
  17216. var mergeTds = [];
  17217. utils.each(deleteTds, function (td) {
  17218. if (td.rowSpan == 1) {
  17219. td.parentNode.removeChild(td);
  17220. } else {
  17221. mergeTds.push(td);
  17222. }
  17223. });
  17224. utils.each(mergeTds, function (td) {
  17225. td.rowSpan--;
  17226. });
  17227. row.parentNode.removeChild(row);
  17228. //浏览器方法本身存在bug,采用自定义方法删除
  17229. //this.table.deleteRow(rowIndex);
  17230. this.update();
  17231. },
  17232. insertCol:function (colIndex, sourceCell, defaultValue) {
  17233. var rowsNum = this.rowsNum,
  17234. rowIndex = 0,
  17235. tableRow, cell,
  17236. backWidth = parseInt((this.table.offsetWidth - (this.colsNum + 1) * 20 - (this.colsNum + 1)) / (this.colsNum + 1), 10),
  17237. isInsertTitleCol = typeof sourceCell == 'string' && sourceCell.toUpperCase() == 'TH';
  17238. function replaceTdToTh(rowIndex, cell, tableRow) {
  17239. if (rowIndex == 0) {
  17240. var th = cell.nextSibling || cell.previousSibling;
  17241. if (th.tagName == 'TH') {
  17242. th = cell.ownerDocument.createElement("th");
  17243. th.appendChild(cell.firstChild);
  17244. tableRow.insertBefore(th, cell);
  17245. domUtils.remove(cell)
  17246. }
  17247. }else{
  17248. if (cell.tagName == 'TH') {
  17249. var td = cell.ownerDocument.createElement("td");
  17250. td.appendChild(cell.firstChild);
  17251. tableRow.insertBefore(td, cell);
  17252. domUtils.remove(cell)
  17253. }
  17254. }
  17255. }
  17256. var preCell;
  17257. if (colIndex == 0 || colIndex == this.colsNum) {
  17258. for (; rowIndex < rowsNum; rowIndex++) {
  17259. tableRow = this.table.rows[rowIndex];
  17260. preCell = tableRow.cells[colIndex == 0 ? colIndex : tableRow.cells.length];
  17261. cell = this.cloneCell(sourceCell, true); //tableRow.insertCell(colIndex == 0 ? colIndex : tableRow.cells.length);
  17262. this.setCellContent(cell);
  17263. cell.setAttribute('vAlign', cell.getAttribute('vAlign'));
  17264. preCell && cell.setAttribute('width', preCell.getAttribute('width'));
  17265. if (!colIndex) {
  17266. tableRow.insertBefore(cell, tableRow.cells[0]);
  17267. } else {
  17268. domUtils.insertAfter(tableRow.cells[tableRow.cells.length - 1], cell);
  17269. }
  17270. if(!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow)
  17271. }
  17272. } else {
  17273. for (; rowIndex < rowsNum; rowIndex++) {
  17274. var cellInfo = this.indexTable[rowIndex][colIndex];
  17275. if (cellInfo.colIndex < colIndex) {
  17276. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  17277. cell.colSpan = cellInfo.colSpan + 1;
  17278. } else {
  17279. tableRow = this.table.rows[rowIndex];
  17280. preCell = tableRow.cells[cellInfo.cellIndex];
  17281. cell = this.cloneCell(sourceCell, true);//tableRow.insertCell(cellInfo.cellIndex);
  17282. this.setCellContent(cell);
  17283. cell.setAttribute('vAlign', cell.getAttribute('vAlign'));
  17284. preCell && cell.setAttribute('width', preCell.getAttribute('width'));
  17285. //防止IE下报错
  17286. preCell ? tableRow.insertBefore(cell, preCell) : tableRow.appendChild(cell);
  17287. }
  17288. if(!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow);
  17289. }
  17290. }
  17291. //框选时插入不触发contentchange,需要手动更新索引
  17292. this.update();
  17293. this.updateWidth(backWidth, defaultValue || {tdPadding:10, tdBorder:1});
  17294. },
  17295. updateWidth:function (width, defaultValue) {
  17296. var table = this.table,
  17297. tmpWidth = UETable.getWidth(table) - defaultValue.tdPadding * 2 - defaultValue.tdBorder + width;
  17298. if (tmpWidth < table.ownerDocument.body.offsetWidth) {
  17299. table.setAttribute("width", tmpWidth);
  17300. return;
  17301. }
  17302. var tds = domUtils.getElementsByTagName(this.table, "td th");
  17303. utils.each(tds, function (td) {
  17304. td.setAttribute("width", width);
  17305. })
  17306. },
  17307. deleteCol:function (colIndex) {
  17308. var indexTable = this.indexTable,
  17309. tableRows = this.table.rows,
  17310. backTableWidth = this.table.getAttribute("width"),
  17311. backTdWidth = 0,
  17312. rowsNum = this.rowsNum,
  17313. cacheMap = {};
  17314. for (var rowIndex = 0; rowIndex < rowsNum;) {
  17315. var infoRow = indexTable[rowIndex],
  17316. cellInfo = infoRow[colIndex],
  17317. key = cellInfo.rowIndex + '_' + cellInfo.colIndex;
  17318. // 跳过已经处理过的Cell
  17319. if (cacheMap[key])continue;
  17320. cacheMap[key] = 1;
  17321. var cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex);
  17322. if (!backTdWidth) backTdWidth = cell && parseInt(cell.offsetWidth / cell.colSpan, 10).toFixed(0);
  17323. // 如果Cell的colSpan大于1, 就修改colSpan, 否则就删掉这个Cell
  17324. if (cell.colSpan > 1) {
  17325. cell.colSpan--;
  17326. } else {
  17327. tableRows[rowIndex].deleteCell(cellInfo.cellIndex);
  17328. }
  17329. rowIndex += cellInfo.rowSpan || 1;
  17330. }
  17331. this.table.setAttribute("width", backTableWidth - backTdWidth);
  17332. this.update();
  17333. },
  17334. splitToCells:function (cell) {
  17335. var me = this,
  17336. cells = this.splitToRows(cell);
  17337. utils.each(cells, function (cell) {
  17338. me.splitToCols(cell);
  17339. })
  17340. },
  17341. splitToRows:function (cell) {
  17342. var cellInfo = this.getCellInfo(cell),
  17343. rowIndex = cellInfo.rowIndex,
  17344. colIndex = cellInfo.colIndex,
  17345. results = [];
  17346. // 修改Cell的rowSpan
  17347. cell.rowSpan = 1;
  17348. results.push(cell);
  17349. // 补齐单元格
  17350. for (var i = rowIndex, endRow = rowIndex + cellInfo.rowSpan; i < endRow; i++) {
  17351. if (i == rowIndex)continue;
  17352. var tableRow = this.table.rows[i],
  17353. tmpCell = tableRow.insertCell(colIndex - this.getPreviewMergedCellsNum(i, colIndex));
  17354. tmpCell.colSpan = cellInfo.colSpan;
  17355. this.setCellContent(tmpCell);
  17356. tmpCell.setAttribute('vAlign', cell.getAttribute('vAlign'));
  17357. tmpCell.setAttribute('align', cell.getAttribute('align'));
  17358. if (cell.style.cssText) {
  17359. tmpCell.style.cssText = cell.style.cssText;
  17360. }
  17361. results.push(tmpCell);
  17362. }
  17363. this.update();
  17364. return results;
  17365. },
  17366. getPreviewMergedCellsNum:function (rowIndex, colIndex) {
  17367. var indexRow = this.indexTable[rowIndex],
  17368. num = 0;
  17369. for (var i = 0; i < colIndex;) {
  17370. var colSpan = indexRow[i].colSpan,
  17371. tmpRowIndex = indexRow[i].rowIndex;
  17372. num += (colSpan - (tmpRowIndex == rowIndex ? 1 : 0));
  17373. i += colSpan;
  17374. }
  17375. return num;
  17376. },
  17377. splitToCols:function (cell) {
  17378. var backWidth = (cell.offsetWidth / cell.colSpan - 22).toFixed(0),
  17379. cellInfo = this.getCellInfo(cell),
  17380. rowIndex = cellInfo.rowIndex,
  17381. colIndex = cellInfo.colIndex,
  17382. results = [];
  17383. // 修改Cell的rowSpan
  17384. cell.colSpan = 1;
  17385. cell.setAttribute("width", backWidth);
  17386. results.push(cell);
  17387. // 补齐单元格
  17388. for (var j = colIndex, endCol = colIndex + cellInfo.colSpan; j < endCol; j++) {
  17389. if (j == colIndex)continue;
  17390. var tableRow = this.table.rows[rowIndex],
  17391. tmpCell = tableRow.insertCell(this.indexTable[rowIndex][j].cellIndex + 1);
  17392. tmpCell.rowSpan = cellInfo.rowSpan;
  17393. this.setCellContent(tmpCell);
  17394. tmpCell.setAttribute('vAlign', cell.getAttribute('vAlign'));
  17395. tmpCell.setAttribute('align', cell.getAttribute('align'));
  17396. tmpCell.setAttribute('width', backWidth);
  17397. if (cell.style.cssText) {
  17398. tmpCell.style.cssText = cell.style.cssText;
  17399. }
  17400. //处理th的情况
  17401. if (cell.tagName == 'TH') {
  17402. var th = cell.ownerDocument.createElement('th');
  17403. th.appendChild(tmpCell.firstChild);
  17404. th.setAttribute('vAlign', cell.getAttribute('vAlign'));
  17405. th.rowSpan = tmpCell.rowSpan;
  17406. tableRow.insertBefore(th, tmpCell);
  17407. domUtils.remove(tmpCell);
  17408. }
  17409. results.push(tmpCell);
  17410. }
  17411. this.update();
  17412. return results;
  17413. },
  17414. isLastCell:function (cell, rowsNum, colsNum) {
  17415. rowsNum = rowsNum || this.rowsNum;
  17416. colsNum = colsNum || this.colsNum;
  17417. var cellInfo = this.getCellInfo(cell);
  17418. return ((cellInfo.rowIndex + cellInfo.rowSpan) == rowsNum) &&
  17419. ((cellInfo.colIndex + cellInfo.colSpan) == colsNum);
  17420. },
  17421. getLastCell:function (cells) {
  17422. cells = cells || this.table.getElementsByTagName("td");
  17423. var firstInfo = this.getCellInfo(cells[0]);
  17424. var me = this, last = cells[0],
  17425. tr = last.parentNode,
  17426. cellsNum = 0, cols = 0, rows;
  17427. utils.each(cells, function (cell) {
  17428. if (cell.parentNode == tr)cols += cell.colSpan || 1;
  17429. cellsNum += cell.rowSpan * cell.colSpan || 1;
  17430. });
  17431. rows = cellsNum / cols;
  17432. utils.each(cells, function (cell) {
  17433. if (me.isLastCell(cell, rows, cols)) {
  17434. last = cell;
  17435. return false;
  17436. }
  17437. });
  17438. return last;
  17439. },
  17440. selectRow:function (rowIndex) {
  17441. var indexRow = this.indexTable[rowIndex],
  17442. start = this.getCell(indexRow[0].rowIndex, indexRow[0].cellIndex),
  17443. end = this.getCell(indexRow[this.colsNum - 1].rowIndex, indexRow[this.colsNum - 1].cellIndex),
  17444. range = this.getCellsRange(start, end);
  17445. this.setSelected(range);
  17446. },
  17447. selectTable:function () {
  17448. var tds = this.table.getElementsByTagName("td"),
  17449. range = this.getCellsRange(tds[0], tds[tds.length - 1]);
  17450. this.setSelected(range);
  17451. },
  17452. setBackground:function (cells, value) {
  17453. if (typeof value === "string") {
  17454. utils.each(cells, function (cell) {
  17455. cell.style.backgroundColor = value;
  17456. })
  17457. } else if (typeof value === "object") {
  17458. value = utils.extend({
  17459. repeat:true,
  17460. colorList:["#ddd", "#fff"]
  17461. }, value);
  17462. var rowIndex = this.getCellInfo(cells[0]).rowIndex,
  17463. count = 0,
  17464. colors = value.colorList,
  17465. getColor = function (list, index, repeat) {
  17466. return list[index] ? list[index] : repeat ? list[index % list.length] : "";
  17467. };
  17468. for (var i = 0, cell; cell = cells[i++];) {
  17469. var cellInfo = this.getCellInfo(cell);
  17470. cell.style.backgroundColor = getColor(colors, ((rowIndex + count) == cellInfo.rowIndex) ? count : ++count, value.repeat);
  17471. }
  17472. }
  17473. },
  17474. removeBackground:function (cells) {
  17475. utils.each(cells, function (cell) {
  17476. cell.style.backgroundColor = "";
  17477. })
  17478. }
  17479. };
  17480. function showError(e) {
  17481. }
  17482. })();
  17483. // plugins/table.cmds.js
  17484. /**
  17485. * Created with JetBrains PhpStorm.
  17486. * User: taoqili
  17487. * Date: 13-2-20
  17488. * Time: 下午6:25
  17489. * To change this template use File | Settings | File Templates.
  17490. */
  17491. ;
  17492. (function () {
  17493. var UT = UE.UETable,
  17494. getTableItemsByRange = function (editor) {
  17495. return UT.getTableItemsByRange(editor);
  17496. },
  17497. getUETableBySelected = function (editor) {
  17498. return UT.getUETableBySelected(editor)
  17499. },
  17500. getDefaultValue = function (editor, table) {
  17501. return UT.getDefaultValue(editor, table);
  17502. },
  17503. getUETable = function (tdOrTable) {
  17504. return UT.getUETable(tdOrTable);
  17505. };
  17506. UE.commands['inserttable'] = {
  17507. queryCommandState: function () {
  17508. return getTableItemsByRange(this).table ? -1 : 0;
  17509. },
  17510. execCommand: function (cmd, opt) {
  17511. function createTable(opt, tdWidth) {
  17512. var html = [],
  17513. rowsNum = opt.numRows,
  17514. colsNum = opt.numCols;
  17515. for (var r = 0; r < rowsNum; r++) {
  17516. html.push('<tr' + (r == 0 ? ' class="firstRow"':'') + '>');
  17517. for (var c = 0; c < colsNum; c++) {
  17518. html.push('<td width="' + tdWidth + '" vAlign="' + opt.tdvalign + '" >' + (browser.ie && browser.version < 11 ? domUtils.fillChar : '<br/>') + '</td>')
  17519. }
  17520. html.push('</tr>')
  17521. }
  17522. //禁止指定table-width
  17523. return '<table><tbody>' + html.join('') + '</tbody></table>'
  17524. }
  17525. if (!opt) {
  17526. opt = utils.extend({}, {
  17527. numCols: this.options.defaultCols,
  17528. numRows: this.options.defaultRows,
  17529. tdvalign: this.options.tdvalign
  17530. })
  17531. }
  17532. var me = this;
  17533. var range = this.selection.getRange(),
  17534. start = range.startContainer,
  17535. firstParentBlock = domUtils.findParent(start, function (node) {
  17536. return domUtils.isBlockElm(node);
  17537. }, true) || me.body;
  17538. var defaultValue = getDefaultValue(me),
  17539. tableWidth = firstParentBlock.offsetWidth,
  17540. tdWidth = Math.floor(tableWidth / opt.numCols - defaultValue.tdPadding * 2 - defaultValue.tdBorder);
  17541. //todo其他属性
  17542. !opt.tdvalign && (opt.tdvalign = me.options.tdvalign);
  17543. me.execCommand("inserthtml", createTable(opt, tdWidth));
  17544. }
  17545. };
  17546. UE.commands['insertparagraphbeforetable'] = {
  17547. queryCommandState: function () {
  17548. return getTableItemsByRange(this).cell ? 0 : -1;
  17549. },
  17550. execCommand: function () {
  17551. var table = getTableItemsByRange(this).table;
  17552. if (table) {
  17553. var p = this.document.createElement("p");
  17554. p.innerHTML = browser.ie ? '&nbsp;' : '<br />';
  17555. table.parentNode.insertBefore(p, table);
  17556. this.selection.getRange().setStart(p, 0).setCursor();
  17557. }
  17558. }
  17559. };
  17560. UE.commands['deletetable'] = {
  17561. queryCommandState: function () {
  17562. var rng = this.selection.getRange();
  17563. return domUtils.findParentByTagName(rng.startContainer, 'table', true) ? 0 : -1;
  17564. },
  17565. execCommand: function (cmd, table) {
  17566. var rng = this.selection.getRange();
  17567. table = table || domUtils.findParentByTagName(rng.startContainer, 'table', true);
  17568. if (table) {
  17569. var next = table.nextSibling;
  17570. if (!next) {
  17571. next = domUtils.createElement(this.document, 'p', {
  17572. 'innerHTML': browser.ie ? domUtils.fillChar : '<br/>'
  17573. });
  17574. table.parentNode.insertBefore(next, table);
  17575. }
  17576. domUtils.remove(table);
  17577. rng = this.selection.getRange();
  17578. if (next.nodeType == 3) {
  17579. rng.setStartBefore(next)
  17580. } else {
  17581. rng.setStart(next, 0)
  17582. }
  17583. rng.setCursor(false, true)
  17584. this.fireEvent("tablehasdeleted")
  17585. }
  17586. }
  17587. };
  17588. UE.commands['cellalign'] = {
  17589. queryCommandState: function () {
  17590. return getSelectedArr(this).length ? 0 : -1
  17591. },
  17592. execCommand: function (cmd, align) {
  17593. var selectedTds = getSelectedArr(this);
  17594. if (selectedTds.length) {
  17595. for (var i = 0, ci; ci = selectedTds[i++];) {
  17596. ci.setAttribute('align', align);
  17597. }
  17598. }
  17599. }
  17600. };
  17601. UE.commands['cellvalign'] = {
  17602. queryCommandState: function () {
  17603. return getSelectedArr(this).length ? 0 : -1;
  17604. },
  17605. execCommand: function (cmd, valign) {
  17606. var selectedTds = getSelectedArr(this);
  17607. if (selectedTds.length) {
  17608. for (var i = 0, ci; ci = selectedTds[i++];) {
  17609. ci.setAttribute('vAlign', valign);
  17610. }
  17611. }
  17612. }
  17613. };
  17614. UE.commands['insertcaption'] = {
  17615. queryCommandState: function () {
  17616. var table = getTableItemsByRange(this).table;
  17617. if (table) {
  17618. return table.getElementsByTagName('caption').length == 0 ? 1 : -1;
  17619. }
  17620. return -1;
  17621. },
  17622. execCommand: function () {
  17623. var table = getTableItemsByRange(this).table;
  17624. if (table) {
  17625. var caption = this.document.createElement('caption');
  17626. caption.innerHTML = browser.ie ? domUtils.fillChar : '<br/>';
  17627. table.insertBefore(caption, table.firstChild);
  17628. var range = this.selection.getRange();
  17629. range.setStart(caption, 0).setCursor();
  17630. }
  17631. }
  17632. };
  17633. UE.commands['deletecaption'] = {
  17634. queryCommandState: function () {
  17635. var rng = this.selection.getRange(),
  17636. table = domUtils.findParentByTagName(rng.startContainer, 'table');
  17637. if (table) {
  17638. return table.getElementsByTagName('caption').length == 0 ? -1 : 1;
  17639. }
  17640. return -1;
  17641. },
  17642. execCommand: function () {
  17643. var rng = this.selection.getRange(),
  17644. table = domUtils.findParentByTagName(rng.startContainer, 'table');
  17645. if (table) {
  17646. domUtils.remove(table.getElementsByTagName('caption')[0]);
  17647. var range = this.selection.getRange();
  17648. range.setStart(table.rows[0].cells[0], 0).setCursor();
  17649. }
  17650. }
  17651. };
  17652. UE.commands['inserttitle'] = {
  17653. queryCommandState: function () {
  17654. var table = getTableItemsByRange(this).table;
  17655. if (table) {
  17656. var firstRow = table.rows[0];
  17657. return firstRow.cells[firstRow.cells.length-1].tagName.toLowerCase() != 'th' ? 0 : -1
  17658. }
  17659. return -1;
  17660. },
  17661. execCommand: function () {
  17662. var table = getTableItemsByRange(this).table;
  17663. if (table) {
  17664. getUETable(table).insertRow(0, 'th');
  17665. }
  17666. var th = table.getElementsByTagName('th')[0];
  17667. this.selection.getRange().setStart(th, 0).setCursor(false, true);
  17668. }
  17669. };
  17670. UE.commands['deletetitle'] = {
  17671. queryCommandState: function () {
  17672. var table = getTableItemsByRange(this).table;
  17673. if (table) {
  17674. var firstRow = table.rows[0];
  17675. return firstRow.cells[firstRow.cells.length-1].tagName.toLowerCase() == 'th' ? 0 : -1
  17676. }
  17677. return -1;
  17678. },
  17679. execCommand: function () {
  17680. var table = getTableItemsByRange(this).table;
  17681. if (table) {
  17682. domUtils.remove(table.rows[0])
  17683. }
  17684. var td = table.getElementsByTagName('td')[0];
  17685. this.selection.getRange().setStart(td, 0).setCursor(false, true);
  17686. }
  17687. };
  17688. UE.commands['inserttitlecol'] = {
  17689. queryCommandState: function () {
  17690. var table = getTableItemsByRange(this).table;
  17691. if (table) {
  17692. var lastRow = table.rows[table.rows.length-1];
  17693. return lastRow.getElementsByTagName('th').length ? -1 : 0;
  17694. }
  17695. return -1;
  17696. },
  17697. execCommand: function (cmd) {
  17698. var table = getTableItemsByRange(this).table;
  17699. if (table) {
  17700. getUETable(table).insertCol(0, 'th');
  17701. }
  17702. resetTdWidth(table, this);
  17703. var th = table.getElementsByTagName('th')[0];
  17704. this.selection.getRange().setStart(th, 0).setCursor(false, true);
  17705. }
  17706. };
  17707. UE.commands['deletetitlecol'] = {
  17708. queryCommandState: function () {
  17709. var table = getTableItemsByRange(this).table;
  17710. if (table) {
  17711. var lastRow = table.rows[table.rows.length-1];
  17712. return lastRow.getElementsByTagName('th').length ? 0 : -1;
  17713. }
  17714. return -1;
  17715. },
  17716. execCommand: function () {
  17717. var table = getTableItemsByRange(this).table;
  17718. if (table) {
  17719. for(var i = 0; i< table.rows.length; i++ ){
  17720. domUtils.remove(table.rows[i].children[0])
  17721. }
  17722. }
  17723. resetTdWidth(table, this);
  17724. var td = table.getElementsByTagName('td')[0];
  17725. this.selection.getRange().setStart(td, 0).setCursor(false, true);
  17726. }
  17727. };
  17728. UE.commands["mergeright"] = {
  17729. queryCommandState: function (cmd) {
  17730. var tableItems = getTableItemsByRange(this),
  17731. table = tableItems.table,
  17732. cell = tableItems.cell;
  17733. if (!table || !cell) return -1;
  17734. var ut = getUETable(table);
  17735. if (ut.selectedTds.length) return -1;
  17736. var cellInfo = ut.getCellInfo(cell),
  17737. rightColIndex = cellInfo.colIndex + cellInfo.colSpan;
  17738. if (rightColIndex >= ut.colsNum) return -1; // 如果处于最右边则不能向右合并
  17739. var rightCellInfo = ut.indexTable[cellInfo.rowIndex][rightColIndex],
  17740. rightCell = table.rows[rightCellInfo.rowIndex].cells[rightCellInfo.cellIndex];
  17741. if (!rightCell || cell.tagName != rightCell.tagName) return -1; // TH和TD不能相互合并
  17742. // 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
  17743. return (rightCellInfo.rowIndex == cellInfo.rowIndex && rightCellInfo.rowSpan == cellInfo.rowSpan) ? 0 : -1;
  17744. },
  17745. execCommand: function (cmd) {
  17746. var rng = this.selection.getRange(),
  17747. bk = rng.createBookmark(true);
  17748. var cell = getTableItemsByRange(this).cell,
  17749. ut = getUETable(cell);
  17750. ut.mergeRight(cell);
  17751. rng.moveToBookmark(bk).select();
  17752. }
  17753. };
  17754. UE.commands["mergedown"] = {
  17755. queryCommandState: function (cmd) {
  17756. var tableItems = getTableItemsByRange(this),
  17757. table = tableItems.table,
  17758. cell = tableItems.cell;
  17759. if (!table || !cell) return -1;
  17760. var ut = getUETable(table);
  17761. if (ut.selectedTds.length)return -1;
  17762. var cellInfo = ut.getCellInfo(cell),
  17763. downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan;
  17764. if (downRowIndex >= ut.rowsNum) return -1; // 如果处于最下边则不能向下合并
  17765. var downCellInfo = ut.indexTable[downRowIndex][cellInfo.colIndex],
  17766. downCell = table.rows[downCellInfo.rowIndex].cells[downCellInfo.cellIndex];
  17767. if (!downCell || cell.tagName != downCell.tagName) return -1; // TH和TD不能相互合并
  17768. // 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
  17769. return (downCellInfo.colIndex == cellInfo.colIndex && downCellInfo.colSpan == cellInfo.colSpan) ? 0 : -1;
  17770. },
  17771. execCommand: function () {
  17772. var rng = this.selection.getRange(),
  17773. bk = rng.createBookmark(true);
  17774. var cell = getTableItemsByRange(this).cell,
  17775. ut = getUETable(cell);
  17776. ut.mergeDown(cell);
  17777. rng.moveToBookmark(bk).select();
  17778. }
  17779. };
  17780. UE.commands["mergecells"] = {
  17781. queryCommandState: function () {
  17782. return getUETableBySelected(this) ? 0 : -1;
  17783. },
  17784. execCommand: function () {
  17785. var ut = getUETableBySelected(this);
  17786. if (ut && ut.selectedTds.length) {
  17787. var cell = ut.selectedTds[0];
  17788. ut.mergeRange();
  17789. var rng = this.selection.getRange();
  17790. if (domUtils.isEmptyBlock(cell)) {
  17791. rng.setStart(cell, 0).collapse(true)
  17792. } else {
  17793. rng.selectNodeContents(cell)
  17794. }
  17795. rng.select();
  17796. }
  17797. }
  17798. };
  17799. UE.commands["insertrow"] = {
  17800. queryCommandState: function () {
  17801. var tableItems = getTableItemsByRange(this),
  17802. cell = tableItems.cell;
  17803. return cell && (cell.tagName == "TD" || (cell.tagName == 'TH' && tableItems.tr !== tableItems.table.rows[0])) &&
  17804. getUETable(tableItems.table).rowsNum < this.options.maxRowNum ? 0 : -1;
  17805. },
  17806. execCommand: function () {
  17807. var rng = this.selection.getRange(),
  17808. bk = rng.createBookmark(true);
  17809. var tableItems = getTableItemsByRange(this),
  17810. cell = tableItems.cell,
  17811. table = tableItems.table,
  17812. ut = getUETable(table),
  17813. cellInfo = ut.getCellInfo(cell);
  17814. //ut.insertRow(!ut.selectedTds.length ? cellInfo.rowIndex:ut.cellsRange.beginRowIndex,'');
  17815. if (!ut.selectedTds.length) {
  17816. ut.insertRow(cellInfo.rowIndex, cell);
  17817. } else {
  17818. var range = ut.cellsRange;
  17819. for (var i = 0, len = range.endRowIndex - range.beginRowIndex + 1; i < len; i++) {
  17820. ut.insertRow(range.beginRowIndex, cell);
  17821. }
  17822. }
  17823. rng.moveToBookmark(bk).select();
  17824. if (table.getAttribute("interlaced") === "enabled")this.fireEvent("interlacetable", table);
  17825. }
  17826. };
  17827. //后插入行
  17828. UE.commands["insertrownext"] = {
  17829. queryCommandState: function () {
  17830. var tableItems = getTableItemsByRange(this),
  17831. cell = tableItems.cell;
  17832. return cell && (cell.tagName == "TD") && getUETable(tableItems.table).rowsNum < this.options.maxRowNum ? 0 : -1;
  17833. },
  17834. execCommand: function () {
  17835. var rng = this.selection.getRange(),
  17836. bk = rng.createBookmark(true);
  17837. var tableItems = getTableItemsByRange(this),
  17838. cell = tableItems.cell,
  17839. table = tableItems.table,
  17840. ut = getUETable(table),
  17841. cellInfo = ut.getCellInfo(cell);
  17842. //ut.insertRow(!ut.selectedTds.length? cellInfo.rowIndex + cellInfo.rowSpan : ut.cellsRange.endRowIndex + 1,'');
  17843. if (!ut.selectedTds.length) {
  17844. ut.insertRow(cellInfo.rowIndex + cellInfo.rowSpan, cell);
  17845. } else {
  17846. var range = ut.cellsRange;
  17847. for (var i = 0, len = range.endRowIndex - range.beginRowIndex + 1; i < len; i++) {
  17848. ut.insertRow(range.endRowIndex + 1, cell);
  17849. }
  17850. }
  17851. rng.moveToBookmark(bk).select();
  17852. if (table.getAttribute("interlaced") === "enabled")this.fireEvent("interlacetable", table);
  17853. }
  17854. };
  17855. UE.commands["deleterow"] = {
  17856. queryCommandState: function () {
  17857. var tableItems = getTableItemsByRange(this);
  17858. return tableItems.cell ? 0 : -1;
  17859. },
  17860. execCommand: function () {
  17861. var cell = getTableItemsByRange(this).cell,
  17862. ut = getUETable(cell),
  17863. cellsRange = ut.cellsRange,
  17864. cellInfo = ut.getCellInfo(cell),
  17865. preCell = ut.getVSideCell(cell),
  17866. nextCell = ut.getVSideCell(cell, true),
  17867. rng = this.selection.getRange();
  17868. if (utils.isEmptyObject(cellsRange)) {
  17869. ut.deleteRow(cellInfo.rowIndex);
  17870. } else {
  17871. for (var i = cellsRange.beginRowIndex; i < cellsRange.endRowIndex + 1; i++) {
  17872. ut.deleteRow(cellsRange.beginRowIndex);
  17873. }
  17874. }
  17875. var table = ut.table;
  17876. if (!table.getElementsByTagName('td').length) {
  17877. var nextSibling = table.nextSibling;
  17878. domUtils.remove(table);
  17879. if (nextSibling) {
  17880. rng.setStart(nextSibling, 0).setCursor(false, true);
  17881. }
  17882. } else {
  17883. if (cellInfo.rowSpan == 1 || cellInfo.rowSpan == cellsRange.endRowIndex - cellsRange.beginRowIndex + 1) {
  17884. if (nextCell || preCell) rng.selectNodeContents(nextCell || preCell).setCursor(false, true);
  17885. } else {
  17886. var newCell = ut.getCell(cellInfo.rowIndex, ut.indexTable[cellInfo.rowIndex][cellInfo.colIndex].cellIndex);
  17887. if (newCell) rng.selectNodeContents(newCell).setCursor(false, true);
  17888. }
  17889. }
  17890. if (table.getAttribute("interlaced") === "enabled")this.fireEvent("interlacetable", table);
  17891. }
  17892. };
  17893. UE.commands["insertcol"] = {
  17894. queryCommandState: function (cmd) {
  17895. var tableItems = getTableItemsByRange(this),
  17896. cell = tableItems.cell;
  17897. return cell && (cell.tagName == "TD" || (cell.tagName == 'TH' && cell !== tableItems.tr.cells[0])) &&
  17898. getUETable(tableItems.table).colsNum < this.options.maxColNum ? 0 : -1;
  17899. },
  17900. execCommand: function (cmd) {
  17901. var rng = this.selection.getRange(),
  17902. bk = rng.createBookmark(true);
  17903. if (this.queryCommandState(cmd) == -1)return;
  17904. var cell = getTableItemsByRange(this).cell,
  17905. ut = getUETable(cell),
  17906. cellInfo = ut.getCellInfo(cell);
  17907. //ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex:ut.cellsRange.beginColIndex);
  17908. if (!ut.selectedTds.length) {
  17909. ut.insertCol(cellInfo.colIndex, cell);
  17910. } else {
  17911. var range = ut.cellsRange;
  17912. for (var i = 0, len = range.endColIndex - range.beginColIndex + 1; i < len; i++) {
  17913. ut.insertCol(range.beginColIndex, cell);
  17914. }
  17915. }
  17916. rng.moveToBookmark(bk).select(true);
  17917. }
  17918. };
  17919. UE.commands["insertcolnext"] = {
  17920. queryCommandState: function () {
  17921. var tableItems = getTableItemsByRange(this),
  17922. cell = tableItems.cell;
  17923. return cell && getUETable(tableItems.table).colsNum < this.options.maxColNum ? 0 : -1;
  17924. },
  17925. execCommand: function () {
  17926. var rng = this.selection.getRange(),
  17927. bk = rng.createBookmark(true);
  17928. var cell = getTableItemsByRange(this).cell,
  17929. ut = getUETable(cell),
  17930. cellInfo = ut.getCellInfo(cell);
  17931. //ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex + cellInfo.colSpan:ut.cellsRange.endColIndex +1);
  17932. if (!ut.selectedTds.length) {
  17933. ut.insertCol(cellInfo.colIndex + cellInfo.colSpan, cell);
  17934. } else {
  17935. var range = ut.cellsRange;
  17936. for (var i = 0, len = range.endColIndex - range.beginColIndex + 1; i < len; i++) {
  17937. ut.insertCol(range.endColIndex + 1, cell);
  17938. }
  17939. }
  17940. rng.moveToBookmark(bk).select();
  17941. }
  17942. };
  17943. UE.commands["deletecol"] = {
  17944. queryCommandState: function () {
  17945. var tableItems = getTableItemsByRange(this);
  17946. return tableItems.cell ? 0 : -1;
  17947. },
  17948. execCommand: function () {
  17949. var cell = getTableItemsByRange(this).cell,
  17950. ut = getUETable(cell),
  17951. range = ut.cellsRange,
  17952. cellInfo = ut.getCellInfo(cell),
  17953. preCell = ut.getHSideCell(cell),
  17954. nextCell = ut.getHSideCell(cell, true);
  17955. if (utils.isEmptyObject(range)) {
  17956. ut.deleteCol(cellInfo.colIndex);
  17957. } else {
  17958. for (var i = range.beginColIndex; i < range.endColIndex + 1; i++) {
  17959. ut.deleteCol(range.beginColIndex);
  17960. }
  17961. }
  17962. var table = ut.table,
  17963. rng = this.selection.getRange();
  17964. if (!table.getElementsByTagName('td').length) {
  17965. var nextSibling = table.nextSibling;
  17966. domUtils.remove(table);
  17967. if (nextSibling) {
  17968. rng.setStart(nextSibling, 0).setCursor(false, true);
  17969. }
  17970. } else {
  17971. if (domUtils.inDoc(cell, this.document)) {
  17972. rng.setStart(cell, 0).setCursor(false, true);
  17973. } else {
  17974. if (nextCell && domUtils.inDoc(nextCell, this.document)) {
  17975. rng.selectNodeContents(nextCell).setCursor(false, true);
  17976. } else {
  17977. if (preCell && domUtils.inDoc(preCell, this.document)) {
  17978. rng.selectNodeContents(preCell).setCursor(true, true);
  17979. }
  17980. }
  17981. }
  17982. }
  17983. }
  17984. };
  17985. UE.commands["splittocells"] = {
  17986. queryCommandState: function () {
  17987. var tableItems = getTableItemsByRange(this),
  17988. cell = tableItems.cell;
  17989. if (!cell) return -1;
  17990. var ut = getUETable(tableItems.table);
  17991. if (ut.selectedTds.length > 0) return -1;
  17992. return cell && (cell.colSpan > 1 || cell.rowSpan > 1) ? 0 : -1;
  17993. },
  17994. execCommand: function () {
  17995. var rng = this.selection.getRange(),
  17996. bk = rng.createBookmark(true);
  17997. var cell = getTableItemsByRange(this).cell,
  17998. ut = getUETable(cell);
  17999. ut.splitToCells(cell);
  18000. rng.moveToBookmark(bk).select();
  18001. }
  18002. };
  18003. UE.commands["splittorows"] = {
  18004. queryCommandState: function () {
  18005. var tableItems = getTableItemsByRange(this),
  18006. cell = tableItems.cell;
  18007. if (!cell) return -1;
  18008. var ut = getUETable(tableItems.table);
  18009. if (ut.selectedTds.length > 0) return -1;
  18010. return cell && cell.rowSpan > 1 ? 0 : -1;
  18011. },
  18012. execCommand: function () {
  18013. var rng = this.selection.getRange(),
  18014. bk = rng.createBookmark(true);
  18015. var cell = getTableItemsByRange(this).cell,
  18016. ut = getUETable(cell);
  18017. ut.splitToRows(cell);
  18018. rng.moveToBookmark(bk).select();
  18019. }
  18020. };
  18021. UE.commands["splittocols"] = {
  18022. queryCommandState: function () {
  18023. var tableItems = getTableItemsByRange(this),
  18024. cell = tableItems.cell;
  18025. if (!cell) return -1;
  18026. var ut = getUETable(tableItems.table);
  18027. if (ut.selectedTds.length > 0) return -1;
  18028. return cell && cell.colSpan > 1 ? 0 : -1;
  18029. },
  18030. execCommand: function () {
  18031. var rng = this.selection.getRange(),
  18032. bk = rng.createBookmark(true);
  18033. var cell = getTableItemsByRange(this).cell,
  18034. ut = getUETable(cell);
  18035. ut.splitToCols(cell);
  18036. rng.moveToBookmark(bk).select();
  18037. }
  18038. };
  18039. UE.commands["adaptbytext"] =
  18040. UE.commands["adaptbywindow"] = {
  18041. queryCommandState: function () {
  18042. return getTableItemsByRange(this).table ? 0 : -1
  18043. },
  18044. execCommand: function (cmd) {
  18045. var tableItems = getTableItemsByRange(this),
  18046. table = tableItems.table;
  18047. if (table) {
  18048. if (cmd == 'adaptbywindow') {
  18049. resetTdWidth(table, this);
  18050. } else {
  18051. var cells = domUtils.getElementsByTagName(table, "td th");
  18052. utils.each(cells, function (cell) {
  18053. cell.removeAttribute("width");
  18054. });
  18055. table.removeAttribute("width");
  18056. }
  18057. }
  18058. }
  18059. };
  18060. //平均分配各列
  18061. UE.commands['averagedistributecol'] = {
  18062. queryCommandState: function () {
  18063. var ut = getUETableBySelected(this);
  18064. if (!ut) return -1;
  18065. return ut.isFullRow() || ut.isFullCol() ? 0 : -1;
  18066. },
  18067. execCommand: function (cmd) {
  18068. var me = this,
  18069. ut = getUETableBySelected(me);
  18070. function getAverageWidth() {
  18071. var tb = ut.table,
  18072. averageWidth, sumWidth = 0, colsNum = 0,
  18073. tbAttr = getDefaultValue(me, tb);
  18074. if (ut.isFullRow()) {
  18075. sumWidth = tb.offsetWidth;
  18076. colsNum = ut.colsNum;
  18077. } else {
  18078. var begin = ut.cellsRange.beginColIndex,
  18079. end = ut.cellsRange.endColIndex,
  18080. node;
  18081. for (var i = begin; i <= end;) {
  18082. node = ut.selectedTds[i];
  18083. sumWidth += node.offsetWidth;
  18084. i += node.colSpan;
  18085. colsNum += 1;
  18086. }
  18087. }
  18088. averageWidth = Math.ceil(sumWidth / colsNum) - tbAttr.tdBorder * 2 - tbAttr.tdPadding * 2;
  18089. return averageWidth;
  18090. }
  18091. function setAverageWidth(averageWidth) {
  18092. utils.each(domUtils.getElementsByTagName(ut.table, "th"), function (node) {
  18093. node.setAttribute("width", "");
  18094. });
  18095. var cells = ut.isFullRow() ? domUtils.getElementsByTagName(ut.table, "td") : ut.selectedTds;
  18096. utils.each(cells, function (node) {
  18097. if (node.colSpan == 1) {
  18098. node.setAttribute("width", averageWidth);
  18099. }
  18100. });
  18101. }
  18102. if (ut && ut.selectedTds.length) {
  18103. setAverageWidth(getAverageWidth());
  18104. }
  18105. }
  18106. };
  18107. //平均分配各行
  18108. UE.commands['averagedistributerow'] = {
  18109. queryCommandState: function () {
  18110. var ut = getUETableBySelected(this);
  18111. if (!ut) return -1;
  18112. if (ut.selectedTds && /th/ig.test(ut.selectedTds[0].tagName)) return -1;
  18113. return ut.isFullRow() || ut.isFullCol() ? 0 : -1;
  18114. },
  18115. execCommand: function (cmd) {
  18116. var me = this,
  18117. ut = getUETableBySelected(me);
  18118. function getAverageHeight() {
  18119. var averageHeight, rowNum, sumHeight = 0,
  18120. tb = ut.table,
  18121. tbAttr = getDefaultValue(me, tb),
  18122. tdpadding = parseInt(domUtils.getComputedStyle(tb.getElementsByTagName('td')[0], "padding-top"));
  18123. if (ut.isFullCol()) {
  18124. var captionArr = domUtils.getElementsByTagName(tb, "caption"),
  18125. thArr = domUtils.getElementsByTagName(tb, "th"),
  18126. captionHeight, thHeight;
  18127. if (captionArr.length > 0) {
  18128. captionHeight = captionArr[0].offsetHeight;
  18129. }
  18130. if (thArr.length > 0) {
  18131. thHeight = thArr[0].offsetHeight;
  18132. }
  18133. sumHeight = tb.offsetHeight - (captionHeight || 0) - (thHeight || 0);
  18134. rowNum = thArr.length == 0 ? ut.rowsNum : (ut.rowsNum - 1);
  18135. } else {
  18136. var begin = ut.cellsRange.beginRowIndex,
  18137. end = ut.cellsRange.endRowIndex,
  18138. count = 0,
  18139. trs = domUtils.getElementsByTagName(tb, "tr");
  18140. for (var i = begin; i <= end; i++) {
  18141. sumHeight += trs[i].offsetHeight;
  18142. count += 1;
  18143. }
  18144. rowNum = count;
  18145. }
  18146. //ie8下是混杂模式
  18147. if (browser.ie && browser.version < 9) {
  18148. averageHeight = Math.ceil(sumHeight / rowNum);
  18149. } else {
  18150. averageHeight = Math.ceil(sumHeight / rowNum) - tbAttr.tdBorder * 2 - tdpadding * 2;
  18151. }
  18152. return averageHeight;
  18153. }
  18154. function setAverageHeight(averageHeight) {
  18155. var cells = ut.isFullCol() ? domUtils.getElementsByTagName(ut.table, "td") : ut.selectedTds;
  18156. utils.each(cells, function (node) {
  18157. if (node.rowSpan == 1) {
  18158. node.setAttribute("height", averageHeight);
  18159. }
  18160. });
  18161. }
  18162. if (ut && ut.selectedTds.length) {
  18163. setAverageHeight(getAverageHeight());
  18164. }
  18165. }
  18166. };
  18167. //单元格对齐方式
  18168. UE.commands['cellalignment'] = {
  18169. queryCommandState: function () {
  18170. return getTableItemsByRange(this).table ? 0 : -1
  18171. },
  18172. execCommand: function (cmd, data) {
  18173. var me = this,
  18174. ut = getUETableBySelected(me);
  18175. if (!ut) {
  18176. var start = me.selection.getStart(),
  18177. cell = start && domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
  18178. if (!/caption/ig.test(cell.tagName)) {
  18179. domUtils.setAttributes(cell, data);
  18180. } else {
  18181. cell.style.textAlign = data.align;
  18182. cell.style.verticalAlign = data.vAlign;
  18183. }
  18184. me.selection.getRange().setCursor(true);
  18185. } else {
  18186. utils.each(ut.selectedTds, function (cell) {
  18187. domUtils.setAttributes(cell, data);
  18188. });
  18189. }
  18190. },
  18191. /**
  18192. * 查询当前点击的单元格的对齐状态, 如果当前已经选择了多个单元格, 则会返回所有单元格经过统一协调过后的状态
  18193. * @see UE.UETable.getTableCellAlignState
  18194. */
  18195. queryCommandValue: function (cmd) {
  18196. var activeMenuCell = getTableItemsByRange( this).cell;
  18197. if( !activeMenuCell ) {
  18198. activeMenuCell = getSelectedArr(this)[0];
  18199. }
  18200. if (!activeMenuCell) {
  18201. return null;
  18202. } else {
  18203. //获取同时选中的其他单元格
  18204. var cells = UE.UETable.getUETable(activeMenuCell).selectedTds;
  18205. !cells.length && ( cells = activeMenuCell );
  18206. return UE.UETable.getTableCellAlignState(cells);
  18207. }
  18208. }
  18209. };
  18210. //表格对齐方式
  18211. UE.commands['tablealignment'] = {
  18212. queryCommandState: function () {
  18213. if (browser.ie && browser.version < 8) {
  18214. return -1;
  18215. }
  18216. return getTableItemsByRange(this).table ? 0 : -1
  18217. },
  18218. execCommand: function (cmd, value) {
  18219. var me = this,
  18220. start = me.selection.getStart(),
  18221. table = start && domUtils.findParentByTagName(start, ["table"], true);
  18222. if (table) {
  18223. table.setAttribute("align",value);
  18224. }
  18225. }
  18226. };
  18227. //表格属性
  18228. UE.commands['edittable'] = {
  18229. queryCommandState: function () {
  18230. return getTableItemsByRange(this).table ? 0 : -1
  18231. },
  18232. execCommand: function (cmd, color) {
  18233. var rng = this.selection.getRange(),
  18234. table = domUtils.findParentByTagName(rng.startContainer, 'table');
  18235. if (table) {
  18236. var arr = domUtils.getElementsByTagName(table, "td").concat(
  18237. domUtils.getElementsByTagName(table, "th"),
  18238. domUtils.getElementsByTagName(table, "caption")
  18239. );
  18240. utils.each(arr, function (node) {
  18241. node.style.borderColor = color;
  18242. });
  18243. }
  18244. }
  18245. };
  18246. //单元格属性
  18247. UE.commands['edittd'] = {
  18248. queryCommandState: function () {
  18249. return getTableItemsByRange(this).table ? 0 : -1
  18250. },
  18251. execCommand: function (cmd, bkColor) {
  18252. var me = this,
  18253. ut = getUETableBySelected(me);
  18254. if (!ut) {
  18255. var start = me.selection.getStart(),
  18256. cell = start && domUtils.findParentByTagName(start, ["td", "th", "caption"], true);
  18257. if (cell) {
  18258. cell.style.backgroundColor = bkColor;
  18259. }
  18260. } else {
  18261. utils.each(ut.selectedTds, function (cell) {
  18262. cell.style.backgroundColor = bkColor;
  18263. });
  18264. }
  18265. }
  18266. };
  18267. UE.commands["settablebackground"] = {
  18268. queryCommandState: function () {
  18269. return getSelectedArr(this).length > 1 ? 0 : -1;
  18270. },
  18271. execCommand: function (cmd, value) {
  18272. var cells, ut;
  18273. cells = getSelectedArr(this);
  18274. ut = getUETable(cells[0]);
  18275. ut.setBackground(cells, value);
  18276. }
  18277. };
  18278. UE.commands["cleartablebackground"] = {
  18279. queryCommandState: function () {
  18280. var cells = getSelectedArr(this);
  18281. if (!cells.length)return -1;
  18282. for (var i = 0, cell; cell = cells[i++];) {
  18283. if (cell.style.backgroundColor !== "") return 0;
  18284. }
  18285. return -1;
  18286. },
  18287. execCommand: function () {
  18288. var cells = getSelectedArr(this),
  18289. ut = getUETable(cells[0]);
  18290. ut.removeBackground(cells);
  18291. }
  18292. };
  18293. UE.commands["interlacetable"] = UE.commands["uninterlacetable"] = {
  18294. queryCommandState: function (cmd) {
  18295. var table = getTableItemsByRange(this).table;
  18296. if (!table) return -1;
  18297. var interlaced = table.getAttribute("interlaced");
  18298. if (cmd == "interlacetable") {
  18299. //TODO 待定
  18300. //是否需要待定,如果设置,则命令只能单次执行成功,但反射具备toggle效果;否则可以覆盖前次命令,但反射将不存在toggle效果
  18301. return (interlaced === "enabled") ? -1 : 0;
  18302. } else {
  18303. return (!interlaced || interlaced === "disabled") ? -1 : 0;
  18304. }
  18305. },
  18306. execCommand: function (cmd, classList) {
  18307. var table = getTableItemsByRange(this).table;
  18308. if (cmd == "interlacetable") {
  18309. table.setAttribute("interlaced", "enabled");
  18310. this.fireEvent("interlacetable", table, classList);
  18311. } else {
  18312. table.setAttribute("interlaced", "disabled");
  18313. this.fireEvent("uninterlacetable", table);
  18314. }
  18315. }
  18316. };
  18317. UE.commands["setbordervisible"] = {
  18318. queryCommandState: function (cmd) {
  18319. var table = getTableItemsByRange(this).table;
  18320. if (!table) return -1;
  18321. return 0;
  18322. },
  18323. execCommand: function () {
  18324. var table = getTableItemsByRange(this).table;
  18325. utils.each(domUtils.getElementsByTagName(table,'td'),function(td){
  18326. td.style.borderWidth = '1px';
  18327. td.style.borderStyle = 'solid';
  18328. })
  18329. }
  18330. };
  18331. function resetTdWidth(table, editor) {
  18332. var tds = domUtils.getElementsByTagName(table,'td th');
  18333. utils.each(tds, function (td) {
  18334. td.removeAttribute("width");
  18335. });
  18336. table.setAttribute('width', getTableWidth(editor, true, getDefaultValue(editor, table)));
  18337. var tdsWidths = [];
  18338. setTimeout(function () {
  18339. utils.each(tds, function (td) {
  18340. (td.colSpan == 1) && tdsWidths.push(td.offsetWidth)
  18341. })
  18342. utils.each(tds, function (td,i) {
  18343. (td.colSpan == 1) && td.setAttribute("width", tdsWidths[i] + "");
  18344. })
  18345. }, 0);
  18346. }
  18347. function getTableWidth(editor, needIEHack, defaultValue) {
  18348. var body = editor.body;
  18349. return body.offsetWidth - (needIEHack ? parseInt(domUtils.getComputedStyle(body, 'margin-left'), 10) * 2 : 0) - defaultValue.tableBorder * 2 - (editor.options.offsetWidth || 0);
  18350. }
  18351. function getSelectedArr(editor) {
  18352. var cell = getTableItemsByRange(editor).cell;
  18353. if (cell) {
  18354. var ut = getUETable(cell);
  18355. return ut.selectedTds.length ? ut.selectedTds : [cell];
  18356. } else {
  18357. return [];
  18358. }
  18359. }
  18360. })();
  18361. // plugins/table.action.js
  18362. /**
  18363. * Created with JetBrains PhpStorm.
  18364. * User: taoqili
  18365. * Date: 12-10-12
  18366. * Time: 上午10:05
  18367. * To change this template use File | Settings | File Templates.
  18368. */
  18369. UE.plugins['table'] = function () {
  18370. var me = this,
  18371. tabTimer = null,
  18372. //拖动计时器
  18373. tableDragTimer = null,
  18374. //双击计时器
  18375. tableResizeTimer = null,
  18376. //单元格最小宽度
  18377. cellMinWidth = 5,
  18378. isInResizeBuffer = false,
  18379. //单元格边框大小
  18380. cellBorderWidth = 5,
  18381. //鼠标偏移距离
  18382. offsetOfTableCell = 10,
  18383. //记录在有限时间内的点击状态, 共有3个取值, 0, 1, 2。 0代表未初始化, 1代表单击了1次,2代表2次
  18384. singleClickState = 0,
  18385. userActionStatus = null,
  18386. //双击允许的时间范围
  18387. dblclickTime = 360,
  18388. UT = UE.UETable,
  18389. getUETable = function (tdOrTable) {
  18390. return UT.getUETable(tdOrTable);
  18391. },
  18392. getUETableBySelected = function (editor) {
  18393. return UT.getUETableBySelected(editor);
  18394. },
  18395. getDefaultValue = function (editor, table) {
  18396. return UT.getDefaultValue(editor, table);
  18397. },
  18398. removeSelectedClass = function (cells) {
  18399. return UT.removeSelectedClass(cells);
  18400. };
  18401. function showError(e) {
  18402. // throw e;
  18403. }
  18404. me.ready(function(){
  18405. var me = this;
  18406. var orgGetText = me.selection.getText;
  18407. me.selection.getText = function(){
  18408. var table = getUETableBySelected(me);
  18409. if(table){
  18410. var str = '';
  18411. utils.each(table.selectedTds,function(td){
  18412. str += td[browser.ie?'innerText':'textContent'];
  18413. })
  18414. return str;
  18415. }else{
  18416. return orgGetText.call(me.selection)
  18417. }
  18418. }
  18419. })
  18420. //处理拖动及框选相关方法
  18421. var startTd = null, //鼠标按下时的锚点td
  18422. currentTd = null, //当前鼠标经过时的td
  18423. onDrag = "", //指示当前拖动状态,其值可为"","h","v" ,分别表示未拖动状态,横向拖动状态,纵向拖动状态,用于鼠标移动过程中的判断
  18424. onBorder = false, //检测鼠标按下时是否处在单元格边缘位置
  18425. dragButton = null,
  18426. dragOver = false,
  18427. dragLine = null, //模拟的拖动线
  18428. dragTd = null; //发生拖动的目标td
  18429. var mousedown = false,
  18430. //todo 判断混乱模式
  18431. needIEHack = true;
  18432. me.setOpt({
  18433. 'maxColNum':20,
  18434. 'maxRowNum':100,
  18435. 'defaultCols':5,
  18436. 'defaultRows':5,
  18437. 'tdvalign':'top',
  18438. 'cursorpath':me.options.UEDITOR_HOME_URL + "themes/default/images/cursor_",
  18439. 'tableDragable':false,
  18440. 'classList':["ue-table-interlace-color-single","ue-table-interlace-color-double"]
  18441. });
  18442. me.getUETable = getUETable;
  18443. var commands = {
  18444. 'deletetable':1,
  18445. 'inserttable':1,
  18446. 'cellvalign':1,
  18447. 'insertcaption':1,
  18448. 'deletecaption':1,
  18449. 'inserttitle':1,
  18450. 'deletetitle':1,
  18451. "mergeright":1,
  18452. "mergedown":1,
  18453. "mergecells":1,
  18454. "insertrow":1,
  18455. "insertrownext":1,
  18456. "deleterow":1,
  18457. "insertcol":1,
  18458. "insertcolnext":1,
  18459. "deletecol":1,
  18460. "splittocells":1,
  18461. "splittorows":1,
  18462. "splittocols":1,
  18463. "adaptbytext":1,
  18464. "adaptbywindow":1,
  18465. "adaptbycustomer":1,
  18466. "insertparagraph":1,
  18467. "insertparagraphbeforetable":1,
  18468. "averagedistributecol":1,
  18469. "averagedistributerow":1
  18470. };
  18471. me.ready(function () {
  18472. utils.cssRule('table',
  18473. //选中的td上的样式
  18474. '.selectTdClass{background-color:#edf5fa !important}' +
  18475. 'table.noBorderTable td,table.noBorderTable th,table.noBorderTable caption{border:1px dashed #ddd !important}' +
  18476. //插入的表格的默认样式
  18477. 'table{margin-bottom:10px;border-collapse:collapse;display:table;}' +
  18478. 'td,th{padding: 5px 10px;border: 1px solid #DDD;}' +
  18479. 'caption{border:1px dashed #DDD;border-bottom:0;padding:3px;text-align:center;}' +
  18480. 'th{border-top:1px solid #BBB;background-color:#F7F7F7;}' +
  18481. 'table tr.firstRow th{border-top-width:2px;}' +
  18482. '.ue-table-interlace-color-single{ background-color: #fcfcfc; } .ue-table-interlace-color-double{ background-color: #f7faff; }' +
  18483. 'td p{margin:0;padding:0;}', me.document);
  18484. var tableCopyList, isFullCol, isFullRow;
  18485. //注册del/backspace事件
  18486. me.addListener('keydown', function (cmd, evt) {
  18487. var me = this;
  18488. var keyCode = evt.keyCode || evt.which;
  18489. if (keyCode == 8) {
  18490. var ut = getUETableBySelected(me);
  18491. if (ut && ut.selectedTds.length) {
  18492. if (ut.isFullCol()) {
  18493. me.execCommand('deletecol')
  18494. } else if (ut.isFullRow()) {
  18495. me.execCommand('deleterow')
  18496. } else {
  18497. me.fireEvent('delcells');
  18498. }
  18499. domUtils.preventDefault(evt);
  18500. }
  18501. var caption = domUtils.findParentByTagName(me.selection.getStart(), 'caption', true),
  18502. range = me.selection.getRange();
  18503. if (range.collapsed && caption && isEmptyBlock(caption)) {
  18504. me.fireEvent('saveScene');
  18505. var table = caption.parentNode;
  18506. domUtils.remove(caption);
  18507. if (table) {
  18508. range.setStart(table.rows[0].cells[0], 0).setCursor(false, true);
  18509. }
  18510. me.fireEvent('saveScene');
  18511. }
  18512. }
  18513. if (keyCode == 46) {
  18514. ut = getUETableBySelected(me);
  18515. if (ut) {
  18516. me.fireEvent('saveScene');
  18517. for (var i = 0, ci; ci = ut.selectedTds[i++];) {
  18518. domUtils.fillNode(me.document, ci)
  18519. }
  18520. me.fireEvent('saveScene');
  18521. domUtils.preventDefault(evt);
  18522. }
  18523. }
  18524. if (keyCode == 13) {
  18525. var rng = me.selection.getRange(),
  18526. caption = domUtils.findParentByTagName(rng.startContainer, 'caption', true);
  18527. if (caption) {
  18528. var table = domUtils.findParentByTagName(caption, 'table');
  18529. if (!rng.collapsed) {
  18530. rng.deleteContents();
  18531. me.fireEvent('saveScene');
  18532. } else {
  18533. if (caption) {
  18534. rng.setStart(table.rows[0].cells[0], 0).setCursor(false, true);
  18535. }
  18536. }
  18537. domUtils.preventDefault(evt);
  18538. return;
  18539. }
  18540. if (rng.collapsed) {
  18541. var table = domUtils.findParentByTagName(rng.startContainer, 'table');
  18542. if (table) {
  18543. var cell = table.rows[0].cells[0],
  18544. start = domUtils.findParentByTagName(me.selection.getStart(), ['td', 'th'], true),
  18545. preNode = table.previousSibling;
  18546. if (cell === start && (!preNode || preNode.nodeType == 1 && preNode.tagName == 'TABLE' ) && domUtils.isStartInblock(rng)) {
  18547. var first = domUtils.findParent(me.selection.getStart(), function(n){return domUtils.isBlockElm(n)}, true);
  18548. if(first && ( /t(h|d)/i.test(first.tagName) || first === start.firstChild )){
  18549. me.execCommand('insertparagraphbeforetable');
  18550. domUtils.preventDefault(evt);
  18551. }
  18552. }
  18553. }
  18554. }
  18555. }
  18556. if ((evt.ctrlKey || evt.metaKey) && evt.keyCode == '67') {
  18557. tableCopyList = null;
  18558. var ut = getUETableBySelected(me);
  18559. if (ut) {
  18560. var tds = ut.selectedTds;
  18561. isFullCol = ut.isFullCol();
  18562. isFullRow = ut.isFullRow();
  18563. tableCopyList = [
  18564. [ut.cloneCell(tds[0],null,true)]
  18565. ];
  18566. for (var i = 1, ci; ci = tds[i]; i++) {
  18567. if (ci.parentNode !== tds[i - 1].parentNode) {
  18568. tableCopyList.push([ut.cloneCell(ci,null,true)]);
  18569. } else {
  18570. tableCopyList[tableCopyList.length - 1].push(ut.cloneCell(ci,null,true));
  18571. }
  18572. }
  18573. }
  18574. }
  18575. });
  18576. me.addListener("tablehasdeleted",function(){
  18577. toggleDraggableState(this, false, "", null);
  18578. if (dragButton)domUtils.remove(dragButton);
  18579. });
  18580. me.addListener('beforepaste', function (cmd, html) {
  18581. var me = this;
  18582. var rng = me.selection.getRange();
  18583. if (domUtils.findParentByTagName(rng.startContainer, 'caption', true)) {
  18584. var div = me.document.createElement("div");
  18585. div.innerHTML = html.html;
  18586. //trace:3729
  18587. html.html = div[browser.ie9below ? 'innerText' : 'textContent'];
  18588. return;
  18589. }
  18590. var table = getUETableBySelected(me);
  18591. if (tableCopyList) {
  18592. me.fireEvent('saveScene');
  18593. var rng = me.selection.getRange();
  18594. var td = domUtils.findParentByTagName(rng.startContainer, ['td', 'th'], true), tmpNode, preNode;
  18595. if (td) {
  18596. var ut = getUETable(td);
  18597. if (isFullRow) {
  18598. var rowIndex = ut.getCellInfo(td).rowIndex;
  18599. if (td.tagName == 'TH') {
  18600. rowIndex++;
  18601. }
  18602. for (var i = 0, ci; ci = tableCopyList[i++];) {
  18603. var tr = ut.insertRow(rowIndex++, "td");
  18604. for (var j = 0, cj; cj = ci[j]; j++) {
  18605. var cell = tr.cells[j];
  18606. if (!cell) {
  18607. cell = tr.insertCell(j)
  18608. }
  18609. cell.innerHTML = cj.innerHTML;
  18610. cj.getAttribute('width') && cell.setAttribute('width', cj.getAttribute('width'));
  18611. cj.getAttribute('vAlign') && cell.setAttribute('vAlign', cj.getAttribute('vAlign'));
  18612. cj.getAttribute('align') && cell.setAttribute('align', cj.getAttribute('align'));
  18613. cj.style.cssText && (cell.style.cssText = cj.style.cssText)
  18614. }
  18615. for (var j = 0, cj; cj = tr.cells[j]; j++) {
  18616. if (!ci[j])
  18617. break;
  18618. cj.innerHTML = ci[j].innerHTML;
  18619. ci[j].getAttribute('width') && cj.setAttribute('width', ci[j].getAttribute('width'));
  18620. ci[j].getAttribute('vAlign') && cj.setAttribute('vAlign', ci[j].getAttribute('vAlign'));
  18621. ci[j].getAttribute('align') && cj.setAttribute('align', ci[j].getAttribute('align'));
  18622. ci[j].style.cssText && (cj.style.cssText = ci[j].style.cssText)
  18623. }
  18624. }
  18625. } else {
  18626. if (isFullCol) {
  18627. cellInfo = ut.getCellInfo(td);
  18628. var maxColNum = 0;
  18629. for (var j = 0, ci = tableCopyList[0], cj; cj = ci[j++];) {
  18630. maxColNum += cj.colSpan || 1;
  18631. }
  18632. me.__hasEnterExecCommand = true;
  18633. for (i = 0; i < maxColNum; i++) {
  18634. me.execCommand('insertcol');
  18635. }
  18636. me.__hasEnterExecCommand = false;
  18637. td = ut.table.rows[0].cells[cellInfo.cellIndex];
  18638. if (td.tagName == 'TH') {
  18639. td = ut.table.rows[1].cells[cellInfo.cellIndex];
  18640. }
  18641. }
  18642. for (var i = 0, ci; ci = tableCopyList[i++];) {
  18643. tmpNode = td;
  18644. for (var j = 0, cj; cj = ci[j++];) {
  18645. if (td) {
  18646. td.innerHTML = cj.innerHTML;
  18647. //todo 定制处理
  18648. cj.getAttribute('width') && td.setAttribute('width', cj.getAttribute('width'));
  18649. cj.getAttribute('vAlign') && td.setAttribute('vAlign', cj.getAttribute('vAlign'));
  18650. cj.getAttribute('align') && td.setAttribute('align', cj.getAttribute('align'));
  18651. cj.style.cssText && (td.style.cssText = cj.style.cssText);
  18652. preNode = td;
  18653. td = td.nextSibling;
  18654. } else {
  18655. var cloneTd = cj.cloneNode(true);
  18656. domUtils.removeAttributes(cloneTd, ['class', 'rowSpan', 'colSpan']);
  18657. preNode.parentNode.appendChild(cloneTd)
  18658. }
  18659. }
  18660. td = ut.getNextCell(tmpNode, true, true);
  18661. if (!tableCopyList[i])
  18662. break;
  18663. if (!td) {
  18664. var cellInfo = ut.getCellInfo(tmpNode);
  18665. ut.table.insertRow(ut.table.rows.length);
  18666. ut.update();
  18667. td = ut.getVSideCell(tmpNode, true);
  18668. }
  18669. }
  18670. }
  18671. ut.update();
  18672. } else {
  18673. table = me.document.createElement('table');
  18674. for (var i = 0, ci; ci = tableCopyList[i++];) {
  18675. var tr = table.insertRow(table.rows.length);
  18676. for (var j = 0, cj; cj = ci[j++];) {
  18677. cloneTd = UT.cloneCell(cj,null,true);
  18678. domUtils.removeAttributes(cloneTd, ['class']);
  18679. tr.appendChild(cloneTd)
  18680. }
  18681. if (j == 2 && cloneTd.rowSpan > 1) {
  18682. cloneTd.rowSpan = 1;
  18683. }
  18684. }
  18685. var defaultValue = getDefaultValue(me),
  18686. width = me.body.offsetWidth -
  18687. (needIEHack ? parseInt(domUtils.getComputedStyle(me.body, 'margin-left'), 10) * 2 : 0) - defaultValue.tableBorder * 2 - (me.options.offsetWidth || 0);
  18688. me.execCommand('insertHTML', '<table ' +
  18689. ( isFullCol && isFullRow ? 'width="' + width + '"' : '') +
  18690. '>' + table.innerHTML.replace(/>\s*</g, '><').replace(/\bth\b/gi, "td") + '</table>')
  18691. }
  18692. me.fireEvent('contentchange');
  18693. me.fireEvent('saveScene');
  18694. html.html = '';
  18695. return true;
  18696. } else {
  18697. var div = me.document.createElement("div"), tables;
  18698. div.innerHTML = html.html;
  18699. tables = div.getElementsByTagName("table");
  18700. if (domUtils.findParentByTagName(me.selection.getStart(), 'table')) {
  18701. utils.each(tables, function (t) {
  18702. domUtils.remove(t)
  18703. });
  18704. if (domUtils.findParentByTagName(me.selection.getStart(), 'caption', true)) {
  18705. div.innerHTML = div[browser.ie ? 'innerText' : 'textContent'];
  18706. }
  18707. } else {
  18708. utils.each(tables, function (table) {
  18709. removeStyleSize(table, true);
  18710. domUtils.removeAttributes(table, ['style', 'border']);
  18711. utils.each(domUtils.getElementsByTagName(table, "td"), function (td) {
  18712. if (isEmptyBlock(td)) {
  18713. domUtils.fillNode(me.document, td);
  18714. }
  18715. removeStyleSize(td, true);
  18716. // domUtils.removeAttributes(td, ['style'])
  18717. });
  18718. });
  18719. }
  18720. html.html = div.innerHTML;
  18721. }
  18722. });
  18723. me.addListener('afterpaste', function () {
  18724. utils.each(domUtils.getElementsByTagName(me.body, "table"), function (table) {
  18725. if (table.offsetWidth > me.body.offsetWidth) {
  18726. var defaultValue = getDefaultValue(me, table);
  18727. 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'
  18728. }
  18729. })
  18730. });
  18731. me.addListener('blur', function () {
  18732. tableCopyList = null;
  18733. });
  18734. var timer;
  18735. me.addListener('keydown', function () {
  18736. clearTimeout(timer);
  18737. timer = setTimeout(function () {
  18738. var rng = me.selection.getRange(),
  18739. cell = domUtils.findParentByTagName(rng.startContainer, ['th', 'td'], true);
  18740. if (cell) {
  18741. var table = cell.parentNode.parentNode.parentNode;
  18742. if (table.offsetWidth > table.getAttribute("width")) {
  18743. cell.style.wordBreak = "break-all";
  18744. }
  18745. }
  18746. }, 100);
  18747. });
  18748. me.addListener("selectionchange", function () {
  18749. toggleDraggableState(me, false, "", null);
  18750. });
  18751. //内容变化时触发索引更新
  18752. //todo 可否考虑标记检测,如果不涉及表格的变化就不进行索引重建和更新
  18753. me.addListener("contentchange", function () {
  18754. var me = this;
  18755. //尽可能排除一些不需要更新的状况
  18756. hideDragLine(me);
  18757. if (getUETableBySelected(me))return;
  18758. var rng = me.selection.getRange();
  18759. var start = rng.startContainer;
  18760. start = domUtils.findParentByTagName(start, ['td', 'th'], true);
  18761. utils.each(domUtils.getElementsByTagName(me.document, 'table'), function (table) {
  18762. if (me.fireEvent("excludetable", table) === true) return;
  18763. table.ueTable = new UT(table);
  18764. //trace:3742
  18765. // utils.each(domUtils.getElementsByTagName(me.document, 'td'), function (td) {
  18766. //
  18767. // if (domUtils.isEmptyBlock(td) && td !== start) {
  18768. // domUtils.fillNode(me.document, td);
  18769. // if (browser.ie && browser.version == 6) {
  18770. // td.innerHTML = '&nbsp;'
  18771. // }
  18772. // }
  18773. // });
  18774. // utils.each(domUtils.getElementsByTagName(me.document, 'th'), function (th) {
  18775. // if (domUtils.isEmptyBlock(th) && th !== start) {
  18776. // domUtils.fillNode(me.document, th);
  18777. // if (browser.ie && browser.version == 6) {
  18778. // th.innerHTML = '&nbsp;'
  18779. // }
  18780. // }
  18781. // });
  18782. table.onmouseover = function () {
  18783. me.fireEvent('tablemouseover', table);
  18784. };
  18785. table.onmousemove = function () {
  18786. me.fireEvent('tablemousemove', table);
  18787. me.options.tableDragable && toggleDragButton(true, this, me);
  18788. utils.defer(function(){
  18789. me.fireEvent('contentchange',50)
  18790. },true)
  18791. };
  18792. table.onmouseout = function () {
  18793. me.fireEvent('tablemouseout', table);
  18794. toggleDraggableState(me, false, "", null);
  18795. hideDragLine(me);
  18796. };
  18797. table.onclick = function (evt) {
  18798. evt = me.window.event || evt;
  18799. var target = getParentTdOrTh(evt.target || evt.srcElement);
  18800. if (!target)return;
  18801. var ut = getUETable(target),
  18802. table = ut.table,
  18803. cellInfo = ut.getCellInfo(target),
  18804. cellsRange,
  18805. rng = me.selection.getRange();
  18806. // if ("topLeft" == inPosition(table, mouseCoords(evt))) {
  18807. // cellsRange = ut.getCellsRange(ut.table.rows[0].cells[0], ut.getLastCell());
  18808. // ut.setSelected(cellsRange);
  18809. // return;
  18810. // }
  18811. // if ("bottomRight" == inPosition(table, mouseCoords(evt))) {
  18812. //
  18813. // return;
  18814. // }
  18815. if (inTableSide(table, target, evt, true)) {
  18816. var endTdCol = ut.getCell(ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].rowIndex, ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].cellIndex);
  18817. if (evt.shiftKey && ut.selectedTds.length) {
  18818. if (ut.selectedTds[0] !== endTdCol) {
  18819. cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdCol);
  18820. ut.setSelected(cellsRange);
  18821. } else {
  18822. rng && rng.selectNodeContents(endTdCol).select();
  18823. }
  18824. } else {
  18825. if (target !== endTdCol) {
  18826. cellsRange = ut.getCellsRange(target, endTdCol);
  18827. ut.setSelected(cellsRange);
  18828. } else {
  18829. rng && rng.selectNodeContents(endTdCol).select();
  18830. }
  18831. }
  18832. return;
  18833. }
  18834. if (inTableSide(table, target, evt)) {
  18835. var endTdRow = ut.getCell(ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].rowIndex, ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].cellIndex);
  18836. if (evt.shiftKey && ut.selectedTds.length) {
  18837. if (ut.selectedTds[0] !== endTdRow) {
  18838. cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdRow);
  18839. ut.setSelected(cellsRange);
  18840. } else {
  18841. rng && rng.selectNodeContents(endTdRow).select();
  18842. }
  18843. } else {
  18844. if (target !== endTdRow) {
  18845. cellsRange = ut.getCellsRange(target, endTdRow);
  18846. ut.setSelected(cellsRange);
  18847. } else {
  18848. rng && rng.selectNodeContents(endTdRow).select();
  18849. }
  18850. }
  18851. }
  18852. };
  18853. });
  18854. switchBorderColor(me, true);
  18855. });
  18856. domUtils.on(me.document, "mousemove", mouseMoveEvent);
  18857. domUtils.on(me.document, "mouseout", function (evt) {
  18858. var target = evt.target || evt.srcElement;
  18859. if (target.tagName == "TABLE") {
  18860. toggleDraggableState(me, false, "", null);
  18861. }
  18862. });
  18863. /**
  18864. * 表格隔行变色
  18865. */
  18866. me.addListener("interlacetable",function(type,table,classList){
  18867. if(!table) return;
  18868. var me = this,
  18869. rows = table.rows,
  18870. len = rows.length,
  18871. getClass = function(list,index,repeat){
  18872. return list[index] ? list[index] : repeat ? list[index % list.length]: "";
  18873. };
  18874. for(var i = 0;i<len;i++){
  18875. rows[i].className = getClass( classList|| me.options.classList,i,true);
  18876. }
  18877. });
  18878. me.addListener("uninterlacetable",function(type,table){
  18879. if(!table) return;
  18880. var me = this,
  18881. rows = table.rows,
  18882. classList = me.options.classList,
  18883. len = rows.length;
  18884. for(var i = 0;i<len;i++){
  18885. domUtils.removeClasses( rows[i], classList );
  18886. }
  18887. });
  18888. me.addListener("mousedown", mouseDownEvent);
  18889. me.addListener("mouseup", mouseUpEvent);
  18890. //拖动的时候触发mouseup
  18891. domUtils.on( me.body, 'dragstart', function( evt ){
  18892. mouseUpEvent.call( me, 'dragstart', evt );
  18893. });
  18894. me.addOutputRule(function(root){
  18895. utils.each(root.getNodesByTagName('div'),function(n){
  18896. if (n.getAttr('id') == 'ue_tableDragLine') {
  18897. n.parentNode.removeChild(n);
  18898. }
  18899. });
  18900. });
  18901. var currentRowIndex = 0;
  18902. me.addListener("mousedown", function () {
  18903. currentRowIndex = 0;
  18904. });
  18905. me.addListener('tabkeydown', function () {
  18906. var range = this.selection.getRange(),
  18907. common = range.getCommonAncestor(true, true),
  18908. table = domUtils.findParentByTagName(common, 'table');
  18909. if (table) {
  18910. if (domUtils.findParentByTagName(common, 'caption', true)) {
  18911. var cell = domUtils.getElementsByTagName(table, 'th td');
  18912. if (cell && cell.length) {
  18913. range.setStart(cell[0], 0).setCursor(false, true)
  18914. }
  18915. } else {
  18916. var cell = domUtils.findParentByTagName(common, ['td', 'th'], true),
  18917. ua = getUETable(cell);
  18918. currentRowIndex = cell.rowSpan > 1 ? currentRowIndex : ua.getCellInfo(cell).rowIndex;
  18919. var nextCell = ua.getTabNextCell(cell, currentRowIndex);
  18920. if (nextCell) {
  18921. if (isEmptyBlock(nextCell)) {
  18922. range.setStart(nextCell, 0).setCursor(false, true)
  18923. } else {
  18924. range.selectNodeContents(nextCell).select()
  18925. }
  18926. } else {
  18927. me.fireEvent('saveScene');
  18928. me.__hasEnterExecCommand = true;
  18929. this.execCommand('insertrownext');
  18930. me.__hasEnterExecCommand = false;
  18931. range = this.selection.getRange();
  18932. range.setStart(table.rows[table.rows.length - 1].cells[0], 0).setCursor();
  18933. me.fireEvent('saveScene');
  18934. }
  18935. }
  18936. return true;
  18937. }
  18938. });
  18939. browser.ie && me.addListener('selectionchange', function () {
  18940. toggleDraggableState(this, false, "", null);
  18941. });
  18942. me.addListener("keydown", function (type, evt) {
  18943. var me = this;
  18944. //处理在表格的最后一个输入tab产生新的表格
  18945. var keyCode = evt.keyCode || evt.which;
  18946. if (keyCode == 8 || keyCode == 46) {
  18947. return;
  18948. }
  18949. var notCtrlKey = !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey;
  18950. notCtrlKey && removeSelectedClass(domUtils.getElementsByTagName(me.body, "td"));
  18951. var ut = getUETableBySelected(me);
  18952. if (!ut) return;
  18953. notCtrlKey && ut.clearSelected();
  18954. });
  18955. me.addListener("beforegetcontent", function () {
  18956. switchBorderColor(this, false);
  18957. browser.ie && utils.each(this.document.getElementsByTagName('caption'), function (ci) {
  18958. if (domUtils.isEmptyNode(ci)) {
  18959. ci.innerHTML = '&nbsp;'
  18960. }
  18961. });
  18962. });
  18963. me.addListener("aftergetcontent", function () {
  18964. switchBorderColor(this, true);
  18965. });
  18966. me.addListener("getAllHtml", function () {
  18967. removeSelectedClass(me.document.getElementsByTagName("td"));
  18968. });
  18969. //修正全屏状态下插入的表格宽度在非全屏状态下撑开编辑器的情况
  18970. me.addListener("fullscreenchanged", function (type, fullscreen) {
  18971. if (!fullscreen) {
  18972. var ratio = this.body.offsetWidth / document.body.offsetWidth,
  18973. tables = domUtils.getElementsByTagName(this.body, "table");
  18974. utils.each(tables, function (table) {
  18975. if (table.offsetWidth < me.body.offsetWidth) return false;
  18976. var tds = domUtils.getElementsByTagName(table, "td"),
  18977. backWidths = [];
  18978. utils.each(tds, function (td) {
  18979. backWidths.push(td.offsetWidth);
  18980. });
  18981. for (var i = 0, td; td = tds[i]; i++) {
  18982. td.setAttribute("width", Math.floor(backWidths[i] * ratio));
  18983. }
  18984. table.setAttribute("width", Math.floor(getTableWidth(me, needIEHack, getDefaultValue(me))))
  18985. });
  18986. }
  18987. });
  18988. //重写execCommand命令,用于处理框选时的处理
  18989. var oldExecCommand = me.execCommand;
  18990. me.execCommand = function (cmd, datatat) {
  18991. var me = this,
  18992. args = arguments;
  18993. cmd = cmd.toLowerCase();
  18994. var ut = getUETableBySelected(me), tds,
  18995. range = new dom.Range(me.document),
  18996. cmdFun = me.commands[cmd] || UE.commands[cmd],
  18997. result;
  18998. if (!cmdFun) return;
  18999. if (ut && !commands[cmd] && !cmdFun.notNeedUndo && !me.__hasEnterExecCommand) {
  19000. me.__hasEnterExecCommand = true;
  19001. me.fireEvent("beforeexeccommand", cmd);
  19002. tds = ut.selectedTds;
  19003. var lastState = -2, lastValue = -2, value, state;
  19004. for (var i = 0, td; td = tds[i]; i++) {
  19005. if (isEmptyBlock(td)) {
  19006. range.setStart(td, 0).setCursor(false, true)
  19007. } else {
  19008. range.selectNode(td).select(true);
  19009. }
  19010. state = me.queryCommandState(cmd);
  19011. value = me.queryCommandValue(cmd);
  19012. if (state != -1) {
  19013. if (lastState !== state || lastValue !== value) {
  19014. me._ignoreContentChange = true;
  19015. result = oldExecCommand.apply(me, arguments);
  19016. me._ignoreContentChange = false;
  19017. }
  19018. lastState = me.queryCommandState(cmd);
  19019. lastValue = me.queryCommandValue(cmd);
  19020. if (domUtils.isEmptyBlock(td)) {
  19021. domUtils.fillNode(me.document, td)
  19022. }
  19023. }
  19024. }
  19025. range.setStart(tds[0], 0).shrinkBoundary(true).setCursor(false, true);
  19026. me.fireEvent('contentchange');
  19027. me.fireEvent("afterexeccommand", cmd);
  19028. me.__hasEnterExecCommand = false;
  19029. me._selectionChange();
  19030. } else {
  19031. result = oldExecCommand.apply(me, arguments);
  19032. }
  19033. return result;
  19034. };
  19035. });
  19036. /**
  19037. * 删除obj的宽高style,改成属性宽高
  19038. * @param obj
  19039. * @param replaceToProperty
  19040. */
  19041. function removeStyleSize(obj, replaceToProperty) {
  19042. removeStyle(obj, "width", true);
  19043. removeStyle(obj, "height", true);
  19044. }
  19045. function removeStyle(obj, styleName, replaceToProperty) {
  19046. if (obj.style[styleName]) {
  19047. replaceToProperty && obj.setAttribute(styleName, parseInt(obj.style[styleName], 10));
  19048. obj.style[styleName] = "";
  19049. }
  19050. }
  19051. function getParentTdOrTh(ele) {
  19052. if (ele.tagName == "TD" || ele.tagName == "TH") return ele;
  19053. var td;
  19054. if (td = domUtils.findParentByTagName(ele, "td", true) || domUtils.findParentByTagName(ele, "th", true)) return td;
  19055. return null;
  19056. }
  19057. function isEmptyBlock(node) {
  19058. var reg = new RegExp(domUtils.fillChar, 'g');
  19059. if (node[browser.ie ? 'innerText' : 'textContent'].replace(/^\s*$/, '').replace(reg, '').length > 0) {
  19060. return 0;
  19061. }
  19062. for (var n in dtd.$isNotEmpty) {
  19063. if (node.getElementsByTagName(n).length) {
  19064. return 0;
  19065. }
  19066. }
  19067. return 1;
  19068. }
  19069. function mouseCoords(evt) {
  19070. if (evt.pageX || evt.pageY) {
  19071. return { x:evt.pageX, y:evt.pageY };
  19072. }
  19073. return {
  19074. x:evt.clientX + me.document.body.scrollLeft - me.document.body.clientLeft,
  19075. y:evt.clientY + me.document.body.scrollTop - me.document.body.clientTop
  19076. };
  19077. }
  19078. function mouseMoveEvent(evt) {
  19079. if( isEditorDisabled() ) {
  19080. return;
  19081. }
  19082. try {
  19083. //普通状态下鼠标移动
  19084. var target = getParentTdOrTh(evt.target || evt.srcElement),
  19085. pos;
  19086. //区分用户的行为是拖动还是双击
  19087. if( isInResizeBuffer ) {
  19088. me.body.style.webkitUserSelect = 'none';
  19089. if( Math.abs( userActionStatus.x - evt.clientX ) > offsetOfTableCell || Math.abs( userActionStatus.y - evt.clientY ) > offsetOfTableCell ) {
  19090. clearTableDragTimer();
  19091. isInResizeBuffer = false;
  19092. singleClickState = 0;
  19093. //drag action
  19094. tableBorderDrag(evt);
  19095. }
  19096. }
  19097. //修改单元格大小时的鼠标移动
  19098. if (onDrag && dragTd) {
  19099. singleClickState = 0;
  19100. me.body.style.webkitUserSelect = 'none';
  19101. me.selection.getNative()[browser.ie9below ? 'empty' : 'removeAllRanges']();
  19102. pos = mouseCoords(evt);
  19103. toggleDraggableState(me, true, onDrag, pos, target);
  19104. if (onDrag == "h") {
  19105. dragLine.style.left = getPermissionX(dragTd, evt) + "px";
  19106. } else if (onDrag == "v") {
  19107. dragLine.style.top = getPermissionY(dragTd, evt) + "px";
  19108. }
  19109. return;
  19110. }
  19111. //当鼠标处于table上时,修改移动过程中的光标状态
  19112. if (target) {
  19113. //针对使用table作为容器的组件不触发拖拽效果
  19114. if (me.fireEvent('excludetable', target) === true)
  19115. return;
  19116. pos = mouseCoords(evt);
  19117. var state = getRelation(target, pos),
  19118. table = domUtils.findParentByTagName(target, "table", true);
  19119. if (inTableSide(table, target, evt, true)) {
  19120. if (me.fireEvent("excludetable", table) === true) return;
  19121. me.body.style.cursor = "url(" + me.options.cursorpath + "h.png),pointer";
  19122. } else if (inTableSide(table, target, evt)) {
  19123. if (me.fireEvent("excludetable", table) === true) return;
  19124. me.body.style.cursor = "url(" + me.options.cursorpath + "v.png),pointer";
  19125. } else {
  19126. me.body.style.cursor = "text";
  19127. var curCell = target;
  19128. if (/\d/.test(state)) {
  19129. state = state.replace(/\d/, '');
  19130. target = getUETable(target).getPreviewCell(target, state == "v");
  19131. }
  19132. //位于第一行的顶部或者第一列的左边时不可拖动
  19133. toggleDraggableState(me, target ? !!state : false, target ? state : '', pos, target);
  19134. }
  19135. } else {
  19136. toggleDragButton(false, table, me);
  19137. }
  19138. } catch (e) {
  19139. showError(e);
  19140. }
  19141. }
  19142. var dragButtonTimer;
  19143. function toggleDragButton(show, table, editor) {
  19144. if (!show) {
  19145. if (dragOver)return;
  19146. dragButtonTimer = setTimeout(function () {
  19147. !dragOver && dragButton && dragButton.parentNode && dragButton.parentNode.removeChild(dragButton);
  19148. }, 2000);
  19149. } else {
  19150. createDragButton(table, editor);
  19151. }
  19152. }
  19153. function createDragButton(table, editor) {
  19154. var pos = domUtils.getXY(table),
  19155. doc = table.ownerDocument;
  19156. if (dragButton && dragButton.parentNode)return dragButton;
  19157. dragButton = doc.createElement("div");
  19158. dragButton.contentEditable = false;
  19159. dragButton.innerHTML = "";
  19160. 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;";
  19161. domUtils.unSelectable(dragButton);
  19162. dragButton.onmouseover = function (evt) {
  19163. dragOver = true;
  19164. };
  19165. dragButton.onmouseout = function (evt) {
  19166. dragOver = false;
  19167. };
  19168. domUtils.on(dragButton, 'click', function (type, evt) {
  19169. doClick(evt, this);
  19170. });
  19171. domUtils.on(dragButton, 'dblclick', function (type, evt) {
  19172. doDblClick(evt);
  19173. });
  19174. domUtils.on(dragButton, 'dragstart', function (type, evt) {
  19175. domUtils.preventDefault(evt);
  19176. });
  19177. var timer;
  19178. function doClick(evt, button) {
  19179. // 部分浏览器下需要清理
  19180. clearTimeout(timer);
  19181. timer = setTimeout(function () {
  19182. editor.fireEvent("tableClicked", table, button);
  19183. }, 300);
  19184. }
  19185. function doDblClick(evt) {
  19186. clearTimeout(timer);
  19187. var ut = getUETable(table),
  19188. start = table.rows[0].cells[0],
  19189. end = ut.getLastCell(),
  19190. range = ut.getCellsRange(start, end);
  19191. editor.selection.getRange().setStart(start, 0).setCursor(false, true);
  19192. ut.setSelected(range);
  19193. }
  19194. doc.body.appendChild(dragButton);
  19195. }
  19196. // function inPosition(table, pos) {
  19197. // var tablePos = domUtils.getXY(table),
  19198. // width = table.offsetWidth,
  19199. // height = table.offsetHeight;
  19200. // if (pos.x - tablePos.x < 5 && pos.y - tablePos.y < 5) {
  19201. // return "topLeft";
  19202. // } else if (tablePos.x + width - pos.x < 5 && tablePos.y + height - pos.y < 5) {
  19203. // return "bottomRight";
  19204. // }
  19205. // }
  19206. function inTableSide(table, cell, evt, top) {
  19207. var pos = mouseCoords(evt),
  19208. state = getRelation(cell, pos);
  19209. if (top) {
  19210. var caption = table.getElementsByTagName("caption")[0],
  19211. capHeight = caption ? caption.offsetHeight : 0;
  19212. return (state == "v1") && ((pos.y - domUtils.getXY(table).y - capHeight) < 8);
  19213. } else {
  19214. return (state == "h1") && ((pos.x - domUtils.getXY(table).x) < 8);
  19215. }
  19216. }
  19217. /**
  19218. * 获取拖动时允许的X轴坐标
  19219. * @param dragTd
  19220. * @param evt
  19221. */
  19222. function getPermissionX(dragTd, evt) {
  19223. var ut = getUETable(dragTd);
  19224. if (ut) {
  19225. var preTd = ut.getSameEndPosCells(dragTd, "x")[0],
  19226. nextTd = ut.getSameStartPosXCells(dragTd)[0],
  19227. mouseX = mouseCoords(evt).x,
  19228. left = (preTd ? domUtils.getXY(preTd).x : domUtils.getXY(ut.table).x) + 20 ,
  19229. right = nextTd ? domUtils.getXY(nextTd).x + nextTd.offsetWidth - 20 : (me.body.offsetWidth + 5 || parseInt(domUtils.getComputedStyle(me.body, "width"), 10));
  19230. left += cellMinWidth;
  19231. right -= cellMinWidth;
  19232. return mouseX < left ? left : mouseX > right ? right : mouseX;
  19233. }
  19234. }
  19235. /**
  19236. * 获取拖动时允许的Y轴坐标
  19237. */
  19238. function getPermissionY(dragTd, evt) {
  19239. try {
  19240. var top = domUtils.getXY(dragTd).y,
  19241. mousePosY = mouseCoords(evt).y;
  19242. return mousePosY < top ? top : mousePosY;
  19243. } catch (e) {
  19244. showError(e);
  19245. }
  19246. }
  19247. /**
  19248. * 移动状态切换
  19249. */
  19250. function toggleDraggableState(editor, draggable, dir, mousePos, cell) {
  19251. try {
  19252. editor.body.style.cursor = dir == "h" ? "col-resize" : dir == "v" ? "row-resize" : "text";
  19253. if (browser.ie) {
  19254. if (dir && !mousedown && !getUETableBySelected(editor)) {
  19255. getDragLine(editor, editor.document);
  19256. showDragLineAt(dir, cell);
  19257. } else {
  19258. hideDragLine(editor)
  19259. }
  19260. }
  19261. onBorder = draggable;
  19262. } catch (e) {
  19263. showError(e);
  19264. }
  19265. }
  19266. /**
  19267. * 获取与UETable相关的resize line
  19268. * @param uetable UETable对象
  19269. */
  19270. function getResizeLineByUETable() {
  19271. var lineId = '_UETableResizeLine',
  19272. line = this.document.getElementById( lineId );
  19273. if( !line ) {
  19274. line = this.document.createElement("div");
  19275. line.id = lineId;
  19276. line.contnetEditable = false;
  19277. line.setAttribute("unselectable", "on");
  19278. var styles = {
  19279. width: 2*cellBorderWidth + 1 + 'px',
  19280. position: 'absolute',
  19281. 'z-index': 100000,
  19282. cursor: 'col-resize',
  19283. background: 'red',
  19284. display: 'none'
  19285. };
  19286. //切换状态
  19287. line.onmouseout = function(){
  19288. this.style.display = 'none';
  19289. };
  19290. utils.extend( line.style, styles );
  19291. this.document.body.appendChild( line );
  19292. }
  19293. return line;
  19294. }
  19295. /**
  19296. * 更新resize-line
  19297. */
  19298. function updateResizeLine( cell, uetable ) {
  19299. var line = getResizeLineByUETable.call( this ),
  19300. table = uetable.table,
  19301. styles = {
  19302. top: domUtils.getXY( table ).y + 'px',
  19303. left: domUtils.getXY( cell).x + cell.offsetWidth - cellBorderWidth + 'px',
  19304. display: 'block',
  19305. height: table.offsetHeight + 'px'
  19306. };
  19307. utils.extend( line.style, styles );
  19308. }
  19309. /**
  19310. * 显示resize-line
  19311. */
  19312. function showResizeLine( cell ) {
  19313. var uetable = getUETable( cell );
  19314. updateResizeLine.call( this, cell, uetable );
  19315. }
  19316. /**
  19317. * 获取鼠标与当前单元格的相对位置
  19318. * @param ele
  19319. * @param mousePos
  19320. */
  19321. function getRelation(ele, mousePos) {
  19322. var elePos = domUtils.getXY(ele);
  19323. if( !elePos ) {
  19324. return '';
  19325. }
  19326. if (elePos.x + ele.offsetWidth - mousePos.x < cellBorderWidth) {
  19327. return "h";
  19328. }
  19329. if (mousePos.x - elePos.x < cellBorderWidth) {
  19330. return 'h1'
  19331. }
  19332. if (elePos.y + ele.offsetHeight - mousePos.y < cellBorderWidth) {
  19333. return "v";
  19334. }
  19335. if (mousePos.y - elePos.y < cellBorderWidth) {
  19336. return 'v1'
  19337. }
  19338. return '';
  19339. }
  19340. function mouseDownEvent(type, evt) {
  19341. if( isEditorDisabled() ) {
  19342. return ;
  19343. }
  19344. userActionStatus = {
  19345. x: evt.clientX,
  19346. y: evt.clientY
  19347. };
  19348. //右键菜单单独处理
  19349. if (evt.button == 2) {
  19350. var ut = getUETableBySelected(me),
  19351. flag = false;
  19352. if (ut) {
  19353. var td = getTargetTd(me, evt);
  19354. utils.each(ut.selectedTds, function (ti) {
  19355. if (ti === td) {
  19356. flag = true;
  19357. }
  19358. });
  19359. if (!flag) {
  19360. removeSelectedClass(domUtils.getElementsByTagName(me.body, "th td"));
  19361. ut.clearSelected()
  19362. } else {
  19363. td = ut.selectedTds[0];
  19364. setTimeout(function () {
  19365. me.selection.getRange().setStart(td, 0).setCursor(false, true);
  19366. }, 0);
  19367. }
  19368. }
  19369. } else {
  19370. tableClickHander( evt );
  19371. }
  19372. }
  19373. //清除表格的计时器
  19374. function clearTableTimer() {
  19375. tabTimer && clearTimeout( tabTimer );
  19376. tabTimer = null;
  19377. }
  19378. //双击收缩
  19379. function tableDbclickHandler(evt) {
  19380. singleClickState = 0;
  19381. evt = evt || me.window.event;
  19382. var target = getParentTdOrTh(evt.target || evt.srcElement);
  19383. if (target) {
  19384. var h;
  19385. if (h = getRelation(target, mouseCoords(evt))) {
  19386. hideDragLine( me );
  19387. if (h == 'h1') {
  19388. h = 'h';
  19389. if (inTableSide(domUtils.findParentByTagName(target, "table"), target, evt)) {
  19390. me.execCommand('adaptbywindow');
  19391. } else {
  19392. target = getUETable(target).getPreviewCell(target);
  19393. if (target) {
  19394. var rng = me.selection.getRange();
  19395. rng.selectNodeContents(target).setCursor(true, true)
  19396. }
  19397. }
  19398. }
  19399. if (h == 'h') {
  19400. var ut = getUETable(target),
  19401. table = ut.table,
  19402. cells = getCellsByMoveBorder( target, table, true );
  19403. cells = extractArray( cells, 'left' );
  19404. ut.width = ut.offsetWidth;
  19405. var oldWidth = [],
  19406. newWidth = [];
  19407. utils.each( cells, function( cell ){
  19408. oldWidth.push( cell.offsetWidth );
  19409. } );
  19410. utils.each( cells, function( cell ){
  19411. cell.removeAttribute("width");
  19412. } );
  19413. window.setTimeout( function(){
  19414. //是否允许改变
  19415. var changeable = true;
  19416. utils.each( cells, function( cell, index ){
  19417. var width = cell.offsetWidth;
  19418. if( width > oldWidth[index] ) {
  19419. changeable = false;
  19420. return false;
  19421. }
  19422. newWidth.push( width );
  19423. } );
  19424. var change = changeable ? newWidth : oldWidth;
  19425. utils.each( cells, function( cell, index ){
  19426. cell.width = change[index] - getTabcellSpace();
  19427. } );
  19428. }, 0 );
  19429. // minWidth -= cellMinWidth;
  19430. //
  19431. // table.removeAttribute("width");
  19432. // utils.each(cells, function (cell) {
  19433. // cell.style.width = "";
  19434. // cell.width -= minWidth;
  19435. // });
  19436. }
  19437. }
  19438. }
  19439. }
  19440. function tableClickHander( evt ) {
  19441. removeSelectedClass(domUtils.getElementsByTagName(me.body, "td th"));
  19442. //trace:3113
  19443. //选中单元格,点击table外部,不会清掉table上挂的ueTable,会引起getUETableBySelected方法返回值
  19444. utils.each(me.document.getElementsByTagName('table'), function (t) {
  19445. t.ueTable = null;
  19446. });
  19447. startTd = getTargetTd(me, evt);
  19448. if( !startTd ) return;
  19449. var table = domUtils.findParentByTagName(startTd, "table", true);
  19450. ut = getUETable(table);
  19451. ut && ut.clearSelected();
  19452. //判断当前鼠标状态
  19453. if (!onBorder) {
  19454. me.document.body.style.webkitUserSelect = '';
  19455. mousedown = true;
  19456. me.addListener('mouseover', mouseOverEvent);
  19457. } else {
  19458. //边框上的动作处理
  19459. borderActionHandler( evt );
  19460. }
  19461. }
  19462. //处理表格边框上的动作, 这里做延时处理,避免两种动作互相影响
  19463. function borderActionHandler( evt ) {
  19464. if ( browser.ie ) {
  19465. evt = reconstruct(evt );
  19466. }
  19467. clearTableDragTimer();
  19468. //是否正在等待resize的缓冲中
  19469. isInResizeBuffer = true;
  19470. tableDragTimer = setTimeout(function(){
  19471. tableBorderDrag( evt );
  19472. }, dblclickTime);
  19473. }
  19474. function extractArray( originArr, key ) {
  19475. var result = [],
  19476. tmp = null;
  19477. for( var i = 0, len = originArr.length; i<len; i++ ) {
  19478. tmp = originArr[ i ][ key ];
  19479. if( tmp ) {
  19480. result.push( tmp );
  19481. }
  19482. }
  19483. return result;
  19484. }
  19485. function clearTableDragTimer() {
  19486. tableDragTimer && clearTimeout(tableDragTimer);
  19487. tableDragTimer = null;
  19488. }
  19489. function reconstruct( obj ) {
  19490. var attrs = ['pageX', 'pageY', 'clientX', 'clientY', 'srcElement', 'target'],
  19491. newObj = {};
  19492. if( obj ) {
  19493. for( var i = 0, key, val; key = attrs[i]; i++ ) {
  19494. val=obj[ key ];
  19495. val && (newObj[ key ] = val);
  19496. }
  19497. }
  19498. return newObj;
  19499. }
  19500. //边框拖动
  19501. function tableBorderDrag( evt ) {
  19502. isInResizeBuffer = false;
  19503. startTd = evt.target || evt.srcElement;
  19504. if( !startTd ) return;
  19505. var state = getRelation(startTd, mouseCoords(evt));
  19506. if (/\d/.test(state)) {
  19507. state = state.replace(/\d/, '');
  19508. startTd = getUETable(startTd).getPreviewCell(startTd, state == 'v');
  19509. }
  19510. hideDragLine(me);
  19511. getDragLine(me, me.document);
  19512. me.fireEvent('saveScene');
  19513. showDragLineAt(state, startTd);
  19514. mousedown = true;
  19515. //拖动开始
  19516. onDrag = state;
  19517. dragTd = startTd;
  19518. }
  19519. function mouseUpEvent(type, evt) {
  19520. if( isEditorDisabled() ) {
  19521. return ;
  19522. }
  19523. clearTableDragTimer();
  19524. isInResizeBuffer = false;
  19525. if( onBorder ) {
  19526. singleClickState = ++singleClickState % 3;
  19527. userActionStatus = {
  19528. x: evt.clientX,
  19529. y: evt.clientY
  19530. };
  19531. tableResizeTimer = setTimeout(function(){
  19532. singleClickState > 0 && singleClickState--;
  19533. }, dblclickTime );
  19534. if( singleClickState === 2 ) {
  19535. singleClickState = 0;
  19536. tableDbclickHandler(evt);
  19537. return;
  19538. }
  19539. }
  19540. if (evt.button == 2)return;
  19541. var me = this;
  19542. //清除表格上原生跨选问题
  19543. var range = me.selection.getRange(),
  19544. start = domUtils.findParentByTagName(range.startContainer, 'table', true),
  19545. end = domUtils.findParentByTagName(range.endContainer, 'table', true);
  19546. if (start || end) {
  19547. if (start === end) {
  19548. start = domUtils.findParentByTagName(range.startContainer, ['td', 'th', 'caption'], true);
  19549. end = domUtils.findParentByTagName(range.endContainer, ['td', 'th', 'caption'], true);
  19550. if (start !== end) {
  19551. me.selection.clearRange()
  19552. }
  19553. } else {
  19554. me.selection.clearRange()
  19555. }
  19556. }
  19557. mousedown = false;
  19558. me.document.body.style.webkitUserSelect = '';
  19559. //拖拽状态下的mouseUP
  19560. if ( onDrag && dragTd ) {
  19561. me.selection.getNative()[browser.ie9below ? 'empty' : 'removeAllRanges']();
  19562. singleClickState = 0;
  19563. dragLine = me.document.getElementById('ue_tableDragLine');
  19564. // trace 3973
  19565. if (dragLine) {
  19566. var dragTdPos = domUtils.getXY(dragTd),
  19567. dragLinePos = domUtils.getXY(dragLine);
  19568. switch (onDrag) {
  19569. case "h":
  19570. changeColWidth(dragTd, dragLinePos.x - dragTdPos.x);
  19571. break;
  19572. case "v":
  19573. changeRowHeight(dragTd, dragLinePos.y - dragTdPos.y - dragTd.offsetHeight);
  19574. break;
  19575. default:
  19576. }
  19577. onDrag = "";
  19578. dragTd = null;
  19579. hideDragLine(me);
  19580. me.fireEvent('saveScene');
  19581. return;
  19582. }
  19583. }
  19584. //正常状态下的mouseup
  19585. if (!startTd) {
  19586. var target = domUtils.findParentByTagName(evt.target || evt.srcElement, "td", true);
  19587. if (!target) target = domUtils.findParentByTagName(evt.target || evt.srcElement, "th", true);
  19588. if (target && (target.tagName == "TD" || target.tagName == "TH")) {
  19589. if (me.fireEvent("excludetable", target) === true) return;
  19590. range = new dom.Range(me.document);
  19591. range.setStart(target, 0).setCursor(false, true);
  19592. }
  19593. } else {
  19594. var ut = getUETable(startTd),
  19595. cell = ut ? ut.selectedTds[0] : null;
  19596. if (cell) {
  19597. range = new dom.Range(me.document);
  19598. if (domUtils.isEmptyBlock(cell)) {
  19599. range.setStart(cell, 0).setCursor(false, true);
  19600. } else {
  19601. range.selectNodeContents(cell).shrinkBoundary().setCursor(false, true);
  19602. }
  19603. } else {
  19604. range = me.selection.getRange().shrinkBoundary();
  19605. if (!range.collapsed) {
  19606. var start = domUtils.findParentByTagName(range.startContainer, ['td', 'th'], true),
  19607. end = domUtils.findParentByTagName(range.endContainer, ['td', 'th'], true);
  19608. //在table里边的不能清除
  19609. if (start && !end || !start && end || start && end && start !== end) {
  19610. range.setCursor(false, true);
  19611. }
  19612. }
  19613. }
  19614. startTd = null;
  19615. me.removeListener('mouseover', mouseOverEvent);
  19616. }
  19617. me._selectionChange(250, evt);
  19618. }
  19619. function mouseOverEvent(type, evt) {
  19620. if( isEditorDisabled() ) {
  19621. return;
  19622. }
  19623. var me = this,
  19624. tar = evt.target || evt.srcElement;
  19625. currentTd = domUtils.findParentByTagName(tar, "td", true) || domUtils.findParentByTagName(tar, "th", true);
  19626. //需要判断两个TD是否位于同一个表格内
  19627. if (startTd && currentTd &&
  19628. ((startTd.tagName == "TD" && currentTd.tagName == "TD") || (startTd.tagName == "TH" && currentTd.tagName == "TH")) &&
  19629. domUtils.findParentByTagName(startTd, 'table') == domUtils.findParentByTagName(currentTd, 'table')) {
  19630. var ut = getUETable(currentTd);
  19631. if (startTd != currentTd) {
  19632. me.document.body.style.webkitUserSelect = 'none';
  19633. me.selection.getNative()[browser.ie9below ? 'empty' : 'removeAllRanges']();
  19634. var range = ut.getCellsRange(startTd, currentTd);
  19635. ut.setSelected(range);
  19636. } else {
  19637. me.document.body.style.webkitUserSelect = '';
  19638. ut.clearSelected();
  19639. }
  19640. }
  19641. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
  19642. }
  19643. function setCellHeight(cell, height, backHeight) {
  19644. var lineHight = parseInt(domUtils.getComputedStyle(cell, "line-height"), 10),
  19645. tmpHeight = backHeight + height;
  19646. height = tmpHeight < lineHight ? lineHight : tmpHeight;
  19647. if (cell.style.height) cell.style.height = "";
  19648. cell.rowSpan == 1 ? cell.setAttribute("height", height) : (cell.removeAttribute && cell.removeAttribute("height"));
  19649. }
  19650. function getWidth(cell) {
  19651. if (!cell)return 0;
  19652. return parseInt(domUtils.getComputedStyle(cell, "width"), 10);
  19653. }
  19654. function changeColWidth(cell, changeValue) {
  19655. var ut = getUETable(cell);
  19656. if (ut) {
  19657. //根据当前移动的边框获取相关的单元格
  19658. var table = ut.table,
  19659. cells = getCellsByMoveBorder( cell, table );
  19660. table.style.width = "";
  19661. table.removeAttribute("width");
  19662. //修正改变量
  19663. changeValue = correctChangeValue( changeValue, cell, cells );
  19664. if (cell.nextSibling) {
  19665. var i=0;
  19666. utils.each( cells, function( cellGroup ){
  19667. cellGroup.left.width = (+cellGroup.left.width)+changeValue;
  19668. cellGroup.right && ( cellGroup.right.width = (+cellGroup.right.width)-changeValue );
  19669. } );
  19670. } else {
  19671. utils.each( cells, function( cellGroup ){
  19672. cellGroup.left.width -= -changeValue;
  19673. } );
  19674. }
  19675. }
  19676. }
  19677. function isEditorDisabled() {
  19678. return me.body.contentEditable === "false";
  19679. }
  19680. function changeRowHeight(td, changeValue) {
  19681. if (Math.abs(changeValue) < 10) return;
  19682. var ut = getUETable(td);
  19683. if (ut) {
  19684. var cells = ut.getSameEndPosCells(td, "y"),
  19685. //备份需要连带变化的td的原始高度,否则后期无法获取正确的值
  19686. backHeight = cells[0] ? cells[0].offsetHeight : 0;
  19687. for (var i = 0, cell; cell = cells[i++];) {
  19688. setCellHeight(cell, changeValue, backHeight);
  19689. }
  19690. }
  19691. }
  19692. /**
  19693. * 获取调整单元格大小的相关单元格
  19694. * @isContainMergeCell 返回的结果中是否包含发生合并后的单元格
  19695. */
  19696. function getCellsByMoveBorder( cell, table, isContainMergeCell ) {
  19697. if( !table ) {
  19698. table = domUtils.findParentByTagName( cell, 'table' );
  19699. }
  19700. if( !table ) {
  19701. return null;
  19702. }
  19703. //获取到该单元格所在行的序列号
  19704. var index = domUtils.getNodeIndex( cell ),
  19705. temp = cell,
  19706. rows = table.rows,
  19707. colIndex = 0;
  19708. while( temp ) {
  19709. //获取到当前单元格在未发生单元格合并时的序列
  19710. if( temp.nodeType === 1 ) {
  19711. colIndex += (temp.colSpan || 1);
  19712. }
  19713. temp = temp.previousSibling;
  19714. }
  19715. temp = null;
  19716. //记录想关的单元格
  19717. var borderCells = [];
  19718. utils.each(rows, function( tabRow ){
  19719. var cells = tabRow.cells,
  19720. currIndex = 0;
  19721. utils.each( cells, function( tabCell ){
  19722. currIndex += (tabCell.colSpan || 1);
  19723. if( currIndex === colIndex ) {
  19724. borderCells.push({
  19725. left: tabCell,
  19726. right: tabCell.nextSibling || null
  19727. });
  19728. return false;
  19729. } else if( currIndex > colIndex ) {
  19730. if( isContainMergeCell ) {
  19731. borderCells.push({
  19732. left: tabCell
  19733. });
  19734. }
  19735. return false;
  19736. }
  19737. } );
  19738. });
  19739. return borderCells;
  19740. }
  19741. /**
  19742. * 通过给定的单元格集合获取最小的单元格width
  19743. */
  19744. function getMinWidthByTableCells( cells ) {
  19745. var minWidth = Number.MAX_VALUE;
  19746. for( var i = 0, curCell; curCell = cells[ i ] ; i++ ) {
  19747. minWidth = Math.min( minWidth, curCell.width || getTableCellWidth( curCell ) );
  19748. }
  19749. return minWidth;
  19750. }
  19751. function correctChangeValue( changeValue, relatedCell, cells ) {
  19752. //为单元格的paading预留空间
  19753. changeValue -= getTabcellSpace();
  19754. if( changeValue < 0 ) {
  19755. return 0;
  19756. }
  19757. changeValue -= getTableCellWidth( relatedCell );
  19758. //确定方向
  19759. var direction = changeValue < 0 ? 'left':'right';
  19760. changeValue = Math.abs(changeValue);
  19761. //只关心非最后一个单元格就可以
  19762. utils.each( cells, function( cellGroup ){
  19763. var curCell = cellGroup[direction];
  19764. //为单元格保留最小空间
  19765. if( curCell ) {
  19766. changeValue = Math.min( changeValue, getTableCellWidth( curCell )-cellMinWidth );
  19767. }
  19768. } );
  19769. //修正越界
  19770. changeValue = changeValue < 0 ? 0 : changeValue;
  19771. return direction === 'left' ? -changeValue : changeValue;
  19772. }
  19773. function getTableCellWidth( cell ) {
  19774. var width = 0,
  19775. //偏移纠正量
  19776. offset = 0,
  19777. width = cell.offsetWidth - getTabcellSpace();
  19778. //最后一个节点纠正一下
  19779. if( !cell.nextSibling ) {
  19780. width -= getTableCellOffset( cell );
  19781. }
  19782. width = width < 0 ? 0 : width;
  19783. try {
  19784. cell.width = width;
  19785. } catch(e) {
  19786. }
  19787. return width;
  19788. }
  19789. /**
  19790. * 获取单元格所在表格的最末单元格的偏移量
  19791. */
  19792. function getTableCellOffset( cell ) {
  19793. tab = domUtils.findParentByTagName( cell, "table", false);
  19794. if( tab.offsetVal === undefined ) {
  19795. var prev = cell.previousSibling;
  19796. if( prev ) {
  19797. //最后一个单元格和前一个单元格的width diff结果 如果恰好为一个border width, 则条件成立
  19798. tab.offsetVal = cell.offsetWidth - prev.offsetWidth === UT.borderWidth ? UT.borderWidth : 0;
  19799. } else {
  19800. tab.offsetVal = 0;
  19801. }
  19802. }
  19803. return tab.offsetVal;
  19804. }
  19805. function getTabcellSpace() {
  19806. if( UT.tabcellSpace === undefined ) {
  19807. var cell = null,
  19808. tab = me.document.createElement("table"),
  19809. tbody = me.document.createElement("tbody"),
  19810. trow = me.document.createElement("tr"),
  19811. tabcell = me.document.createElement("td"),
  19812. mirror = null;
  19813. tabcell.style.cssText = 'border: 0;';
  19814. tabcell.width = 1;
  19815. trow.appendChild( tabcell );
  19816. trow.appendChild( mirror = tabcell.cloneNode( false ) );
  19817. tbody.appendChild( trow );
  19818. tab.appendChild( tbody );
  19819. tab.style.cssText = "visibility: hidden;";
  19820. me.body.appendChild( tab );
  19821. UT.paddingSpace = tabcell.offsetWidth - 1;
  19822. var tmpTabWidth = tab.offsetWidth;
  19823. tabcell.style.cssText = '';
  19824. mirror.style.cssText = '';
  19825. UT.borderWidth = ( tab.offsetWidth - tmpTabWidth ) / 3;
  19826. UT.tabcellSpace = UT.paddingSpace + UT.borderWidth;
  19827. me.body.removeChild( tab );
  19828. }
  19829. getTabcellSpace = function(){ return UT.tabcellSpace; };
  19830. return UT.tabcellSpace;
  19831. }
  19832. function getDragLine(editor, doc) {
  19833. if (mousedown)return;
  19834. dragLine = editor.document.createElement("div");
  19835. domUtils.setAttributes(dragLine, {
  19836. id:"ue_tableDragLine",
  19837. unselectable:'on',
  19838. contenteditable:false,
  19839. 'onresizestart':'return false',
  19840. 'ondragstart':'return false',
  19841. 'onselectstart':'return false',
  19842. style:"background-color:blue;position:absolute;padding:0;margin:0;background-image:none;border:0px none;opacity:0;filter:alpha(opacity=0)"
  19843. });
  19844. editor.body.appendChild(dragLine);
  19845. }
  19846. function hideDragLine(editor) {
  19847. if (mousedown)return;
  19848. var line;
  19849. while (line = editor.document.getElementById('ue_tableDragLine')) {
  19850. domUtils.remove(line)
  19851. }
  19852. }
  19853. /**
  19854. * 依据state(v|h)在cell位置显示横线
  19855. * @param state
  19856. * @param cell
  19857. */
  19858. function showDragLineAt(state, cell) {
  19859. if (!cell) return;
  19860. var table = domUtils.findParentByTagName(cell, "table"),
  19861. caption = table.getElementsByTagName('caption'),
  19862. width = table.offsetWidth,
  19863. height = table.offsetHeight - (caption.length > 0 ? caption[0].offsetHeight : 0),
  19864. tablePos = domUtils.getXY(table),
  19865. cellPos = domUtils.getXY(cell), css;
  19866. switch (state) {
  19867. case "h":
  19868. css = 'height:' + height + 'px;top:' + (tablePos.y + (caption.length > 0 ? caption[0].offsetHeight : 0)) + 'px;left:' + (cellPos.x + cell.offsetWidth);
  19869. dragLine.style.cssText = css + 'px;position: absolute;display:block;background-color:blue;width:1px;border:0; color:blue;opacity:.3;filter:alpha(opacity=30)';
  19870. break;
  19871. case "v":
  19872. css = 'width:' + width + 'px;left:' + tablePos.x + 'px;top:' + (cellPos.y + cell.offsetHeight );
  19873. //必须加上border:0和color:blue,否则低版ie不支持背景色显示
  19874. 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)';
  19875. break;
  19876. default:
  19877. }
  19878. }
  19879. /**
  19880. * 当表格边框颜色为白色时设置为虚线,true为添加虚线
  19881. * @param editor
  19882. * @param flag
  19883. */
  19884. function switchBorderColor(editor, flag) {
  19885. var tableArr = domUtils.getElementsByTagName(editor.body, "table"), color;
  19886. for (var i = 0, node; node = tableArr[i++];) {
  19887. var td = domUtils.getElementsByTagName(node, "td");
  19888. if (td[0]) {
  19889. if (flag) {
  19890. color = (td[0].style.borderColor).replace(/\s/g, "");
  19891. if (/(#ffffff)|(rgb\(255,255,255\))/ig.test(color))
  19892. domUtils.addClass(node, "noBorderTable")
  19893. } else {
  19894. domUtils.removeClasses(node, "noBorderTable")
  19895. }
  19896. }
  19897. }
  19898. }
  19899. function getTableWidth(editor, needIEHack, defaultValue) {
  19900. var body = editor.body;
  19901. return body.offsetWidth - (needIEHack ? parseInt(domUtils.getComputedStyle(body, 'margin-left'), 10) * 2 : 0) - defaultValue.tableBorder * 2 - (editor.options.offsetWidth || 0);
  19902. }
  19903. /**
  19904. * 获取当前拖动的单元格
  19905. */
  19906. function getTargetTd(editor, evt) {
  19907. var target = domUtils.findParentByTagName(evt.target || evt.srcElement, ["td", "th"], true),
  19908. dir = null;
  19909. if( !target ) {
  19910. return null;
  19911. }
  19912. dir = getRelation( target, mouseCoords( evt ) );
  19913. //如果有前一个节点, 需要做一个修正, 否则可能会得到一个错误的td
  19914. if( !target ) {
  19915. return null;
  19916. }
  19917. if( dir === 'h1' && target.previousSibling ) {
  19918. var position = domUtils.getXY( target),
  19919. cellWidth = target.offsetWidth;
  19920. if( Math.abs( position.x + cellWidth - evt.clientX ) > cellWidth / 3 ) {
  19921. target = target.previousSibling;
  19922. }
  19923. } else if( dir === 'v1' && target.parentNode.previousSibling ) {
  19924. var position = domUtils.getXY( target),
  19925. cellHeight = target.offsetHeight;
  19926. if( Math.abs( position.y + cellHeight - evt.clientY ) > cellHeight / 3 ) {
  19927. target = target.parentNode.previousSibling.firstChild;
  19928. }
  19929. }
  19930. //排除了非td内部以及用于代码高亮部分的td
  19931. return target && !(editor.fireEvent("excludetable", target) === true) ? target : null;
  19932. }
  19933. };
  19934. // plugins/table.sort.js
  19935. /**
  19936. * Created with JetBrains PhpStorm.
  19937. * User: Jinqn
  19938. * Date: 13-10-12
  19939. * Time: 上午10:20
  19940. * To change this template use File | Settings | File Templates.
  19941. */
  19942. UE.UETable.prototype.sortTable = function (sortByCellIndex, compareFn) {
  19943. var table = this.table,
  19944. rows = table.rows,
  19945. trArray = [],
  19946. flag = rows[0].cells[0].tagName === "TH",
  19947. lastRowIndex = 0;
  19948. if(this.selectedTds.length){
  19949. var range = this.cellsRange,
  19950. len = range.endRowIndex + 1;
  19951. for (var i = range.beginRowIndex; i < len; i++) {
  19952. trArray[i] = rows[i];
  19953. }
  19954. trArray.splice(0,range.beginRowIndex);
  19955. lastRowIndex = (range.endRowIndex +1) === this.rowsNum ? 0 : range.endRowIndex +1;
  19956. }else{
  19957. for (var i = 0,len = rows.length; i < len; i++) {
  19958. trArray[i] = rows[i];
  19959. }
  19960. }
  19961. var Fn = {
  19962. 'reversecurrent': function(td1,td2){
  19963. return 1;
  19964. },
  19965. 'orderbyasc': function(td1,td2){
  19966. var value1 = td1.innerText||td1.textContent,
  19967. value2 = td2.innerText||td2.textContent;
  19968. return value1.localeCompare(value2);
  19969. },
  19970. 'reversebyasc': function(td1,td2){
  19971. var value1 = td1.innerHTML,
  19972. value2 = td2.innerHTML;
  19973. return value2.localeCompare(value1);
  19974. },
  19975. 'orderbynum': function(td1,td2){
  19976. var value1 = td1[browser.ie ? 'innerText':'textContent'].match(/\d+/),
  19977. value2 = td2[browser.ie ? 'innerText':'textContent'].match(/\d+/);
  19978. if(value1) value1 = +value1[0];
  19979. if(value2) value2 = +value2[0];
  19980. return (value1||0) - (value2||0);
  19981. },
  19982. 'reversebynum': function(td1,td2){
  19983. var value1 = td1[browser.ie ? 'innerText':'textContent'].match(/\d+/),
  19984. value2 = td2[browser.ie ? 'innerText':'textContent'].match(/\d+/);
  19985. if(value1) value1 = +value1[0];
  19986. if(value2) value2 = +value2[0];
  19987. return (value2||0) - (value1||0);
  19988. }
  19989. };
  19990. //对表格设置排序的标记data-sort-type
  19991. table.setAttribute('data-sort-type', compareFn && typeof compareFn === "string" && Fn[compareFn] ? compareFn:'');
  19992. //th不参与排序
  19993. flag && trArray.splice(0, 1);
  19994. trArray = utils.sort(trArray,function (tr1, tr2) {
  19995. var result;
  19996. if (compareFn && typeof compareFn === "function") {
  19997. result = compareFn.call(this, tr1.cells[sortByCellIndex], tr2.cells[sortByCellIndex]);
  19998. } else if (compareFn && typeof compareFn === "number") {
  19999. result = 1;
  20000. } else if (compareFn && typeof compareFn === "string" && Fn[compareFn]) {
  20001. result = Fn[compareFn].call(this, tr1.cells[sortByCellIndex], tr2.cells[sortByCellIndex]);
  20002. } else {
  20003. result = Fn['orderbyasc'].call(this, tr1.cells[sortByCellIndex], tr2.cells[sortByCellIndex]);
  20004. }
  20005. return result;
  20006. });
  20007. var fragment = table.ownerDocument.createDocumentFragment();
  20008. for (var j = 0, len = trArray.length; j < len; j++) {
  20009. fragment.appendChild(trArray[j]);
  20010. }
  20011. var tbody = table.getElementsByTagName("tbody")[0];
  20012. if(!lastRowIndex){
  20013. tbody.appendChild(fragment);
  20014. }else{
  20015. tbody.insertBefore(fragment,rows[lastRowIndex- range.endRowIndex + range.beginRowIndex - 1])
  20016. }
  20017. };
  20018. UE.plugins['tablesort'] = function () {
  20019. var me = this,
  20020. UT = UE.UETable,
  20021. getUETable = function (tdOrTable) {
  20022. return UT.getUETable(tdOrTable);
  20023. },
  20024. getTableItemsByRange = function (editor) {
  20025. return UT.getTableItemsByRange(editor);
  20026. };
  20027. me.ready(function () {
  20028. //添加表格可排序的样式
  20029. utils.cssRule('tablesort',
  20030. 'table.sortEnabled tr.firstRow th,table.sortEnabled tr.firstRow td{padding-right:20px;background-repeat: no-repeat;background-position: center right;' +
  20031. ' background-image:url(' + me.options.themePath + me.options.theme + '/images/sortable.png);}',
  20032. me.document);
  20033. //做单元格合并操作时,清除可排序标识
  20034. me.addListener("afterexeccommand", function (type, cmd) {
  20035. if( cmd == 'mergeright' || cmd == 'mergedown' || cmd == 'mergecells') {
  20036. this.execCommand('disablesort');
  20037. }
  20038. });
  20039. });
  20040. //表格排序
  20041. UE.commands['sorttable'] = {
  20042. queryCommandState: function () {
  20043. var me = this,
  20044. tableItems = getTableItemsByRange(me);
  20045. if (!tableItems.cell) return -1;
  20046. var table = tableItems.table,
  20047. cells = table.getElementsByTagName("td");
  20048. for (var i = 0, cell; cell = cells[i++];) {
  20049. if (cell.rowSpan != 1 || cell.colSpan != 1) return -1;
  20050. }
  20051. return 0;
  20052. },
  20053. execCommand: function (cmd, fn) {
  20054. var me = this,
  20055. range = me.selection.getRange(),
  20056. bk = range.createBookmark(true),
  20057. tableItems = getTableItemsByRange(me),
  20058. cell = tableItems.cell,
  20059. ut = getUETable(tableItems.table),
  20060. cellInfo = ut.getCellInfo(cell);
  20061. ut.sortTable(cellInfo.cellIndex, fn);
  20062. range.moveToBookmark(bk);
  20063. try{
  20064. range.select();
  20065. }catch(e){}
  20066. }
  20067. };
  20068. //设置表格可排序,清除表格可排序
  20069. UE.commands["enablesort"] = UE.commands["disablesort"] = {
  20070. queryCommandState: function (cmd) {
  20071. var table = getTableItemsByRange(this).table;
  20072. if(table && cmd=='enablesort') {
  20073. var cells = domUtils.getElementsByTagName(table, 'th td');
  20074. for(var i = 0; i<cells.length; i++) {
  20075. if(cells[i].getAttribute('colspan')>1 || cells[i].getAttribute('rowspan')>1) return -1;
  20076. }
  20077. }
  20078. return !table ? -1: cmd=='enablesort' ^ table.getAttribute('data-sort')!='sortEnabled' ? -1:0;
  20079. },
  20080. execCommand: function (cmd) {
  20081. var table = getTableItemsByRange(this).table;
  20082. table.setAttribute("data-sort", cmd == "enablesort" ? "sortEnabled" : "sortDisabled");
  20083. cmd == "enablesort" ? domUtils.addClass(table,"sortEnabled"):domUtils.removeClasses(table,"sortEnabled");
  20084. }
  20085. };
  20086. };
  20087. // plugins/contextmenu.js
  20088. ///import core
  20089. ///commands 右键菜单
  20090. ///commandsName ContextMenu
  20091. ///commandsTitle 右键菜单
  20092. /**
  20093. * 右键菜单
  20094. * @function
  20095. * @name baidu.editor.plugins.contextmenu
  20096. * @author zhanyi
  20097. */
  20098. UE.plugins['contextmenu'] = function () {
  20099. var me = this;
  20100. me.setOpt('enableContextMenu',true);
  20101. if(me.getOpt('enableContextMenu') === false){
  20102. return;
  20103. }
  20104. var lang = me.getLang( "contextMenu" ),
  20105. menu,
  20106. items = me.options.contextMenu || [
  20107. {label:lang['selectall'], cmdName:'selectall'},
  20108. {
  20109. label:lang.cleardoc,
  20110. cmdName:'cleardoc',
  20111. exec:function () {
  20112. if ( confirm( lang.confirmclear ) ) {
  20113. this.execCommand( 'cleardoc' );
  20114. }
  20115. }
  20116. },
  20117. '-',
  20118. {
  20119. label:lang.unlink,
  20120. cmdName:'unlink'
  20121. },
  20122. '-',
  20123. {
  20124. group:lang.paragraph,
  20125. icon:'justifyjustify',
  20126. subMenu:[
  20127. {
  20128. label:lang.justifyleft,
  20129. cmdName:'justify',
  20130. value:'left'
  20131. },
  20132. {
  20133. label:lang.justifyright,
  20134. cmdName:'justify',
  20135. value:'right'
  20136. },
  20137. {
  20138. label:lang.justifycenter,
  20139. cmdName:'justify',
  20140. value:'center'
  20141. },
  20142. {
  20143. label:lang.justifyjustify,
  20144. cmdName:'justify',
  20145. value:'justify'
  20146. }
  20147. ]
  20148. },
  20149. '-',
  20150. {
  20151. group:lang.table,
  20152. icon:'table',
  20153. subMenu:[
  20154. {
  20155. label:lang.inserttable,
  20156. cmdName:'inserttable'
  20157. },
  20158. {
  20159. label:lang.deletetable,
  20160. cmdName:'deletetable'
  20161. },
  20162. '-',
  20163. {
  20164. label:lang.deleterow,
  20165. cmdName:'deleterow'
  20166. },
  20167. {
  20168. label:lang.deletecol,
  20169. cmdName:'deletecol'
  20170. },
  20171. {
  20172. label:lang.insertcol,
  20173. cmdName:'insertcol'
  20174. },
  20175. {
  20176. label:lang.insertcolnext,
  20177. cmdName:'insertcolnext'
  20178. },
  20179. {
  20180. label:lang.insertrow,
  20181. cmdName:'insertrow'
  20182. },
  20183. {
  20184. label:lang.insertrownext,
  20185. cmdName:'insertrownext'
  20186. },
  20187. '-',
  20188. {
  20189. label:lang.insertcaption,
  20190. cmdName:'insertcaption'
  20191. },
  20192. {
  20193. label:lang.deletecaption,
  20194. cmdName:'deletecaption'
  20195. },
  20196. {
  20197. label:lang.inserttitle,
  20198. cmdName:'inserttitle'
  20199. },
  20200. {
  20201. label:lang.deletetitle,
  20202. cmdName:'deletetitle'
  20203. },
  20204. {
  20205. label:lang.inserttitlecol,
  20206. cmdName:'inserttitlecol'
  20207. },
  20208. {
  20209. label:lang.deletetitlecol,
  20210. cmdName:'deletetitlecol'
  20211. },
  20212. '-',
  20213. {
  20214. label:lang.mergecells,
  20215. cmdName:'mergecells'
  20216. },
  20217. {
  20218. label:lang.mergeright,
  20219. cmdName:'mergeright'
  20220. },
  20221. {
  20222. label:lang.mergedown,
  20223. cmdName:'mergedown'
  20224. },
  20225. '-',
  20226. {
  20227. label:lang.splittorows,
  20228. cmdName:'splittorows'
  20229. },
  20230. {
  20231. label:lang.splittocols,
  20232. cmdName:'splittocols'
  20233. },
  20234. {
  20235. label:lang.splittocells,
  20236. cmdName:'splittocells'
  20237. },
  20238. '-',
  20239. {
  20240. label:lang.averageDiseRow,
  20241. cmdName:'averagedistributerow'
  20242. },
  20243. {
  20244. label:lang.averageDisCol,
  20245. cmdName:'averagedistributecol'
  20246. },
  20247. '-',
  20248. {
  20249. label:lang.edittd,
  20250. cmdName:'edittd',
  20251. exec:function () {
  20252. if ( UE.ui['edittd'] ) {
  20253. new UE.ui['edittd']( this );
  20254. }
  20255. this.getDialog('edittd').open();
  20256. }
  20257. },
  20258. {
  20259. label:lang.edittable,
  20260. cmdName:'edittable',
  20261. exec:function () {
  20262. if ( UE.ui['edittable'] ) {
  20263. new UE.ui['edittable']( this );
  20264. }
  20265. this.getDialog('edittable').open();
  20266. }
  20267. },
  20268. {
  20269. label:lang.setbordervisible,
  20270. cmdName:'setbordervisible'
  20271. }
  20272. ]
  20273. },
  20274. {
  20275. group:lang.tablesort,
  20276. icon:'tablesort',
  20277. subMenu:[
  20278. {
  20279. label:lang.enablesort,
  20280. cmdName:'enablesort'
  20281. },
  20282. {
  20283. label:lang.disablesort,
  20284. cmdName:'disablesort'
  20285. },
  20286. '-',
  20287. {
  20288. label:lang.reversecurrent,
  20289. cmdName:'sorttable',
  20290. value:'reversecurrent'
  20291. },
  20292. {
  20293. label:lang.orderbyasc,
  20294. cmdName:'sorttable',
  20295. value:'orderbyasc'
  20296. },
  20297. {
  20298. label:lang.reversebyasc,
  20299. cmdName:'sorttable',
  20300. value:'reversebyasc'
  20301. },
  20302. {
  20303. label:lang.orderbynum,
  20304. cmdName:'sorttable',
  20305. value:'orderbynum'
  20306. },
  20307. {
  20308. label:lang.reversebynum,
  20309. cmdName:'sorttable',
  20310. value:'reversebynum'
  20311. }
  20312. ]
  20313. },
  20314. {
  20315. group:lang.borderbk,
  20316. icon:'borderBack',
  20317. subMenu:[
  20318. {
  20319. label:lang.setcolor,
  20320. cmdName:"interlacetable",
  20321. exec:function(){
  20322. this.execCommand("interlacetable");
  20323. }
  20324. },
  20325. {
  20326. label:lang.unsetcolor,
  20327. cmdName:"uninterlacetable",
  20328. exec:function(){
  20329. this.execCommand("uninterlacetable");
  20330. }
  20331. },
  20332. {
  20333. label:lang.setbackground,
  20334. cmdName:"settablebackground",
  20335. exec:function(){
  20336. this.execCommand("settablebackground",{repeat:true,colorList:["#bbb","#ccc"]});
  20337. }
  20338. },
  20339. {
  20340. label:lang.unsetbackground,
  20341. cmdName:"cleartablebackground",
  20342. exec:function(){
  20343. this.execCommand("cleartablebackground");
  20344. }
  20345. },
  20346. {
  20347. label:lang.redandblue,
  20348. cmdName:"settablebackground",
  20349. exec:function(){
  20350. this.execCommand("settablebackground",{repeat:true,colorList:["red","blue"]});
  20351. }
  20352. },
  20353. {
  20354. label:lang.threecolorgradient,
  20355. cmdName:"settablebackground",
  20356. exec:function(){
  20357. this.execCommand("settablebackground",{repeat:true,colorList:["#aaa","#bbb","#ccc"]});
  20358. }
  20359. }
  20360. ]
  20361. },
  20362. {
  20363. group:lang.aligntd,
  20364. icon:'aligntd',
  20365. subMenu:[
  20366. {
  20367. cmdName:'cellalignment',
  20368. value:{align:'left',vAlign:'top'}
  20369. },
  20370. {
  20371. cmdName:'cellalignment',
  20372. value:{align:'center',vAlign:'top'}
  20373. },
  20374. {
  20375. cmdName:'cellalignment',
  20376. value:{align:'right',vAlign:'top'}
  20377. },
  20378. {
  20379. cmdName:'cellalignment',
  20380. value:{align:'left',vAlign:'middle'}
  20381. },
  20382. {
  20383. cmdName:'cellalignment',
  20384. value:{align:'center',vAlign:'middle'}
  20385. },
  20386. {
  20387. cmdName:'cellalignment',
  20388. value:{align:'right',vAlign:'middle'}
  20389. },
  20390. {
  20391. cmdName:'cellalignment',
  20392. value:{align:'left',vAlign:'bottom'}
  20393. },
  20394. {
  20395. cmdName:'cellalignment',
  20396. value:{align:'center',vAlign:'bottom'}
  20397. },
  20398. {
  20399. cmdName:'cellalignment',
  20400. value:{align:'right',vAlign:'bottom'}
  20401. }
  20402. ]
  20403. },
  20404. {
  20405. group:lang.aligntable,
  20406. icon:'aligntable',
  20407. subMenu:[
  20408. {
  20409. cmdName:'tablealignment',
  20410. className: 'left',
  20411. label:lang.tableleft,
  20412. value:"left"
  20413. },
  20414. {
  20415. cmdName:'tablealignment',
  20416. className: 'center',
  20417. label:lang.tablecenter,
  20418. value:"center"
  20419. },
  20420. {
  20421. cmdName:'tablealignment',
  20422. className: 'right',
  20423. label:lang.tableright,
  20424. value:"right"
  20425. }
  20426. ]
  20427. },
  20428. '-',
  20429. {
  20430. label:lang.insertparagraphbefore,
  20431. cmdName:'insertparagraph',
  20432. value:true
  20433. },
  20434. {
  20435. label:lang.insertparagraphafter,
  20436. cmdName:'insertparagraph'
  20437. },
  20438. {
  20439. label:lang['copy'],
  20440. cmdName:'copy'
  20441. },
  20442. {
  20443. label:lang['paste'],
  20444. cmdName:'paste'
  20445. }
  20446. ];
  20447. if ( !items.length ) {
  20448. return;
  20449. }
  20450. var uiUtils = UE.ui.uiUtils;
  20451. me.addListener( 'contextmenu', function ( type, evt ) {
  20452. var offset = uiUtils.getViewportOffsetByEvent( evt );
  20453. me.fireEvent( 'beforeselectionchange' );
  20454. if ( menu ) {
  20455. menu.destroy();
  20456. }
  20457. for ( var i = 0, ti, contextItems = []; ti = items[i]; i++ ) {
  20458. var last;
  20459. (function ( item ) {
  20460. if ( item == '-' ) {
  20461. if ( (last = contextItems[contextItems.length - 1 ] ) && last !== '-' ) {
  20462. contextItems.push( '-' );
  20463. }
  20464. } else if ( item.hasOwnProperty( "group" ) ) {
  20465. for ( var j = 0, cj, subMenu = []; cj = item.subMenu[j]; j++ ) {
  20466. (function ( subItem ) {
  20467. if ( subItem == '-' ) {
  20468. if ( (last = subMenu[subMenu.length - 1 ] ) && last !== '-' ) {
  20469. subMenu.push( '-' );
  20470. }else{
  20471. subMenu.splice(subMenu.length-1);
  20472. }
  20473. } else {
  20474. if ( (me.commands[subItem.cmdName] || UE.commands[subItem.cmdName] || subItem.query) &&
  20475. (subItem.query ? subItem.query() : me.queryCommandState( subItem.cmdName )) > -1 ) {
  20476. subMenu.push( {
  20477. 'label':subItem.label || me.getLang( "contextMenu." + subItem.cmdName + (subItem.value || '') )||"",
  20478. 'className':'edui-for-' +subItem.cmdName + ( subItem.className ? ( ' edui-for-' + subItem.cmdName + '-' + subItem.className ) : '' ),
  20479. onclick:subItem.exec ? function () {
  20480. subItem.exec.call( me );
  20481. } : function () {
  20482. me.execCommand( subItem.cmdName, subItem.value );
  20483. }
  20484. } );
  20485. }
  20486. }
  20487. })( cj );
  20488. }
  20489. if ( subMenu.length ) {
  20490. function getLabel(){
  20491. switch (item.icon){
  20492. case "table":
  20493. return me.getLang( "contextMenu.table" );
  20494. case "justifyjustify":
  20495. return me.getLang( "contextMenu.paragraph" );
  20496. case "aligntd":
  20497. return me.getLang("contextMenu.aligntd");
  20498. case "aligntable":
  20499. return me.getLang("contextMenu.aligntable");
  20500. case "tablesort":
  20501. return lang.tablesort;
  20502. case "borderBack":
  20503. return lang.borderbk;
  20504. default :
  20505. return '';
  20506. }
  20507. }
  20508. contextItems.push( {
  20509. //todo 修正成自动获取方式
  20510. 'label':getLabel(),
  20511. className:'edui-for-' + item.icon,
  20512. 'subMenu':{
  20513. items:subMenu,
  20514. editor:me
  20515. }
  20516. } );
  20517. }
  20518. } else {
  20519. //有可能commmand没有加载右键不能出来,或者没有command也想能展示出来添加query方法
  20520. if ( (me.commands[item.cmdName] || UE.commands[item.cmdName] || item.query) &&
  20521. (item.query ? item.query.call(me) : me.queryCommandState( item.cmdName )) > -1 ) {
  20522. contextItems.push( {
  20523. 'label':item.label || me.getLang( "contextMenu." + item.cmdName ),
  20524. className:'edui-for-' + (item.icon ? item.icon : item.cmdName + (item.value || '')),
  20525. onclick:item.exec ? function () {
  20526. item.exec.call( me );
  20527. } : function () {
  20528. me.execCommand( item.cmdName, item.value );
  20529. }
  20530. } );
  20531. }
  20532. }
  20533. })( ti );
  20534. }
  20535. if ( contextItems[contextItems.length - 1] == '-' ) {
  20536. contextItems.pop();
  20537. }
  20538. menu = new UE.ui.Menu( {
  20539. items:contextItems,
  20540. className:"edui-contextmenu",
  20541. editor:me
  20542. } );
  20543. menu.render();
  20544. menu.showAt( offset );
  20545. me.fireEvent("aftershowcontextmenu",menu);
  20546. domUtils.preventDefault( evt );
  20547. if ( browser.ie ) {
  20548. var ieRange;
  20549. try {
  20550. ieRange = me.selection.getNative().createRange();
  20551. } catch ( e ) {
  20552. return;
  20553. }
  20554. if ( ieRange.item ) {
  20555. var range = new dom.Range( me.document );
  20556. range.selectNode( ieRange.item( 0 ) ).select( true, true );
  20557. }
  20558. }
  20559. });
  20560. // 添加复制的flash按钮
  20561. me.addListener('aftershowcontextmenu', function(type, menu) {
  20562. if (me.zeroclipboard) {
  20563. var items = menu.items;
  20564. for (var key in items) {
  20565. if (items[key].className == 'edui-for-copy') {
  20566. me.zeroclipboard.clip(items[key].getDom());
  20567. }
  20568. }
  20569. }
  20570. });
  20571. };
  20572. // plugins/shortcutmenu.js
  20573. ///import core
  20574. ///commands 弹出菜单
  20575. // commandsName popupmenu
  20576. ///commandsTitle 弹出菜单
  20577. /**
  20578. * 弹出菜单
  20579. * @function
  20580. * @name baidu.editor.plugins.popupmenu
  20581. * @author xuheng
  20582. */
  20583. UE.plugins['shortcutmenu'] = function () {
  20584. var me = this,
  20585. menu,
  20586. items = me.options.shortcutMenu || [];
  20587. if (!items.length) {
  20588. return;
  20589. }
  20590. me.addListener ('contextmenu mouseup' , function (type , e) {
  20591. var me = this,
  20592. customEvt = {
  20593. type : type ,
  20594. target : e.target || e.srcElement ,
  20595. screenX : e.screenX ,
  20596. screenY : e.screenY ,
  20597. clientX : e.clientX ,
  20598. clientY : e.clientY
  20599. };
  20600. setTimeout (function () {
  20601. var rng = me.selection.getRange ();
  20602. if (rng.collapsed === false || type == "contextmenu") {
  20603. if (!menu) {
  20604. menu = new baidu.editor.ui.ShortCutMenu ({
  20605. editor : me ,
  20606. items : items ,
  20607. theme : me.options.theme ,
  20608. className : 'edui-shortcutmenu'
  20609. });
  20610. menu.render ();
  20611. me.fireEvent ("afterrendershortcutmenu" , menu);
  20612. }
  20613. menu.show (customEvt , !!UE.plugins['contextmenu']);
  20614. }
  20615. });
  20616. if (type == 'contextmenu') {
  20617. domUtils.preventDefault (e);
  20618. if (browser.ie9below) {
  20619. var ieRange;
  20620. try {
  20621. ieRange = me.selection.getNative().createRange();
  20622. } catch (e) {
  20623. return;
  20624. }
  20625. if (ieRange.item) {
  20626. var range = new dom.Range (me.document);
  20627. range.selectNode (ieRange.item (0)).select (true , true);
  20628. }
  20629. }
  20630. }
  20631. });
  20632. me.addListener ('keydown' , function (type) {
  20633. if (type == "keydown") {
  20634. menu && !menu.isHidden && menu.hide ();
  20635. }
  20636. });
  20637. };
  20638. // plugins/basestyle.js
  20639. /**
  20640. * B、I、sub、super命令支持
  20641. * @file
  20642. * @since 1.2.6.1
  20643. */
  20644. UE.plugins['basestyle'] = function(){
  20645. /**
  20646. * 字体加粗
  20647. * @command bold
  20648. * @param { String } cmd 命令字符串
  20649. * @remind 对已加粗的文本内容执行该命令, 将取消加粗
  20650. * @method execCommand
  20651. * @example
  20652. * ```javascript
  20653. * //editor是编辑器实例
  20654. * //对当前选中的文本内容执行加粗操作
  20655. * //第一次执行, 文本内容加粗
  20656. * editor.execCommand( 'bold' );
  20657. *
  20658. * //第二次执行, 文本内容取消加粗
  20659. * editor.execCommand( 'bold' );
  20660. * ```
  20661. */
  20662. /**
  20663. * 字体倾斜
  20664. * @command italic
  20665. * @method execCommand
  20666. * @param { String } cmd 命令字符串
  20667. * @remind 对已倾斜的文本内容执行该命令, 将取消倾斜
  20668. * @example
  20669. * ```javascript
  20670. * //editor是编辑器实例
  20671. * //对当前选中的文本内容执行斜体操作
  20672. * //第一次操作, 文本内容将变成斜体
  20673. * editor.execCommand( 'italic' );
  20674. *
  20675. * //再次对同一文本内容执行, 则文本内容将恢复正常
  20676. * editor.execCommand( 'italic' );
  20677. * ```
  20678. */
  20679. /**
  20680. * 下标文本,与“superscript”命令互斥
  20681. * @command subscript
  20682. * @method execCommand
  20683. * @remind 把选中的文本内容切换成下标文本, 如果当前选中的文本已经是下标, 则该操作会把文本内容还原成正常文本
  20684. * @param { String } cmd 命令字符串
  20685. * @example
  20686. * ```javascript
  20687. * //editor是编辑器实例
  20688. * //对当前选中的文本内容执行下标操作
  20689. * //第一次操作, 文本内容将变成下标文本
  20690. * editor.execCommand( 'subscript' );
  20691. *
  20692. * //再次对同一文本内容执行, 则文本内容将恢复正常
  20693. * editor.execCommand( 'subscript' );
  20694. * ```
  20695. */
  20696. /**
  20697. * 上标文本,与“subscript”命令互斥
  20698. * @command superscript
  20699. * @method execCommand
  20700. * @remind 把选中的文本内容切换成上标文本, 如果当前选中的文本已经是上标, 则该操作会把文本内容还原成正常文本
  20701. * @param { String } cmd 命令字符串
  20702. * @example
  20703. * ```javascript
  20704. * //editor是编辑器实例
  20705. * //对当前选中的文本内容执行上标操作
  20706. * //第一次操作, 文本内容将变成上标文本
  20707. * editor.execCommand( 'superscript' );
  20708. *
  20709. * //再次对同一文本内容执行, 则文本内容将恢复正常
  20710. * editor.execCommand( 'superscript' );
  20711. * ```
  20712. */
  20713. var basestyles = {
  20714. 'bold':['strong','b'],
  20715. 'italic':['em','i'],
  20716. 'subscript':['sub'],
  20717. 'superscript':['sup']
  20718. },
  20719. getObj = function(editor,tagNames){
  20720. return domUtils.filterNodeList(editor.selection.getStartElementPath(),tagNames);
  20721. },
  20722. me = this;
  20723. //添加快捷键
  20724. me.addshortcutkey({
  20725. "Bold" : "ctrl+66",//^B
  20726. "Italic" : "ctrl+73", //^I
  20727. "Underline" : "ctrl+85"//^U
  20728. });
  20729. me.addInputRule(function(root){
  20730. utils.each(root.getNodesByTagName('b i'),function(node){
  20731. switch (node.tagName){
  20732. case 'b':
  20733. node.tagName = 'strong';
  20734. break;
  20735. case 'i':
  20736. node.tagName = 'em';
  20737. }
  20738. });
  20739. });
  20740. for ( var style in basestyles ) {
  20741. (function( cmd, tagNames ) {
  20742. me.commands[cmd] = {
  20743. execCommand : function( cmdName ) {
  20744. var range = me.selection.getRange(),obj = getObj(this,tagNames);
  20745. if ( range.collapsed ) {
  20746. if ( obj ) {
  20747. var tmpText = me.document.createTextNode('');
  20748. range.insertNode( tmpText ).removeInlineStyle( tagNames );
  20749. range.setStartBefore(tmpText);
  20750. domUtils.remove(tmpText);
  20751. } else {
  20752. var tmpNode = range.document.createElement( tagNames[0] );
  20753. if(cmdName == 'superscript' || cmdName == 'subscript'){
  20754. tmpText = me.document.createTextNode('');
  20755. range.insertNode(tmpText)
  20756. .removeInlineStyle(['sub','sup'])
  20757. .setStartBefore(tmpText)
  20758. .collapse(true);
  20759. }
  20760. range.insertNode( tmpNode ).setStart( tmpNode, 0 );
  20761. }
  20762. range.collapse( true );
  20763. } else {
  20764. if(cmdName == 'superscript' || cmdName == 'subscript'){
  20765. if(!obj || obj.tagName.toLowerCase() != cmdName){
  20766. range.removeInlineStyle(['sub','sup']);
  20767. }
  20768. }
  20769. obj ? range.removeInlineStyle( tagNames ) : range.applyInlineStyle( tagNames[0] );
  20770. }
  20771. range.select();
  20772. },
  20773. queryCommandState : function() {
  20774. return getObj(this,tagNames) ? 1 : 0;
  20775. }
  20776. };
  20777. })( style, basestyles[style] );
  20778. }
  20779. };
  20780. // plugins/elementpath.js
  20781. /**
  20782. * 选取路径命令
  20783. * @file
  20784. */
  20785. UE.plugins['elementpath'] = function(){
  20786. var currentLevel,
  20787. tagNames,
  20788. me = this;
  20789. me.setOpt('elementPathEnabled',true);
  20790. if(!me.options.elementPathEnabled){
  20791. return;
  20792. }
  20793. me.commands['elementpath'] = {
  20794. execCommand : function( cmdName, level ) {
  20795. var start = tagNames[level],
  20796. range = me.selection.getRange();
  20797. currentLevel = level*1;
  20798. range.selectNode(start).select();
  20799. },
  20800. queryCommandValue : function() {
  20801. //产生一个副本,不能修改原来的startElementPath;
  20802. var parents = [].concat(this.selection.getStartElementPath()).reverse(),
  20803. names = [];
  20804. tagNames = parents;
  20805. for(var i=0,ci;ci=parents[i];i++){
  20806. if(ci.nodeType == 3) {
  20807. continue;
  20808. }
  20809. var name = ci.tagName.toLowerCase();
  20810. if(name == 'img' && ci.getAttribute('anchorname')){
  20811. name = 'anchor';
  20812. }
  20813. names[i] = name;
  20814. if(currentLevel == i){
  20815. currentLevel = -1;
  20816. break;
  20817. }
  20818. }
  20819. return names;
  20820. }
  20821. };
  20822. };
  20823. // plugins/formatmatch.js
  20824. /**
  20825. * 格式刷,只格式inline的
  20826. * @file
  20827. * @since 1.2.6.1
  20828. */
  20829. /**
  20830. * 格式刷
  20831. * @command formatmatch
  20832. * @method execCommand
  20833. * @remind 该操作不能复制段落格式
  20834. * @param { String } cmd 命令字符串
  20835. * @example
  20836. * ```javascript
  20837. * //editor是编辑器实例
  20838. * //获取格式刷
  20839. * editor.execCommand( 'formatmatch' );
  20840. * ```
  20841. */
  20842. UE.plugins['formatmatch'] = function(){
  20843. var me = this,
  20844. list = [],img,
  20845. flag = 0;
  20846. me.addListener('reset',function(){
  20847. list = [];
  20848. flag = 0;
  20849. });
  20850. function addList(type,evt){
  20851. if(browser.webkit){
  20852. var target = evt.target.tagName == 'IMG' ? evt.target : null;
  20853. }
  20854. function addFormat(range){
  20855. if(text){
  20856. range.selectNode(text);
  20857. }
  20858. return range.applyInlineStyle(list[list.length-1].tagName,null,list);
  20859. }
  20860. me.undoManger && me.undoManger.save();
  20861. var range = me.selection.getRange(),
  20862. imgT = target || range.getClosedNode();
  20863. if(img && imgT && imgT.tagName == 'IMG'){
  20864. //trace:964
  20865. imgT.style.cssText += ';float:' + (img.style.cssFloat || img.style.styleFloat ||'none') + ';display:' + (img.style.display||'inline');
  20866. img = null;
  20867. }else{
  20868. if(!img){
  20869. var collapsed = range.collapsed;
  20870. if(collapsed){
  20871. var text = me.document.createTextNode('match');
  20872. range.insertNode(text).select();
  20873. }
  20874. me.__hasEnterExecCommand = true;
  20875. //不能把block上的属性干掉
  20876. //trace:1553
  20877. var removeFormatAttributes = me.options.removeFormatAttributes;
  20878. me.options.removeFormatAttributes = '';
  20879. me.execCommand('removeformat');
  20880. me.options.removeFormatAttributes = removeFormatAttributes;
  20881. me.__hasEnterExecCommand = false;
  20882. //trace:969
  20883. range = me.selection.getRange();
  20884. if(list.length){
  20885. addFormat(range);
  20886. }
  20887. if(text){
  20888. range.setStartBefore(text).collapse(true);
  20889. }
  20890. range.select();
  20891. text && domUtils.remove(text);
  20892. }
  20893. }
  20894. me.undoManger && me.undoManger.save();
  20895. me.removeListener('mouseup',addList);
  20896. flag = 0;
  20897. }
  20898. me.commands['formatmatch'] = {
  20899. execCommand : function( cmdName ) {
  20900. if(flag){
  20901. flag = 0;
  20902. list = [];
  20903. me.removeListener('mouseup',addList);
  20904. return;
  20905. }
  20906. var range = me.selection.getRange();
  20907. img = range.getClosedNode();
  20908. if(!img || img.tagName != 'IMG'){
  20909. range.collapse(true).shrinkBoundary();
  20910. var start = range.startContainer;
  20911. list = domUtils.findParents(start,true,function(node){
  20912. return !domUtils.isBlockElm(node) && node.nodeType == 1;
  20913. });
  20914. //a不能加入格式刷, 并且克隆节点
  20915. for(var i=0,ci;ci=list[i];i++){
  20916. if(ci.tagName == 'A'){
  20917. list.splice(i,1);
  20918. break;
  20919. }
  20920. }
  20921. }
  20922. me.addListener('mouseup',addList);
  20923. flag = 1;
  20924. },
  20925. queryCommandState : function() {
  20926. return flag;
  20927. },
  20928. notNeedUndo : 1
  20929. };
  20930. };
  20931. // plugins/searchreplace.js
  20932. ///import core
  20933. ///commands 查找替换
  20934. ///commandsName SearchReplace
  20935. ///commandsTitle 查询替换
  20936. ///commandsDialog dialogs\searchreplace
  20937. /**
  20938. * @description 查找替换
  20939. * @author zhanyi
  20940. */
  20941. UE.plugin.register('searchreplace',function(){
  20942. var me = this;
  20943. var _blockElm = {'table':1,'tbody':1,'tr':1,'ol':1,'ul':1};
  20944. function findTextInString(textContent,opt,currentIndex){
  20945. var str = opt.searchStr;
  20946. if(opt.dir == -1){
  20947. textContent = textContent.split('').reverse().join('');
  20948. str = str.split('').reverse().join('');
  20949. currentIndex = textContent.length - currentIndex;
  20950. }
  20951. var reg = new RegExp(str,'g' + (opt.casesensitive ? '' : 'i')),match;
  20952. while(match = reg.exec(textContent)){
  20953. if(match.index >= currentIndex){
  20954. return opt.dir == -1 ? textContent.length - match.index - opt.searchStr.length : match.index;
  20955. }
  20956. }
  20957. return -1
  20958. }
  20959. function findTextBlockElm(node,currentIndex,opt){
  20960. var textContent,index,methodName = opt.all || opt.dir == 1 ? 'getNextDomNode' : 'getPreDomNode';
  20961. if(domUtils.isBody(node)){
  20962. node = node.firstChild;
  20963. }
  20964. var first = 1;
  20965. while(node){
  20966. textContent = node.nodeType == 3 ? node.nodeValue : node[browser.ie ? 'innerText' : 'textContent'];
  20967. index = findTextInString(textContent,opt,currentIndex );
  20968. first = 0;
  20969. if(index!=-1){
  20970. return {
  20971. 'node':node,
  20972. 'index':index
  20973. }
  20974. }
  20975. node = domUtils[methodName](node);
  20976. while(node && _blockElm[node.nodeName.toLowerCase()]){
  20977. node = domUtils[methodName](node,true);
  20978. }
  20979. if(node){
  20980. currentIndex = opt.dir == -1 ? (node.nodeType == 3 ? node.nodeValue : node[browser.ie ? 'innerText' : 'textContent']).length : 0;
  20981. }
  20982. }
  20983. }
  20984. function findNTextInBlockElm(node,index,str){
  20985. var currentIndex = 0,
  20986. currentNode = node.firstChild,
  20987. currentNodeLength = 0,
  20988. result;
  20989. while(currentNode){
  20990. if(currentNode.nodeType == 3){
  20991. currentNodeLength = currentNode.nodeValue.replace(/(^[\t\r\n]+)|([\t\r\n]+$)/,'').length;
  20992. currentIndex += currentNodeLength;
  20993. if(currentIndex >= index){
  20994. return {
  20995. 'node':currentNode,
  20996. 'index': currentNodeLength - (currentIndex - index)
  20997. }
  20998. }
  20999. }else if(!dtd.$empty[currentNode.tagName]){
  21000. currentNodeLength = currentNode[browser.ie ? 'innerText' : 'textContent'].replace(/(^[\t\r\n]+)|([\t\r\n]+$)/,'').length
  21001. currentIndex += currentNodeLength;
  21002. if(currentIndex >= index){
  21003. result = findNTextInBlockElm(currentNode,currentNodeLength - (currentIndex - index),str);
  21004. if(result){
  21005. return result;
  21006. }
  21007. }
  21008. }
  21009. currentNode = domUtils.getNextDomNode(currentNode);
  21010. }
  21011. }
  21012. function searchReplace(me,opt){
  21013. var rng = me.selection.getRange(),
  21014. startBlockNode,
  21015. searchStr = opt.searchStr,
  21016. span = me.document.createElement('span');
  21017. span.innerHTML = '$$ueditor_searchreplace_key$$';
  21018. rng.shrinkBoundary(true);
  21019. //判断是不是第一次选中
  21020. if(!rng.collapsed){
  21021. rng.select();
  21022. var rngText = me.selection.getText();
  21023. if(new RegExp('^' + opt.searchStr + '$',(opt.casesensitive ? '' : 'i')).test(rngText)){
  21024. if(opt.replaceStr != undefined){
  21025. replaceText(rng,opt.replaceStr);
  21026. rng.select();
  21027. return true;
  21028. }else{
  21029. rng.collapse(opt.dir == -1)
  21030. }
  21031. }
  21032. }
  21033. rng.insertNode(span);
  21034. rng.enlargeToBlockElm(true);
  21035. startBlockNode = rng.startContainer;
  21036. var currentIndex = startBlockNode[browser.ie ? 'innerText' : 'textContent'].indexOf('$$ueditor_searchreplace_key$$');
  21037. rng.setStartBefore(span);
  21038. domUtils.remove(span);
  21039. var result = findTextBlockElm(startBlockNode,currentIndex,opt);
  21040. if(result){
  21041. var rngStart = findNTextInBlockElm(result.node,result.index,searchStr);
  21042. var rngEnd = findNTextInBlockElm(result.node,result.index + searchStr.length,searchStr);
  21043. rng.setStart(rngStart.node,rngStart.index).setEnd(rngEnd.node,rngEnd.index);
  21044. if(opt.replaceStr !== undefined){
  21045. replaceText(rng,opt.replaceStr)
  21046. }
  21047. rng.select();
  21048. return true;
  21049. }else{
  21050. rng.setCursor()
  21051. }
  21052. }
  21053. function replaceText(rng,str){
  21054. str = me.document.createTextNode(str);
  21055. rng.deleteContents().insertNode(str);
  21056. }
  21057. return {
  21058. commands:{
  21059. 'searchreplace':{
  21060. execCommand:function(cmdName,opt){
  21061. utils.extend(opt,{
  21062. all : false,
  21063. casesensitive : false,
  21064. dir : 1
  21065. },true);
  21066. var num = 0;
  21067. if(opt.all){
  21068. var rng = me.selection.getRange(),
  21069. first = me.body.firstChild;
  21070. if(first && first.nodeType == 1){
  21071. rng.setStart(first,0);
  21072. rng.shrinkBoundary(true);
  21073. }else if(first.nodeType == 3){
  21074. rng.setStartBefore(first)
  21075. }
  21076. rng.collapse(true).select(true);
  21077. if(opt.replaceStr !== undefined){
  21078. me.fireEvent('saveScene');
  21079. }
  21080. while(searchReplace(this,opt)){
  21081. num++;
  21082. }
  21083. if(num){
  21084. me.fireEvent('saveScene');
  21085. }
  21086. }else{
  21087. if(opt.replaceStr !== undefined){
  21088. me.fireEvent('saveScene');
  21089. }
  21090. if(searchReplace(this,opt)){
  21091. num++
  21092. }
  21093. if(num){
  21094. me.fireEvent('saveScene');
  21095. }
  21096. }
  21097. return num;
  21098. },
  21099. notNeedUndo:1
  21100. }
  21101. }
  21102. }
  21103. });
  21104. // plugins/customstyle.js
  21105. /**
  21106. * 自定义样式
  21107. * @file
  21108. * @since 1.2.6.1
  21109. */
  21110. /**
  21111. * 根据config配置文件里“customstyle”选项的值对匹配的标签执行样式替换。
  21112. * @command customstyle
  21113. * @method execCommand
  21114. * @param { String } cmd 命令字符串
  21115. * @example
  21116. * ```javascript
  21117. * editor.execCommand( 'customstyle' );
  21118. * ```
  21119. */
  21120. UE.plugins['customstyle'] = function() {
  21121. var me = this;
  21122. me.setOpt({ 'customstyle':[
  21123. {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;'},
  21124. {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;'},
  21125. {tag:'span',name:'im', style:'font-size:16px;font-style:italic;font-weight:bold;line-height:18px;'},
  21126. {tag:'span',name:'hi', style:'font-size:16px;font-style:italic;font-weight:bold;color:rgb(51, 153, 204);line-height:18px;'}
  21127. ]});
  21128. me.commands['customstyle'] = {
  21129. execCommand : function(cmdName, obj) {
  21130. var me = this,
  21131. tagName = obj.tag,
  21132. node = domUtils.findParent(me.selection.getStart(), function(node) {
  21133. return node.getAttribute('label');
  21134. }, true),
  21135. range,bk,tmpObj = {};
  21136. for (var p in obj) {
  21137. if(obj[p]!==undefined)
  21138. tmpObj[p] = obj[p];
  21139. }
  21140. delete tmpObj.tag;
  21141. if (node && node.getAttribute('label') == obj.label) {
  21142. range = this.selection.getRange();
  21143. bk = range.createBookmark();
  21144. if (range.collapsed) {
  21145. //trace:1732 删掉自定义标签,要有p来回填站位
  21146. if(dtd.$block[node.tagName]){
  21147. var fillNode = me.document.createElement('p');
  21148. domUtils.moveChild(node, fillNode);
  21149. node.parentNode.insertBefore(fillNode, node);
  21150. domUtils.remove(node);
  21151. }else{
  21152. domUtils.remove(node,true);
  21153. }
  21154. } else {
  21155. var common = domUtils.getCommonAncestor(bk.start, bk.end),
  21156. nodes = domUtils.getElementsByTagName(common, tagName);
  21157. if(new RegExp(tagName,'i').test(common.tagName)){
  21158. nodes.push(common);
  21159. }
  21160. for (var i = 0,ni; ni = nodes[i++];) {
  21161. if (ni.getAttribute('label') == obj.label) {
  21162. var ps = domUtils.getPosition(ni, bk.start),pe = domUtils.getPosition(ni, bk.end);
  21163. if ((ps & domUtils.POSITION_FOLLOWING || ps & domUtils.POSITION_CONTAINS)
  21164. &&
  21165. (pe & domUtils.POSITION_PRECEDING || pe & domUtils.POSITION_CONTAINS)
  21166. )
  21167. if (dtd.$block[tagName]) {
  21168. var fillNode = me.document.createElement('p');
  21169. domUtils.moveChild(ni, fillNode);
  21170. ni.parentNode.insertBefore(fillNode, ni);
  21171. }
  21172. domUtils.remove(ni, true);
  21173. }
  21174. }
  21175. node = domUtils.findParent(common, function(node) {
  21176. return node.getAttribute('label') == obj.label;
  21177. }, true);
  21178. if (node) {
  21179. domUtils.remove(node, true);
  21180. }
  21181. }
  21182. range.moveToBookmark(bk).select();
  21183. } else {
  21184. if (dtd.$block[tagName]) {
  21185. this.execCommand('paragraph', tagName, tmpObj,'customstyle');
  21186. range = me.selection.getRange();
  21187. if (!range.collapsed) {
  21188. range.collapse();
  21189. node = domUtils.findParent(me.selection.getStart(), function(node) {
  21190. return node.getAttribute('label') == obj.label;
  21191. }, true);
  21192. var pNode = me.document.createElement('p');
  21193. domUtils.insertAfter(node, pNode);
  21194. domUtils.fillNode(me.document, pNode);
  21195. range.setStart(pNode, 0).setCursor();
  21196. }
  21197. } else {
  21198. range = me.selection.getRange();
  21199. if (range.collapsed) {
  21200. node = me.document.createElement(tagName);
  21201. domUtils.setAttributes(node, tmpObj);
  21202. range.insertNode(node).setStart(node, 0).setCursor();
  21203. return;
  21204. }
  21205. bk = range.createBookmark();
  21206. range.applyInlineStyle(tagName, tmpObj).moveToBookmark(bk).select();
  21207. }
  21208. }
  21209. },
  21210. queryCommandValue : function() {
  21211. var parent = domUtils.filterNodeList(
  21212. this.selection.getStartElementPath(),
  21213. function(node){return node.getAttribute('label')}
  21214. );
  21215. return parent ? parent.getAttribute('label') : '';
  21216. }
  21217. };
  21218. //当去掉customstyle是,如果是块元素,用p代替
  21219. me.addListener('keyup', function(type, evt) {
  21220. var keyCode = evt.keyCode || evt.which;
  21221. if (keyCode == 32 || keyCode == 13) {
  21222. var range = me.selection.getRange();
  21223. if (range.collapsed) {
  21224. var node = domUtils.findParent(me.selection.getStart(), function(node) {
  21225. return node.getAttribute('label');
  21226. }, true);
  21227. if (node && dtd.$block[node.tagName] && domUtils.isEmptyNode(node)) {
  21228. var p = me.document.createElement('p');
  21229. domUtils.insertAfter(node, p);
  21230. domUtils.fillNode(me.document, p);
  21231. domUtils.remove(node);
  21232. range.setStart(p, 0).setCursor();
  21233. }
  21234. }
  21235. }
  21236. });
  21237. };
  21238. // plugins/catchremoteimage.js
  21239. ///import core
  21240. ///commands 远程图片抓取
  21241. ///commandsName catchRemoteImage,catchremoteimageenable
  21242. ///commandsTitle 远程图片抓取
  21243. /**
  21244. * 远程图片抓取,当开启本插件时所有不符合本地域名的图片都将被抓取成为本地服务器上的图片
  21245. */
  21246. UE.plugins['catchremoteimage'] = function () {
  21247. var me = this,
  21248. ajax = UE.ajax;
  21249. /* 设置默认值 */
  21250. if (me.options.catchRemoteImageEnable === false) return;
  21251. me.setOpt({
  21252. catchRemoteImageEnable: false
  21253. });
  21254. me.addListener("afterpaste", function () {
  21255. me.fireEvent("catchRemoteImage");
  21256. });
  21257. me.addListener("catchRemoteImage", function () {
  21258. var catcherLocalDomain = me.getOpt('catcherLocalDomain'),
  21259. catcherActionUrl = me.getActionUrl(me.getOpt('catcherActionName')),
  21260. catcherUrlPrefix = me.getOpt('catcherUrlPrefix'),
  21261. catcherFieldName = me.getOpt('catcherFieldName');
  21262. var remoteImages = [],
  21263. imgs = domUtils.getElementsByTagName(me.document, "img"),
  21264. test = function (src, urls) {
  21265. if (src.indexOf(location.host) != -1 || /(^\.)|(^\/)/.test(src)) {
  21266. return true;
  21267. }
  21268. if (urls) {
  21269. for (var j = 0, url; url = urls[j++];) {
  21270. if (src.indexOf(url) !== -1) {
  21271. return true;
  21272. }
  21273. }
  21274. }
  21275. return false;
  21276. };
  21277. for (var i = 0, ci; ci = imgs[i++];) {
  21278. if (ci.getAttribute("word_img")) {
  21279. continue;
  21280. }
  21281. var src = ci.getAttribute("_src") || ci.src || "";
  21282. if (/^(https?|ftp):/i.test(src) && !test(src, catcherLocalDomain)) {
  21283. remoteImages.push(src);
  21284. }
  21285. }
  21286. if (remoteImages.length) {
  21287. catchremoteimage(remoteImages, {
  21288. //成功抓取
  21289. success: function (r) {
  21290. try {
  21291. var info = r.state !== undefined ? r:eval("(" + r.responseText + ")");
  21292. } catch (e) {
  21293. return;
  21294. }
  21295. /* 获取源路径和新路径 */
  21296. var i, j, ci, cj, oldSrc, newSrc, list = info.list;
  21297. for (i = 0; ci = imgs[i++];) {
  21298. oldSrc = ci.getAttribute("_src") || ci.src || "";
  21299. for (j = 0; cj = list[j++];) {
  21300. if (oldSrc == cj.source && cj.state == "SUCCESS") { //抓取失败时不做替换处理
  21301. newSrc = catcherUrlPrefix + cj.url;
  21302. domUtils.setAttributes(ci, {
  21303. "src": newSrc,
  21304. "_src": newSrc
  21305. });
  21306. break;
  21307. }
  21308. }
  21309. }
  21310. me.fireEvent('catchremotesuccess')
  21311. },
  21312. //回调失败,本次请求超时
  21313. error: function () {
  21314. me.fireEvent("catchremoteerror");
  21315. }
  21316. });
  21317. }
  21318. function catchremoteimage(imgs, callbacks) {
  21319. var params = utils.serializeParam(me.queryCommandValue('serverparam')) || '',
  21320. url = utils.formatUrl(catcherActionUrl + (catcherActionUrl.indexOf('?') == -1 ? '?':'&') + params),
  21321. isJsonp = utils.isCrossDomainUrl(url),
  21322. opt = {
  21323. 'method': 'POST',
  21324. 'dataType': isJsonp ? 'jsonp':'',
  21325. 'timeout': 60000, //单位:毫秒,回调请求超时设置。目标用户如果网速不是很快的话此处建议设置一个较大的数值
  21326. 'onsuccess': callbacks["success"],
  21327. 'onerror': callbacks["error"]
  21328. };
  21329. opt[catcherFieldName] = imgs;
  21330. ajax.request(url, opt);
  21331. }
  21332. });
  21333. };
  21334. // plugins/snapscreen.js
  21335. /**
  21336. * 截屏插件,为UEditor提供插入支持
  21337. * @file
  21338. * @since 1.4.2
  21339. */
  21340. UE.plugin.register('snapscreen', function (){
  21341. var me = this;
  21342. var snapplugin;
  21343. function getLocation(url){
  21344. var search,
  21345. a = document.createElement('a'),
  21346. params = utils.serializeParam(me.queryCommandValue('serverparam')) || '';
  21347. a.href = url;
  21348. if (browser.ie) {
  21349. a.href = a.href;
  21350. }
  21351. search = a.search;
  21352. if (params) {
  21353. search = search + (search.indexOf('?') == -1 ? '?':'&')+ params;
  21354. search = search.replace(/[&]+/ig, '&');
  21355. }
  21356. return {
  21357. 'port': a.port,
  21358. 'hostname': a.hostname,
  21359. 'path': a.pathname + search || + a.hash
  21360. }
  21361. }
  21362. return {
  21363. commands:{
  21364. /**
  21365. * 字体背景颜色
  21366. * @command snapscreen
  21367. * @method execCommand
  21368. * @param { String } cmd 命令字符串
  21369. * @example
  21370. * ```javascript
  21371. * editor.execCommand('snapscreen');
  21372. * ```
  21373. */
  21374. 'snapscreen':{
  21375. execCommand:function (cmd) {
  21376. var url, local, res;
  21377. var lang = me.getLang("snapScreen_plugin");
  21378. if(!snapplugin){
  21379. var container = me.container;
  21380. var doc = me.container.ownerDocument || me.container.document;
  21381. snapplugin = doc.createElement("object");
  21382. try{snapplugin.type = "application/x-pluginbaidusnap";}catch(e){
  21383. return;
  21384. }
  21385. snapplugin.style.cssText = "position:absolute;left:-9999px;width:0;height:0;";
  21386. snapplugin.setAttribute("width","0");
  21387. snapplugin.setAttribute("height","0");
  21388. container.appendChild(snapplugin);
  21389. }
  21390. function onSuccess(rs){
  21391. try{
  21392. rs = eval("("+ rs +")");
  21393. if(rs.state == 'SUCCESS'){
  21394. var opt = me.options;
  21395. me.execCommand('insertimage', {
  21396. src: opt.snapscreenUrlPrefix + rs.url,
  21397. _src: opt.snapscreenUrlPrefix + rs.url,
  21398. alt: rs.title || '',
  21399. floatStyle: opt.snapscreenImgAlign
  21400. });
  21401. } else {
  21402. alert(rs.state);
  21403. }
  21404. }catch(e){
  21405. alert(lang.callBackErrorMsg);
  21406. }
  21407. }
  21408. url = me.getActionUrl(me.getOpt('snapscreenActionName'));
  21409. local = getLocation(url);
  21410. setTimeout(function () {
  21411. try{
  21412. res =snapplugin.saveSnapshot(local.hostname, local.path, local.port);
  21413. }catch(e){
  21414. me.ui._dialogs['snapscreenDialog'].open();
  21415. return;
  21416. }
  21417. onSuccess(res);
  21418. }, 50);
  21419. },
  21420. queryCommandState: function(){
  21421. return (navigator.userAgent.indexOf("Windows",0) != -1) ? 0:-1;
  21422. }
  21423. }
  21424. }
  21425. }
  21426. });
  21427. // plugins/insertparagraph.js
  21428. /**
  21429. * 插入段落
  21430. * @file
  21431. * @since 1.2.6.1
  21432. */
  21433. /**
  21434. * 插入段落
  21435. * @command insertparagraph
  21436. * @method execCommand
  21437. * @param { String } cmd 命令字符串
  21438. * @example
  21439. * ```javascript
  21440. * //editor是编辑器实例
  21441. * editor.execCommand( 'insertparagraph' );
  21442. * ```
  21443. */
  21444. UE.commands['insertparagraph'] = {
  21445. execCommand : function( cmdName,front) {
  21446. var me = this,
  21447. range = me.selection.getRange(),
  21448. start = range.startContainer,tmpNode;
  21449. while(start ){
  21450. if(domUtils.isBody(start)){
  21451. break;
  21452. }
  21453. tmpNode = start;
  21454. start = start.parentNode;
  21455. }
  21456. if(tmpNode){
  21457. var p = me.document.createElement('p');
  21458. if(front){
  21459. tmpNode.parentNode.insertBefore(p,tmpNode)
  21460. }else{
  21461. tmpNode.parentNode.insertBefore(p,tmpNode.nextSibling)
  21462. }
  21463. domUtils.fillNode(me.document,p);
  21464. range.setStart(p,0).setCursor(false,true);
  21465. }
  21466. }
  21467. };
  21468. // plugins/webapp.js
  21469. /**
  21470. * 百度应用
  21471. * @file
  21472. * @since 1.2.6.1
  21473. */
  21474. /**
  21475. * 插入百度应用
  21476. * @command webapp
  21477. * @method execCommand
  21478. * @remind 需要百度APPKey
  21479. * @remind 百度应用主页: <a href="http://app.baidu.com/" target="_blank">http://app.baidu.com/</a>
  21480. * @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度,
  21481. * height=>应用容器高度,logo=>应用logo,url=>应用地址
  21482. * @example
  21483. * ```javascript
  21484. * //editor是编辑器实例
  21485. * //在编辑器里插入一个“植物大战僵尸”的APP
  21486. * editor.execCommand( 'webapp' , {
  21487. * title: '植物大战僵尸',
  21488. * width: 560,
  21489. * height: 465,
  21490. * logo: '应用展示的图片',
  21491. * url: '百度应用的地址'
  21492. * } );
  21493. * ```
  21494. */
  21495. //UE.plugins['webapp'] = function () {
  21496. // var me = this;
  21497. // function createInsertStr( obj, toIframe, addParagraph ) {
  21498. // return !toIframe ?
  21499. // (addParagraph ? '<p>' : '') + '<img title="'+obj.title+'" width="' + obj.width + '" height="' + obj.height + '"' +
  21500. // ' 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 + '" />' +
  21501. // (addParagraph ? '</p>' : '')
  21502. // :
  21503. // '<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>';
  21504. // }
  21505. //
  21506. // function switchImgAndIframe( img2frame ) {
  21507. // var tmpdiv,
  21508. // nodes = domUtils.getElementsByTagName( me.document, !img2frame ? "iframe" : "img" );
  21509. // for ( var i = 0, node; node = nodes[i++]; ) {
  21510. // if ( node.className != "edui-faked-webapp" ){
  21511. // continue;
  21512. // }
  21513. // tmpdiv = me.document.createElement( "div" );
  21514. // 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 );
  21515. // node.parentNode.replaceChild( tmpdiv.firstChild, node );
  21516. // }
  21517. // }
  21518. //
  21519. // me.addListener( "beforegetcontent", function () {
  21520. // switchImgAndIframe( true );
  21521. // } );
  21522. // me.addListener( 'aftersetcontent', function () {
  21523. // switchImgAndIframe( false );
  21524. // } );
  21525. // me.addListener( 'aftergetcontent', function ( cmdName ) {
  21526. // if ( cmdName == 'aftergetcontent' && me.queryCommandState( 'source' ) ){
  21527. // return;
  21528. // }
  21529. // switchImgAndIframe( false );
  21530. // } );
  21531. //
  21532. // me.commands['webapp'] = {
  21533. // execCommand:function ( cmd, obj ) {
  21534. // me.execCommand( "inserthtml", createInsertStr( obj, false,true ) );
  21535. // }
  21536. // };
  21537. //};
  21538. UE.plugin.register('webapp', function (){
  21539. var me = this;
  21540. function createInsertStr(obj,toEmbed){
  21541. return !toEmbed ?
  21542. '<img title="'+obj.title+'" width="' + obj.width + '" height="' + obj.height + '"' +
  21543. ' src="' + me.options.UEDITOR_HOME_URL + 'themes/default/images/spacer.gif" _logo_url="'+obj.logo+'" style="background:url(' + obj.logo
  21544. +') no-repeat center center; border:1px solid gray;" class="edui-faked-webapp" _url="' + obj.url + '" ' +
  21545. (obj.align && !obj.cssfloat? 'align="' + obj.align + '"' : '') +
  21546. (obj.cssfloat ? 'style="float:' + obj.cssfloat + '"' : '') +
  21547. '/>'
  21548. :
  21549. '<iframe class="edui-faked-webapp" title="'+obj.title+'" ' +
  21550. (obj.align && !obj.cssfloat? 'align="' + obj.align + '"' : '') +
  21551. (obj.cssfloat ? 'style="float:' + obj.cssfloat + '"' : '') +
  21552. 'width="' + obj.width + '" height="' + obj.height + '" scrolling="no" frameborder="0" src="' + obj.url + '" logo_url = "'+obj.logo+'"></iframe>'
  21553. }
  21554. return {
  21555. outputRule: function(root){
  21556. utils.each(root.getNodesByTagName('img'),function(node){
  21557. var html;
  21558. if(node.getAttr('class') == 'edui-faked-webapp'){
  21559. html = createInsertStr({
  21560. title:node.getAttr('title'),
  21561. 'width':node.getAttr('width'),
  21562. 'height':node.getAttr('height'),
  21563. 'align':node.getAttr('align'),
  21564. 'cssfloat':node.getStyle('float'),
  21565. 'url':node.getAttr("_url"),
  21566. 'logo':node.getAttr('_logo_url')
  21567. },true);
  21568. var embed = UE.uNode.createElement(html);
  21569. node.parentNode.replaceChild(embed,node);
  21570. }
  21571. })
  21572. },
  21573. inputRule:function(root){
  21574. utils.each(root.getNodesByTagName('iframe'),function(node){
  21575. if(node.getAttr('class') == 'edui-faked-webapp'){
  21576. var img = UE.uNode.createElement(createInsertStr({
  21577. title:node.getAttr('title'),
  21578. 'width':node.getAttr('width'),
  21579. 'height':node.getAttr('height'),
  21580. 'align':node.getAttr('align'),
  21581. 'cssfloat':node.getStyle('float'),
  21582. 'url':node.getAttr("src"),
  21583. 'logo':node.getAttr('logo_url')
  21584. }));
  21585. node.parentNode.replaceChild(img,node);
  21586. }
  21587. })
  21588. },
  21589. commands:{
  21590. /**
  21591. * 插入百度应用
  21592. * @command webapp
  21593. * @method execCommand
  21594. * @remind 需要百度APPKey
  21595. * @remind 百度应用主页: <a href="http://app.baidu.com/" target="_blank">http://app.baidu.com/</a>
  21596. * @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度,
  21597. * height=>应用容器高度,logo=>应用logo,url=>应用地址
  21598. * @example
  21599. * ```javascript
  21600. * //editor是编辑器实例
  21601. * //在编辑器里插入一个“植物大战僵尸”的APP
  21602. * editor.execCommand( 'webapp' , {
  21603. * title: '植物大战僵尸',
  21604. * width: 560,
  21605. * height: 465,
  21606. * logo: '应用展示的图片',
  21607. * url: '百度应用的地址'
  21608. * } );
  21609. * ```
  21610. */
  21611. 'webapp':{
  21612. execCommand:function (cmd, obj) {
  21613. var me = this,
  21614. str = createInsertStr(utils.extend(obj,{
  21615. align:'none'
  21616. }), false);
  21617. me.execCommand("inserthtml",str);
  21618. },
  21619. queryCommandState:function () {
  21620. var me = this,
  21621. img = me.selection.getRange().getClosedNode(),
  21622. flag = img && (img.className == "edui-faked-webapp");
  21623. return flag ? 1 : 0;
  21624. }
  21625. }
  21626. }
  21627. }
  21628. });
  21629. // plugins/template.js
  21630. ///import core
  21631. ///import plugins\inserthtml.js
  21632. ///import plugins\cleardoc.js
  21633. ///commands 模板
  21634. ///commandsName template
  21635. ///commandsTitle 模板
  21636. ///commandsDialog dialogs\template
  21637. UE.plugins['template'] = function () {
  21638. UE.commands['template'] = {
  21639. execCommand:function (cmd, obj) {
  21640. obj.html && this.execCommand("inserthtml", obj.html);
  21641. }
  21642. };
  21643. this.addListener("click", function (type, evt) {
  21644. var el = evt.target || evt.srcElement,
  21645. range = this.selection.getRange();
  21646. var tnode = domUtils.findParent(el, function (node) {
  21647. if (node.className && domUtils.hasClass(node, "ue_t")) {
  21648. return node;
  21649. }
  21650. }, true);
  21651. tnode && range.selectNode(tnode).shrinkBoundary().select();
  21652. });
  21653. this.addListener("keydown", function (type, evt) {
  21654. var range = this.selection.getRange();
  21655. if (!range.collapsed) {
  21656. if (!evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
  21657. var tnode = domUtils.findParent(range.startContainer, function (node) {
  21658. if (node.className && domUtils.hasClass(node, "ue_t")) {
  21659. return node;
  21660. }
  21661. }, true);
  21662. if (tnode) {
  21663. domUtils.removeClasses(tnode, ["ue_t"]);
  21664. }
  21665. }
  21666. }
  21667. });
  21668. };
  21669. // plugins/music.js
  21670. /**
  21671. * 插入音乐命令
  21672. * @file
  21673. */
  21674. UE.plugin.register('music', function (){
  21675. var me = this;
  21676. function creatInsertStr(url,width,height,align,cssfloat,toEmbed){
  21677. return !toEmbed ?
  21678. '<img ' +
  21679. (align && !cssfloat? 'align="' + align + '"' : '') +
  21680. (cssfloat ? 'style="float:' + cssfloat + '"' : '') +
  21681. ' width="'+ width +'" height="' + height + '" _url="'+url+'" class="edui-faked-music"' +
  21682. ' src="'+me.options.langPath+me.options.lang+'/images/music.png" />'
  21683. :
  21684. '<embed type="application/x-shockwave-flash" class="edui-faked-music" pluginspage="http://www.macromedia.com/go/getflashplayer"' +
  21685. ' src="' + url + '" width="' + width + '" height="' + height + '" '+ (align && !cssfloat? 'align="' + align + '"' : '') +
  21686. (cssfloat ? 'style="float:' + cssfloat + '"' : '') +
  21687. ' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >';
  21688. }
  21689. return {
  21690. outputRule: function(root){
  21691. utils.each(root.getNodesByTagName('img'),function(node){
  21692. var html;
  21693. if(node.getAttr('class') == 'edui-faked-music'){
  21694. var cssfloat = node.getStyle('float');
  21695. var align = node.getAttr('align');
  21696. html = creatInsertStr(node.getAttr("_url"), node.getAttr('width'), node.getAttr('height'), align, cssfloat, true);
  21697. var embed = UE.uNode.createElement(html);
  21698. node.parentNode.replaceChild(embed,node);
  21699. }
  21700. })
  21701. },
  21702. inputRule:function(root){
  21703. utils.each(root.getNodesByTagName('embed'),function(node){
  21704. if(node.getAttr('class') == 'edui-faked-music'){
  21705. var cssfloat = node.getStyle('float');
  21706. var align = node.getAttr('align');
  21707. html = creatInsertStr(node.getAttr("src"), node.getAttr('width'), node.getAttr('height'), align, cssfloat,false);
  21708. var img = UE.uNode.createElement(html);
  21709. node.parentNode.replaceChild(img,node);
  21710. }
  21711. })
  21712. },
  21713. commands:{
  21714. /**
  21715. * 插入音乐
  21716. * @command music
  21717. * @method execCommand
  21718. * @param { Object } musicOptions 插入音乐的参数项, 支持的key有: url=>音乐地址;
  21719. * width=>音乐容器宽度;height=>音乐容器高度;align=>音乐文件的对齐方式, 可选值有: left, center, right, none
  21720. * @example
  21721. * ```javascript
  21722. * //editor是编辑器实例
  21723. * //在编辑器里插入一个“植物大战僵尸”的APP
  21724. * editor.execCommand( 'music' , {
  21725. * width: 400,
  21726. * height: 95,
  21727. * align: "center",
  21728. * url: "音乐地址"
  21729. * } );
  21730. * ```
  21731. */
  21732. 'music':{
  21733. execCommand:function (cmd, musicObj) {
  21734. var me = this,
  21735. str = creatInsertStr(musicObj.url, musicObj.width || 400, musicObj.height || 95, "none", false);
  21736. me.execCommand("inserthtml",str);
  21737. },
  21738. queryCommandState:function () {
  21739. var me = this,
  21740. img = me.selection.getRange().getClosedNode(),
  21741. flag = img && (img.className == "edui-faked-music");
  21742. return flag ? 1 : 0;
  21743. }
  21744. }
  21745. }
  21746. }
  21747. });
  21748. // plugins/autoupload.js
  21749. /**
  21750. * @description
  21751. * 1.拖放文件到编辑区域,自动上传并插入到选区
  21752. * 2.插入粘贴板的图片,自动上传并插入到选区
  21753. * @author Jinqn
  21754. * @date 2013-10-14
  21755. */
  21756. UE.plugin.register('autoupload', function (){
  21757. function sendAndInsertFile(file, editor) {
  21758. var me = editor;
  21759. //模拟数据
  21760. var fieldName, urlPrefix, maxSize, allowFiles, actionUrl,
  21761. loadingHtml, errorHandler, successHandler,
  21762. filetype = /image\/\w+/i.test(file.type) ? 'image':'file',
  21763. loadingId = 'loading_' + (+new Date()).toString(36);
  21764. fieldName = me.getOpt(filetype + 'FieldName');
  21765. urlPrefix = me.getOpt(filetype + 'UrlPrefix');
  21766. maxSize = me.getOpt(filetype + 'MaxSize');
  21767. allowFiles = me.getOpt(filetype + 'AllowFiles');
  21768. actionUrl = me.getActionUrl(me.getOpt(filetype + 'ActionName'));
  21769. errorHandler = function(title) {
  21770. var loader = me.document.getElementById(loadingId);
  21771. loader && domUtils.remove(loader);
  21772. me.fireEvent('showmessage', {
  21773. 'id': loadingId,
  21774. 'content': title,
  21775. 'type': 'error',
  21776. 'timeout': 4000
  21777. });
  21778. };
  21779. if (filetype == 'image') {
  21780. loadingHtml = '<img class="loadingclass" id="' + loadingId + '" src="' +
  21781. me.options.themePath + me.options.theme +
  21782. '/images/spacer.gif" title="' + (me.getLang('autoupload.loading') || '') + '" >';
  21783. successHandler = function(data) {
  21784. var link = urlPrefix + data.url,
  21785. loader = me.document.getElementById(loadingId);
  21786. if (loader) {
  21787. loader.setAttribute('src', link);
  21788. loader.setAttribute('_src', link);
  21789. loader.setAttribute('title', data.title || '');
  21790. loader.setAttribute('alt', data.original || '');
  21791. loader.removeAttribute('id');
  21792. domUtils.removeClasses(loader, 'loadingclass');
  21793. }
  21794. };
  21795. } else {
  21796. loadingHtml = '<p>' +
  21797. '<img class="loadingclass" id="' + loadingId + '" src="' +
  21798. me.options.themePath + me.options.theme +
  21799. '/images/spacer.gif" title="' + (me.getLang('autoupload.loading') || '') + '" >' +
  21800. '</p>';
  21801. successHandler = function(data) {
  21802. var link = urlPrefix + data.url,
  21803. loader = me.document.getElementById(loadingId);
  21804. var rng = me.selection.getRange(),
  21805. bk = rng.createBookmark();
  21806. rng.selectNode(loader).select();
  21807. me.execCommand('insertfile', {'url': link});
  21808. rng.moveToBookmark(bk).select();
  21809. };
  21810. }
  21811. /* 插入loading的占位符 */
  21812. me.execCommand('inserthtml', loadingHtml);
  21813. /* 判断后端配置是否没有加载成功 */
  21814. if (!me.getOpt(filetype + 'ActionName')) {
  21815. errorHandler(me.getLang('autoupload.errorLoadConfig'));
  21816. return;
  21817. }
  21818. /* 判断文件大小是否超出限制 */
  21819. if(file.size > maxSize) {
  21820. errorHandler(me.getLang('autoupload.exceedSizeError'));
  21821. return;
  21822. }
  21823. /* 判断文件格式是否超出允许 */
  21824. var fileext = file.name ? file.name.substr(file.name.lastIndexOf('.')):'';
  21825. if ((fileext && filetype != 'image') || (allowFiles && (allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') == -1)) {
  21826. errorHandler(me.getLang('autoupload.exceedTypeError'));
  21827. return;
  21828. }
  21829. /* 创建Ajax并提交 */
  21830. var xhr = new XMLHttpRequest(),
  21831. fd = new FormData(),
  21832. params = utils.serializeParam(me.queryCommandValue('serverparam')) || '',
  21833. url = utils.formatUrl(actionUrl + (actionUrl.indexOf('?') == -1 ? '?':'&') + params);
  21834. fd.append(fieldName, file, file.name || ('blob.' + file.type.substr('image/'.length)));
  21835. fd.append('type', 'ajax');
  21836. xhr.open("post", url, true);
  21837. xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
  21838. xhr.addEventListener('load', function (e) {
  21839. try{
  21840. var json = (new Function("return " + utils.trim(e.target.response)))();
  21841. if (json.state == 'SUCCESS' && json.url) {
  21842. successHandler(json);
  21843. } else {
  21844. errorHandler(json.state);
  21845. }
  21846. }catch(er){
  21847. errorHandler(me.getLang('autoupload.loadError'));
  21848. }
  21849. });
  21850. xhr.send(fd);
  21851. }
  21852. function getPasteImage(e){
  21853. return e.clipboardData && e.clipboardData.items && e.clipboardData.items.length == 1 && /^image\//.test(e.clipboardData.items[0].type) ? e.clipboardData.items:null;
  21854. }
  21855. function getDropImage(e){
  21856. return e.dataTransfer && e.dataTransfer.files ? e.dataTransfer.files:null;
  21857. }
  21858. return {
  21859. outputRule: function(root){
  21860. utils.each(root.getNodesByTagName('img'),function(n){
  21861. if (/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr('class'))) {
  21862. n.parentNode.removeChild(n);
  21863. }
  21864. });
  21865. utils.each(root.getNodesByTagName('p'),function(n){
  21866. if (/\bloadpara\b/.test(n.getAttr('class'))) {
  21867. n.parentNode.removeChild(n);
  21868. }
  21869. });
  21870. },
  21871. bindEvents:{
  21872. //插入粘贴板的图片,拖放插入图片
  21873. 'ready':function(e){
  21874. var me = this;
  21875. if(window.FormData && window.FileReader) {
  21876. domUtils.on(me.body, 'paste drop', function(e){
  21877. var hasImg = false,
  21878. items;
  21879. //获取粘贴板文件列表或者拖放文件列表
  21880. items = e.type == 'paste' ? getPasteImage(e):getDropImage(e);
  21881. if(items){
  21882. var len = items.length,
  21883. file;
  21884. while (len--){
  21885. file = items[len];
  21886. if(file.getAsFile) file = file.getAsFile();
  21887. if(file && file.size > 0) {
  21888. sendAndInsertFile(file, me);
  21889. hasImg = true;
  21890. }
  21891. }
  21892. hasImg && e.preventDefault();
  21893. }
  21894. });
  21895. //取消拖放图片时出现的文字光标位置提示
  21896. domUtils.on(me.body, 'dragover', function (e) {
  21897. if(e.dataTransfer.types[0] == 'Files') {
  21898. e.preventDefault();
  21899. }
  21900. });
  21901. //设置loading的样式
  21902. utils.cssRule('loading',
  21903. '.loadingclass{display:inline-block;cursor:default;background: url(\''
  21904. + this.options.themePath
  21905. + this.options.theme +'/images/loading.gif\') no-repeat center center transparent;border:1px solid #cccccc;margin-left:1px;height: 22px;width: 22px;}\n' +
  21906. '.loaderrorclass{display:inline-block;cursor:default;background: url(\''
  21907. + this.options.themePath
  21908. + this.options.theme +'/images/loaderror.png\') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;' +
  21909. '}',
  21910. this.document);
  21911. }
  21912. }
  21913. }
  21914. }
  21915. });
  21916. // plugins/autosave.js
  21917. UE.plugin.register('autosave', function (){
  21918. var me = this,
  21919. //无限循环保护
  21920. lastSaveTime = new Date(),
  21921. //最小保存间隔时间
  21922. MIN_TIME = 20,
  21923. //auto save key
  21924. saveKey = null;
  21925. function save ( editor ) {
  21926. var saveData;
  21927. if ( new Date() - lastSaveTime < MIN_TIME ) {
  21928. return;
  21929. }
  21930. if ( !editor.hasContents() ) {
  21931. //这里不能调用命令来删除, 会造成事件死循环
  21932. saveKey && me.removePreferences( saveKey );
  21933. return;
  21934. }
  21935. lastSaveTime = new Date();
  21936. editor._saveFlag = null;
  21937. saveData = me.body.innerHTML;
  21938. if ( editor.fireEvent( "beforeautosave", {
  21939. content: saveData
  21940. } ) === false ) {
  21941. return;
  21942. }
  21943. me.setPreferences( saveKey, saveData );
  21944. editor.fireEvent( "afterautosave", {
  21945. content: saveData
  21946. } );
  21947. }
  21948. return {
  21949. defaultOptions: {
  21950. //默认间隔时间
  21951. saveInterval: 500,
  21952. enableAutoSave: true // HaoChuan9421
  21953. },
  21954. bindEvents:{
  21955. 'ready':function(){
  21956. var _suffix = "-drafts-data",
  21957. key = null;
  21958. if ( me.key ) {
  21959. key = me.key + _suffix;
  21960. } else {
  21961. key = ( me.container.parentNode.id || 'ue-common' ) + _suffix;
  21962. }
  21963. //页面地址+编辑器ID 保持唯一
  21964. saveKey = ( location.protocol + location.host + location.pathname ).replace( /[.:\/]/g, '_' ) + key;
  21965. },
  21966. 'contentchange': function () {
  21967. // HaoChuan9421
  21968. if (!me.getOpt('enableAutoSave')) {
  21969. return;
  21970. }
  21971. if ( !saveKey ) {
  21972. return;
  21973. }
  21974. if ( me._saveFlag ) {
  21975. window.clearTimeout( me._saveFlag );
  21976. }
  21977. if ( me.options.saveInterval > 0 ) {
  21978. me._saveFlag = window.setTimeout( function () {
  21979. save( me );
  21980. }, me.options.saveInterval );
  21981. } else {
  21982. save(me);
  21983. }
  21984. }
  21985. },
  21986. commands:{
  21987. 'clearlocaldata':{
  21988. execCommand:function (cmd, name) {
  21989. if ( saveKey && me.getPreferences( saveKey ) ) {
  21990. me.removePreferences( saveKey )
  21991. }
  21992. },
  21993. notNeedUndo: true,
  21994. ignoreContentChange:true
  21995. },
  21996. 'getlocaldata':{
  21997. execCommand:function (cmd, name) {
  21998. return saveKey ? me.getPreferences( saveKey ) || '' : '';
  21999. },
  22000. notNeedUndo: true,
  22001. ignoreContentChange:true
  22002. },
  22003. 'drafts':{
  22004. execCommand:function (cmd, name) {
  22005. if ( saveKey ) {
  22006. me.body.innerHTML = me.getPreferences( saveKey ) || '<p>'+domUtils.fillHtml+'</p>';
  22007. me.focus(true);
  22008. }
  22009. },
  22010. queryCommandState: function () {
  22011. return saveKey ? ( me.getPreferences( saveKey ) === null ? -1 : 0 ) : -1;
  22012. },
  22013. notNeedUndo: true,
  22014. ignoreContentChange:true
  22015. }
  22016. }
  22017. }
  22018. });
  22019. // plugins/charts.js
  22020. UE.plugin.register('charts', function (){
  22021. var me = this;
  22022. return {
  22023. bindEvents: {
  22024. 'chartserror': function () {
  22025. }
  22026. },
  22027. commands:{
  22028. 'charts': {
  22029. execCommand: function ( cmd, data ) {
  22030. var tableNode = domUtils.findParentByTagName(this.selection.getRange().startContainer, 'table', true),
  22031. flagText = [],
  22032. config = {};
  22033. if ( !tableNode ) {
  22034. return false;
  22035. }
  22036. if ( !validData( tableNode ) ) {
  22037. me.fireEvent( "chartserror" );
  22038. return false;
  22039. }
  22040. config.title = data.title || '';
  22041. config.subTitle = data.subTitle || '';
  22042. config.xTitle = data.xTitle || '';
  22043. config.yTitle = data.yTitle || '';
  22044. config.suffix = data.suffix || '';
  22045. config.tip = data.tip || '';
  22046. //数据对齐方式
  22047. config.dataFormat = data.tableDataFormat || '';
  22048. //图表类型
  22049. config.chartType = data.chartType || 0;
  22050. for ( var key in config ) {
  22051. if ( !config.hasOwnProperty( key ) ) {
  22052. continue;
  22053. }
  22054. flagText.push( key+":"+config[ key ] );
  22055. }
  22056. tableNode.setAttribute( "data-chart", flagText.join( ";" ) );
  22057. domUtils.addClass( tableNode, "edui-charts-table" );
  22058. },
  22059. queryCommandState: function ( cmd, name ) {
  22060. var tableNode = domUtils.findParentByTagName(this.selection.getRange().startContainer, 'table', true);
  22061. return tableNode && validData( tableNode ) ? 0 : -1;
  22062. }
  22063. }
  22064. },
  22065. inputRule:function(root){
  22066. utils.each(root.getNodesByTagName('table'),function( tableNode ){
  22067. if ( tableNode.getAttr("data-chart") !== undefined ) {
  22068. tableNode.setAttr("style");
  22069. }
  22070. })
  22071. },
  22072. outputRule:function(root){
  22073. utils.each(root.getNodesByTagName('table'),function( tableNode ){
  22074. if ( tableNode.getAttr("data-chart") !== undefined ) {
  22075. tableNode.setAttr("style", "display: none;");
  22076. }
  22077. })
  22078. }
  22079. }
  22080. function validData ( table ) {
  22081. var firstRows = null,
  22082. cellCount = 0;
  22083. //行数不够
  22084. if ( table.rows.length < 2 ) {
  22085. return false;
  22086. }
  22087. //列数不够
  22088. if ( table.rows[0].cells.length < 2 ) {
  22089. return false;
  22090. }
  22091. //第一行所有cell必须是th
  22092. firstRows = table.rows[ 0 ].cells;
  22093. cellCount = firstRows.length;
  22094. for ( var i = 0, cell; cell = firstRows[ i ]; i++ ) {
  22095. if ( cell.tagName.toLowerCase() !== 'th' ) {
  22096. return false;
  22097. }
  22098. }
  22099. for ( var i = 1, row; row = table.rows[ i ]; i++ ) {
  22100. //每行单元格数不匹配, 返回false
  22101. if ( row.cells.length != cellCount ) {
  22102. return false;
  22103. }
  22104. //第一列不是th也返回false
  22105. if ( row.cells[0].tagName.toLowerCase() !== 'th' ) {
  22106. return false;
  22107. }
  22108. for ( var j = 1, cell; cell = row.cells[ j ]; j++ ) {
  22109. var value = utils.trim( ( cell.innerText || cell.textContent || '' ) );
  22110. value = value.replace( new RegExp( UE.dom.domUtils.fillChar, 'g' ), '' ).replace( /^\s+|\s+$/g, '' );
  22111. //必须是数字
  22112. if ( !/^\d*\.?\d+$/.test( value ) ) {
  22113. return false;
  22114. }
  22115. }
  22116. }
  22117. return true;
  22118. }
  22119. });
  22120. // plugins/section.js
  22121. /**
  22122. * 目录大纲支持插件
  22123. * @file
  22124. * @since 1.3.0
  22125. */
  22126. UE.plugin.register('section', function (){
  22127. /* 目录节点对象 */
  22128. function Section(option){
  22129. this.tag = '';
  22130. this.level = -1,
  22131. this.dom = null;
  22132. this.nextSection = null;
  22133. this.previousSection = null;
  22134. this.parentSection = null;
  22135. this.startAddress = [];
  22136. this.endAddress = [];
  22137. this.children = [];
  22138. }
  22139. function getSection(option) {
  22140. var section = new Section();
  22141. return utils.extend(section, option);
  22142. }
  22143. function getNodeFromAddress(startAddress, root) {
  22144. var current = root;
  22145. for(var i = 0;i < startAddress.length; i++) {
  22146. if(!current.childNodes) return null;
  22147. current = current.childNodes[startAddress[i]];
  22148. }
  22149. return current;
  22150. }
  22151. var me = this;
  22152. return {
  22153. bindMultiEvents:{
  22154. type: 'aftersetcontent afterscencerestore',
  22155. handler: function(){
  22156. me.fireEvent('updateSections');
  22157. }
  22158. },
  22159. bindEvents:{
  22160. /* 初始化、拖拽、粘贴、执行setcontent之后 */
  22161. 'ready': function (){
  22162. me.fireEvent('updateSections');
  22163. domUtils.on(me.body, 'drop paste', function(){
  22164. me.fireEvent('updateSections');
  22165. });
  22166. },
  22167. /* 执行paragraph命令之后 */
  22168. 'afterexeccommand': function (type, cmd) {
  22169. if(cmd == 'paragraph') {
  22170. me.fireEvent('updateSections');
  22171. }
  22172. },
  22173. /* 部分键盘操作,触发updateSections事件 */
  22174. 'keyup': function (type, e) {
  22175. var me = this,
  22176. range = me.selection.getRange();
  22177. if(range.collapsed != true) {
  22178. me.fireEvent('updateSections');
  22179. } else {
  22180. var keyCode = e.keyCode || e.which;
  22181. if(keyCode == 13 || keyCode == 8 || keyCode == 46) {
  22182. me.fireEvent('updateSections');
  22183. }
  22184. }
  22185. }
  22186. },
  22187. commands:{
  22188. 'getsections': {
  22189. execCommand: function (cmd, levels) {
  22190. var levelFn = levels || ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
  22191. for (var i = 0; i < levelFn.length; i++) {
  22192. if (typeof levelFn[i] == 'string') {
  22193. levelFn[i] = function(fn){
  22194. return function(node){
  22195. return node.tagName == fn.toUpperCase()
  22196. };
  22197. }(levelFn[i]);
  22198. } else if (typeof levelFn[i] != 'function') {
  22199. levelFn[i] = function (node) {
  22200. return null;
  22201. }
  22202. }
  22203. }
  22204. function getSectionLevel(node) {
  22205. for (var i = 0; i < levelFn.length; i++) {
  22206. if (levelFn[i](node)) return i;
  22207. }
  22208. return -1;
  22209. }
  22210. var me = this,
  22211. Directory = getSection({'level':-1, 'title':'root'}),
  22212. previous = Directory;
  22213. function traversal(node, Directory) {
  22214. var level,
  22215. tmpSection = null,
  22216. parent,
  22217. child,
  22218. children = node.childNodes;
  22219. for (var i = 0, len = children.length; i < len; i++) {
  22220. child = children[i];
  22221. level = getSectionLevel(child);
  22222. if (level >= 0) {
  22223. var address = me.selection.getRange().selectNode(child).createAddress(true).startAddress,
  22224. current = getSection({
  22225. 'tag': child.tagName,
  22226. 'title': child.innerText || child.textContent || '',
  22227. 'level': level,
  22228. 'dom': child,
  22229. 'startAddress': utils.clone(address, []),
  22230. 'endAddress': utils.clone(address, []),
  22231. 'children': []
  22232. });
  22233. previous.nextSection = current;
  22234. current.previousSection = previous;
  22235. parent = previous;
  22236. while(level <= parent.level){
  22237. parent = parent.parentSection;
  22238. }
  22239. current.parentSection = parent;
  22240. parent.children.push(current);
  22241. tmpSection = previous = current;
  22242. } else {
  22243. child.nodeType === 1 && traversal(child, Directory);
  22244. tmpSection && tmpSection.endAddress[tmpSection.endAddress.length - 1] ++;
  22245. }
  22246. }
  22247. }
  22248. traversal(me.body, Directory);
  22249. return Directory;
  22250. },
  22251. notNeedUndo: true
  22252. },
  22253. 'movesection': {
  22254. execCommand: function (cmd, sourceSection, targetSection, isAfter) {
  22255. var me = this,
  22256. targetAddress,
  22257. target;
  22258. if(!sourceSection || !targetSection || targetSection.level == -1) return;
  22259. targetAddress = isAfter ? targetSection.endAddress:targetSection.startAddress;
  22260. target = getNodeFromAddress(targetAddress, me.body);
  22261. /* 判断目标地址是否被源章节包含 */
  22262. if(!targetAddress || !target || isContainsAddress(sourceSection.startAddress, sourceSection.endAddress, targetAddress)) return;
  22263. var startNode = getNodeFromAddress(sourceSection.startAddress, me.body),
  22264. endNode = getNodeFromAddress(sourceSection.endAddress, me.body),
  22265. current,
  22266. nextNode;
  22267. if(isAfter) {
  22268. current = endNode;
  22269. while ( current && !(domUtils.getPosition( startNode, current ) & domUtils.POSITION_FOLLOWING) ) {
  22270. nextNode = current.previousSibling;
  22271. domUtils.insertAfter(target, current);
  22272. if(current == startNode) break;
  22273. current = nextNode;
  22274. }
  22275. } else {
  22276. current = startNode;
  22277. while ( current && !(domUtils.getPosition( current, endNode ) & domUtils.POSITION_FOLLOWING) ) {
  22278. nextNode = current.nextSibling;
  22279. target.parentNode.insertBefore(current, target);
  22280. if(current == endNode) break;
  22281. current = nextNode;
  22282. }
  22283. }
  22284. me.fireEvent('updateSections');
  22285. /* 获取地址的包含关系 */
  22286. function isContainsAddress(startAddress, endAddress, addressTarget){
  22287. var isAfterStartAddress = false,
  22288. isBeforeEndAddress = false;
  22289. for(var i = 0; i< startAddress.length; i++){
  22290. if(i >= addressTarget.length) break;
  22291. if(addressTarget[i] > startAddress[i]) {
  22292. isAfterStartAddress = true;
  22293. break;
  22294. } else if(addressTarget[i] < startAddress[i]) {
  22295. break;
  22296. }
  22297. }
  22298. for(var i = 0; i< endAddress.length; i++){
  22299. if(i >= addressTarget.length) break;
  22300. if(addressTarget[i] < startAddress[i]) {
  22301. isBeforeEndAddress = true;
  22302. break;
  22303. } else if(addressTarget[i] > startAddress[i]) {
  22304. break;
  22305. }
  22306. }
  22307. return isAfterStartAddress && isBeforeEndAddress;
  22308. }
  22309. }
  22310. },
  22311. 'deletesection': {
  22312. execCommand: function (cmd, section, keepChildren) {
  22313. var me = this;
  22314. if(!section) return;
  22315. function getNodeFromAddress(startAddress) {
  22316. var current = me.body;
  22317. for(var i = 0;i < startAddress.length; i++) {
  22318. if(!current.childNodes) return null;
  22319. current = current.childNodes[startAddress[i]];
  22320. }
  22321. return current;
  22322. }
  22323. var startNode = getNodeFromAddress(section.startAddress),
  22324. endNode = getNodeFromAddress(section.endAddress),
  22325. current = startNode,
  22326. nextNode;
  22327. if(!keepChildren) {
  22328. while ( current && domUtils.inDoc(endNode, me.document) && !(domUtils.getPosition( current, endNode ) & domUtils.POSITION_FOLLOWING) ) {
  22329. nextNode = current.nextSibling;
  22330. domUtils.remove(current);
  22331. current = nextNode;
  22332. }
  22333. } else {
  22334. domUtils.remove(current);
  22335. }
  22336. me.fireEvent('updateSections');
  22337. }
  22338. },
  22339. 'selectsection': {
  22340. execCommand: function (cmd, section) {
  22341. if(!section && !section.dom) return false;
  22342. var me = this,
  22343. range = me.selection.getRange(),
  22344. address = {
  22345. 'startAddress':utils.clone(section.startAddress, []),
  22346. 'endAddress':utils.clone(section.endAddress, [])
  22347. };
  22348. address.endAddress[address.endAddress.length - 1]++;
  22349. range.moveToAddress(address).select().scrollToView();
  22350. return true;
  22351. },
  22352. notNeedUndo: true
  22353. },
  22354. 'scrolltosection': {
  22355. execCommand: function (cmd, section) {
  22356. if(!section && !section.dom) return false;
  22357. var me = this,
  22358. range = me.selection.getRange(),
  22359. address = {
  22360. 'startAddress':section.startAddress,
  22361. 'endAddress':section.endAddress
  22362. };
  22363. address.endAddress[address.endAddress.length - 1]++;
  22364. range.moveToAddress(address).scrollToView();
  22365. return true;
  22366. },
  22367. notNeedUndo: true
  22368. }
  22369. }
  22370. }
  22371. });
  22372. // plugins/simpleupload.js
  22373. /**
  22374. * @description
  22375. * 简单上传:点击按钮,直接选择文件上传。
  22376. * 原 UEditor 作者使用了 form 表单 + iframe 的方式上传
  22377. * 但由于同源策略的限制,父页面无法访问跨域的 iframe 内容
  22378. * 导致无法获取接口返回的数据,使得单图上传无法在跨域的情况下使用
  22379. * 这里改为普通的XHR上传,兼容到IE10+
  22380. * @author HaoChuan9421 <hc199421@gmail.com>
  22381. * @date 2018-12-20
  22382. */
  22383. UE.plugin.register('simpleupload', function() {
  22384. var me = this,
  22385. containerBtn,
  22386. timestrap = (+new Date()).toString(36);
  22387. function initUploadBtn() {
  22388. var w = containerBtn.offsetWidth || 20,
  22389. h = containerBtn.offsetHeight || 20,
  22390. btnStyle = 'display:block;width:' + w + 'px;height:' + h + 'px;overflow:hidden;border:0;margin:0;padding:0;position:absolute;top:0;left:0;filter:alpha(opacity=0);-moz-opacity:0;-khtml-opacity: 0;opacity: 0;cursor:pointer;';
  22391. var form = document.createElement('form');
  22392. var input = document.createElement('input');
  22393. form.id = 'edui_form_' + timestrap;
  22394. form.enctype = 'multipart/form-data';
  22395. form.style = btnStyle;
  22396. input.id = 'edui_input_' + timestrap;
  22397. input.type = 'file'
  22398. input.accept = 'image/*';
  22399. input.name = me.options.imageFieldName;
  22400. input.style = btnStyle;
  22401. form.appendChild(input);
  22402. containerBtn.appendChild(form);
  22403. input.addEventListener('change', function(event) {
  22404. if (!input.value) return;
  22405. var loadingId = 'loading_' + (+new Date()).toString(36);
  22406. var imageActionUrl = me.getActionUrl(me.getOpt('imageActionName'));
  22407. var params = utils.serializeParam(me.queryCommandValue('serverparam')) || '';
  22408. var action = utils.formatUrl(imageActionUrl + (imageActionUrl.indexOf('?') == -1 ? '?' : '&') + params);
  22409. var allowFiles = me.getOpt('imageAllowFiles');
  22410. me.focus();
  22411. me.execCommand('inserthtml', '<img class="loadingclass" id="' + loadingId + '" src="' + me.options.themePath + me.options.theme + '/images/spacer.gif" title="' + (me.getLang('simpleupload.loading') || '') + '" >');
  22412. function showErrorLoader(title) {
  22413. if (loadingId) {
  22414. var loader = me.document.getElementById(loadingId);
  22415. loader && domUtils.remove(loader);
  22416. me.fireEvent('showmessage', {
  22417. 'id': loadingId,
  22418. 'content': title,
  22419. 'type': 'error',
  22420. 'timeout': 4000
  22421. });
  22422. }
  22423. }
  22424. /* 判断后端配置是否没有加载成功 */
  22425. if (!me.getOpt('imageActionName')) {
  22426. showErrorLoader(me.getLang('autoupload.errorLoadConfig'));
  22427. return;
  22428. }
  22429. // 判断文件格式是否错误
  22430. var filename = input.value,
  22431. fileext = filename ? filename.substr(filename.lastIndexOf('.')) : '';
  22432. if (!fileext || (allowFiles && (allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') == -1)) {
  22433. showErrorLoader(me.getLang('simpleupload.exceedTypeError'));
  22434. return;
  22435. }
  22436. var xhr = new XMLHttpRequest()
  22437. xhr.open('post', action, true)
  22438. if (me.options.headers && Object.prototype.toString.apply(me.options.headers) === "[object Object]") {
  22439. for (var key in me.options.headers) {
  22440. xhr.setRequestHeader(key, me.options.headers[key])
  22441. }
  22442. }
  22443. xhr.onload = function() {
  22444. if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
  22445. var res = JSON.parse(xhr.responseText)
  22446. var link = me.options.imageUrlPrefix + res.url;
  22447. if (res.state == 'SUCCESS' && res.url) {
  22448. loader = me.document.getElementById(loadingId);
  22449. loader.setAttribute('src', link);
  22450. loader.setAttribute('_src', link);
  22451. loader.setAttribute('title', res.title || '');
  22452. loader.setAttribute('alt', res.original || '');
  22453. loader.removeAttribute('id');
  22454. domUtils.removeClasses(loader, 'loadingclass');
  22455. me.fireEvent("contentchange");
  22456. } else {
  22457. showErrorLoader(res.state);
  22458. }
  22459. } else {
  22460. showErrorLoader(me.getLang('simpleupload.loadError'));
  22461. }
  22462. };
  22463. xhr.onerror = function() {
  22464. showErrorLoader(me.getLang('simpleupload.loadError'));
  22465. };
  22466. xhr.send(new FormData(form));
  22467. form.reset();
  22468. })
  22469. }
  22470. return {
  22471. bindEvents: {
  22472. 'ready': function() {
  22473. //设置loading的样式
  22474. utils.cssRule('loading',
  22475. '.loadingclass{display:inline-block;cursor:default;background: url(\'' +
  22476. this.options.themePath +
  22477. this.options.theme + '/images/loading.gif\') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;}\n' +
  22478. '.loaderrorclass{display:inline-block;cursor:default;background: url(\'' +
  22479. this.options.themePath +
  22480. this.options.theme + '/images/loaderror.png\') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;' +
  22481. '}',
  22482. this.document);
  22483. },
  22484. /* 初始化简单上传按钮 */
  22485. 'simpleuploadbtnready': function(type, container) {
  22486. containerBtn = container;
  22487. me.afterConfigReady(initUploadBtn);
  22488. }
  22489. },
  22490. outputRule: function(root) {
  22491. utils.each(root.getNodesByTagName('img'), function(n) {
  22492. if (/\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr('class'))) {
  22493. n.parentNode.removeChild(n);
  22494. }
  22495. });
  22496. }
  22497. }
  22498. });
  22499. // plugins/serverparam.js
  22500. /**
  22501. * 服务器提交的额外参数列表设置插件
  22502. * @file
  22503. * @since 1.2.6.1
  22504. */
  22505. UE.plugin.register('serverparam', function (){
  22506. var me = this,
  22507. serverParam = {};
  22508. return {
  22509. commands:{
  22510. /**
  22511. * 修改服务器提交的额外参数列表,清除所有项
  22512. * @command serverparam
  22513. * @method execCommand
  22514. * @param { String } cmd 命令字符串
  22515. * @example
  22516. * ```javascript
  22517. * editor.execCommand('serverparam');
  22518. * editor.queryCommandValue('serverparam'); //返回空
  22519. * ```
  22520. */
  22521. /**
  22522. * 修改服务器提交的额外参数列表,删除指定项
  22523. * @command serverparam
  22524. * @method execCommand
  22525. * @param { String } cmd 命令字符串
  22526. * @param { String } key 要清除的属性
  22527. * @example
  22528. * ```javascript
  22529. * editor.execCommand('serverparam', 'name'); //删除属性name
  22530. * ```
  22531. */
  22532. /**
  22533. * 修改服务器提交的额外参数列表,使用键值添加项
  22534. * @command serverparam
  22535. * @method execCommand
  22536. * @param { String } cmd 命令字符串
  22537. * @param { String } key 要添加的属性
  22538. * @param { String } value 要添加属性的值
  22539. * @example
  22540. * ```javascript
  22541. * editor.execCommand('serverparam', 'name', 'hello');
  22542. * editor.queryCommandValue('serverparam'); //返回对象 {'name': 'hello'}
  22543. * ```
  22544. */
  22545. /**
  22546. * 修改服务器提交的额外参数列表,传入键值对对象添加多项
  22547. * @command serverparam
  22548. * @method execCommand
  22549. * @param { String } cmd 命令字符串
  22550. * @param { Object } key 传入的键值对对象
  22551. * @example
  22552. * ```javascript
  22553. * editor.execCommand('serverparam', {'name': 'hello'});
  22554. * editor.queryCommandValue('serverparam'); //返回对象 {'name': 'hello'}
  22555. * ```
  22556. */
  22557. /**
  22558. * 修改服务器提交的额外参数列表,使用自定义函数添加多项
  22559. * @command serverparam
  22560. * @method execCommand
  22561. * @param { String } cmd 命令字符串
  22562. * @param { Function } key 自定义获取参数的函数
  22563. * @example
  22564. * ```javascript
  22565. * editor.execCommand('serverparam', function(editor){
  22566. * return {'key': 'value'};
  22567. * });
  22568. * editor.queryCommandValue('serverparam'); //返回对象 {'key': 'value'}
  22569. * ```
  22570. */
  22571. /**
  22572. * 获取服务器提交的额外参数列表
  22573. * @command serverparam
  22574. * @method queryCommandValue
  22575. * @param { String } cmd 命令字符串
  22576. * @example
  22577. * ```javascript
  22578. * editor.queryCommandValue( 'serverparam' ); //返回对象 {'key': 'value'}
  22579. * ```
  22580. */
  22581. 'serverparam':{
  22582. execCommand:function (cmd, key, value) {
  22583. if (key === undefined || key === null) { //不传参数,清空列表
  22584. serverParam = {};
  22585. } else if (utils.isString(key)) { //传入键值
  22586. if(value === undefined || value === null) {
  22587. delete serverParam[key];
  22588. } else {
  22589. serverParam[key] = value;
  22590. }
  22591. } else if (utils.isObject(key)) { //传入对象,覆盖列表项
  22592. utils.extend(serverParam, key, true);
  22593. } else if (utils.isFunction(key)){ //传入函数,添加列表项
  22594. utils.extend(serverParam, key(), true);
  22595. }
  22596. },
  22597. queryCommandValue: function(){
  22598. return serverParam || {};
  22599. }
  22600. }
  22601. }
  22602. }
  22603. });
  22604. // plugins/insertfile.js
  22605. /**
  22606. * 插入附件
  22607. */
  22608. UE.plugin.register('insertfile', function (){
  22609. var me = this;
  22610. function getFileIcon(url){
  22611. var ext = url.substr(url.lastIndexOf('.') + 1).toLowerCase(),
  22612. maps = {
  22613. "rar":"icon_rar.gif",
  22614. "zip":"icon_rar.gif",
  22615. "tar":"icon_rar.gif",
  22616. "gz":"icon_rar.gif",
  22617. "bz2":"icon_rar.gif",
  22618. "doc":"icon_doc.gif",
  22619. "docx":"icon_doc.gif",
  22620. "pdf":"icon_pdf.gif",
  22621. "mp3":"icon_mp3.gif",
  22622. "xls":"icon_xls.gif",
  22623. "chm":"icon_chm.gif",
  22624. "ppt":"icon_ppt.gif",
  22625. "pptx":"icon_ppt.gif",
  22626. "avi":"icon_mv.gif",
  22627. "rmvb":"icon_mv.gif",
  22628. "wmv":"icon_mv.gif",
  22629. "flv":"icon_mv.gif",
  22630. "swf":"icon_mv.gif",
  22631. "rm":"icon_mv.gif",
  22632. "exe":"icon_exe.gif",
  22633. "psd":"icon_psd.gif",
  22634. "txt":"icon_txt.gif",
  22635. "jpg":"icon_jpg.gif",
  22636. "png":"icon_jpg.gif",
  22637. "jpeg":"icon_jpg.gif",
  22638. "gif":"icon_jpg.gif",
  22639. "ico":"icon_jpg.gif",
  22640. "bmp":"icon_jpg.gif"
  22641. };
  22642. return maps[ext] ? maps[ext]:maps['txt'];
  22643. }
  22644. return {
  22645. commands:{
  22646. 'insertfile': {
  22647. execCommand: function (command, filelist){
  22648. filelist = utils.isArray(filelist) ? filelist : [filelist];
  22649. var i, item, icon, title,
  22650. html = '',
  22651. URL = me.getOpt('UEDITOR_HOME_URL'),
  22652. iconDir = URL + (URL.substr(URL.length - 1) == '/' ? '':'/') + 'dialogs/attachment/fileTypeImages/';
  22653. for (i = 0; i < filelist.length; i++) {
  22654. item = filelist[i];
  22655. icon = iconDir + getFileIcon(item.url);
  22656. title = item.title || item.url.substr(item.url.lastIndexOf('/') + 1);
  22657. html += '<p style="line-height: 16px;">' +
  22658. '<img style="vertical-align: middle; margin-right: 2px;" src="'+ icon + '" _src="' + icon + '" />' +
  22659. '<a style="font-size:12px; color:#0066cc;" href="' + item.url +'" title="' + title + '">' + title + '</a>' +
  22660. '</p>';
  22661. }
  22662. me.execCommand('insertHtml', html);
  22663. }
  22664. }
  22665. }
  22666. }
  22667. });
  22668. // plugins/xssFilter.js
  22669. /**
  22670. * @file xssFilter.js
  22671. * @desc xss过滤器
  22672. * @author robbenmu
  22673. */
  22674. UE.plugins.xssFilter = function() {
  22675. var config = UEDITOR_CONFIG;
  22676. var whitList = config.whitList;
  22677. function filter(node) {
  22678. var tagName = node.tagName;
  22679. var attrs = node.attrs;
  22680. if (!whitList.hasOwnProperty(tagName)) {
  22681. node.parentNode.removeChild(node);
  22682. return false;
  22683. }
  22684. UE.utils.each(attrs, function (val, key) {
  22685. if (whitList[tagName].indexOf(key) === -1) {
  22686. node.setAttr(key);
  22687. }
  22688. });
  22689. }
  22690. // 添加inserthtml\paste等操作用的过滤规则
  22691. if (whitList && config.xssFilterRules) {
  22692. this.options.filterRules = function () {
  22693. var result = {};
  22694. UE.utils.each(whitList, function(val, key) {
  22695. result[key] = function (node) {
  22696. return filter(node);
  22697. };
  22698. });
  22699. return result;
  22700. }();
  22701. }
  22702. var tagList = [];
  22703. UE.utils.each(whitList, function (val, key) {
  22704. tagList.push(key);
  22705. });
  22706. // 添加input过滤规则
  22707. //
  22708. if (whitList && config.inputXssFilter) {
  22709. this.addInputRule(function (root) {
  22710. root.traversal(function(node) {
  22711. if (node.type !== 'element') {
  22712. return false;
  22713. }
  22714. filter(node);
  22715. });
  22716. });
  22717. }
  22718. // 添加output过滤规则
  22719. //
  22720. if (whitList && config.outputXssFilter) {
  22721. this.addOutputRule(function (root) {
  22722. root.traversal(function(node) {
  22723. if (node.type !== 'element') {
  22724. return false;
  22725. }
  22726. filter(node);
  22727. });
  22728. });
  22729. }
  22730. };
  22731. // ui/ui.js
  22732. var baidu = baidu || {};
  22733. baidu.editor = baidu.editor || {};
  22734. UE.ui = baidu.editor.ui = {};
  22735. // ui/uiutils.js
  22736. (function (){
  22737. var browser = baidu.editor.browser,
  22738. domUtils = baidu.editor.dom.domUtils;
  22739. var magic = '$EDITORUI';
  22740. var root = window[magic] = {};
  22741. var uidMagic = 'ID' + magic;
  22742. var uidCount = 0;
  22743. var uiUtils = baidu.editor.ui.uiUtils = {
  22744. uid: function (obj){
  22745. return (obj ? obj[uidMagic] || (obj[uidMagic] = ++ uidCount) : ++ uidCount);
  22746. },
  22747. hook: function ( fn, callback ) {
  22748. var dg;
  22749. if (fn && fn._callbacks) {
  22750. dg = fn;
  22751. } else {
  22752. dg = function (){
  22753. var q;
  22754. if (fn) {
  22755. q = fn.apply(this, arguments);
  22756. }
  22757. var callbacks = dg._callbacks;
  22758. var k = callbacks.length;
  22759. while (k --) {
  22760. var r = callbacks[k].apply(this, arguments);
  22761. if (q === undefined) {
  22762. q = r;
  22763. }
  22764. }
  22765. return q;
  22766. };
  22767. dg._callbacks = [];
  22768. }
  22769. dg._callbacks.push(callback);
  22770. return dg;
  22771. },
  22772. createElementByHtml: function (html){
  22773. var el = document.createElement('div');
  22774. el.innerHTML = html;
  22775. el = el.firstChild;
  22776. el.parentNode.removeChild(el);
  22777. return el;
  22778. },
  22779. getViewportElement: function (){
  22780. return (browser.ie && browser.quirks) ?
  22781. document.body : document.documentElement;
  22782. },
  22783. getClientRect: function (element){
  22784. var bcr;
  22785. //trace IE6下在控制编辑器显隐时可能会报错,catch一下
  22786. try{
  22787. bcr = element.getBoundingClientRect();
  22788. }catch(e){
  22789. bcr={left:0,top:0,height:0,width:0}
  22790. }
  22791. var rect = {
  22792. left: Math.round(bcr.left),
  22793. top: Math.round(bcr.top),
  22794. height: Math.round(bcr.bottom - bcr.top),
  22795. width: Math.round(bcr.right - bcr.left)
  22796. };
  22797. var doc;
  22798. while ((doc = element.ownerDocument) !== document &&
  22799. (element = domUtils.getWindow(doc).frameElement)) {
  22800. bcr = element.getBoundingClientRect();
  22801. rect.left += bcr.left;
  22802. rect.top += bcr.top;
  22803. }
  22804. rect.bottom = rect.top + rect.height;
  22805. rect.right = rect.left + rect.width;
  22806. return rect;
  22807. },
  22808. getViewportRect: function (){
  22809. var viewportEl = uiUtils.getViewportElement();
  22810. var width = (window.innerWidth || viewportEl.clientWidth) | 0;
  22811. var height = (window.innerHeight ||viewportEl.clientHeight) | 0;
  22812. return {
  22813. left: 0,
  22814. top: 0,
  22815. height: height,
  22816. width: width,
  22817. bottom: height,
  22818. right: width
  22819. };
  22820. },
  22821. setViewportOffset: function (element, offset){
  22822. var rect;
  22823. var fixedLayer = uiUtils.getFixedLayer();
  22824. if (element.parentNode === fixedLayer) {
  22825. element.style.left = offset.left + 'px';
  22826. element.style.top = offset.top + 'px';
  22827. } else {
  22828. domUtils.setViewportOffset(element, offset);
  22829. }
  22830. },
  22831. getEventOffset: function (evt){
  22832. var el = evt.target || evt.srcElement;
  22833. var rect = uiUtils.getClientRect(el);
  22834. var offset = uiUtils.getViewportOffsetByEvent(evt);
  22835. return {
  22836. left: offset.left - rect.left,
  22837. top: offset.top - rect.top
  22838. };
  22839. },
  22840. getViewportOffsetByEvent: function (evt){
  22841. var el = evt.target || evt.srcElement;
  22842. var frameEl = domUtils.getWindow(el).frameElement;
  22843. var offset = {
  22844. left: evt.clientX,
  22845. top: evt.clientY
  22846. };
  22847. if (frameEl && el.ownerDocument !== document) {
  22848. var rect = uiUtils.getClientRect(frameEl);
  22849. offset.left += rect.left;
  22850. offset.top += rect.top;
  22851. }
  22852. return offset;
  22853. },
  22854. setGlobal: function (id, obj){
  22855. root[id] = obj;
  22856. return magic + '["' + id + '"]';
  22857. },
  22858. unsetGlobal: function (id){
  22859. delete root[id];
  22860. },
  22861. copyAttributes: function (tgt, src){
  22862. var attributes = src.attributes;
  22863. var k = attributes.length;
  22864. while (k --) {
  22865. var attrNode = attributes[k];
  22866. if ( attrNode.nodeName != 'style' && attrNode.nodeName != 'class' && (!browser.ie || attrNode.specified) ) {
  22867. tgt.setAttribute(attrNode.nodeName, attrNode.nodeValue);
  22868. }
  22869. }
  22870. if (src.className) {
  22871. domUtils.addClass(tgt,src.className);
  22872. }
  22873. if (src.style.cssText) {
  22874. tgt.style.cssText += ';' + src.style.cssText;
  22875. }
  22876. },
  22877. removeStyle: function (el, styleName){
  22878. if (el.style.removeProperty) {
  22879. el.style.removeProperty(styleName);
  22880. } else if (el.style.removeAttribute) {
  22881. el.style.removeAttribute(styleName);
  22882. } else throw '';
  22883. },
  22884. contains: function (elA, elB){
  22885. return elA && elB && (elA === elB ? false : (
  22886. elA.contains ? elA.contains(elB) :
  22887. elA.compareDocumentPosition(elB) & 16
  22888. ));
  22889. },
  22890. startDrag: function (evt, callbacks,doc){
  22891. var doc = doc || document;
  22892. var startX = evt.clientX;
  22893. var startY = evt.clientY;
  22894. function handleMouseMove(evt){
  22895. var x = evt.clientX - startX;
  22896. var y = evt.clientY - startY;
  22897. callbacks.ondragmove(x, y,evt);
  22898. if (evt.stopPropagation) {
  22899. evt.stopPropagation();
  22900. } else {
  22901. evt.cancelBubble = true;
  22902. }
  22903. }
  22904. if (doc.addEventListener) {
  22905. function handleMouseUp(evt){
  22906. doc.removeEventListener('mousemove', handleMouseMove, true);
  22907. doc.removeEventListener('mouseup', handleMouseUp, true);
  22908. window.removeEventListener('mouseup', handleMouseUp, true);
  22909. callbacks.ondragstop();
  22910. }
  22911. doc.addEventListener('mousemove', handleMouseMove, true);
  22912. doc.addEventListener('mouseup', handleMouseUp, true);
  22913. window.addEventListener('mouseup', handleMouseUp, true);
  22914. evt.preventDefault();
  22915. } else {
  22916. var elm = evt.srcElement;
  22917. elm.setCapture();
  22918. function releaseCaptrue(){
  22919. elm.releaseCapture();
  22920. elm.detachEvent('onmousemove', handleMouseMove);
  22921. elm.detachEvent('onmouseup', releaseCaptrue);
  22922. elm.detachEvent('onlosecaptrue', releaseCaptrue);
  22923. callbacks.ondragstop();
  22924. }
  22925. elm.attachEvent('onmousemove', handleMouseMove);
  22926. elm.attachEvent('onmouseup', releaseCaptrue);
  22927. elm.attachEvent('onlosecaptrue', releaseCaptrue);
  22928. evt.returnValue = false;
  22929. }
  22930. callbacks.ondragstart();
  22931. },
  22932. getFixedLayer: function (){
  22933. var layer = document.getElementById('edui_fixedlayer');
  22934. if (layer == null) {
  22935. layer = document.createElement('div');
  22936. layer.id = 'edui_fixedlayer';
  22937. document.body.appendChild(layer);
  22938. if (browser.ie && browser.version <= 8) {
  22939. layer.style.position = 'absolute';
  22940. bindFixedLayer();
  22941. setTimeout(updateFixedOffset);
  22942. } else {
  22943. layer.style.position = 'fixed';
  22944. }
  22945. layer.style.left = '0';
  22946. layer.style.top = '0';
  22947. layer.style.width = '0';
  22948. layer.style.height = '0';
  22949. }
  22950. return layer;
  22951. },
  22952. makeUnselectable: function (element){
  22953. if (browser.opera || (browser.ie && browser.version < 9)) {
  22954. element.unselectable = 'on';
  22955. if (element.hasChildNodes()) {
  22956. for (var i=0; i<element.childNodes.length; i++) {
  22957. if (element.childNodes[i].nodeType == 1) {
  22958. uiUtils.makeUnselectable(element.childNodes[i]);
  22959. }
  22960. }
  22961. }
  22962. } else {
  22963. if (element.style.MozUserSelect !== undefined) {
  22964. element.style.MozUserSelect = 'none';
  22965. } else if (element.style.WebkitUserSelect !== undefined) {
  22966. element.style.WebkitUserSelect = 'none';
  22967. } else if (element.style.KhtmlUserSelect !== undefined) {
  22968. element.style.KhtmlUserSelect = 'none';
  22969. }
  22970. }
  22971. }
  22972. };
  22973. function updateFixedOffset(){
  22974. var layer = document.getElementById('edui_fixedlayer');
  22975. uiUtils.setViewportOffset(layer, {
  22976. left: 0,
  22977. top: 0
  22978. });
  22979. // layer.style.display = 'none';
  22980. // layer.style.display = 'block';
  22981. //#trace: 1354
  22982. // setTimeout(updateFixedOffset);
  22983. }
  22984. function bindFixedLayer(adjOffset){
  22985. domUtils.on(window, 'scroll', updateFixedOffset);
  22986. domUtils.on(window, 'resize', baidu.editor.utils.defer(updateFixedOffset, 0, true));
  22987. }
  22988. })();
  22989. // ui/uibase.js
  22990. (function () {
  22991. var utils = baidu.editor.utils,
  22992. uiUtils = baidu.editor.ui.uiUtils,
  22993. EventBase = baidu.editor.EventBase,
  22994. UIBase = baidu.editor.ui.UIBase = function () {
  22995. };
  22996. UIBase.prototype = {
  22997. className:'',
  22998. uiName:'',
  22999. initOptions:function (options) {
  23000. var me = this;
  23001. for (var k in options) {
  23002. me[k] = options[k];
  23003. }
  23004. this.id = this.id || 'edui' + uiUtils.uid();
  23005. },
  23006. initUIBase:function () {
  23007. this._globalKey = utils.unhtml(uiUtils.setGlobal(this.id, this));
  23008. },
  23009. render:function (holder) {
  23010. var html = this.renderHtml();
  23011. var el = uiUtils.createElementByHtml(html);
  23012. //by xuheng 给每个node添加class
  23013. var list = domUtils.getElementsByTagName(el, "*");
  23014. var theme = "edui-" + (this.theme || this.editor.options.theme);
  23015. var layer = document.getElementById('edui_fixedlayer');
  23016. for (var i = 0, node; node = list[i++];) {
  23017. domUtils.addClass(node, theme);
  23018. }
  23019. domUtils.addClass(el, theme);
  23020. if(layer){
  23021. layer.className="";
  23022. domUtils.addClass(layer,theme);
  23023. }
  23024. var seatEl = this.getDom();
  23025. if (seatEl != null) {
  23026. seatEl.parentNode.replaceChild(el, seatEl);
  23027. uiUtils.copyAttributes(el, seatEl);
  23028. } else {
  23029. if (typeof holder == 'string') {
  23030. holder = document.getElementById(holder);
  23031. }
  23032. holder = holder || uiUtils.getFixedLayer();
  23033. domUtils.addClass(holder, theme);
  23034. holder.appendChild(el);
  23035. }
  23036. this.postRender();
  23037. },
  23038. getDom:function (name) {
  23039. if (!name) {
  23040. return document.getElementById(this.id);
  23041. } else {
  23042. return document.getElementById(this.id + '_' + name);
  23043. }
  23044. },
  23045. postRender:function () {
  23046. this.fireEvent('postrender');
  23047. },
  23048. getHtmlTpl:function () {
  23049. return '';
  23050. },
  23051. formatHtml:function (tpl) {
  23052. var prefix = 'edui-' + this.uiName;
  23053. return (tpl
  23054. .replace(/##/g, this.id)
  23055. .replace(/%%-/g, this.uiName ? prefix + '-' : '')
  23056. .replace(/%%/g, (this.uiName ? prefix : '') + ' ' + this.className)
  23057. .replace(/\$\$/g, this._globalKey));
  23058. },
  23059. renderHtml:function () {
  23060. return this.formatHtml(this.getHtmlTpl());
  23061. },
  23062. dispose:function () {
  23063. var box = this.getDom();
  23064. if (box) baidu.editor.dom.domUtils.remove(box);
  23065. uiUtils.unsetGlobal(this.id);
  23066. }
  23067. };
  23068. utils.inherits(UIBase, EventBase);
  23069. })();
  23070. // ui/separator.js
  23071. (function (){
  23072. var utils = baidu.editor.utils,
  23073. UIBase = baidu.editor.ui.UIBase,
  23074. Separator = baidu.editor.ui.Separator = function (options){
  23075. this.initOptions(options);
  23076. this.initSeparator();
  23077. };
  23078. Separator.prototype = {
  23079. uiName: 'separator',
  23080. initSeparator: function (){
  23081. this.initUIBase();
  23082. },
  23083. getHtmlTpl: function (){
  23084. return '<div id="##" class="edui-box %%"></div>';
  23085. }
  23086. };
  23087. utils.inherits(Separator, UIBase);
  23088. })();
  23089. // ui/mask.js
  23090. ///import core
  23091. ///import uicore
  23092. (function (){
  23093. var utils = baidu.editor.utils,
  23094. domUtils = baidu.editor.dom.domUtils,
  23095. UIBase = baidu.editor.ui.UIBase,
  23096. uiUtils = baidu.editor.ui.uiUtils;
  23097. var Mask = baidu.editor.ui.Mask = function (options){
  23098. this.initOptions(options);
  23099. this.initUIBase();
  23100. };
  23101. Mask.prototype = {
  23102. getHtmlTpl: function (){
  23103. return '<div id="##" class="edui-mask %%" onclick="return $$._onClick(event, this);" onmousedown="return $$._onMouseDown(event, this);"></div>';
  23104. },
  23105. postRender: function (){
  23106. var me = this;
  23107. domUtils.on(window, 'resize', function (){
  23108. setTimeout(function (){
  23109. if (!me.isHidden()) {
  23110. me._fill();
  23111. }
  23112. });
  23113. });
  23114. },
  23115. show: function (zIndex){
  23116. this._fill();
  23117. this.getDom().style.display = '';
  23118. this.getDom().style.zIndex = zIndex;
  23119. },
  23120. hide: function (){
  23121. this.getDom().style.display = 'none';
  23122. this.getDom().style.zIndex = '';
  23123. },
  23124. isHidden: function (){
  23125. return this.getDom().style.display == 'none';
  23126. },
  23127. _onMouseDown: function (){
  23128. return false;
  23129. },
  23130. _onClick: function (e, target){
  23131. this.fireEvent('click', e, target);
  23132. },
  23133. _fill: function (){
  23134. var el = this.getDom();
  23135. var vpRect = uiUtils.getViewportRect();
  23136. el.style.width = vpRect.width + 'px';
  23137. el.style.height = vpRect.height + 'px';
  23138. }
  23139. };
  23140. utils.inherits(Mask, UIBase);
  23141. })();
  23142. // ui/popup.js
  23143. ///import core
  23144. ///import uicore
  23145. (function () {
  23146. var utils = baidu.editor.utils,
  23147. uiUtils = baidu.editor.ui.uiUtils,
  23148. domUtils = baidu.editor.dom.domUtils,
  23149. UIBase = baidu.editor.ui.UIBase,
  23150. Popup = baidu.editor.ui.Popup = function (options){
  23151. this.initOptions(options);
  23152. this.initPopup();
  23153. };
  23154. var allPopups = [];
  23155. function closeAllPopup( evt,el ){
  23156. for ( var i = 0; i < allPopups.length; i++ ) {
  23157. var pop = allPopups[i];
  23158. if (!pop.isHidden()) {
  23159. if (pop.queryAutoHide(el) !== false) {
  23160. if(evt&&/scroll/ig.test(evt.type)&&pop.className=="edui-wordpastepop") return;
  23161. pop.hide();
  23162. }
  23163. }
  23164. }
  23165. if(allPopups.length)
  23166. pop.editor.fireEvent("afterhidepop");
  23167. }
  23168. Popup.postHide = closeAllPopup;
  23169. var ANCHOR_CLASSES = ['edui-anchor-topleft','edui-anchor-topright',
  23170. 'edui-anchor-bottomleft','edui-anchor-bottomright'];
  23171. Popup.prototype = {
  23172. SHADOW_RADIUS: 5,
  23173. content: null,
  23174. _hidden: false,
  23175. autoRender: true,
  23176. canSideLeft: true,
  23177. canSideUp: true,
  23178. initPopup: function (){
  23179. this.initUIBase();
  23180. allPopups.push( this );
  23181. },
  23182. getHtmlTpl: function (){
  23183. return '<div id="##" class="edui-popup %%" onmousedown="return false;">' +
  23184. ' <div id="##_body" class="edui-popup-body">' +
  23185. ' <iframe style="position:absolute;z-index:-1;left:0;top:0;background-color: transparent;" frameborder="0" width="100%" height="100%" src="about:blank"></iframe>' +
  23186. ' <div class="edui-shadow"></div>' +
  23187. ' <div id="##_content" class="edui-popup-content">' +
  23188. this.getContentHtmlTpl() +
  23189. ' </div>' +
  23190. ' </div>' +
  23191. '</div>';
  23192. },
  23193. getContentHtmlTpl: function (){
  23194. if(this.content){
  23195. if (typeof this.content == 'string') {
  23196. return this.content;
  23197. }
  23198. return this.content.renderHtml();
  23199. }else{
  23200. return ''
  23201. }
  23202. },
  23203. _UIBase_postRender: UIBase.prototype.postRender,
  23204. postRender: function (){
  23205. if (this.content instanceof UIBase) {
  23206. this.content.postRender();
  23207. }
  23208. //捕获鼠标滚轮
  23209. if( this.captureWheel && !this.captured ) {
  23210. this.captured = true;
  23211. var winHeight = ( document.documentElement.clientHeight || document.body.clientHeight ) - 80,
  23212. _height = this.getDom().offsetHeight,
  23213. _top = uiUtils.getClientRect( this.combox.getDom() ).top,
  23214. content = this.getDom('content'),
  23215. ifr = this.getDom('body').getElementsByTagName('iframe'),
  23216. me = this;
  23217. ifr.length && ( ifr = ifr[0] );
  23218. while( _top + _height > winHeight ) {
  23219. _height -= 30;
  23220. }
  23221. content.style.height = _height + 'px';
  23222. //同步更改iframe高度
  23223. ifr && ( ifr.style.height = _height + 'px' );
  23224. //阻止在combox上的鼠标滚轮事件, 防止用户的正常操作被误解
  23225. if( window.XMLHttpRequest ) {
  23226. domUtils.on( content, ( 'onmousewheel' in document.body ) ? 'mousewheel' :'DOMMouseScroll' , function(e){
  23227. if(e.preventDefault) {
  23228. e.preventDefault();
  23229. } else {
  23230. e.returnValue = false;
  23231. }
  23232. if( e.wheelDelta ) {
  23233. content.scrollTop -= ( e.wheelDelta / 120 )*60;
  23234. } else {
  23235. content.scrollTop -= ( e.detail / -3 )*60;
  23236. }
  23237. });
  23238. } else {
  23239. //ie6
  23240. domUtils.on( this.getDom(), 'mousewheel' , function(e){
  23241. e.returnValue = false;
  23242. me.getDom('content').scrollTop -= ( e.wheelDelta / 120 )*60;
  23243. });
  23244. }
  23245. }
  23246. this.fireEvent('postRenderAfter');
  23247. this.hide(true);
  23248. this._UIBase_postRender();
  23249. },
  23250. _doAutoRender: function (){
  23251. if (!this.getDom() && this.autoRender) {
  23252. this.render();
  23253. }
  23254. },
  23255. mesureSize: function (){
  23256. var box = this.getDom('content');
  23257. return uiUtils.getClientRect(box);
  23258. },
  23259. fitSize: function (){
  23260. if( this.captureWheel && this.sized ) {
  23261. return this.__size;
  23262. }
  23263. this.sized = true;
  23264. var popBodyEl = this.getDom('body');
  23265. popBodyEl.style.width = '';
  23266. popBodyEl.style.height = '';
  23267. var size = this.mesureSize();
  23268. if( this.captureWheel ) {
  23269. popBodyEl.style.width = -(-20 -size.width) + 'px';
  23270. var height = parseInt( this.getDom('content').style.height, 10 );
  23271. !window.isNaN( height ) && ( size.height = height );
  23272. } else {
  23273. popBodyEl.style.width = size.width + 'px';
  23274. }
  23275. popBodyEl.style.height = size.height + 'px';
  23276. this.__size = size;
  23277. this.captureWheel && (this.getDom('content').style.overflow = 'auto');
  23278. return size;
  23279. },
  23280. showAnchor: function ( element, hoz ){
  23281. this.showAnchorRect( uiUtils.getClientRect( element ), hoz );
  23282. },
  23283. showAnchorRect: function ( rect, hoz, adj ){
  23284. this._doAutoRender();
  23285. var vpRect = uiUtils.getViewportRect();
  23286. this.getDom().style.visibility = 'hidden';
  23287. this._show();
  23288. var popSize = this.fitSize();
  23289. var sideLeft, sideUp, left, top;
  23290. if (hoz) {
  23291. sideLeft = this.canSideLeft && (rect.right + popSize.width > vpRect.right && rect.left > popSize.width);
  23292. sideUp = this.canSideUp && (rect.top + popSize.height > vpRect.bottom && rect.bottom > popSize.height);
  23293. left = (sideLeft ? rect.left - popSize.width : rect.right);
  23294. top = (sideUp ? rect.bottom - popSize.height : rect.top);
  23295. } else {
  23296. sideLeft = this.canSideLeft && (rect.right + popSize.width > vpRect.right && rect.left > popSize.width);
  23297. sideUp = this.canSideUp && (rect.top + popSize.height > vpRect.bottom && rect.bottom > popSize.height);
  23298. left = (sideLeft ? rect.right - popSize.width : rect.left);
  23299. top = (sideUp ? rect.top - popSize.height : rect.bottom);
  23300. }
  23301. var popEl = this.getDom();
  23302. uiUtils.setViewportOffset(popEl, {
  23303. left: left,
  23304. top: top
  23305. });
  23306. domUtils.removeClasses(popEl, ANCHOR_CLASSES);
  23307. popEl.className += ' ' + ANCHOR_CLASSES[(sideUp ? 1 : 0) * 2 + (sideLeft ? 1 : 0)];
  23308. if(this.editor){
  23309. popEl.style.zIndex = this.editor.container.style.zIndex * 1 + 10;
  23310. baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex = popEl.style.zIndex - 1;
  23311. }
  23312. this.getDom().style.visibility = 'visible';
  23313. },
  23314. showAt: function (offset) {
  23315. var left = offset.left;
  23316. var top = offset.top;
  23317. var rect = {
  23318. left: left,
  23319. top: top,
  23320. right: left,
  23321. bottom: top,
  23322. height: 0,
  23323. width: 0
  23324. };
  23325. this.showAnchorRect(rect, false, true);
  23326. },
  23327. _show: function (){
  23328. if (this._hidden) {
  23329. var box = this.getDom();
  23330. box.style.display = '';
  23331. this._hidden = false;
  23332. // if (box.setActive) {
  23333. // box.setActive();
  23334. // }
  23335. this.fireEvent('show');
  23336. }
  23337. },
  23338. isHidden: function (){
  23339. return this._hidden;
  23340. },
  23341. show: function (){
  23342. this._doAutoRender();
  23343. this._show();
  23344. },
  23345. hide: function (notNofity){
  23346. if (!this._hidden && this.getDom()) {
  23347. this.getDom().style.display = 'none';
  23348. this._hidden = true;
  23349. if (!notNofity) {
  23350. this.fireEvent('hide');
  23351. }
  23352. }
  23353. },
  23354. queryAutoHide: function (el){
  23355. return !el || !uiUtils.contains(this.getDom(), el);
  23356. }
  23357. };
  23358. utils.inherits(Popup, UIBase);
  23359. domUtils.on( document, 'mousedown', function ( evt ) {
  23360. var el = evt.target || evt.srcElement;
  23361. closeAllPopup( evt,el );
  23362. } );
  23363. domUtils.on( window, 'scroll', function (evt,el) {
  23364. closeAllPopup( evt,el );
  23365. } );
  23366. })();
  23367. // ui/colorpicker.js
  23368. ///import core
  23369. ///import uicore
  23370. (function (){
  23371. var utils = baidu.editor.utils,
  23372. UIBase = baidu.editor.ui.UIBase,
  23373. ColorPicker = baidu.editor.ui.ColorPicker = function (options){
  23374. this.initOptions(options);
  23375. this.noColorText = this.noColorText || this.editor.getLang("clearColor");
  23376. this.initUIBase();
  23377. };
  23378. ColorPicker.prototype = {
  23379. getHtmlTpl: function (){
  23380. return genColorPicker(this.noColorText,this.editor);
  23381. },
  23382. _onTableClick: function (evt){
  23383. var tgt = evt.target || evt.srcElement;
  23384. var color = tgt.getAttribute('data-color');
  23385. if (color) {
  23386. this.fireEvent('pickcolor', color);
  23387. }
  23388. },
  23389. _onTableOver: function (evt){
  23390. var tgt = evt.target || evt.srcElement;
  23391. var color = tgt.getAttribute('data-color');
  23392. if (color) {
  23393. this.getDom('preview').style.backgroundColor = color;
  23394. }
  23395. },
  23396. _onTableOut: function (){
  23397. this.getDom('preview').style.backgroundColor = '';
  23398. },
  23399. _onPickNoColor: function (){
  23400. this.fireEvent('picknocolor');
  23401. }
  23402. };
  23403. utils.inherits(ColorPicker, UIBase);
  23404. var COLORS = (
  23405. 'ffffff,000000,eeece1,1f497d,4f81bd,c0504d,9bbb59,8064a2,4bacc6,f79646,' +
  23406. 'f2f2f2,7f7f7f,ddd9c3,c6d9f0,dbe5f1,f2dcdb,ebf1dd,e5e0ec,dbeef3,fdeada,' +
  23407. 'd8d8d8,595959,c4bd97,8db3e2,b8cce4,e5b9b7,d7e3bc,ccc1d9,b7dde8,fbd5b5,' +
  23408. 'bfbfbf,3f3f3f,938953,548dd4,95b3d7,d99694,c3d69b,b2a2c7,92cddc,fac08f,' +
  23409. 'a5a5a5,262626,494429,17365d,366092,953734,76923c,5f497a,31859b,e36c09,' +
  23410. '7f7f7f,0c0c0c,1d1b10,0f243e,244061,632423,4f6128,3f3151,205867,974806,' +
  23411. 'c00000,ff0000,ffc000,ffff00,92d050,00b050,00b0f0,0070c0,002060,7030a0,').split(',');
  23412. function genColorPicker(noColorText,editor){
  23413. var html = '<div id="##" class="edui-colorpicker %%">' +
  23414. '<div class="edui-colorpicker-topbar edui-clearfix">' +
  23415. '<div unselectable="on" id="##_preview" class="edui-colorpicker-preview"></div>' +
  23416. '<div unselectable="on" class="edui-colorpicker-nocolor" onclick="$$._onPickNoColor(event, this);">'+ noColorText +'</div>' +
  23417. '</div>' +
  23418. '<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">' +
  23419. '<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>'+
  23420. '<tr class="edui-colorpicker-tablefirstrow" >';
  23421. for (var i=0; i<COLORS.length; i++) {
  23422. if (i && i%10 === 0) {
  23423. 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"':'')+'>';
  23424. }
  23425. 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"' +
  23426. ' data-color="#'+ COLORS[i] +'"'+
  23427. ' style="background-color:#'+ COLORS[i] +';border:solid #ccc;'+
  23428. (i<10 || i>=60?'border-width:1px;':
  23429. i>=10&&i<20?'border-width:1px 1px 0 1px;':
  23430. 'border-width:0 1px 0 1px;')+
  23431. '"' +
  23432. '></a></td>':'';
  23433. }
  23434. html += '</tr></table></div>';
  23435. return html;
  23436. }
  23437. })();
  23438. // ui/tablepicker.js
  23439. ///import core
  23440. ///import uicore
  23441. (function (){
  23442. var utils = baidu.editor.utils,
  23443. uiUtils = baidu.editor.ui.uiUtils,
  23444. UIBase = baidu.editor.ui.UIBase;
  23445. var TablePicker = baidu.editor.ui.TablePicker = function (options){
  23446. this.initOptions(options);
  23447. this.initTablePicker();
  23448. };
  23449. TablePicker.prototype = {
  23450. defaultNumRows: 10,
  23451. defaultNumCols: 10,
  23452. maxNumRows: 20,
  23453. maxNumCols: 20,
  23454. numRows: 10,
  23455. numCols: 10,
  23456. lengthOfCellSide: 22,
  23457. initTablePicker: function (){
  23458. this.initUIBase();
  23459. },
  23460. getHtmlTpl: function (){
  23461. var me = this;
  23462. return '<div id="##" class="edui-tablepicker %%">' +
  23463. '<div class="edui-tablepicker-body">' +
  23464. '<div class="edui-infoarea">' +
  23465. '<span id="##_label" class="edui-label"></span>' +
  23466. '</div>' +
  23467. '<div class="edui-pickarea"' +
  23468. ' onmousemove="$$._onMouseMove(event, this);"' +
  23469. ' onmouseover="$$._onMouseOver(event, this);"' +
  23470. ' onmouseout="$$._onMouseOut(event, this);"' +
  23471. ' onclick="$$._onClick(event, this);"' +
  23472. '>' +
  23473. '<div id="##_overlay" class="edui-overlay"></div>' +
  23474. '</div>' +
  23475. '</div>' +
  23476. '</div>';
  23477. },
  23478. _UIBase_render: UIBase.prototype.render,
  23479. render: function (holder){
  23480. this._UIBase_render(holder);
  23481. this.getDom('label').innerHTML = '0'+this.editor.getLang("t_row")+' x 0'+this.editor.getLang("t_col");
  23482. },
  23483. _track: function (numCols, numRows){
  23484. var style = this.getDom('overlay').style;
  23485. var sideLen = this.lengthOfCellSide;
  23486. style.width = numCols * sideLen + 'px';
  23487. style.height = numRows * sideLen + 'px';
  23488. var label = this.getDom('label');
  23489. label.innerHTML = numCols +this.editor.getLang("t_col")+' x ' + numRows + this.editor.getLang("t_row");
  23490. this.numCols = numCols;
  23491. this.numRows = numRows;
  23492. },
  23493. _onMouseOver: function (evt, el){
  23494. var rel = evt.relatedTarget || evt.fromElement;
  23495. if (!uiUtils.contains(el, rel) && el !== rel) {
  23496. this.getDom('label').innerHTML = '0'+this.editor.getLang("t_col")+' x 0'+this.editor.getLang("t_row");
  23497. this.getDom('overlay').style.visibility = '';
  23498. }
  23499. },
  23500. _onMouseOut: function (evt, el){
  23501. var rel = evt.relatedTarget || evt.toElement;
  23502. if (!uiUtils.contains(el, rel) && el !== rel) {
  23503. this.getDom('label').innerHTML = '0'+this.editor.getLang("t_col")+' x 0'+this.editor.getLang("t_row");
  23504. this.getDom('overlay').style.visibility = 'hidden';
  23505. }
  23506. },
  23507. _onMouseMove: function (evt, el){
  23508. var style = this.getDom('overlay').style;
  23509. var offset = uiUtils.getEventOffset(evt);
  23510. var sideLen = this.lengthOfCellSide;
  23511. var numCols = Math.ceil(offset.left / sideLen);
  23512. var numRows = Math.ceil(offset.top / sideLen);
  23513. this._track(numCols, numRows);
  23514. },
  23515. _onClick: function (){
  23516. this.fireEvent('picktable', this.numCols, this.numRows);
  23517. }
  23518. };
  23519. utils.inherits(TablePicker, UIBase);
  23520. })();
  23521. // ui/stateful.js
  23522. (function (){
  23523. var browser = baidu.editor.browser,
  23524. domUtils = baidu.editor.dom.domUtils,
  23525. uiUtils = baidu.editor.ui.uiUtils;
  23526. var TPL_STATEFUL = 'onmousedown="$$.Stateful_onMouseDown(event, this);"' +
  23527. ' onmouseup="$$.Stateful_onMouseUp(event, this);"' +
  23528. ( browser.ie ? (
  23529. ' onmouseenter="$$.Stateful_onMouseEnter(event, this);"' +
  23530. ' onmouseleave="$$.Stateful_onMouseLeave(event, this);"' )
  23531. : (
  23532. ' onmouseover="$$.Stateful_onMouseOver(event, this);"' +
  23533. ' onmouseout="$$.Stateful_onMouseOut(event, this);"' ));
  23534. baidu.editor.ui.Stateful = {
  23535. alwalysHoverable: false,
  23536. target:null,//目标元素和this指向dom不一样
  23537. Stateful_init: function (){
  23538. this._Stateful_dGetHtmlTpl = this.getHtmlTpl;
  23539. this.getHtmlTpl = this.Stateful_getHtmlTpl;
  23540. },
  23541. Stateful_getHtmlTpl: function (){
  23542. var tpl = this._Stateful_dGetHtmlTpl();
  23543. // 使用function避免$转义
  23544. return tpl.replace(/stateful/g, function (){ return TPL_STATEFUL; });
  23545. },
  23546. Stateful_onMouseEnter: function (evt, el){
  23547. this.target=el;
  23548. if (!this.isDisabled() || this.alwalysHoverable) {
  23549. this.addState('hover');
  23550. this.fireEvent('over');
  23551. }
  23552. },
  23553. Stateful_onMouseLeave: function (evt, el){
  23554. if (!this.isDisabled() || this.alwalysHoverable) {
  23555. this.removeState('hover');
  23556. this.removeState('active');
  23557. this.fireEvent('out');
  23558. }
  23559. },
  23560. Stateful_onMouseOver: function (evt, el){
  23561. var rel = evt.relatedTarget;
  23562. if (!uiUtils.contains(el, rel) && el !== rel) {
  23563. this.Stateful_onMouseEnter(evt, el);
  23564. }
  23565. },
  23566. Stateful_onMouseOut: function (evt, el){
  23567. var rel = evt.relatedTarget;
  23568. if (!uiUtils.contains(el, rel) && el !== rel) {
  23569. this.Stateful_onMouseLeave(evt, el);
  23570. }
  23571. },
  23572. Stateful_onMouseDown: function (evt, el){
  23573. if (!this.isDisabled()) {
  23574. this.addState('active');
  23575. }
  23576. },
  23577. Stateful_onMouseUp: function (evt, el){
  23578. if (!this.isDisabled()) {
  23579. this.removeState('active');
  23580. }
  23581. },
  23582. Stateful_postRender: function (){
  23583. if (this.disabled && !this.hasState('disabled')) {
  23584. this.addState('disabled');
  23585. }
  23586. },
  23587. hasState: function (state){
  23588. return domUtils.hasClass(this.getStateDom(), 'edui-state-' + state);
  23589. },
  23590. addState: function (state){
  23591. if (!this.hasState(state)) {
  23592. this.getStateDom().className += ' edui-state-' + state;
  23593. }
  23594. },
  23595. removeState: function (state){
  23596. if (this.hasState(state)) {
  23597. domUtils.removeClasses(this.getStateDom(), ['edui-state-' + state]);
  23598. }
  23599. },
  23600. getStateDom: function (){
  23601. return this.getDom('state');
  23602. },
  23603. isChecked: function (){
  23604. return this.hasState('checked');
  23605. },
  23606. setChecked: function (checked){
  23607. if (!this.isDisabled() && checked) {
  23608. this.addState('checked');
  23609. } else {
  23610. this.removeState('checked');
  23611. }
  23612. },
  23613. isDisabled: function (){
  23614. return this.hasState('disabled');
  23615. },
  23616. setDisabled: function (disabled){
  23617. if (disabled) {
  23618. this.removeState('hover');
  23619. this.removeState('checked');
  23620. this.removeState('active');
  23621. this.addState('disabled');
  23622. } else {
  23623. this.removeState('disabled');
  23624. }
  23625. }
  23626. };
  23627. })();
  23628. // ui/button.js
  23629. ///import core
  23630. ///import uicore
  23631. ///import ui/stateful.js
  23632. (function (){
  23633. var utils = baidu.editor.utils,
  23634. UIBase = baidu.editor.ui.UIBase,
  23635. Stateful = baidu.editor.ui.Stateful,
  23636. Button = baidu.editor.ui.Button = function (options){
  23637. if(options.name){
  23638. var btnName = options.name;
  23639. var cssRules = options.cssRules;
  23640. if(!options.className){
  23641. options.className = 'edui-for-' + btnName;
  23642. }
  23643. options.cssRules = '.edui-default .edui-for-'+ btnName +' .edui-icon {'+ cssRules +'}'
  23644. }
  23645. this.initOptions(options);
  23646. this.initButton();
  23647. };
  23648. Button.prototype = {
  23649. uiName: 'button',
  23650. label: '',
  23651. title: '',
  23652. showIcon: true,
  23653. showText: true,
  23654. cssRules:'',
  23655. initButton: function (){
  23656. this.initUIBase();
  23657. this.Stateful_init();
  23658. if(this.cssRules){
  23659. utils.cssRule('edui-customize-'+this.name+'-style',this.cssRules);
  23660. }
  23661. },
  23662. getHtmlTpl: function (){
  23663. return '<div id="##" class="edui-box %%">' +
  23664. '<div id="##_state" stateful>' +
  23665. '<div class="%%-wrap"><div id="##_body" unselectable="on" ' + (this.title ? 'title="' + this.title + '"' : '') +
  23666. ' class="%%-body" onmousedown="return $$._onMouseDown(event, this);" onclick="return $$._onClick(event, this);">' +
  23667. (this.showIcon ? '<div class="edui-box edui-icon"></div>' : '') +
  23668. (this.showText ? '<div class="edui-box edui-label">' + this.label + '</div>' : '') +
  23669. '</div>' +
  23670. '</div>' +
  23671. '</div></div>';
  23672. },
  23673. postRender: function (){
  23674. this.Stateful_postRender();
  23675. this.setDisabled(this.disabled)
  23676. },
  23677. _onMouseDown: function (e){
  23678. var target = e.target || e.srcElement,
  23679. tagName = target && target.tagName && target.tagName.toLowerCase();
  23680. if (tagName == 'input' || tagName == 'object' || tagName == 'object') {
  23681. return false;
  23682. }
  23683. },
  23684. _onClick: function (){
  23685. if (!this.isDisabled()) {
  23686. this.fireEvent('click');
  23687. }
  23688. },
  23689. setTitle: function(text){
  23690. var label = this.getDom('label');
  23691. label.innerHTML = text;
  23692. }
  23693. };
  23694. utils.inherits(Button, UIBase);
  23695. utils.extend(Button.prototype, Stateful);
  23696. })();
  23697. // ui/splitbutton.js
  23698. ///import core
  23699. ///import uicore
  23700. ///import ui/stateful.js
  23701. (function (){
  23702. var utils = baidu.editor.utils,
  23703. uiUtils = baidu.editor.ui.uiUtils,
  23704. domUtils = baidu.editor.dom.domUtils,
  23705. UIBase = baidu.editor.ui.UIBase,
  23706. Stateful = baidu.editor.ui.Stateful,
  23707. SplitButton = baidu.editor.ui.SplitButton = function (options){
  23708. this.initOptions(options);
  23709. this.initSplitButton();
  23710. };
  23711. SplitButton.prototype = {
  23712. popup: null,
  23713. uiName: 'splitbutton',
  23714. title: '',
  23715. initSplitButton: function (){
  23716. this.initUIBase();
  23717. this.Stateful_init();
  23718. var me = this;
  23719. if (this.popup != null) {
  23720. var popup = this.popup;
  23721. this.popup = null;
  23722. this.setPopup(popup);
  23723. }
  23724. },
  23725. _UIBase_postRender: UIBase.prototype.postRender,
  23726. postRender: function (){
  23727. this.Stateful_postRender();
  23728. this._UIBase_postRender();
  23729. },
  23730. setPopup: function (popup){
  23731. if (this.popup === popup) return;
  23732. if (this.popup != null) {
  23733. this.popup.dispose();
  23734. }
  23735. popup.addListener('show', utils.bind(this._onPopupShow, this));
  23736. popup.addListener('hide', utils.bind(this._onPopupHide, this));
  23737. popup.addListener('postrender', utils.bind(function (){
  23738. popup.getDom('body').appendChild(
  23739. uiUtils.createElementByHtml('<div id="' +
  23740. this.popup.id + '_bordereraser" class="edui-bordereraser edui-background" style="width:' +
  23741. (uiUtils.getClientRect(this.getDom()).width + 20) + 'px"></div>')
  23742. );
  23743. popup.getDom().className += ' ' + this.className;
  23744. }, this));
  23745. this.popup = popup;
  23746. },
  23747. _onPopupShow: function (){
  23748. this.addState('opened');
  23749. },
  23750. _onPopupHide: function (){
  23751. this.removeState('opened');
  23752. },
  23753. getHtmlTpl: function (){
  23754. return '<div id="##" class="edui-box %%">' +
  23755. '<div '+ (this.title ? 'title="' + this.title + '"' : '') +' id="##_state" stateful><div class="%%-body">' +
  23756. '<div id="##_button_body" class="edui-box edui-button-body" onclick="$$._onButtonClick(event, this);">' +
  23757. '<div class="edui-box edui-icon"></div>' +
  23758. '</div>' +
  23759. '<div class="edui-box edui-splitborder"></div>' +
  23760. '<div class="edui-box edui-arrow" onclick="$$._onArrowClick();"></div>' +
  23761. '</div></div></div>';
  23762. },
  23763. showPopup: function (){
  23764. // 当popup往上弹出的时候,做特殊处理
  23765. var rect = uiUtils.getClientRect(this.getDom());
  23766. rect.top -= this.popup.SHADOW_RADIUS;
  23767. rect.height += this.popup.SHADOW_RADIUS;
  23768. this.popup.showAnchorRect(rect);
  23769. },
  23770. _onArrowClick: function (event, el){
  23771. if (!this.isDisabled()) {
  23772. this.showPopup();
  23773. }
  23774. },
  23775. _onButtonClick: function (){
  23776. if (!this.isDisabled()) {
  23777. this.fireEvent('buttonclick');
  23778. }
  23779. }
  23780. };
  23781. utils.inherits(SplitButton, UIBase);
  23782. utils.extend(SplitButton.prototype, Stateful, true);
  23783. })();
  23784. // ui/colorbutton.js
  23785. ///import core
  23786. ///import uicore
  23787. ///import ui/colorpicker.js
  23788. ///import ui/popup.js
  23789. ///import ui/splitbutton.js
  23790. (function (){
  23791. var utils = baidu.editor.utils,
  23792. uiUtils = baidu.editor.ui.uiUtils,
  23793. ColorPicker = baidu.editor.ui.ColorPicker,
  23794. Popup = baidu.editor.ui.Popup,
  23795. SplitButton = baidu.editor.ui.SplitButton,
  23796. ColorButton = baidu.editor.ui.ColorButton = function (options){
  23797. this.initOptions(options);
  23798. this.initColorButton();
  23799. };
  23800. ColorButton.prototype = {
  23801. initColorButton: function (){
  23802. var me = this;
  23803. this.popup = new Popup({
  23804. content: new ColorPicker({
  23805. noColorText: me.editor.getLang("clearColor"),
  23806. editor:me.editor,
  23807. onpickcolor: function (t, color){
  23808. me._onPickColor(color);
  23809. },
  23810. onpicknocolor: function (t, color){
  23811. me._onPickNoColor(color);
  23812. }
  23813. }),
  23814. editor:me.editor
  23815. });
  23816. this.initSplitButton();
  23817. },
  23818. _SplitButton_postRender: SplitButton.prototype.postRender,
  23819. postRender: function (){
  23820. this._SplitButton_postRender();
  23821. this.getDom('button_body').appendChild(
  23822. uiUtils.createElementByHtml('<div id="' + this.id + '_colorlump" class="edui-colorlump"></div>')
  23823. );
  23824. this.getDom().className += ' edui-colorbutton';
  23825. },
  23826. setColor: function (color){
  23827. this.getDom('colorlump').style.backgroundColor = color;
  23828. this.color = color;
  23829. },
  23830. _onPickColor: function (color){
  23831. if (this.fireEvent('pickcolor', color) !== false) {
  23832. this.setColor(color);
  23833. this.popup.hide();
  23834. }
  23835. },
  23836. _onPickNoColor: function (color){
  23837. if (this.fireEvent('picknocolor') !== false) {
  23838. this.popup.hide();
  23839. }
  23840. }
  23841. };
  23842. utils.inherits(ColorButton, SplitButton);
  23843. })();
  23844. // ui/tablebutton.js
  23845. ///import core
  23846. ///import uicore
  23847. ///import ui/popup.js
  23848. ///import ui/tablepicker.js
  23849. ///import ui/splitbutton.js
  23850. (function (){
  23851. var utils = baidu.editor.utils,
  23852. Popup = baidu.editor.ui.Popup,
  23853. TablePicker = baidu.editor.ui.TablePicker,
  23854. SplitButton = baidu.editor.ui.SplitButton,
  23855. TableButton = baidu.editor.ui.TableButton = function (options){
  23856. this.initOptions(options);
  23857. this.initTableButton();
  23858. };
  23859. TableButton.prototype = {
  23860. initTableButton: function (){
  23861. var me = this;
  23862. this.popup = new Popup({
  23863. content: new TablePicker({
  23864. editor:me.editor,
  23865. onpicktable: function (t, numCols, numRows){
  23866. me._onPickTable(numCols, numRows);
  23867. }
  23868. }),
  23869. 'editor':me.editor
  23870. });
  23871. this.initSplitButton();
  23872. },
  23873. _onPickTable: function (numCols, numRows){
  23874. if (this.fireEvent('picktable', numCols, numRows) !== false) {
  23875. this.popup.hide();
  23876. }
  23877. }
  23878. };
  23879. utils.inherits(TableButton, SplitButton);
  23880. })();
  23881. // ui/autotypesetpicker.js
  23882. ///import core
  23883. ///import uicore
  23884. (function () {
  23885. var utils = baidu.editor.utils,
  23886. UIBase = baidu.editor.ui.UIBase;
  23887. var AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker = function (options) {
  23888. this.initOptions(options);
  23889. this.initAutoTypeSetPicker();
  23890. };
  23891. AutoTypeSetPicker.prototype = {
  23892. initAutoTypeSetPicker:function () {
  23893. this.initUIBase();
  23894. },
  23895. getHtmlTpl:function () {
  23896. var me = this.editor,
  23897. opt = me.options.autotypeset,
  23898. lang = me.getLang("autoTypeSet");
  23899. var textAlignInputName = 'textAlignValue' + me.uid,
  23900. imageBlockInputName = 'imageBlockLineValue' + me.uid,
  23901. symbolConverInputName = 'symbolConverValue' + me.uid;
  23902. return '<div id="##" class="edui-autotypesetpicker %%">' +
  23903. '<div class="edui-autotypesetpicker-body">' +
  23904. '<table >' +
  23905. '<tr><td nowrap><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>' +
  23906. '<tr><td nowrap><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>' +
  23907. '<tr>' +
  23908. '<td nowrap><input type="checkbox" name="textAlign" ' + (opt["textAlign"] ? "checked" : "" ) + '>' + lang.alignment + '</td>' +
  23909. '<td colspan="2" id="' + textAlignInputName + '">' +
  23910. '<input type="radio" name="'+ textAlignInputName +'" value="left" ' + ((opt["textAlign"] && opt["textAlign"] == "left") ? "checked" : "") + '>' + me.getLang("justifyleft") +
  23911. '<input type="radio" name="'+ textAlignInputName +'" value="center" ' + ((opt["textAlign"] && opt["textAlign"] == "center") ? "checked" : "") + '>' + me.getLang("justifycenter") +
  23912. '<input type="radio" name="'+ textAlignInputName +'" value="right" ' + ((opt["textAlign"] && opt["textAlign"] == "right") ? "checked" : "") + '>' + me.getLang("justifyright") +
  23913. '</td>' +
  23914. '</tr>' +
  23915. '<tr>' +
  23916. '<td nowrap><input type="checkbox" name="imageBlockLine" ' + (opt["imageBlockLine"] ? "checked" : "" ) + '>' + lang.imageFloat + '</td>' +
  23917. '<td nowrap id="'+ imageBlockInputName +'">' +
  23918. '<input type="radio" name="'+ imageBlockInputName +'" value="none" ' + ((opt["imageBlockLine"] && opt["imageBlockLine"] == "none") ? "checked" : "") + '>' + me.getLang("default") +
  23919. '<input type="radio" name="'+ imageBlockInputName +'" value="left" ' + ((opt["imageBlockLine"] && opt["imageBlockLine"] == "left") ? "checked" : "") + '>' + me.getLang("justifyleft") +
  23920. '<input type="radio" name="'+ imageBlockInputName +'" value="center" ' + ((opt["imageBlockLine"] && opt["imageBlockLine"] == "center") ? "checked" : "") + '>' + me.getLang("justifycenter") +
  23921. '<input type="radio" name="'+ imageBlockInputName +'" value="right" ' + ((opt["imageBlockLine"] && opt["imageBlockLine"] == "right") ? "checked" : "") + '>' + me.getLang("justifyright") +
  23922. '</td>' +
  23923. '</tr>' +
  23924. '<tr><td nowrap><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>' +
  23925. '<tr><td nowrap colspan="3"><input type="checkbox" name="removeEmptyNode" ' + (opt["removeEmptyNode"] ? "checked" : "" ) + '>' + lang.removeHtml + '</td></tr>' +
  23926. '<tr><td nowrap colspan="3"><input type="checkbox" name="pasteFilter" ' + (opt["pasteFilter"] ? "checked" : "" ) + '>' + lang.pasteFilter + '</td></tr>' +
  23927. '<tr>' +
  23928. '<td nowrap><input type="checkbox" name="symbolConver" ' + (opt["bdc2sb"] || opt["tobdc"] ? "checked" : "" ) + '>' + lang.symbol + '</td>' +
  23929. '<td id="' + symbolConverInputName + '">' +
  23930. '<input type="radio" name="bdc" value="bdc2sb" ' + (opt["bdc2sb"] ? "checked" : "" ) + '>' + lang.bdc2sb +
  23931. '<input type="radio" name="bdc" value="tobdc" ' + (opt["tobdc"] ? "checked" : "" ) + '>' + lang.tobdc + '' +
  23932. '</td>' +
  23933. '<td nowrap align="right"><button >' + lang.run + '</button></td>' +
  23934. '</tr>' +
  23935. '</table>' +
  23936. '</div>' +
  23937. '</div>';
  23938. },
  23939. _UIBase_render:UIBase.prototype.render
  23940. };
  23941. utils.inherits(AutoTypeSetPicker, UIBase);
  23942. })();
  23943. // ui/autotypesetbutton.js
  23944. ///import core
  23945. ///import uicore
  23946. ///import ui/popup.js
  23947. ///import ui/autotypesetpicker.js
  23948. ///import ui/splitbutton.js
  23949. (function (){
  23950. var utils = baidu.editor.utils,
  23951. Popup = baidu.editor.ui.Popup,
  23952. AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker,
  23953. SplitButton = baidu.editor.ui.SplitButton,
  23954. AutoTypeSetButton = baidu.editor.ui.AutoTypeSetButton = function (options){
  23955. this.initOptions(options);
  23956. this.initAutoTypeSetButton();
  23957. };
  23958. function getPara(me){
  23959. var opt = {},
  23960. cont = me.getDom(),
  23961. editorId = me.editor.uid,
  23962. inputType = null,
  23963. attrName = null,
  23964. ipts = domUtils.getElementsByTagName(cont,"input");
  23965. for(var i=ipts.length-1,ipt;ipt=ipts[i--];){
  23966. inputType = ipt.getAttribute("type");
  23967. if(inputType=="checkbox"){
  23968. attrName = ipt.getAttribute("name");
  23969. opt[attrName] && delete opt[attrName];
  23970. if(ipt.checked){
  23971. var attrValue = document.getElementById( attrName + "Value" + editorId );
  23972. if(attrValue){
  23973. if(/input/ig.test(attrValue.tagName)){
  23974. opt[attrName] = attrValue.value;
  23975. } else {
  23976. var iptChilds = attrValue.getElementsByTagName("input");
  23977. for(var j=iptChilds.length-1,iptchild;iptchild=iptChilds[j--];){
  23978. if(iptchild.checked){
  23979. opt[attrName] = iptchild.value;
  23980. break;
  23981. }
  23982. }
  23983. }
  23984. } else {
  23985. opt[attrName] = true;
  23986. }
  23987. } else {
  23988. opt[attrName] = false;
  23989. }
  23990. } else {
  23991. opt[ipt.getAttribute("value")] = ipt.checked;
  23992. }
  23993. }
  23994. var selects = domUtils.getElementsByTagName(cont,"select");
  23995. for(var i=0,si;si=selects[i++];){
  23996. var attr = si.getAttribute('name');
  23997. opt[attr] = opt[attr] ? si.value : '';
  23998. }
  23999. utils.extend(me.editor.options.autotypeset,opt);
  24000. me.editor.setPreferences('autotypeset', opt);
  24001. }
  24002. AutoTypeSetButton.prototype = {
  24003. initAutoTypeSetButton: function (){
  24004. var me = this;
  24005. this.popup = new Popup({
  24006. //传入配置参数
  24007. content: new AutoTypeSetPicker({editor:me.editor}),
  24008. 'editor':me.editor,
  24009. hide : function(){
  24010. if (!this._hidden && this.getDom()) {
  24011. getPara(this);
  24012. this.getDom().style.display = 'none';
  24013. this._hidden = true;
  24014. this.fireEvent('hide');
  24015. }
  24016. }
  24017. });
  24018. var flag = 0;
  24019. this.popup.addListener('postRenderAfter',function(){
  24020. var popupUI = this;
  24021. if(flag)return;
  24022. var cont = this.getDom(),
  24023. btn = cont.getElementsByTagName('button')[0];
  24024. btn.onclick = function(){
  24025. getPara(popupUI);
  24026. me.editor.execCommand('autotypeset');
  24027. popupUI.hide()
  24028. };
  24029. domUtils.on(cont, 'click', function(e) {
  24030. var target = e.target || e.srcElement,
  24031. editorId = me.editor.uid;
  24032. if (target && target.tagName == 'INPUT') {
  24033. // 点击图片浮动的checkbox,去除对应的radio
  24034. if (target.name == 'imageBlockLine' || target.name == 'textAlign' || target.name == 'symbolConver') {
  24035. var checked = target.checked,
  24036. radioTd = document.getElementById( target.name + 'Value' + editorId),
  24037. radios = radioTd.getElementsByTagName('input'),
  24038. defalutSelect = {
  24039. 'imageBlockLine': 'none',
  24040. 'textAlign': 'left',
  24041. 'symbolConver': 'tobdc'
  24042. };
  24043. for (var i = 0; i < radios.length; i++) {
  24044. if (checked) {
  24045. if (radios[i].value == defalutSelect[target.name]) {
  24046. radios[i].checked = 'checked';
  24047. }
  24048. } else {
  24049. radios[i].checked = false;
  24050. }
  24051. }
  24052. }
  24053. // 点击radio,选中对应的checkbox
  24054. if (target.name == ('imageBlockLineValue' + editorId) || target.name == ('textAlignValue' + editorId) || target.name == 'bdc') {
  24055. var checkboxs = target.parentNode.previousSibling.getElementsByTagName('input');
  24056. checkboxs && (checkboxs[0].checked = true);
  24057. }
  24058. getPara(popupUI);
  24059. }
  24060. });
  24061. flag = 1;
  24062. });
  24063. this.initSplitButton();
  24064. }
  24065. };
  24066. utils.inherits(AutoTypeSetButton, SplitButton);
  24067. })();
  24068. // ui/cellalignpicker.js
  24069. ///import core
  24070. ///import uicore
  24071. (function () {
  24072. var utils = baidu.editor.utils,
  24073. Popup = baidu.editor.ui.Popup,
  24074. Stateful = baidu.editor.ui.Stateful,
  24075. UIBase = baidu.editor.ui.UIBase;
  24076. /**
  24077. * 该参数将新增一个参数: selected, 参数类型为一个Object, 形如{ 'align': 'center', 'valign': 'top' }, 表示单元格的初始
  24078. * 对齐状态为: 竖直居上,水平居中; 其中 align的取值为:'center', 'left', 'right'; valign的取值为: 'top', 'middle', 'bottom'
  24079. * @update 2013/4/2 hancong03@baidu.com
  24080. */
  24081. var CellAlignPicker = baidu.editor.ui.CellAlignPicker = function (options) {
  24082. this.initOptions(options);
  24083. this.initSelected();
  24084. this.initCellAlignPicker();
  24085. };
  24086. CellAlignPicker.prototype = {
  24087. //初始化选中状态, 该方法将根据传递进来的参数获取到应该选中的对齐方式图标的索引
  24088. initSelected: function(){
  24089. var status = {
  24090. valign: {
  24091. top: 0,
  24092. middle: 1,
  24093. bottom: 2
  24094. },
  24095. align: {
  24096. left: 0,
  24097. center: 1,
  24098. right: 2
  24099. },
  24100. count: 3
  24101. },
  24102. result = -1;
  24103. if( this.selected ) {
  24104. this.selectedIndex = status.valign[ this.selected.valign ] * status.count + status.align[ this.selected.align ];
  24105. }
  24106. },
  24107. initCellAlignPicker:function () {
  24108. this.initUIBase();
  24109. this.Stateful_init();
  24110. },
  24111. getHtmlTpl:function () {
  24112. var alignType = [ 'left', 'center', 'right' ],
  24113. COUNT = 9,
  24114. tempClassName = null,
  24115. tempIndex = -1,
  24116. tmpl = [];
  24117. for( var i= 0; i<COUNT; i++ ) {
  24118. tempClassName = this.selectedIndex === i ? ' class="edui-cellalign-selected" ' : '';
  24119. tempIndex = i % 3;
  24120. tempIndex === 0 && tmpl.push('<tr>');
  24121. tmpl.push( '<td index="'+ i +'" ' + tempClassName + ' stateful><div class="edui-icon edui-'+ alignType[ tempIndex ] +'"></div></td>' );
  24122. tempIndex === 2 && tmpl.push('</tr>');
  24123. }
  24124. return '<div id="##" class="edui-cellalignpicker %%">' +
  24125. '<div class="edui-cellalignpicker-body">' +
  24126. '<table onclick="$$._onClick(event);">' +
  24127. tmpl.join('') +
  24128. '</table>' +
  24129. '</div>' +
  24130. '</div>';
  24131. },
  24132. getStateDom: function (){
  24133. return this.target;
  24134. },
  24135. _onClick: function (evt){
  24136. var target= evt.target || evt.srcElement;
  24137. if(/icon/.test(target.className)){
  24138. this.items[target.parentNode.getAttribute("index")].onclick();
  24139. Popup.postHide(evt);
  24140. }
  24141. },
  24142. _UIBase_render:UIBase.prototype.render
  24143. };
  24144. utils.inherits(CellAlignPicker, UIBase);
  24145. utils.extend(CellAlignPicker.prototype, Stateful,true);
  24146. })();
  24147. // ui/pastepicker.js
  24148. ///import core
  24149. ///import uicore
  24150. (function () {
  24151. var utils = baidu.editor.utils,
  24152. Stateful = baidu.editor.ui.Stateful,
  24153. uiUtils = baidu.editor.ui.uiUtils,
  24154. UIBase = baidu.editor.ui.UIBase;
  24155. var PastePicker = baidu.editor.ui.PastePicker = function (options) {
  24156. this.initOptions(options);
  24157. this.initPastePicker();
  24158. };
  24159. PastePicker.prototype = {
  24160. initPastePicker:function () {
  24161. this.initUIBase();
  24162. this.Stateful_init();
  24163. },
  24164. getHtmlTpl:function () {
  24165. return '<div class="edui-pasteicon" onclick="$$._onClick(this)"></div>' +
  24166. '<div class="edui-pastecontainer">' +
  24167. '<div class="edui-title">' + this.editor.getLang("pasteOpt") + '</div>' +
  24168. '<div class="edui-button">' +
  24169. '<div title="' + this.editor.getLang("pasteSourceFormat") + '" onclick="$$.format(false)" stateful>' +
  24170. '<div class="edui-richtxticon"></div></div>' +
  24171. '<div title="' + this.editor.getLang("tagFormat") + '" onclick="$$.format(2)" stateful>' +
  24172. '<div class="edui-tagicon"></div></div>' +
  24173. '<div title="' + this.editor.getLang("pasteTextFormat") + '" onclick="$$.format(true)" stateful>' +
  24174. '<div class="edui-plaintxticon"></div></div>' +
  24175. '</div>' +
  24176. '</div>' +
  24177. '</div>'
  24178. },
  24179. getStateDom:function () {
  24180. return this.target;
  24181. },
  24182. format:function (param) {
  24183. this.editor.ui._isTransfer = true;
  24184. this.editor.fireEvent('pasteTransfer', param);
  24185. },
  24186. _onClick:function (cur) {
  24187. var node = domUtils.getNextDomNode(cur),
  24188. screenHt = uiUtils.getViewportRect().height,
  24189. subPop = uiUtils.getClientRect(node);
  24190. if ((subPop.top + subPop.height) > screenHt)
  24191. node.style.top = (-subPop.height - cur.offsetHeight) + "px";
  24192. else
  24193. node.style.top = "";
  24194. if (/hidden/ig.test(domUtils.getComputedStyle(node, "visibility"))) {
  24195. node.style.visibility = "visible";
  24196. domUtils.addClass(cur, "edui-state-opened");
  24197. } else {
  24198. node.style.visibility = "hidden";
  24199. domUtils.removeClasses(cur, "edui-state-opened")
  24200. }
  24201. },
  24202. _UIBase_render:UIBase.prototype.render
  24203. };
  24204. utils.inherits(PastePicker, UIBase);
  24205. utils.extend(PastePicker.prototype, Stateful, true);
  24206. })();
  24207. // ui/toolbar.js
  24208. (function (){
  24209. var utils = baidu.editor.utils,
  24210. uiUtils = baidu.editor.ui.uiUtils,
  24211. UIBase = baidu.editor.ui.UIBase,
  24212. Toolbar = baidu.editor.ui.Toolbar = function (options){
  24213. this.initOptions(options);
  24214. this.initToolbar();
  24215. };
  24216. Toolbar.prototype = {
  24217. items: null,
  24218. initToolbar: function (){
  24219. this.items = this.items || [];
  24220. this.initUIBase();
  24221. },
  24222. add: function (item,index){
  24223. if(index === undefined){
  24224. this.items.push(item);
  24225. }else{
  24226. this.items.splice(index,0,item)
  24227. }
  24228. },
  24229. getHtmlTpl: function (){
  24230. var buff = [];
  24231. for (var i=0; i<this.items.length; i++) {
  24232. buff[i] = this.items[i].renderHtml();
  24233. }
  24234. return '<div id="##" class="edui-toolbar %%" onselectstart="return false;" onmousedown="return $$._onMouseDown(event, this);">' +
  24235. buff.join('') +
  24236. '</div>'
  24237. },
  24238. postRender: function (){
  24239. var box = this.getDom();
  24240. for (var i=0; i<this.items.length; i++) {
  24241. this.items[i].postRender();
  24242. }
  24243. uiUtils.makeUnselectable(box);
  24244. },
  24245. _onMouseDown: function (e){
  24246. var target = e.target || e.srcElement,
  24247. tagName = target && target.tagName && target.tagName.toLowerCase();
  24248. if (tagName == 'input' || tagName == 'object' || tagName == 'object') {
  24249. return false;
  24250. }
  24251. }
  24252. };
  24253. utils.inherits(Toolbar, UIBase);
  24254. })();
  24255. // ui/menu.js
  24256. ///import core
  24257. ///import uicore
  24258. ///import ui\popup.js
  24259. ///import ui\stateful.js
  24260. (function () {
  24261. var utils = baidu.editor.utils,
  24262. domUtils = baidu.editor.dom.domUtils,
  24263. uiUtils = baidu.editor.ui.uiUtils,
  24264. UIBase = baidu.editor.ui.UIBase,
  24265. Popup = baidu.editor.ui.Popup,
  24266. Stateful = baidu.editor.ui.Stateful,
  24267. CellAlignPicker = baidu.editor.ui.CellAlignPicker,
  24268. Menu = baidu.editor.ui.Menu = function (options) {
  24269. this.initOptions(options);
  24270. this.initMenu();
  24271. };
  24272. var menuSeparator = {
  24273. renderHtml:function () {
  24274. return '<div class="edui-menuitem edui-menuseparator"><div class="edui-menuseparator-inner"></div></div>';
  24275. },
  24276. postRender:function () {
  24277. },
  24278. queryAutoHide:function () {
  24279. return true;
  24280. }
  24281. };
  24282. Menu.prototype = {
  24283. items:null,
  24284. uiName:'menu',
  24285. initMenu:function () {
  24286. this.items = this.items || [];
  24287. this.initPopup();
  24288. this.initItems();
  24289. },
  24290. initItems:function () {
  24291. for (var i = 0; i < this.items.length; i++) {
  24292. var item = this.items[i];
  24293. if (item == '-') {
  24294. this.items[i] = this.getSeparator();
  24295. } else if (!(item instanceof MenuItem)) {
  24296. item.editor = this.editor;
  24297. item.theme = this.editor.options.theme;
  24298. this.items[i] = this.createItem(item);
  24299. }
  24300. }
  24301. },
  24302. getSeparator:function () {
  24303. return menuSeparator;
  24304. },
  24305. createItem:function (item) {
  24306. //新增一个参数menu, 该参数存储了menuItem所对应的menu引用
  24307. item.menu = this;
  24308. return new MenuItem(item);
  24309. },
  24310. _Popup_getContentHtmlTpl:Popup.prototype.getContentHtmlTpl,
  24311. getContentHtmlTpl:function () {
  24312. if (this.items.length == 0) {
  24313. return this._Popup_getContentHtmlTpl();
  24314. }
  24315. var buff = [];
  24316. for (var i = 0; i < this.items.length; i++) {
  24317. var item = this.items[i];
  24318. buff[i] = item.renderHtml();
  24319. }
  24320. return ('<div class="%%-body">' + buff.join('') + '</div>');
  24321. },
  24322. _Popup_postRender:Popup.prototype.postRender,
  24323. postRender:function () {
  24324. var me = this;
  24325. for (var i = 0; i < this.items.length; i++) {
  24326. var item = this.items[i];
  24327. item.ownerMenu = this;
  24328. item.postRender();
  24329. }
  24330. domUtils.on(this.getDom(), 'mouseover', function (evt) {
  24331. evt = evt || event;
  24332. var rel = evt.relatedTarget || evt.fromElement;
  24333. var el = me.getDom();
  24334. if (!uiUtils.contains(el, rel) && el !== rel) {
  24335. me.fireEvent('over');
  24336. }
  24337. });
  24338. this._Popup_postRender();
  24339. },
  24340. queryAutoHide:function (el) {
  24341. if (el) {
  24342. if (uiUtils.contains(this.getDom(), el)) {
  24343. return false;
  24344. }
  24345. for (var i = 0; i < this.items.length; i++) {
  24346. var item = this.items[i];
  24347. if (item.queryAutoHide(el) === false) {
  24348. return false;
  24349. }
  24350. }
  24351. }
  24352. },
  24353. clearItems:function () {
  24354. for (var i = 0; i < this.items.length; i++) {
  24355. var item = this.items[i];
  24356. clearTimeout(item._showingTimer);
  24357. clearTimeout(item._closingTimer);
  24358. if (item.subMenu) {
  24359. item.subMenu.destroy();
  24360. }
  24361. }
  24362. this.items = [];
  24363. },
  24364. destroy:function () {
  24365. if (this.getDom()) {
  24366. domUtils.remove(this.getDom());
  24367. }
  24368. this.clearItems();
  24369. },
  24370. dispose:function () {
  24371. this.destroy();
  24372. }
  24373. };
  24374. utils.inherits(Menu, Popup);
  24375. /**
  24376. * @update 2013/04/03 hancong03 新增一个参数menu, 该参数存储了menuItem所对应的menu引用
  24377. * @type {Function}
  24378. */
  24379. var MenuItem = baidu.editor.ui.MenuItem = function (options) {
  24380. this.initOptions(options);
  24381. this.initUIBase();
  24382. this.Stateful_init();
  24383. if (this.subMenu && !(this.subMenu instanceof Menu)) {
  24384. if (options.className && options.className.indexOf("aligntd") != -1) {
  24385. var me = this;
  24386. //获取单元格对齐初始状态
  24387. this.subMenu.selected = this.editor.queryCommandValue( 'cellalignment' );
  24388. this.subMenu = new Popup({
  24389. content:new CellAlignPicker(this.subMenu),
  24390. parentMenu:me,
  24391. editor:me.editor,
  24392. destroy:function () {
  24393. if (this.getDom()) {
  24394. domUtils.remove(this.getDom());
  24395. }
  24396. }
  24397. });
  24398. this.subMenu.addListener("postRenderAfter", function () {
  24399. domUtils.on(this.getDom(), "mouseover", function () {
  24400. me.addState('opened');
  24401. });
  24402. });
  24403. } else {
  24404. this.subMenu = new Menu(this.subMenu);
  24405. }
  24406. }
  24407. };
  24408. MenuItem.prototype = {
  24409. label:'',
  24410. subMenu:null,
  24411. ownerMenu:null,
  24412. uiName:'menuitem',
  24413. alwalysHoverable:true,
  24414. getHtmlTpl:function () {
  24415. return '<div id="##" class="%%" stateful onclick="$$._onClick(event, this);">' +
  24416. '<div class="%%-body">' +
  24417. this.renderLabelHtml() +
  24418. '</div>' +
  24419. '</div>';
  24420. },
  24421. postRender:function () {
  24422. var me = this;
  24423. this.addListener('over', function () {
  24424. me.ownerMenu.fireEvent('submenuover', me);
  24425. if (me.subMenu) {
  24426. me.delayShowSubMenu();
  24427. }
  24428. });
  24429. if (this.subMenu) {
  24430. this.getDom().className += ' edui-hassubmenu';
  24431. this.subMenu.render();
  24432. this.addListener('out', function () {
  24433. me.delayHideSubMenu();
  24434. });
  24435. this.subMenu.addListener('over', function () {
  24436. clearTimeout(me._closingTimer);
  24437. me._closingTimer = null;
  24438. me.addState('opened');
  24439. });
  24440. this.ownerMenu.addListener('hide', function () {
  24441. me.hideSubMenu();
  24442. });
  24443. this.ownerMenu.addListener('submenuover', function (t, subMenu) {
  24444. if (subMenu !== me) {
  24445. me.delayHideSubMenu();
  24446. }
  24447. });
  24448. this.subMenu._bakQueryAutoHide = this.subMenu.queryAutoHide;
  24449. this.subMenu.queryAutoHide = function (el) {
  24450. if (el && uiUtils.contains(me.getDom(), el)) {
  24451. return false;
  24452. }
  24453. return this._bakQueryAutoHide(el);
  24454. };
  24455. }
  24456. this.getDom().style.tabIndex = '-1';
  24457. uiUtils.makeUnselectable(this.getDom());
  24458. this.Stateful_postRender();
  24459. },
  24460. delayShowSubMenu:function () {
  24461. var me = this;
  24462. if (!me.isDisabled()) {
  24463. me.addState('opened');
  24464. clearTimeout(me._showingTimer);
  24465. clearTimeout(me._closingTimer);
  24466. me._closingTimer = null;
  24467. me._showingTimer = setTimeout(function () {
  24468. me.showSubMenu();
  24469. }, 250);
  24470. }
  24471. },
  24472. delayHideSubMenu:function () {
  24473. var me = this;
  24474. if (!me.isDisabled()) {
  24475. me.removeState('opened');
  24476. clearTimeout(me._showingTimer);
  24477. if (!me._closingTimer) {
  24478. me._closingTimer = setTimeout(function () {
  24479. if (!me.hasState('opened')) {
  24480. me.hideSubMenu();
  24481. }
  24482. me._closingTimer = null;
  24483. }, 400);
  24484. }
  24485. }
  24486. },
  24487. renderLabelHtml:function () {
  24488. return '<div class="edui-arrow"></div>' +
  24489. '<div class="edui-box edui-icon"></div>' +
  24490. '<div class="edui-box edui-label %%-label">' + (this.label || '') + '</div>';
  24491. },
  24492. getStateDom:function () {
  24493. return this.getDom();
  24494. },
  24495. queryAutoHide:function (el) {
  24496. if (this.subMenu && this.hasState('opened')) {
  24497. return this.subMenu.queryAutoHide(el);
  24498. }
  24499. },
  24500. _onClick:function (event, this_) {
  24501. if (this.hasState('disabled')) return;
  24502. if (this.fireEvent('click', event, this_) !== false) {
  24503. if (this.subMenu) {
  24504. this.showSubMenu();
  24505. } else {
  24506. Popup.postHide(event);
  24507. }
  24508. }
  24509. },
  24510. showSubMenu:function () {
  24511. var rect = uiUtils.getClientRect(this.getDom());
  24512. rect.right -= 5;
  24513. rect.left += 2;
  24514. rect.width -= 7;
  24515. rect.top -= 4;
  24516. rect.bottom += 4;
  24517. rect.height += 8;
  24518. this.subMenu.showAnchorRect(rect, true, true);
  24519. },
  24520. hideSubMenu:function () {
  24521. this.subMenu.hide();
  24522. }
  24523. };
  24524. utils.inherits(MenuItem, UIBase);
  24525. utils.extend(MenuItem.prototype, Stateful, true);
  24526. })();
  24527. // ui/combox.js
  24528. ///import core
  24529. ///import uicore
  24530. ///import ui/menu.js
  24531. ///import ui/splitbutton.js
  24532. (function (){
  24533. // todo: menu和item提成通用list
  24534. var utils = baidu.editor.utils,
  24535. uiUtils = baidu.editor.ui.uiUtils,
  24536. Menu = baidu.editor.ui.Menu,
  24537. SplitButton = baidu.editor.ui.SplitButton,
  24538. Combox = baidu.editor.ui.Combox = function (options){
  24539. this.initOptions(options);
  24540. this.initCombox();
  24541. };
  24542. Combox.prototype = {
  24543. uiName: 'combox',
  24544. onbuttonclick:function () {
  24545. this.showPopup();
  24546. },
  24547. initCombox: function (){
  24548. var me = this;
  24549. this.items = this.items || [];
  24550. for (var i=0; i<this.items.length; i++) {
  24551. var item = this.items[i];
  24552. item.uiName = 'listitem';
  24553. item.index = i;
  24554. item.onclick = function (){
  24555. me.selectByIndex(this.index);
  24556. };
  24557. }
  24558. this.popup = new Menu({
  24559. items: this.items,
  24560. uiName: 'list',
  24561. editor:this.editor,
  24562. captureWheel: true,
  24563. combox: this
  24564. });
  24565. this.initSplitButton();
  24566. },
  24567. _SplitButton_postRender: SplitButton.prototype.postRender,
  24568. postRender: function (){
  24569. this._SplitButton_postRender();
  24570. this.setLabel(this.label || '');
  24571. this.setValue(this.initValue || '');
  24572. },
  24573. showPopup: function (){
  24574. var rect = uiUtils.getClientRect(this.getDom());
  24575. rect.top += 1;
  24576. rect.bottom -= 1;
  24577. rect.height -= 2;
  24578. this.popup.showAnchorRect(rect);
  24579. },
  24580. getValue: function (){
  24581. return this.value;
  24582. },
  24583. setValue: function (value){
  24584. var index = this.indexByValue(value);
  24585. if (index != -1) {
  24586. this.selectedIndex = index;
  24587. this.setLabel(this.items[index].label);
  24588. this.value = this.items[index].value;
  24589. } else {
  24590. this.selectedIndex = -1;
  24591. this.setLabel(this.getLabelForUnknowValue(value));
  24592. this.value = value;
  24593. }
  24594. },
  24595. setLabel: function (label){
  24596. this.getDom('button_body').innerHTML = label;
  24597. this.label = label;
  24598. },
  24599. getLabelForUnknowValue: function (value){
  24600. return value;
  24601. },
  24602. indexByValue: function (value){
  24603. for (var i=0; i<this.items.length; i++) {
  24604. if (value == this.items[i].value) {
  24605. return i;
  24606. }
  24607. }
  24608. return -1;
  24609. },
  24610. getItem: function (index){
  24611. return this.items[index];
  24612. },
  24613. selectByIndex: function (index){
  24614. if (index < this.items.length && this.fireEvent('select', index) !== false) {
  24615. this.selectedIndex = index;
  24616. this.value = this.items[index].value;
  24617. this.setLabel(this.items[index].label);
  24618. }
  24619. }
  24620. };
  24621. utils.inherits(Combox, SplitButton);
  24622. })();
  24623. // ui/dialog.js
  24624. ///import core
  24625. ///import uicore
  24626. ///import ui/mask.js
  24627. ///import ui/button.js
  24628. (function (){
  24629. var utils = baidu.editor.utils,
  24630. domUtils = baidu.editor.dom.domUtils,
  24631. uiUtils = baidu.editor.ui.uiUtils,
  24632. Mask = baidu.editor.ui.Mask,
  24633. UIBase = baidu.editor.ui.UIBase,
  24634. Button = baidu.editor.ui.Button,
  24635. Dialog = baidu.editor.ui.Dialog = function (options){
  24636. if(options.name){
  24637. var name = options.name;
  24638. var cssRules = options.cssRules;
  24639. if(!options.className){
  24640. options.className = 'edui-for-' + name;
  24641. }
  24642. if(cssRules){
  24643. options.cssRules = '.edui-default .edui-for-'+ name +' .edui-dialog-content {'+ cssRules +'}'
  24644. }
  24645. }
  24646. this.initOptions(utils.extend({
  24647. autoReset: true,
  24648. draggable: true,
  24649. onok: function (){},
  24650. oncancel: function (){},
  24651. onclose: function (t, ok){
  24652. return ok ? this.onok() : this.oncancel();
  24653. },
  24654. //是否控制dialog中的scroll事件, 默认为不阻止
  24655. holdScroll: false
  24656. },options));
  24657. this.initDialog();
  24658. };
  24659. var modalMask;
  24660. var dragMask;
  24661. var activeDialog;
  24662. Dialog.prototype = {
  24663. draggable: false,
  24664. uiName: 'dialog',
  24665. initDialog: function (){
  24666. var me = this,
  24667. theme=this.editor.options.theme;
  24668. if(this.cssRules){
  24669. utils.cssRule('edui-customize-'+this.name+'-style',this.cssRules);
  24670. }
  24671. this.initUIBase();
  24672. this.modalMask = (modalMask || (modalMask = new Mask({
  24673. className: 'edui-dialog-modalmask',
  24674. theme:theme,
  24675. onclick: function (){
  24676. activeDialog && activeDialog.close(false);
  24677. }
  24678. })));
  24679. this.dragMask = (dragMask || (dragMask = new Mask({
  24680. className: 'edui-dialog-dragmask',
  24681. theme:theme
  24682. })));
  24683. this.closeButton = new Button({
  24684. className: 'edui-dialog-closebutton',
  24685. title: me.closeDialog,
  24686. theme:theme,
  24687. onclick: function (){
  24688. me.close(false);
  24689. }
  24690. });
  24691. this.fullscreen && this.initResizeEvent();
  24692. if (this.buttons) {
  24693. for (var i=0; i<this.buttons.length; i++) {
  24694. if (!(this.buttons[i] instanceof Button)) {
  24695. this.buttons[i] = new Button(utils.extend(this.buttons[i],{
  24696. editor : this.editor
  24697. },true));
  24698. }
  24699. }
  24700. }
  24701. },
  24702. initResizeEvent: function () {
  24703. var me = this;
  24704. domUtils.on( window, "resize", function () {
  24705. if ( me._hidden || me._hidden === undefined ) {
  24706. return;
  24707. }
  24708. if ( me.__resizeTimer ) {
  24709. window.clearTimeout( me.__resizeTimer );
  24710. }
  24711. me.__resizeTimer = window.setTimeout( function () {
  24712. me.__resizeTimer = null;
  24713. var dialogWrapNode = me.getDom(),
  24714. contentNode = me.getDom('content'),
  24715. wrapRect = UE.ui.uiUtils.getClientRect( dialogWrapNode ),
  24716. contentRect = UE.ui.uiUtils.getClientRect( contentNode ),
  24717. vpRect = uiUtils.getViewportRect();
  24718. contentNode.style.width = ( vpRect.width - wrapRect.width + contentRect.width ) + "px";
  24719. contentNode.style.height = ( vpRect.height - wrapRect.height + contentRect.height ) + "px";
  24720. dialogWrapNode.style.width = vpRect.width + "px";
  24721. dialogWrapNode.style.height = vpRect.height + "px";
  24722. me.fireEvent( "resize" );
  24723. }, 100 );
  24724. } );
  24725. },
  24726. fitSize: function (){
  24727. var popBodyEl = this.getDom('body');
  24728. // if (!(baidu.editor.browser.ie && baidu.editor.browser.version == 7)) {
  24729. // uiUtils.removeStyle(popBodyEl, 'width');
  24730. // uiUtils.removeStyle(popBodyEl, 'height');
  24731. // }
  24732. var size = this.mesureSize();
  24733. popBodyEl.style.width = size.width + 'px';
  24734. popBodyEl.style.height = size.height + 'px';
  24735. return size;
  24736. },
  24737. safeSetOffset: function (offset){
  24738. var me = this;
  24739. var el = me.getDom();
  24740. var vpRect = uiUtils.getViewportRect();
  24741. var rect = uiUtils.getClientRect(el);
  24742. var left = offset.left;
  24743. if (left + rect.width > vpRect.right) {
  24744. left = vpRect.right - rect.width;
  24745. }
  24746. var top = offset.top;
  24747. if (top + rect.height > vpRect.bottom) {
  24748. top = vpRect.bottom - rect.height;
  24749. }
  24750. el.style.left = Math.max(left, 0) + 'px';
  24751. el.style.top = Math.max(top, 0) + 'px';
  24752. },
  24753. showAtCenter: function (){
  24754. var vpRect = uiUtils.getViewportRect();
  24755. if ( !this.fullscreen ) {
  24756. this.getDom().style.display = '';
  24757. var popSize = this.fitSize();
  24758. var titleHeight = this.getDom('titlebar').offsetHeight | 0;
  24759. var left = vpRect.width / 2 - popSize.width / 2;
  24760. var top = vpRect.height / 2 - (popSize.height - titleHeight) / 2 - titleHeight;
  24761. var popEl = this.getDom();
  24762. this.safeSetOffset({
  24763. left: Math.max(left | 0, 0),
  24764. top: Math.max(top | 0, 0)
  24765. });
  24766. if (!domUtils.hasClass(popEl, 'edui-state-centered')) {
  24767. popEl.className += ' edui-state-centered';
  24768. }
  24769. } else {
  24770. var dialogWrapNode = this.getDom(),
  24771. contentNode = this.getDom('content');
  24772. dialogWrapNode.style.display = "block";
  24773. var wrapRect = UE.ui.uiUtils.getClientRect( dialogWrapNode ),
  24774. contentRect = UE.ui.uiUtils.getClientRect( contentNode );
  24775. dialogWrapNode.style.left = "-100000px";
  24776. contentNode.style.width = ( vpRect.width - wrapRect.width + contentRect.width ) + "px";
  24777. contentNode.style.height = ( vpRect.height - wrapRect.height + contentRect.height ) + "px";
  24778. dialogWrapNode.style.width = vpRect.width + "px";
  24779. dialogWrapNode.style.height = vpRect.height + "px";
  24780. dialogWrapNode.style.left = 0;
  24781. //保存环境的overflow值
  24782. this._originalContext = {
  24783. html: {
  24784. overflowX: document.documentElement.style.overflowX,
  24785. overflowY: document.documentElement.style.overflowY
  24786. },
  24787. body: {
  24788. overflowX: document.body.style.overflowX,
  24789. overflowY: document.body.style.overflowY
  24790. }
  24791. };
  24792. document.documentElement.style.overflowX = 'hidden';
  24793. document.documentElement.style.overflowY = 'hidden';
  24794. document.body.style.overflowX = 'hidden';
  24795. document.body.style.overflowY = 'hidden';
  24796. }
  24797. this._show();
  24798. },
  24799. getContentHtml: function (){
  24800. var contentHtml = '';
  24801. if (typeof this.content == 'string') {
  24802. contentHtml = this.content;
  24803. } else if (this.iframeUrl) {
  24804. contentHtml = '<span id="'+ this.id +'_contmask" class="dialogcontmask"></span><iframe id="'+ this.id +
  24805. '_iframe" class="%%-iframe" height="100%" width="100%" frameborder="0" src="'+ this.iframeUrl +'"></iframe>';
  24806. }
  24807. return contentHtml;
  24808. },
  24809. getHtmlTpl: function (){
  24810. var footHtml = '';
  24811. if (this.buttons) {
  24812. var buff = [];
  24813. for (var i=0; i<this.buttons.length; i++) {
  24814. buff[i] = this.buttons[i].renderHtml();
  24815. }
  24816. footHtml = '<div class="%%-foot">' +
  24817. '<div id="##_buttons" class="%%-buttons">' + buff.join('') + '</div>' +
  24818. '</div>';
  24819. }
  24820. return '<div id="##" class="%%"><div '+ ( !this.fullscreen ? 'class="%%"' : 'class="%%-wrap edui-dialog-fullscreen-flag"' ) +'><div id="##_body" class="%%-body">' +
  24821. '<div class="%%-shadow"></div>' +
  24822. '<div id="##_titlebar" class="%%-titlebar">' +
  24823. '<div class="%%-draghandle" onmousedown="$$._onTitlebarMouseDown(event, this);">' +
  24824. '<span class="%%-caption">' + (this.title || '') + '</span>' +
  24825. '</div>' +
  24826. this.closeButton.renderHtml() +
  24827. '</div>' +
  24828. '<div id="##_content" class="%%-content">'+ ( this.autoReset ? '' : this.getContentHtml()) +'</div>' +
  24829. footHtml +
  24830. '</div></div></div>';
  24831. },
  24832. postRender: function (){
  24833. // todo: 保持居中/记住上次关闭位置选项
  24834. if (!this.modalMask.getDom()) {
  24835. this.modalMask.render();
  24836. this.modalMask.hide();
  24837. }
  24838. if (!this.dragMask.getDom()) {
  24839. this.dragMask.render();
  24840. this.dragMask.hide();
  24841. }
  24842. var me = this;
  24843. this.addListener('show', function (){
  24844. me.modalMask.show(this.getDom().style.zIndex - 2);
  24845. });
  24846. this.addListener('hide', function (){
  24847. me.modalMask.hide();
  24848. });
  24849. if (this.buttons) {
  24850. for (var i=0; i<this.buttons.length; i++) {
  24851. this.buttons[i].postRender();
  24852. }
  24853. }
  24854. domUtils.on(window, 'resize', function (){
  24855. setTimeout(function (){
  24856. if (!me.isHidden()) {
  24857. me.safeSetOffset(uiUtils.getClientRect(me.getDom()));
  24858. }
  24859. });
  24860. });
  24861. //hold住scroll事件,防止dialog的滚动影响页面
  24862. // if( this.holdScroll ) {
  24863. //
  24864. // if( !me.iframeUrl ) {
  24865. // domUtils.on( document.getElementById( me.id + "_iframe"), !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
  24866. // domUtils.preventDefault(e);
  24867. // } );
  24868. // } else {
  24869. // me.addListener('dialogafterreset', function(){
  24870. // window.setTimeout(function(){
  24871. // var iframeWindow = document.getElementById( me.id + "_iframe").contentWindow;
  24872. //
  24873. // if( browser.ie ) {
  24874. //
  24875. // var timer = window.setInterval(function(){
  24876. //
  24877. // if( iframeWindow.document && iframeWindow.document.body ) {
  24878. // window.clearInterval( timer );
  24879. // timer = null;
  24880. // domUtils.on( iframeWindow.document.body, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
  24881. // domUtils.preventDefault(e);
  24882. // } );
  24883. // }
  24884. //
  24885. // }, 100);
  24886. //
  24887. // } else {
  24888. // domUtils.on( iframeWindow, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
  24889. // domUtils.preventDefault(e);
  24890. // } );
  24891. // }
  24892. //
  24893. // }, 1);
  24894. // });
  24895. // }
  24896. //
  24897. // }
  24898. this._hide();
  24899. },
  24900. mesureSize: function (){
  24901. var body = this.getDom('body');
  24902. var width = uiUtils.getClientRect(this.getDom('content')).width;
  24903. var dialogBodyStyle = body.style;
  24904. dialogBodyStyle.width = width;
  24905. return uiUtils.getClientRect(body);
  24906. },
  24907. _onTitlebarMouseDown: function (evt, el){
  24908. if (this.draggable) {
  24909. var rect;
  24910. var vpRect = uiUtils.getViewportRect();
  24911. var me = this;
  24912. uiUtils.startDrag(evt, {
  24913. ondragstart: function (){
  24914. rect = uiUtils.getClientRect(me.getDom());
  24915. me.getDom('contmask').style.visibility = 'visible';
  24916. me.dragMask.show(me.getDom().style.zIndex - 1);
  24917. },
  24918. ondragmove: function (x, y){
  24919. var left = rect.left + x;
  24920. var top = rect.top + y;
  24921. me.safeSetOffset({
  24922. left: left,
  24923. top: top
  24924. });
  24925. },
  24926. ondragstop: function (){
  24927. me.getDom('contmask').style.visibility = 'hidden';
  24928. domUtils.removeClasses(me.getDom(), ['edui-state-centered']);
  24929. me.dragMask.hide();
  24930. }
  24931. });
  24932. }
  24933. },
  24934. reset: function (){
  24935. this.getDom('content').innerHTML = this.getContentHtml();
  24936. this.fireEvent('dialogafterreset');
  24937. },
  24938. _show: function (){
  24939. if (this._hidden) {
  24940. this.getDom().style.display = '';
  24941. //要高过编辑器的zindxe
  24942. this.editor.container.style.zIndex && (this.getDom().style.zIndex = this.editor.container.style.zIndex * 1 + 10);
  24943. this._hidden = false;
  24944. this.fireEvent('show');
  24945. baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex = this.getDom().style.zIndex - 4;
  24946. }
  24947. },
  24948. isHidden: function (){
  24949. return this._hidden;
  24950. },
  24951. _hide: function (){
  24952. if (!this._hidden) {
  24953. var wrapNode = this.getDom();
  24954. wrapNode.style.display = 'none';
  24955. wrapNode.style.zIndex = '';
  24956. wrapNode.style.width = '';
  24957. wrapNode.style.height = '';
  24958. this._hidden = true;
  24959. this.fireEvent('hide');
  24960. }
  24961. },
  24962. open: function (){
  24963. if (this.autoReset) {
  24964. //有可能还没有渲染
  24965. try{
  24966. this.reset();
  24967. }catch(e){
  24968. this.render();
  24969. this.open()
  24970. }
  24971. }
  24972. this.showAtCenter();
  24973. if (this.iframeUrl) {
  24974. try {
  24975. this.getDom('iframe').focus();
  24976. } catch(ex){}
  24977. }
  24978. activeDialog = this;
  24979. },
  24980. _onCloseButtonClick: function (evt, el){
  24981. this.close(false);
  24982. },
  24983. close: function (ok){
  24984. if (this.fireEvent('close', ok) !== false) {
  24985. //还原环境
  24986. if ( this.fullscreen ) {
  24987. document.documentElement.style.overflowX = this._originalContext.html.overflowX;
  24988. document.documentElement.style.overflowY = this._originalContext.html.overflowY;
  24989. document.body.style.overflowX = this._originalContext.body.overflowX;
  24990. document.body.style.overflowY = this._originalContext.body.overflowY;
  24991. delete this._originalContext;
  24992. }
  24993. this._hide();
  24994. //销毁content
  24995. var content = this.getDom('content');
  24996. var iframe = this.getDom('iframe');
  24997. if (content && iframe) {
  24998. var doc = iframe.contentDocument || iframe.contentWindow.document;
  24999. doc && (doc.body.innerHTML = '');
  25000. domUtils.remove(content);
  25001. }
  25002. }
  25003. }
  25004. };
  25005. utils.inherits(Dialog, UIBase);
  25006. })();
  25007. // ui/menubutton.js
  25008. ///import core
  25009. ///import uicore
  25010. ///import ui/menu.js
  25011. ///import ui/splitbutton.js
  25012. (function (){
  25013. var utils = baidu.editor.utils,
  25014. Menu = baidu.editor.ui.Menu,
  25015. SplitButton = baidu.editor.ui.SplitButton,
  25016. MenuButton = baidu.editor.ui.MenuButton = function (options){
  25017. this.initOptions(options);
  25018. this.initMenuButton();
  25019. };
  25020. MenuButton.prototype = {
  25021. initMenuButton: function (){
  25022. var me = this;
  25023. this.uiName = "menubutton";
  25024. this.popup = new Menu({
  25025. items: me.items,
  25026. className: me.className,
  25027. editor:me.editor
  25028. });
  25029. this.popup.addListener('show', function (){
  25030. var list = this;
  25031. for (var i=0; i<list.items.length; i++) {
  25032. list.items[i].removeState('checked');
  25033. if (list.items[i].value == me._value) {
  25034. list.items[i].addState('checked');
  25035. this.value = me._value;
  25036. }
  25037. }
  25038. });
  25039. this.initSplitButton();
  25040. },
  25041. setValue : function(value){
  25042. this._value = value;
  25043. }
  25044. };
  25045. utils.inherits(MenuButton, SplitButton);
  25046. })();
  25047. // ui/multiMenu.js
  25048. ///import core
  25049. ///import uicore
  25050. ///commands 表情
  25051. (function(){
  25052. var utils = baidu.editor.utils,
  25053. Popup = baidu.editor.ui.Popup,
  25054. SplitButton = baidu.editor.ui.SplitButton,
  25055. MultiMenuPop = baidu.editor.ui.MultiMenuPop = function(options){
  25056. this.initOptions(options);
  25057. this.initMultiMenu();
  25058. };
  25059. MultiMenuPop.prototype = {
  25060. initMultiMenu: function (){
  25061. var me = this;
  25062. this.popup = new Popup({
  25063. content: '',
  25064. editor : me.editor,
  25065. iframe_rendered: false,
  25066. onshow: function (){
  25067. if (!this.iframe_rendered) {
  25068. this.iframe_rendered = true;
  25069. this.getDom('content').innerHTML = '<iframe id="'+me.id+'_iframe" src="'+ me.iframeUrl +'" frameborder="0"></iframe>';
  25070. me.editor.container.style.zIndex && (this.getDom().style.zIndex = me.editor.container.style.zIndex * 1 + 1);
  25071. }
  25072. }
  25073. // canSideUp:false,
  25074. // canSideLeft:false
  25075. });
  25076. this.onbuttonclick = function(){
  25077. this.showPopup();
  25078. };
  25079. this.initSplitButton();
  25080. }
  25081. };
  25082. utils.inherits(MultiMenuPop, SplitButton);
  25083. })();
  25084. // ui/shortcutmenu.js
  25085. (function () {
  25086. var UI = baidu.editor.ui,
  25087. UIBase = UI.UIBase,
  25088. uiUtils = UI.uiUtils,
  25089. utils = baidu.editor.utils,
  25090. domUtils = baidu.editor.dom.domUtils;
  25091. var allMenus = [],//存储所有快捷菜单
  25092. timeID,
  25093. isSubMenuShow = false;//是否有子pop显示
  25094. var ShortCutMenu = UI.ShortCutMenu = function (options) {
  25095. this.initOptions (options);
  25096. this.initShortCutMenu ();
  25097. };
  25098. ShortCutMenu.postHide = hideAllMenu;
  25099. ShortCutMenu.prototype = {
  25100. isHidden : true ,
  25101. SPACE : 5 ,
  25102. initShortCutMenu : function () {
  25103. this.items = this.items || [];
  25104. this.initUIBase ();
  25105. this.initItems ();
  25106. this.initEvent ();
  25107. allMenus.push (this);
  25108. } ,
  25109. initEvent : function () {
  25110. var me = this,
  25111. doc = me.editor.document;
  25112. domUtils.on (doc , "mousemove" , function (e) {
  25113. if (me.isHidden === false) {
  25114. //有pop显示就不隐藏快捷菜单
  25115. if (me.getSubMenuMark () || me.eventType == "contextmenu") return;
  25116. var flag = true,
  25117. el = me.getDom (),
  25118. wt = el.offsetWidth,
  25119. ht = el.offsetHeight,
  25120. distanceX = wt / 2 + me.SPACE,//距离中心X标准
  25121. distanceY = ht / 2,//距离中心Y标准
  25122. x = Math.abs (e.screenX - me.left),//离中心距离横坐标
  25123. y = Math.abs (e.screenY - me.top);//离中心距离纵坐标
  25124. clearTimeout (timeID);
  25125. timeID = setTimeout (function () {
  25126. if (y > 0 && y < distanceY) {
  25127. me.setOpacity (el , "1");
  25128. } else if (y > distanceY && y < distanceY + 70) {
  25129. me.setOpacity (el , "0.5");
  25130. flag = false;
  25131. } else if (y > distanceY + 70 && y < distanceY + 140) {
  25132. me.hide ();
  25133. }
  25134. if (flag && x > 0 && x < distanceX) {
  25135. me.setOpacity (el , "1")
  25136. } else if (x > distanceX && x < distanceX + 70) {
  25137. me.setOpacity (el , "0.5")
  25138. } else if (x > distanceX + 70 && x < distanceX + 140) {
  25139. me.hide ();
  25140. }
  25141. });
  25142. }
  25143. });
  25144. //ie\ff下 mouseout不准
  25145. if (browser.chrome) {
  25146. domUtils.on (doc , "mouseout" , function (e) {
  25147. var relatedTgt = e.relatedTarget || e.toElement;
  25148. if (relatedTgt == null || relatedTgt.tagName == "HTML") {
  25149. me.hide ();
  25150. }
  25151. });
  25152. }
  25153. me.editor.addListener ("afterhidepop" , function () {
  25154. if (!me.isHidden) {
  25155. isSubMenuShow = true;
  25156. }
  25157. });
  25158. } ,
  25159. initItems : function () {
  25160. if (utils.isArray (this.items)) {
  25161. for (var i = 0, len = this.items.length ; i < len ; i++) {
  25162. var item = this.items[i].toLowerCase ();
  25163. if (UI[item]) {
  25164. this.items[i] = new UI[item] (this.editor);
  25165. this.items[i].className += " edui-shortcutsubmenu ";
  25166. }
  25167. }
  25168. }
  25169. } ,
  25170. setOpacity : function (el , value) {
  25171. if (browser.ie && browser.version < 9) {
  25172. el.style.filter = "alpha(opacity = " + parseFloat (value) * 100 + ");"
  25173. } else {
  25174. el.style.opacity = value;
  25175. }
  25176. } ,
  25177. getSubMenuMark : function () {
  25178. isSubMenuShow = false;
  25179. var layerEle = uiUtils.getFixedLayer ();
  25180. var list = domUtils.getElementsByTagName (layerEle , "div" , function (node) {
  25181. return domUtils.hasClass (node , "edui-shortcutsubmenu edui-popup")
  25182. });
  25183. for (var i = 0, node ; node = list[i++] ;) {
  25184. if (node.style.display != "none") {
  25185. isSubMenuShow = true;
  25186. }
  25187. }
  25188. return isSubMenuShow;
  25189. } ,
  25190. show : function (e , hasContextmenu) {
  25191. var me = this,
  25192. offset = {},
  25193. el = this.getDom (),
  25194. fixedlayer = uiUtils.getFixedLayer ();
  25195. function setPos (offset) {
  25196. if (offset.left < 0) {
  25197. offset.left = 0;
  25198. }
  25199. if (offset.top < 0) {
  25200. offset.top = 0;
  25201. }
  25202. el.style.cssText = "position:absolute;left:" + offset.left + "px;top:" + offset.top + "px;";
  25203. }
  25204. function setPosByCxtMenu (menu) {
  25205. if (!menu.tagName) {
  25206. menu = menu.getDom ();
  25207. }
  25208. offset.left = parseInt (menu.style.left);
  25209. offset.top = parseInt (menu.style.top);
  25210. offset.top -= el.offsetHeight + 15;
  25211. setPos (offset);
  25212. }
  25213. me.eventType = e.type;
  25214. el.style.cssText = "display:block;left:-9999px";
  25215. if (e.type == "contextmenu" && hasContextmenu) {
  25216. var menu = domUtils.getElementsByTagName (fixedlayer , "div" , "edui-contextmenu")[0];
  25217. if (menu) {
  25218. setPosByCxtMenu (menu)
  25219. } else {
  25220. me.editor.addListener ("aftershowcontextmenu" , function (type , menu) {
  25221. setPosByCxtMenu (menu);
  25222. });
  25223. }
  25224. } else {
  25225. offset = uiUtils.getViewportOffsetByEvent (e);
  25226. offset.top -= el.offsetHeight + me.SPACE;
  25227. offset.left += me.SPACE + 20;
  25228. setPos (offset);
  25229. me.setOpacity (el , 0.2);
  25230. }
  25231. me.isHidden = false;
  25232. me.left = e.screenX + el.offsetWidth / 2 - me.SPACE;
  25233. me.top = e.screenY - (el.offsetHeight / 2) - me.SPACE;
  25234. if (me.editor) {
  25235. el.style.zIndex = me.editor.container.style.zIndex * 1 + 10;
  25236. fixedlayer.style.zIndex = el.style.zIndex - 1;
  25237. }
  25238. } ,
  25239. hide : function () {
  25240. if (this.getDom ()) {
  25241. this.getDom ().style.display = "none";
  25242. }
  25243. this.isHidden = true;
  25244. } ,
  25245. postRender : function () {
  25246. if (utils.isArray (this.items)) {
  25247. for (var i = 0, item ; item = this.items[i++] ;) {
  25248. item.postRender ();
  25249. }
  25250. }
  25251. } ,
  25252. getHtmlTpl : function () {
  25253. var buff;
  25254. if (utils.isArray (this.items)) {
  25255. buff = [];
  25256. for (var i = 0 ; i < this.items.length ; i++) {
  25257. buff[i] = this.items[i].renderHtml ();
  25258. }
  25259. buff = buff.join ("");
  25260. } else {
  25261. buff = this.items;
  25262. }
  25263. return '<div id="##" class="%% edui-toolbar" data-src="shortcutmenu" onmousedown="return false;" onselectstart="return false;" >' +
  25264. buff +
  25265. '</div>';
  25266. }
  25267. };
  25268. utils.inherits (ShortCutMenu , UIBase);
  25269. function hideAllMenu (e) {
  25270. var tgt = e.target || e.srcElement,
  25271. cur = domUtils.findParent (tgt , function (node) {
  25272. return domUtils.hasClass (node , "edui-shortcutmenu") || domUtils.hasClass (node , "edui-popup");
  25273. } , true);
  25274. if (!cur) {
  25275. for (var i = 0, menu ; menu = allMenus[i++] ;) {
  25276. menu.hide ()
  25277. }
  25278. }
  25279. }
  25280. domUtils.on (document , 'mousedown' , function (e) {
  25281. hideAllMenu (e);
  25282. });
  25283. domUtils.on (window , 'scroll' , function (e) {
  25284. hideAllMenu (e);
  25285. });
  25286. }) ();
  25287. // ui/breakline.js
  25288. (function (){
  25289. var utils = baidu.editor.utils,
  25290. UIBase = baidu.editor.ui.UIBase,
  25291. Breakline = baidu.editor.ui.Breakline = function (options){
  25292. this.initOptions(options);
  25293. this.initSeparator();
  25294. };
  25295. Breakline.prototype = {
  25296. uiName: 'Breakline',
  25297. initSeparator: function (){
  25298. this.initUIBase();
  25299. },
  25300. getHtmlTpl: function (){
  25301. return '<br/>';
  25302. }
  25303. };
  25304. utils.inherits(Breakline, UIBase);
  25305. })();
  25306. // ui/message.js
  25307. ///import core
  25308. ///import uicore
  25309. (function () {
  25310. var utils = baidu.editor.utils,
  25311. domUtils = baidu.editor.dom.domUtils,
  25312. UIBase = baidu.editor.ui.UIBase,
  25313. Message = baidu.editor.ui.Message = function (options){
  25314. this.initOptions(options);
  25315. this.initMessage();
  25316. };
  25317. Message.prototype = {
  25318. initMessage: function (){
  25319. this.initUIBase();
  25320. },
  25321. getHtmlTpl: function (){
  25322. return '<div id="##" class="edui-message %%">' +
  25323. ' <div id="##_closer" class="edui-message-closer">×</div>' +
  25324. ' <div id="##_body" class="edui-message-body edui-message-type-info">' +
  25325. ' <iframe style="position:absolute;z-index:-1;left:0;top:0;background-color: transparent;" frameborder="0" width="100%" height="100%" src="about:blank"></iframe>' +
  25326. ' <div class="edui-shadow"></div>' +
  25327. ' <div id="##_content" class="edui-message-content">' +
  25328. ' </div>' +
  25329. ' </div>' +
  25330. '</div>';
  25331. },
  25332. reset: function(opt){
  25333. var me = this;
  25334. if (!opt.keepshow) {
  25335. clearTimeout(this.timer);
  25336. me.timer = setTimeout(function(){
  25337. me.hide();
  25338. }, opt.timeout || 4000);
  25339. }
  25340. opt.content !== undefined && me.setContent(opt.content);
  25341. opt.type !== undefined && me.setType(opt.type);
  25342. me.show();
  25343. },
  25344. postRender: function(){
  25345. var me = this,
  25346. closer = this.getDom('closer');
  25347. closer && domUtils.on(closer, 'click', function(){
  25348. me.hide();
  25349. });
  25350. },
  25351. setContent: function(content){
  25352. this.getDom('content').innerHTML = content;
  25353. },
  25354. setType: function(type){
  25355. type = type || 'info';
  25356. var body = this.getDom('body');
  25357. body.className = body.className.replace(/edui-message-type-[\w-]+/, 'edui-message-type-' + type);
  25358. },
  25359. getContent: function(){
  25360. return this.getDom('content').innerHTML;
  25361. },
  25362. getType: function(){
  25363. var arr = this.getDom('body').match(/edui-message-type-([\w-]+)/);
  25364. return arr ? arr[1]:'';
  25365. },
  25366. show: function (){
  25367. this.getDom().style.display = 'block';
  25368. },
  25369. hide: function (){
  25370. var dom = this.getDom();
  25371. if (dom) {
  25372. dom.style.display = 'none';
  25373. dom.parentNode && dom.parentNode.removeChild(dom);
  25374. }
  25375. }
  25376. };
  25377. utils.inherits(Message, UIBase);
  25378. })();
  25379. // adapter/editorui.js
  25380. //ui跟编辑器的适配層
  25381. //那个按钮弹出是dialog,是下拉筐等都是在这个js中配置
  25382. //自己写的ui也要在这里配置,放到baidu.editor.ui下边,当编辑器实例化的时候会根据ueditor.config中的toolbars找到相应的进行实例化
  25383. (function () {
  25384. var utils = baidu.editor.utils;
  25385. var editorui = baidu.editor.ui;
  25386. var _Dialog = editorui.Dialog;
  25387. editorui.buttons = {};
  25388. editorui.Dialog = function (options) {
  25389. var dialog = new _Dialog(options);
  25390. dialog.addListener('hide', function () {
  25391. if (dialog.editor) {
  25392. var editor = dialog.editor;
  25393. try {
  25394. if (browser.gecko) {
  25395. var y = editor.window.scrollY,
  25396. x = editor.window.scrollX;
  25397. editor.body.focus();
  25398. editor.window.scrollTo(x, y);
  25399. } else {
  25400. editor.focus();
  25401. }
  25402. } catch (ex) {
  25403. }
  25404. }
  25405. });
  25406. return dialog;
  25407. };
  25408. var iframeUrlMap = {
  25409. 'anchor':'~/dialogs/anchor/anchor.html',
  25410. 'insertimage':'~/dialogs/image/image.html',
  25411. 'link':'~/dialogs/link/link.html',
  25412. 'spechars':'~/dialogs/spechars/spechars.html',
  25413. 'searchreplace':'~/dialogs/searchreplace/searchreplace.html',
  25414. 'map':'~/dialogs/map/map.html',
  25415. 'gmap':'~/dialogs/gmap/gmap.html',
  25416. 'insertvideo':'~/dialogs/video/video.html',
  25417. 'help':'~/dialogs/help/help.html',
  25418. 'preview':'~/dialogs/preview/preview.html',
  25419. 'emotion':'~/dialogs/emotion/emotion.html',
  25420. 'wordimage':'~/dialogs/wordimage/wordimage.html',
  25421. 'attachment':'~/dialogs/attachment/attachment.html',
  25422. 'insertframe':'~/dialogs/insertframe/insertframe.html',
  25423. 'edittip':'~/dialogs/table/edittip.html',
  25424. 'edittable':'~/dialogs/table/edittable.html',
  25425. 'edittd':'~/dialogs/table/edittd.html',
  25426. 'webapp':'~/dialogs/webapp/webapp.html',
  25427. 'snapscreen':'~/dialogs/snapscreen/snapscreen.html',
  25428. 'scrawl':'~/dialogs/scrawl/scrawl.html',
  25429. 'music':'~/dialogs/music/music.html',
  25430. 'template':'~/dialogs/template/template.html',
  25431. 'background':'~/dialogs/background/background.html',
  25432. 'charts': '~/dialogs/charts/charts.html'
  25433. };
  25434. //为工具栏添加按钮,以下都是统一的按钮触发命令,所以写在一起
  25435. var btnCmds = ['undo', 'redo', 'formatmatch',
  25436. 'bold', 'italic', 'underline', 'fontborder', 'touppercase', 'tolowercase',
  25437. 'strikethrough', 'subscript', 'superscript', 'source', 'indent', 'outdent',
  25438. 'blockquote', 'pasteplain', 'pagebreak',
  25439. 'selectall', 'print','horizontal', 'removeformat', 'time', 'date', 'unlink',
  25440. 'insertparagraphbeforetable', 'insertrow', 'insertcol', 'mergeright', 'mergedown', 'deleterow',
  25441. 'deletecol', 'splittorows', 'splittocols', 'splittocells', 'mergecells', 'deletetable', 'drafts'];
  25442. for (var i = 0, ci; ci = btnCmds[i++];) {
  25443. ci = ci.toLowerCase();
  25444. editorui[ci] = function (cmd) {
  25445. return function (editor) {
  25446. var ui = new editorui.Button({
  25447. className:'edui-for-' + cmd,
  25448. title:editor.options.labelMap[cmd] || editor.getLang("labelMap." + cmd) || '',
  25449. onclick:function () {
  25450. editor.execCommand(cmd);
  25451. },
  25452. theme:editor.options.theme,
  25453. showText:false
  25454. });
  25455. editorui.buttons[cmd] = ui;
  25456. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  25457. var state = editor.queryCommandState(cmd);
  25458. if (state == -1) {
  25459. ui.setDisabled(true);
  25460. ui.setChecked(false);
  25461. } else {
  25462. if (!uiReady) {
  25463. ui.setDisabled(false);
  25464. ui.setChecked(state);
  25465. }
  25466. }
  25467. });
  25468. return ui;
  25469. };
  25470. }(ci);
  25471. }
  25472. //清除文档
  25473. editorui.cleardoc = function (editor) {
  25474. var ui = new editorui.Button({
  25475. className:'edui-for-cleardoc',
  25476. title:editor.options.labelMap.cleardoc || editor.getLang("labelMap.cleardoc") || '',
  25477. theme:editor.options.theme,
  25478. onclick:function () {
  25479. if (confirm(editor.getLang("confirmClear"))) {
  25480. editor.execCommand('cleardoc');
  25481. }
  25482. }
  25483. });
  25484. editorui.buttons["cleardoc"] = ui;
  25485. editor.addListener('selectionchange', function () {
  25486. ui.setDisabled(editor.queryCommandState('cleardoc') == -1);
  25487. });
  25488. return ui;
  25489. };
  25490. //排版,图片排版,文字方向
  25491. var typeset = {
  25492. 'justify':['left', 'right', 'center', 'justify'],
  25493. 'imagefloat':['none', 'left', 'center', 'right'],
  25494. 'directionality':['ltr', 'rtl']
  25495. };
  25496. for (var p in typeset) {
  25497. (function (cmd, val) {
  25498. for (var i = 0, ci; ci = val[i++];) {
  25499. (function (cmd2) {
  25500. editorui[cmd.replace('float', '') + cmd2] = function (editor) {
  25501. var ui = new editorui.Button({
  25502. className:'edui-for-' + cmd.replace('float', '') + cmd2,
  25503. title:editor.options.labelMap[cmd.replace('float', '') + cmd2] || editor.getLang("labelMap." + cmd.replace('float', '') + cmd2) || '',
  25504. theme:editor.options.theme,
  25505. onclick:function () {
  25506. editor.execCommand(cmd, cmd2);
  25507. }
  25508. });
  25509. editorui.buttons[cmd] = ui;
  25510. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  25511. ui.setDisabled(editor.queryCommandState(cmd) == -1);
  25512. ui.setChecked(editor.queryCommandValue(cmd) == cmd2 && !uiReady);
  25513. });
  25514. return ui;
  25515. };
  25516. })(ci)
  25517. }
  25518. })(p, typeset[p])
  25519. }
  25520. //字体颜色和背景颜色
  25521. for (var i = 0, ci; ci = ['backcolor', 'forecolor'][i++];) {
  25522. editorui[ci] = function (cmd) {
  25523. return function (editor) {
  25524. var ui = new editorui.ColorButton({
  25525. className:'edui-for-' + cmd,
  25526. color:'default',
  25527. title:editor.options.labelMap[cmd] || editor.getLang("labelMap." + cmd) || '',
  25528. editor:editor,
  25529. onpickcolor:function (t, color) {
  25530. editor.execCommand(cmd, color);
  25531. },
  25532. onpicknocolor:function () {
  25533. editor.execCommand(cmd, 'default');
  25534. this.setColor('transparent');
  25535. this.color = 'default';
  25536. },
  25537. onbuttonclick:function () {
  25538. editor.execCommand(cmd, this.color);
  25539. }
  25540. });
  25541. editorui.buttons[cmd] = ui;
  25542. editor.addListener('selectionchange', function () {
  25543. ui.setDisabled(editor.queryCommandState(cmd) == -1);
  25544. });
  25545. return ui;
  25546. };
  25547. }(ci);
  25548. }
  25549. var dialogBtns = {
  25550. noOk:['searchreplace', 'help', 'spechars', 'webapp','preview'],
  25551. ok:['attachment', 'anchor', 'link', 'insertimage', 'map', 'gmap', 'insertframe', 'wordimage',
  25552. 'insertvideo', 'insertframe', 'edittip', 'edittable', 'edittd', 'scrawl', 'template', 'music', 'background', 'charts']
  25553. };
  25554. for (var p in dialogBtns) {
  25555. (function (type, vals) {
  25556. for (var i = 0, ci; ci = vals[i++];) {
  25557. //todo opera下存在问题
  25558. if (browser.opera && ci === "searchreplace") {
  25559. continue;
  25560. }
  25561. (function (cmd) {
  25562. editorui[cmd] = function (editor, iframeUrl, title) {
  25563. iframeUrl = iframeUrl || (editor.options.iframeUrlMap || {})[cmd] || iframeUrlMap[cmd];
  25564. title = editor.options.labelMap[cmd] || editor.getLang("labelMap." + cmd) || '';
  25565. var dialog;
  25566. //没有iframeUrl不创建dialog
  25567. if (iframeUrl) {
  25568. dialog = new editorui.Dialog(utils.extend({
  25569. iframeUrl:editor.ui.mapUrl(iframeUrl),
  25570. editor:editor,
  25571. className:'edui-for-' + cmd,
  25572. title:title,
  25573. holdScroll: cmd === 'insertimage',
  25574. fullscreen: /charts|preview/.test(cmd),
  25575. closeDialog:editor.getLang("closeDialog")
  25576. }, type == 'ok' ? {
  25577. buttons:[
  25578. {
  25579. className:'edui-okbutton',
  25580. label:editor.getLang("ok"),
  25581. editor:editor,
  25582. onclick:function () {
  25583. dialog.close(true);
  25584. }
  25585. },
  25586. {
  25587. className:'edui-cancelbutton',
  25588. label:editor.getLang("cancel"),
  25589. editor:editor,
  25590. onclick:function () {
  25591. dialog.close(false);
  25592. }
  25593. }
  25594. ]
  25595. } : {}));
  25596. editor.ui._dialogs[cmd + "Dialog"] = dialog;
  25597. }
  25598. var ui = new editorui.Button({
  25599. className:'edui-for-' + cmd,
  25600. title:title,
  25601. onclick:function () {
  25602. if (dialog) {
  25603. switch (cmd) {
  25604. case "wordimage":
  25605. var images = editor.execCommand("wordimage");
  25606. if (images && images.length) {
  25607. dialog.render();
  25608. dialog.open();
  25609. }
  25610. break;
  25611. case "scrawl":
  25612. if (editor.queryCommandState("scrawl") != -1) {
  25613. dialog.render();
  25614. dialog.open();
  25615. }
  25616. break;
  25617. default:
  25618. dialog.render();
  25619. dialog.open();
  25620. }
  25621. }
  25622. },
  25623. theme:editor.options.theme,
  25624. disabled:(cmd == 'scrawl' && editor.queryCommandState("scrawl") == -1) || ( cmd == 'charts' )
  25625. });
  25626. editorui.buttons[cmd] = ui;
  25627. editor.addListener('selectionchange', function () {
  25628. //只存在于右键菜单而无工具栏按钮的ui不需要检测状态
  25629. var unNeedCheckState = {'edittable':1};
  25630. if (cmd in unNeedCheckState)return;
  25631. var state = editor.queryCommandState(cmd);
  25632. if (ui.getDom()) {
  25633. ui.setDisabled(state == -1);
  25634. ui.setChecked(state);
  25635. }
  25636. });
  25637. return ui;
  25638. };
  25639. })(ci.toLowerCase())
  25640. }
  25641. })(p, dialogBtns[p]);
  25642. }
  25643. editorui.snapscreen = function (editor, iframeUrl, title) {
  25644. title = editor.options.labelMap['snapscreen'] || editor.getLang("labelMap.snapscreen") || '';
  25645. var ui = new editorui.Button({
  25646. className:'edui-for-snapscreen',
  25647. title:title,
  25648. onclick:function () {
  25649. editor.execCommand("snapscreen");
  25650. },
  25651. theme:editor.options.theme
  25652. });
  25653. editorui.buttons['snapscreen'] = ui;
  25654. iframeUrl = iframeUrl || (editor.options.iframeUrlMap || {})["snapscreen"] || iframeUrlMap["snapscreen"];
  25655. if (iframeUrl) {
  25656. var dialog = new editorui.Dialog({
  25657. iframeUrl:editor.ui.mapUrl(iframeUrl),
  25658. editor:editor,
  25659. className:'edui-for-snapscreen',
  25660. title:title,
  25661. buttons:[
  25662. {
  25663. className:'edui-okbutton',
  25664. label:editor.getLang("ok"),
  25665. editor:editor,
  25666. onclick:function () {
  25667. dialog.close(true);
  25668. }
  25669. },
  25670. {
  25671. className:'edui-cancelbutton',
  25672. label:editor.getLang("cancel"),
  25673. editor:editor,
  25674. onclick:function () {
  25675. dialog.close(false);
  25676. }
  25677. }
  25678. ]
  25679. });
  25680. dialog.render();
  25681. editor.ui._dialogs["snapscreenDialog"] = dialog;
  25682. }
  25683. editor.addListener('selectionchange', function () {
  25684. ui.setDisabled(editor.queryCommandState('snapscreen') == -1);
  25685. });
  25686. return ui;
  25687. };
  25688. editorui.insertcode = function (editor, list, title) {
  25689. list = editor.options['insertcode'] || [];
  25690. title = editor.options.labelMap['insertcode'] || editor.getLang("labelMap.insertcode") || '';
  25691. // if (!list.length) return;
  25692. var items = [];
  25693. utils.each(list,function(key,val){
  25694. items.push({
  25695. label:key,
  25696. value:val,
  25697. theme:editor.options.theme,
  25698. renderLabelHtml:function () {
  25699. return '<div class="edui-label %%-label" >' + (this.label || '') + '</div>';
  25700. }
  25701. });
  25702. });
  25703. var ui = new editorui.Combox({
  25704. editor:editor,
  25705. items:items,
  25706. onselect:function (t, index) {
  25707. editor.execCommand('insertcode', this.items[index].value);
  25708. },
  25709. onbuttonclick:function () {
  25710. this.showPopup();
  25711. },
  25712. title:title,
  25713. initValue:title,
  25714. className:'edui-for-insertcode',
  25715. indexByValue:function (value) {
  25716. if (value) {
  25717. for (var i = 0, ci; ci = this.items[i]; i++) {
  25718. if (ci.value.indexOf(value) != -1)
  25719. return i;
  25720. }
  25721. }
  25722. return -1;
  25723. }
  25724. });
  25725. editorui.buttons['insertcode'] = ui;
  25726. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  25727. if (!uiReady) {
  25728. var state = editor.queryCommandState('insertcode');
  25729. if (state == -1) {
  25730. ui.setDisabled(true);
  25731. } else {
  25732. ui.setDisabled(false);
  25733. var value = editor.queryCommandValue('insertcode');
  25734. if(!value){
  25735. ui.setValue(title);
  25736. return;
  25737. }
  25738. //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
  25739. value && (value = value.replace(/['"]/g, '').split(',')[0]);
  25740. ui.setValue(value);
  25741. }
  25742. }
  25743. });
  25744. return ui;
  25745. };
  25746. editorui.fontfamily = function (editor, list, title) {
  25747. list = editor.options['fontfamily'] || [];
  25748. title = editor.options.labelMap['fontfamily'] || editor.getLang("labelMap.fontfamily") || '';
  25749. if (!list.length) return;
  25750. for (var i = 0, ci, items = []; ci = list[i]; i++) {
  25751. var langLabel = editor.getLang('fontfamily')[ci.name] || "";
  25752. (function (key, val) {
  25753. items.push({
  25754. label:key,
  25755. value:val,
  25756. theme:editor.options.theme,
  25757. renderLabelHtml:function () {
  25758. return '<div class="edui-label %%-label" style="font-family:' +
  25759. utils.unhtml(this.value) + '">' + (this.label || '') + '</div>';
  25760. }
  25761. });
  25762. })(ci.label || langLabel, ci.val)
  25763. }
  25764. var ui = new editorui.Combox({
  25765. editor:editor,
  25766. items:items,
  25767. onselect:function (t, index) {
  25768. editor.execCommand('FontFamily', this.items[index].value);
  25769. },
  25770. onbuttonclick:function () {
  25771. this.showPopup();
  25772. },
  25773. title:title,
  25774. initValue:title,
  25775. className:'edui-for-fontfamily',
  25776. indexByValue:function (value) {
  25777. if (value) {
  25778. for (var i = 0, ci; ci = this.items[i]; i++) {
  25779. if (ci.value.indexOf(value) != -1)
  25780. return i;
  25781. }
  25782. }
  25783. return -1;
  25784. }
  25785. });
  25786. editorui.buttons['fontfamily'] = ui;
  25787. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  25788. if (!uiReady) {
  25789. var state = editor.queryCommandState('FontFamily');
  25790. if (state == -1) {
  25791. ui.setDisabled(true);
  25792. } else {
  25793. ui.setDisabled(false);
  25794. var value = editor.queryCommandValue('FontFamily');
  25795. //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
  25796. value && (value = value.replace(/['"]/g, '').split(',')[0]);
  25797. ui.setValue(value);
  25798. }
  25799. }
  25800. });
  25801. return ui;
  25802. };
  25803. editorui.fontsize = function (editor, list, title) {
  25804. title = editor.options.labelMap['fontsize'] || editor.getLang("labelMap.fontsize") || '';
  25805. list = list || editor.options['fontsize'] || [];
  25806. if (!list.length) return;
  25807. var items = [];
  25808. for (var i = 0; i < list.length; i++) {
  25809. var size = list[i] + 'px';
  25810. items.push({
  25811. label:size,
  25812. value:size,
  25813. theme:editor.options.theme,
  25814. renderLabelHtml:function () {
  25815. return '<div class="edui-label %%-label" style="line-height:1;font-size:' +
  25816. this.value + '">' + (this.label || '') + '</div>';
  25817. }
  25818. });
  25819. }
  25820. var ui = new editorui.Combox({
  25821. editor:editor,
  25822. items:items,
  25823. title:title,
  25824. initValue:title,
  25825. onselect:function (t, index) {
  25826. editor.execCommand('FontSize', this.items[index].value);
  25827. },
  25828. onbuttonclick:function () {
  25829. this.showPopup();
  25830. },
  25831. className:'edui-for-fontsize'
  25832. });
  25833. editorui.buttons['fontsize'] = ui;
  25834. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  25835. if (!uiReady) {
  25836. var state = editor.queryCommandState('FontSize');
  25837. if (state == -1) {
  25838. ui.setDisabled(true);
  25839. } else {
  25840. ui.setDisabled(false);
  25841. ui.setValue(editor.queryCommandValue('FontSize'));
  25842. }
  25843. }
  25844. });
  25845. return ui;
  25846. };
  25847. editorui.paragraph = function (editor, list, title) {
  25848. title = editor.options.labelMap['paragraph'] || editor.getLang("labelMap.paragraph") || '';
  25849. list = editor.options['paragraph'] || [];
  25850. if (utils.isEmptyObject(list)) return;
  25851. var items = [];
  25852. for (var i in list) {
  25853. items.push({
  25854. value:i,
  25855. label:list[i] || editor.getLang("paragraph")[i],
  25856. theme:editor.options.theme,
  25857. renderLabelHtml:function () {
  25858. return '<div class="edui-label %%-label"><span class="edui-for-' + this.value + '">' + (this.label || '') + '</span></div>';
  25859. }
  25860. })
  25861. }
  25862. var ui = new editorui.Combox({
  25863. editor:editor,
  25864. items:items,
  25865. title:title,
  25866. initValue:title,
  25867. className:'edui-for-paragraph',
  25868. onselect:function (t, index) {
  25869. editor.execCommand('Paragraph', this.items[index].value);
  25870. },
  25871. onbuttonclick:function () {
  25872. this.showPopup();
  25873. }
  25874. });
  25875. editorui.buttons['paragraph'] = ui;
  25876. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  25877. if (!uiReady) {
  25878. var state = editor.queryCommandState('Paragraph');
  25879. if (state == -1) {
  25880. ui.setDisabled(true);
  25881. } else {
  25882. ui.setDisabled(false);
  25883. var value = editor.queryCommandValue('Paragraph');
  25884. var index = ui.indexByValue(value);
  25885. if (index != -1) {
  25886. ui.setValue(value);
  25887. } else {
  25888. ui.setValue(ui.initValue);
  25889. }
  25890. }
  25891. }
  25892. });
  25893. return ui;
  25894. };
  25895. //自定义标题
  25896. editorui.customstyle = function (editor) {
  25897. var list = editor.options['customstyle'] || [],
  25898. title = editor.options.labelMap['customstyle'] || editor.getLang("labelMap.customstyle") || '';
  25899. if (!list.length)return;
  25900. var langCs = editor.getLang('customstyle');
  25901. for (var i = 0, items = [], t; t = list[i++];) {
  25902. (function (t) {
  25903. var ck = {};
  25904. ck.label = t.label ? t.label : langCs[t.name];
  25905. ck.style = t.style;
  25906. ck.className = t.className;
  25907. ck.tag = t.tag;
  25908. items.push({
  25909. label:ck.label,
  25910. value:ck,
  25911. theme:editor.options.theme,
  25912. renderLabelHtml:function () {
  25913. return '<div class="edui-label %%-label">' + '<' + ck.tag + ' ' + (ck.className ? ' class="' + ck.className + '"' : "")
  25914. + (ck.style ? ' style="' + ck.style + '"' : "") + '>' + ck.label + "<\/" + ck.tag + ">"
  25915. + '</div>';
  25916. }
  25917. });
  25918. })(t);
  25919. }
  25920. var ui = new editorui.Combox({
  25921. editor:editor,
  25922. items:items,
  25923. title:title,
  25924. initValue:title,
  25925. className:'edui-for-customstyle',
  25926. onselect:function (t, index) {
  25927. editor.execCommand('customstyle', this.items[index].value);
  25928. },
  25929. onbuttonclick:function () {
  25930. this.showPopup();
  25931. },
  25932. indexByValue:function (value) {
  25933. for (var i = 0, ti; ti = this.items[i++];) {
  25934. if (ti.label == value) {
  25935. return i - 1
  25936. }
  25937. }
  25938. return -1;
  25939. }
  25940. });
  25941. editorui.buttons['customstyle'] = ui;
  25942. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  25943. if (!uiReady) {
  25944. var state = editor.queryCommandState('customstyle');
  25945. if (state == -1) {
  25946. ui.setDisabled(true);
  25947. } else {
  25948. ui.setDisabled(false);
  25949. var value = editor.queryCommandValue('customstyle');
  25950. var index = ui.indexByValue(value);
  25951. if (index != -1) {
  25952. ui.setValue(value);
  25953. } else {
  25954. ui.setValue(ui.initValue);
  25955. }
  25956. }
  25957. }
  25958. });
  25959. return ui;
  25960. };
  25961. editorui.inserttable = function (editor, iframeUrl, title) {
  25962. title = editor.options.labelMap['inserttable'] || editor.getLang("labelMap.inserttable") || '';
  25963. var ui = new editorui.TableButton({
  25964. editor:editor,
  25965. title:title,
  25966. className:'edui-for-inserttable',
  25967. onpicktable:function (t, numCols, numRows) {
  25968. editor.execCommand('InsertTable', {numRows:numRows, numCols:numCols, border:1});
  25969. },
  25970. onbuttonclick:function () {
  25971. this.showPopup();
  25972. }
  25973. });
  25974. editorui.buttons['inserttable'] = ui;
  25975. editor.addListener('selectionchange', function () {
  25976. ui.setDisabled(editor.queryCommandState('inserttable') == -1);
  25977. });
  25978. return ui;
  25979. };
  25980. editorui.lineheight = function (editor) {
  25981. var val = editor.options.lineheight || [];
  25982. if (!val.length)return;
  25983. for (var i = 0, ci, items = []; ci = val[i++];) {
  25984. items.push({
  25985. //todo:写死了
  25986. label:ci,
  25987. value:ci,
  25988. theme:editor.options.theme,
  25989. onclick:function () {
  25990. editor.execCommand("lineheight", this.value);
  25991. }
  25992. })
  25993. }
  25994. var ui = new editorui.MenuButton({
  25995. editor:editor,
  25996. className:'edui-for-lineheight',
  25997. title:editor.options.labelMap['lineheight'] || editor.getLang("labelMap.lineheight") || '',
  25998. items:items,
  25999. onbuttonclick:function () {
  26000. var value = editor.queryCommandValue('LineHeight') || this.value;
  26001. editor.execCommand("LineHeight", value);
  26002. }
  26003. });
  26004. editorui.buttons['lineheight'] = ui;
  26005. editor.addListener('selectionchange', function () {
  26006. var state = editor.queryCommandState('LineHeight');
  26007. if (state == -1) {
  26008. ui.setDisabled(true);
  26009. } else {
  26010. ui.setDisabled(false);
  26011. var value = editor.queryCommandValue('LineHeight');
  26012. value && ui.setValue((value + '').replace(/cm/, ''));
  26013. ui.setChecked(state)
  26014. }
  26015. });
  26016. return ui;
  26017. };
  26018. var rowspacings = ['top', 'bottom'];
  26019. for (var r = 0, ri; ri = rowspacings[r++];) {
  26020. (function (cmd) {
  26021. editorui['rowspacing' + cmd] = function (editor) {
  26022. var val = editor.options['rowspacing' + cmd] || [];
  26023. if (!val.length) return null;
  26024. for (var i = 0, ci, items = []; ci = val[i++];) {
  26025. items.push({
  26026. label:ci,
  26027. value:ci,
  26028. theme:editor.options.theme,
  26029. onclick:function () {
  26030. editor.execCommand("rowspacing", this.value, cmd);
  26031. }
  26032. })
  26033. }
  26034. var ui = new editorui.MenuButton({
  26035. editor:editor,
  26036. className:'edui-for-rowspacing' + cmd,
  26037. title:editor.options.labelMap['rowspacing' + cmd] || editor.getLang("labelMap.rowspacing" + cmd) || '',
  26038. items:items,
  26039. onbuttonclick:function () {
  26040. var value = editor.queryCommandValue('rowspacing', cmd) || this.value;
  26041. editor.execCommand("rowspacing", value, cmd);
  26042. }
  26043. });
  26044. editorui.buttons[cmd] = ui;
  26045. editor.addListener('selectionchange', function () {
  26046. var state = editor.queryCommandState('rowspacing', cmd);
  26047. if (state == -1) {
  26048. ui.setDisabled(true);
  26049. } else {
  26050. ui.setDisabled(false);
  26051. var value = editor.queryCommandValue('rowspacing', cmd);
  26052. value && ui.setValue((value + '').replace(/%/, ''));
  26053. ui.setChecked(state)
  26054. }
  26055. });
  26056. return ui;
  26057. }
  26058. })(ri)
  26059. }
  26060. //有序,无序列表
  26061. var lists = ['insertorderedlist', 'insertunorderedlist'];
  26062. for (var l = 0, cl; cl = lists[l++];) {
  26063. (function (cmd) {
  26064. editorui[cmd] = function (editor) {
  26065. var vals = editor.options[cmd],
  26066. _onMenuClick = function () {
  26067. editor.execCommand(cmd, this.value);
  26068. }, items = [];
  26069. for (var i in vals) {
  26070. items.push({
  26071. label:vals[i] || editor.getLang()[cmd][i] || "",
  26072. value:i,
  26073. theme:editor.options.theme,
  26074. onclick:_onMenuClick
  26075. })
  26076. }
  26077. var ui = new editorui.MenuButton({
  26078. editor:editor,
  26079. className:'edui-for-' + cmd,
  26080. title:editor.getLang("labelMap." + cmd) || '',
  26081. 'items':items,
  26082. onbuttonclick:function () {
  26083. var value = editor.queryCommandValue(cmd) || this.value;
  26084. editor.execCommand(cmd, value);
  26085. }
  26086. });
  26087. editorui.buttons[cmd] = ui;
  26088. editor.addListener('selectionchange', function () {
  26089. var state = editor.queryCommandState(cmd);
  26090. if (state == -1) {
  26091. ui.setDisabled(true);
  26092. } else {
  26093. ui.setDisabled(false);
  26094. var value = editor.queryCommandValue(cmd);
  26095. ui.setValue(value);
  26096. ui.setChecked(state)
  26097. }
  26098. });
  26099. return ui;
  26100. };
  26101. })(cl)
  26102. }
  26103. editorui.fullscreen = function (editor, title) {
  26104. title = editor.options.labelMap['fullscreen'] || editor.getLang("labelMap.fullscreen") || '';
  26105. var ui = new editorui.Button({
  26106. className:'edui-for-fullscreen',
  26107. title:title,
  26108. theme:editor.options.theme,
  26109. onclick:function () {
  26110. if (editor.ui) {
  26111. editor.ui.setFullScreen(!editor.ui.isFullScreen());
  26112. }
  26113. this.setChecked(editor.ui.isFullScreen());
  26114. }
  26115. });
  26116. editorui.buttons['fullscreen'] = ui;
  26117. editor.addListener('selectionchange', function () {
  26118. var state = editor.queryCommandState('fullscreen');
  26119. ui.setDisabled(state == -1);
  26120. ui.setChecked(editor.ui.isFullScreen());
  26121. });
  26122. return ui;
  26123. };
  26124. // 表情
  26125. editorui["emotion"] = function (editor, iframeUrl) {
  26126. var cmd = "emotion";
  26127. var ui = new editorui.MultiMenuPop({
  26128. title:editor.options.labelMap[cmd] || editor.getLang("labelMap." + cmd + "") || '',
  26129. editor:editor,
  26130. className:'edui-for-' + cmd,
  26131. iframeUrl:editor.ui.mapUrl(iframeUrl || (editor.options.iframeUrlMap || {})[cmd] || iframeUrlMap[cmd])
  26132. });
  26133. editorui.buttons[cmd] = ui;
  26134. editor.addListener('selectionchange', function () {
  26135. ui.setDisabled(editor.queryCommandState(cmd) == -1)
  26136. });
  26137. return ui;
  26138. };
  26139. editorui.autotypeset = function (editor) {
  26140. var ui = new editorui.AutoTypeSetButton({
  26141. editor:editor,
  26142. title:editor.options.labelMap['autotypeset'] || editor.getLang("labelMap.autotypeset") || '',
  26143. className:'edui-for-autotypeset',
  26144. onbuttonclick:function () {
  26145. editor.execCommand('autotypeset')
  26146. }
  26147. });
  26148. editorui.buttons['autotypeset'] = ui;
  26149. editor.addListener('selectionchange', function () {
  26150. ui.setDisabled(editor.queryCommandState('autotypeset') == -1);
  26151. });
  26152. return ui;
  26153. };
  26154. /* 简单上传插件 */
  26155. editorui["simpleupload"] = function (editor) {
  26156. var name = 'simpleupload',
  26157. ui = new editorui.Button({
  26158. className:'edui-for-' + name,
  26159. title:editor.options.labelMap[name] || editor.getLang("labelMap." + name) || '',
  26160. onclick:function () {},
  26161. theme:editor.options.theme,
  26162. showText:false
  26163. });
  26164. editorui.buttons[name] = ui;
  26165. editor.addListener('ready', function() {
  26166. var b = ui.getDom('body'),
  26167. iconSpan = b.children[0];
  26168. editor.fireEvent('simpleuploadbtnready', iconSpan);
  26169. });
  26170. editor.addListener('selectionchange', function (type, causeByUi, uiReady) {
  26171. var state = editor.queryCommandState(name);
  26172. if (state == -1) {
  26173. ui.setDisabled(true);
  26174. ui.setChecked(false);
  26175. } else {
  26176. if (!uiReady) {
  26177. ui.setDisabled(false);
  26178. ui.setChecked(state);
  26179. }
  26180. }
  26181. });
  26182. return ui;
  26183. };
  26184. })();
  26185. // adapter/editor.js
  26186. ///import core
  26187. ///commands 全屏
  26188. ///commandsName FullScreen
  26189. ///commandsTitle 全屏
  26190. (function () {
  26191. var utils = baidu.editor.utils,
  26192. uiUtils = baidu.editor.ui.uiUtils,
  26193. UIBase = baidu.editor.ui.UIBase,
  26194. domUtils = baidu.editor.dom.domUtils;
  26195. var nodeStack = [];
  26196. function EditorUI(options) {
  26197. this.initOptions(options);
  26198. this.initEditorUI();
  26199. }
  26200. EditorUI.prototype = {
  26201. uiName:'editor',
  26202. initEditorUI:function () {
  26203. this.editor.ui = this;
  26204. this._dialogs = {};
  26205. this.initUIBase();
  26206. this._initToolbars();
  26207. var editor = this.editor,
  26208. me = this;
  26209. editor.addListener('ready', function () {
  26210. //提供getDialog方法
  26211. editor.getDialog = function (name) {
  26212. return editor.ui._dialogs[name + "Dialog"];
  26213. };
  26214. domUtils.on(editor.window, 'scroll', function (evt) {
  26215. baidu.editor.ui.Popup.postHide(evt);
  26216. });
  26217. //提供编辑器实时宽高(全屏时宽高不变化)
  26218. editor.ui._actualFrameWidth = editor.options.initialFrameWidth;
  26219. UE.browser.ie && UE.browser.version === 6 && editor.container.ownerDocument.execCommand("BackgroundImageCache", false, true);
  26220. //display bottom-bar label based on config
  26221. if (editor.options.elementPathEnabled) {
  26222. editor.ui.getDom('elementpath').innerHTML = '<div class="edui-editor-breadcrumb">' + editor.getLang("elementPathTip") + ':</div>';
  26223. }
  26224. if (editor.options.wordCount) {
  26225. function countFn() {
  26226. setCount(editor,me);
  26227. domUtils.un(editor.document, "click", arguments.callee);
  26228. }
  26229. domUtils.on(editor.document, "click", countFn);
  26230. editor.ui.getDom('wordcount').innerHTML = editor.getLang("wordCountTip");
  26231. }
  26232. editor.ui._scale();
  26233. if (editor.options.scaleEnabled) {
  26234. if (editor.autoHeightEnabled) {
  26235. editor.disableAutoHeight();
  26236. }
  26237. me.enableScale();
  26238. } else {
  26239. me.disableScale();
  26240. }
  26241. if (!editor.options.elementPathEnabled && !editor.options.wordCount && !editor.options.scaleEnabled) {
  26242. editor.ui.getDom('elementpath').style.display = "none";
  26243. editor.ui.getDom('wordcount').style.display = "none";
  26244. editor.ui.getDom('scale').style.display = "none";
  26245. }
  26246. if (!editor.selection.isFocus())return;
  26247. editor.fireEvent('selectionchange', false, true);
  26248. });
  26249. editor.addListener('mousedown', function (t, evt) {
  26250. var el = evt.target || evt.srcElement;
  26251. baidu.editor.ui.Popup.postHide(evt, el);
  26252. baidu.editor.ui.ShortCutMenu.postHide(evt);
  26253. });
  26254. editor.addListener("delcells", function () {
  26255. if (UE.ui['edittip']) {
  26256. new UE.ui['edittip'](editor);
  26257. }
  26258. editor.getDialog('edittip').open();
  26259. });
  26260. var pastePop, isPaste = false, timer;
  26261. editor.addListener("afterpaste", function () {
  26262. if(editor.queryCommandState('pasteplain'))
  26263. return;
  26264. if(baidu.editor.ui.PastePicker){
  26265. pastePop = new baidu.editor.ui.Popup({
  26266. content:new baidu.editor.ui.PastePicker({editor:editor}),
  26267. editor:editor,
  26268. className:'edui-wordpastepop'
  26269. });
  26270. pastePop.render();
  26271. }
  26272. isPaste = true;
  26273. });
  26274. editor.addListener("afterinserthtml", function () {
  26275. clearTimeout(timer);
  26276. timer = setTimeout(function () {
  26277. if (pastePop && (isPaste || editor.ui._isTransfer)) {
  26278. if(pastePop.isHidden()){
  26279. var span = domUtils.createElement(editor.document, 'span', {
  26280. 'style':"line-height:0px;",
  26281. 'innerHTML':'\ufeff'
  26282. }),
  26283. range = editor.selection.getRange();
  26284. range.insertNode(span);
  26285. var tmp= getDomNode(span, 'firstChild', 'previousSibling');
  26286. tmp && pastePop.showAnchor(tmp.nodeType == 3 ? tmp.parentNode : tmp);
  26287. domUtils.remove(span);
  26288. }else{
  26289. pastePop.show();
  26290. }
  26291. delete editor.ui._isTransfer;
  26292. isPaste = false;
  26293. }
  26294. }, 200)
  26295. });
  26296. editor.addListener('contextmenu', function (t, evt) {
  26297. baidu.editor.ui.Popup.postHide(evt);
  26298. });
  26299. editor.addListener('keydown', function (t, evt) {
  26300. if (pastePop) pastePop.dispose(evt);
  26301. var keyCode = evt.keyCode || evt.which;
  26302. if(evt.altKey&&keyCode==90){
  26303. UE.ui.buttons['fullscreen'].onclick();
  26304. }
  26305. });
  26306. editor.addListener('wordcount', function (type) {
  26307. setCount(this,me);
  26308. });
  26309. function setCount(editor,ui) {
  26310. editor.setOpt({
  26311. wordCount:true,
  26312. maximumWords:10000,
  26313. wordCountMsg:editor.options.wordCountMsg || editor.getLang("wordCountMsg"),
  26314. wordOverFlowMsg:editor.options.wordOverFlowMsg || editor.getLang("wordOverFlowMsg")
  26315. });
  26316. var opt = editor.options,
  26317. max = opt.maximumWords,
  26318. msg = opt.wordCountMsg ,
  26319. errMsg = opt.wordOverFlowMsg,
  26320. countDom = ui.getDom('wordcount');
  26321. if (!opt.wordCount) {
  26322. return;
  26323. }
  26324. var count = editor.getContentLength(true);
  26325. if (count > max) {
  26326. countDom.innerHTML = errMsg;
  26327. editor.fireEvent("wordcountoverflow");
  26328. } else {
  26329. countDom.innerHTML = msg.replace("{#leave}", max - count).replace("{#count}", count);
  26330. }
  26331. }
  26332. editor.addListener('selectionchange', function () {
  26333. if (editor.options.elementPathEnabled) {
  26334. me[(editor.queryCommandState('elementpath') == -1 ? 'dis' : 'en') + 'ableElementPath']()
  26335. }
  26336. if (editor.options.scaleEnabled) {
  26337. me[(editor.queryCommandState('scale') == -1 ? 'dis' : 'en') + 'ableScale']();
  26338. }
  26339. });
  26340. var popup = new baidu.editor.ui.Popup({
  26341. editor:editor,
  26342. content:'',
  26343. className:'edui-bubble',
  26344. _onEditButtonClick:function () {
  26345. this.hide();
  26346. editor.ui._dialogs.linkDialog.open();
  26347. },
  26348. _onImgEditButtonClick:function (name) {
  26349. this.hide();
  26350. editor.ui._dialogs[name] && editor.ui._dialogs[name].open();
  26351. },
  26352. _onImgSetFloat:function (value) {
  26353. this.hide();
  26354. editor.execCommand("imagefloat", value);
  26355. },
  26356. _setIframeAlign:function (value) {
  26357. var frame = popup.anchorEl;
  26358. var newFrame = frame.cloneNode(true);
  26359. switch (value) {
  26360. case -2:
  26361. newFrame.setAttribute("align", "");
  26362. break;
  26363. case -1:
  26364. newFrame.setAttribute("align", "left");
  26365. break;
  26366. case 1:
  26367. newFrame.setAttribute("align", "right");
  26368. break;
  26369. }
  26370. frame.parentNode.insertBefore(newFrame, frame);
  26371. domUtils.remove(frame);
  26372. popup.anchorEl = newFrame;
  26373. popup.showAnchor(popup.anchorEl);
  26374. },
  26375. _updateIframe:function () {
  26376. var frame = editor._iframe = popup.anchorEl;
  26377. if(domUtils.hasClass(frame, 'ueditor_baidumap')) {
  26378. editor.selection.getRange().selectNode(frame).select();
  26379. editor.ui._dialogs.mapDialog.open();
  26380. popup.hide();
  26381. } else {
  26382. editor.ui._dialogs.insertframeDialog.open();
  26383. popup.hide();
  26384. }
  26385. },
  26386. _onRemoveButtonClick:function (cmdName) {
  26387. editor.execCommand(cmdName);
  26388. this.hide();
  26389. },
  26390. queryAutoHide:function (el) {
  26391. if (el && el.ownerDocument == editor.document) {
  26392. if (el.tagName.toLowerCase() == 'img' || domUtils.findParentByTagName(el, 'a', true)) {
  26393. return el !== popup.anchorEl;
  26394. }
  26395. }
  26396. return baidu.editor.ui.Popup.prototype.queryAutoHide.call(this, el);
  26397. }
  26398. });
  26399. popup.render();
  26400. if (editor.options.imagePopup) {
  26401. editor.addListener('mouseover', function (t, evt) {
  26402. evt = evt || window.event;
  26403. var el = evt.target || evt.srcElement;
  26404. if (editor.ui._dialogs.insertframeDialog && /iframe/ig.test(el.tagName)) {
  26405. var html = popup.formatHtml(
  26406. '<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;' +
  26407. ' <span onclick="$$._updateIframe( this);" class="edui-clickable">' + editor.getLang("modify") + '</span></nobr>');
  26408. if (html) {
  26409. popup.getDom('content').innerHTML = html;
  26410. popup.anchorEl = el;
  26411. popup.showAnchor(popup.anchorEl);
  26412. } else {
  26413. popup.hide();
  26414. }
  26415. }
  26416. });
  26417. editor.addListener('selectionchange', function (t, causeByUi) {
  26418. if (!causeByUi) return;
  26419. var html = '', str = "",
  26420. img = editor.selection.getRange().getClosedNode(),
  26421. dialogs = editor.ui._dialogs;
  26422. if (img && img.tagName == 'IMG') {
  26423. var dialogName = 'insertimageDialog';
  26424. if (img.className.indexOf("edui-faked-video") != -1 || img.className.indexOf("edui-upload-video") != -1) {
  26425. dialogName = "insertvideoDialog"
  26426. }
  26427. if (img.className.indexOf("edui-faked-webapp") != -1) {
  26428. dialogName = "webappDialog"
  26429. }
  26430. if (img.src.indexOf("http://api.map.baidu.com") != -1) {
  26431. dialogName = "mapDialog"
  26432. }
  26433. if (img.className.indexOf("edui-faked-music") != -1) {
  26434. dialogName = "musicDialog"
  26435. }
  26436. if (img.src.indexOf("http://maps.google.com/maps/api/staticmap") != -1) {
  26437. dialogName = "gmapDialog"
  26438. }
  26439. if (img.getAttribute("anchorname")) {
  26440. dialogName = "anchorDialog";
  26441. html = popup.formatHtml(
  26442. '<nobr>' + editor.getLang("property") + ': <span onclick=$$._onImgEditButtonClick("anchorDialog") class="edui-clickable">' + editor.getLang("modify") + '</span>&nbsp;&nbsp;' +
  26443. '<span onclick=$$._onRemoveButtonClick(\'anchor\') class="edui-clickable">' + editor.getLang("delete") + '</span></nobr>');
  26444. }
  26445. if (img.getAttribute("word_img")) {
  26446. //todo 放到dialog去做查询
  26447. editor.word_img = [img.getAttribute("word_img")];
  26448. dialogName = "wordimageDialog"
  26449. }
  26450. if(domUtils.hasClass(img, 'loadingclass') || domUtils.hasClass(img, 'loaderrorclass')) {
  26451. dialogName = "";
  26452. }
  26453. if (!dialogs[dialogName]) {
  26454. return;
  26455. }
  26456. str = '<nobr>' + editor.getLang("property") + ': '+
  26457. '<span onclick=$$._onImgSetFloat("none") class="edui-clickable">' + editor.getLang("default") + '</span>&nbsp;&nbsp;' +
  26458. '<span onclick=$$._onImgSetFloat("left") class="edui-clickable">' + editor.getLang("justifyleft") + '</span>&nbsp;&nbsp;' +
  26459. '<span onclick=$$._onImgSetFloat("right") class="edui-clickable">' + editor.getLang("justifyright") + '</span>&nbsp;&nbsp;' +
  26460. '<span onclick=$$._onImgSetFloat("center") class="edui-clickable">' + editor.getLang("justifycenter") + '</span>&nbsp;&nbsp;'+
  26461. '<span onclick="$$._onImgEditButtonClick(\'' + dialogName + '\');" class="edui-clickable">' + editor.getLang("modify") + '</span></nobr>';
  26462. !html && (html = popup.formatHtml(str))
  26463. }
  26464. if (editor.ui._dialogs.linkDialog) {
  26465. var link = editor.queryCommandValue('link');
  26466. var url;
  26467. if (link && (url = (link.getAttribute('_href') || link.getAttribute('href', 2)))) {
  26468. var txt = url;
  26469. if (url.length > 30) {
  26470. txt = url.substring(0, 20) + "...";
  26471. }
  26472. if (html) {
  26473. html += '<div style="height:5px;"></div>'
  26474. }
  26475. html += popup.formatHtml(
  26476. '<nobr>' + editor.getLang("anthorMsg") + ': <a target="_blank" href="' + url + '" title="' + url + '" >' + txt + '</a>' +
  26477. ' <span class="edui-clickable" onclick="$$._onEditButtonClick();">' + editor.getLang("modify") + '</span>' +
  26478. ' <span class="edui-clickable" onclick="$$._onRemoveButtonClick(\'unlink\');"> ' + editor.getLang("clear") + '</span></nobr>');
  26479. popup.showAnchor(link);
  26480. }
  26481. }
  26482. if (html) {
  26483. popup.getDom('content').innerHTML = html;
  26484. popup.anchorEl = img || link;
  26485. popup.showAnchor(popup.anchorEl);
  26486. } else {
  26487. popup.hide();
  26488. }
  26489. });
  26490. }
  26491. },
  26492. _initToolbars:function () {
  26493. var editor = this.editor;
  26494. var toolbars = this.toolbars || [];
  26495. var toolbarUis = [];
  26496. for (var i = 0; i < toolbars.length; i++) {
  26497. var toolbar = toolbars[i];
  26498. var toolbarUi = new baidu.editor.ui.Toolbar({theme:editor.options.theme});
  26499. for (var j = 0; j < toolbar.length; j++) {
  26500. var toolbarItem = toolbar[j];
  26501. var toolbarItemUi = null;
  26502. if (typeof toolbarItem == 'string') {
  26503. toolbarItem = toolbarItem.toLowerCase();
  26504. if (toolbarItem == '|') {
  26505. toolbarItem = 'Separator';
  26506. }
  26507. if(toolbarItem == '||'){
  26508. toolbarItem = 'Breakline';
  26509. }
  26510. if (baidu.editor.ui[toolbarItem]) {
  26511. toolbarItemUi = new baidu.editor.ui[toolbarItem](editor);
  26512. }
  26513. //fullscreen这里单独处理一下,放到首行去
  26514. if (toolbarItem == 'fullscreen') {
  26515. if (toolbarUis && toolbarUis[0]) {
  26516. toolbarUis[0].items.splice(0, 0, toolbarItemUi);
  26517. } else {
  26518. toolbarItemUi && toolbarUi.items.splice(0, 0, toolbarItemUi);
  26519. }
  26520. continue;
  26521. }
  26522. } else {
  26523. toolbarItemUi = toolbarItem;
  26524. }
  26525. if (toolbarItemUi && toolbarItemUi.id) {
  26526. toolbarUi.add(toolbarItemUi);
  26527. }
  26528. }
  26529. toolbarUis[i] = toolbarUi;
  26530. }
  26531. //接受外部定制的UI(修复因 utils.each 无法准确的循环出对象的全部元素而导致的自定义 UI 不符合预期的 BUG by HaoChuan9421)
  26532. // utils.each(UE._customizeUI,function(obj,key){
  26533. // var itemUI,index;
  26534. // if(obj.id && obj.id != editor.key){
  26535. // return false;
  26536. // }
  26537. // itemUI = obj.execFn.call(editor,editor,key);
  26538. // if(itemUI){
  26539. // index = obj.index;
  26540. // if(index === undefined){
  26541. // index = toolbarUi.items.length;
  26542. // }
  26543. // toolbarUi.add(itemUI,index)
  26544. // }
  26545. // });
  26546. for(var key in UE._customizeUI){
  26547. var obj = UE._customizeUI[key]
  26548. var itemUI,index;
  26549. if(!obj.id || obj.id == editor.key){
  26550. itemUI = obj.execFn.call(editor,editor,key);
  26551. if(itemUI){
  26552. index = obj.index;
  26553. if(index === undefined){
  26554. index = toolbarUi.items.length;
  26555. }
  26556. toolbarUi.add(itemUI,index)
  26557. }
  26558. }
  26559. }
  26560. this.toolbars = toolbarUis;
  26561. },
  26562. getHtmlTpl:function () {
  26563. return '<div id="##" class="%%">' +
  26564. '<div id="##_toolbarbox" class="%%-toolbarbox">' +
  26565. (this.toolbars.length ?
  26566. '<div id="##_toolbarboxouter" class="%%-toolbarboxouter"><div class="%%-toolbarboxinner">' +
  26567. this.renderToolbarBoxHtml() +
  26568. '</div></div>' : '') +
  26569. '<div id="##_toolbarmsg" class="%%-toolbarmsg" style="display:none;">' +
  26570. '<div id = "##_upload_dialog" class="%%-toolbarmsg-upload" onclick="$$.showWordImageDialog();">' + this.editor.getLang("clickToUpload") + '</div>' +
  26571. '<div class="%%-toolbarmsg-close" onclick="$$.hideToolbarMsg();">x</div>' +
  26572. '<div id="##_toolbarmsg_label" class="%%-toolbarmsg-label"></div>' +
  26573. '<div style="height:0;overflow:hidden;clear:both;"></div>' +
  26574. '</div>' +
  26575. '<div id="##_message_holder" class="%%-messageholder"></div>' +
  26576. '</div>' +
  26577. '<div id="##_iframeholder" class="%%-iframeholder">' +
  26578. '</div>' +
  26579. //modify wdcount by matao
  26580. '<div id="##_bottombar" class="%%-bottomContainer"><table><tr>' +
  26581. '<td id="##_elementpath" class="%%-bottombar"></td>' +
  26582. '<td id="##_wordcount" class="%%-wordcount"></td>' +
  26583. '<td id="##_scale" class="%%-scale"><div class="%%-icon"></div></td>' +
  26584. '</tr></table></div>' +
  26585. '<div id="##_scalelayer"></div>' +
  26586. '</div>';
  26587. },
  26588. showWordImageDialog:function () {
  26589. this._dialogs['wordimageDialog'].open();
  26590. },
  26591. renderToolbarBoxHtml:function () {
  26592. var buff = [];
  26593. for (var i = 0; i < this.toolbars.length; i++) {
  26594. buff.push(this.toolbars[i].renderHtml());
  26595. }
  26596. return buff.join('');
  26597. },
  26598. setFullScreen:function (fullscreen) {
  26599. var editor = this.editor,
  26600. container = editor.container.parentNode.parentNode;
  26601. if (this._fullscreen != fullscreen) {
  26602. this._fullscreen = fullscreen;
  26603. this.editor.fireEvent('beforefullscreenchange', fullscreen);
  26604. if (baidu.editor.browser.gecko) {
  26605. var bk = editor.selection.getRange().createBookmark();
  26606. }
  26607. if (fullscreen) {
  26608. while (container.tagName != "BODY") {
  26609. var position = baidu.editor.dom.domUtils.getComputedStyle(container, "position");
  26610. nodeStack.push(position);
  26611. container.style.position = "static";
  26612. container = container.parentNode;
  26613. }
  26614. this._bakHtmlOverflow = document.documentElement.style.overflow;
  26615. this._bakBodyOverflow = document.body.style.overflow;
  26616. this._bakAutoHeight = this.editor.autoHeightEnabled;
  26617. this._bakScrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
  26618. this._bakEditorContaninerWidth = editor.iframe.parentNode.offsetWidth;
  26619. if (this._bakAutoHeight) {
  26620. //当全屏时不能执行自动长高
  26621. editor.autoHeightEnabled = false;
  26622. this.editor.disableAutoHeight();
  26623. }
  26624. document.documentElement.style.overflow = 'hidden';
  26625. //修复,滚动条不收起的问题
  26626. window.scrollTo(0,window.scrollY);
  26627. this._bakCssText = this.getDom().style.cssText;
  26628. this._bakCssText1 = this.getDom('iframeholder').style.cssText;
  26629. editor.iframe.parentNode.style.width = '';
  26630. this._updateFullScreen();
  26631. } else {
  26632. while (container.tagName != "BODY") {
  26633. container.style.position = nodeStack.shift();
  26634. container = container.parentNode;
  26635. }
  26636. this.getDom().style.cssText = this._bakCssText;
  26637. this.getDom('iframeholder').style.cssText = this._bakCssText1;
  26638. if (this._bakAutoHeight) {
  26639. editor.autoHeightEnabled = true;
  26640. this.editor.enableAutoHeight();
  26641. }
  26642. document.documentElement.style.overflow = this._bakHtmlOverflow;
  26643. document.body.style.overflow = this._bakBodyOverflow;
  26644. editor.iframe.parentNode.style.width = this._bakEditorContaninerWidth + 'px';
  26645. window.scrollTo(0, this._bakScrollTop);
  26646. }
  26647. if (browser.gecko && editor.body.contentEditable === 'true') {
  26648. var input = document.createElement('input');
  26649. document.body.appendChild(input);
  26650. editor.body.contentEditable = false;
  26651. setTimeout(function () {
  26652. input.focus();
  26653. setTimeout(function () {
  26654. editor.body.contentEditable = true;
  26655. editor.fireEvent('fullscreenchanged', fullscreen);
  26656. editor.selection.getRange().moveToBookmark(bk).select(true);
  26657. baidu.editor.dom.domUtils.remove(input);
  26658. fullscreen && window.scroll(0, 0);
  26659. }, 0)
  26660. }, 0)
  26661. }
  26662. if(editor.body.contentEditable === 'true'){
  26663. this.editor.fireEvent('fullscreenchanged', fullscreen);
  26664. this.triggerLayout();
  26665. }
  26666. }
  26667. },
  26668. _updateFullScreen:function () {
  26669. if (this._fullscreen) {
  26670. var vpRect = uiUtils.getViewportRect();
  26671. 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);
  26672. uiUtils.setViewportOffset(this.getDom(), { left:0, top:this.editor.options.topOffset || 0 });
  26673. this.editor.setHeight(vpRect.height - this.getDom('toolbarbox').offsetHeight - this.getDom('bottombar').offsetHeight - (this.editor.options.topOffset || 0),true);
  26674. //不手动调一下,会导致全屏失效
  26675. if(browser.gecko){
  26676. try{
  26677. window.onresize();
  26678. }catch(e){
  26679. }
  26680. }
  26681. }
  26682. },
  26683. _updateElementPath:function () {
  26684. var bottom = this.getDom('elementpath'), list;
  26685. if (this.elementPathEnabled && (list = this.editor.queryCommandValue('elementpath'))) {
  26686. var buff = [];
  26687. for (var i = 0, ci; ci = list[i]; i++) {
  26688. buff[i] = this.formatHtml('<span unselectable="on" onclick="$$.editor.execCommand(&quot;elementpath&quot;, &quot;' + i + '&quot;);">' + ci + '</span>');
  26689. }
  26690. bottom.innerHTML = '<div class="edui-editor-breadcrumb" onmousedown="return false;">' + this.editor.getLang("elementPathTip") + ': ' + buff.join(' &gt; ') + '</div>';
  26691. } else {
  26692. bottom.style.display = 'none'
  26693. }
  26694. },
  26695. disableElementPath:function () {
  26696. var bottom = this.getDom('elementpath');
  26697. bottom.innerHTML = '';
  26698. bottom.style.display = 'none';
  26699. this.elementPathEnabled = false;
  26700. },
  26701. enableElementPath:function () {
  26702. var bottom = this.getDom('elementpath');
  26703. bottom.style.display = '';
  26704. this.elementPathEnabled = true;
  26705. this._updateElementPath();
  26706. },
  26707. _scale:function () {
  26708. var doc = document,
  26709. editor = this.editor,
  26710. editorHolder = editor.container,
  26711. editorDocument = editor.document,
  26712. toolbarBox = this.getDom("toolbarbox"),
  26713. bottombar = this.getDom("bottombar"),
  26714. scale = this.getDom("scale"),
  26715. scalelayer = this.getDom("scalelayer");
  26716. var isMouseMove = false,
  26717. position = null,
  26718. minEditorHeight = 0,
  26719. minEditorWidth = editor.options.minFrameWidth,
  26720. pageX = 0,
  26721. pageY = 0,
  26722. scaleWidth = 0,
  26723. scaleHeight = 0;
  26724. function down() {
  26725. position = domUtils.getXY(editorHolder);
  26726. if (!minEditorHeight) {
  26727. minEditorHeight = editor.options.minFrameHeight + toolbarBox.offsetHeight + bottombar.offsetHeight;
  26728. }
  26729. 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:"
  26730. + editorHolder.offsetHeight + "px;z-index:" + (editor.options.zIndex + 1);
  26731. domUtils.on(doc, "mousemove", move);
  26732. domUtils.on(editorDocument, "mouseup", up);
  26733. domUtils.on(doc, "mouseup", up);
  26734. }
  26735. var me = this;
  26736. //by xuheng 全屏时关掉缩放
  26737. this.editor.addListener('fullscreenchanged', function (e, fullScreen) {
  26738. if (fullScreen) {
  26739. me.disableScale();
  26740. } else {
  26741. if (me.editor.options.scaleEnabled) {
  26742. me.enableScale();
  26743. var tmpNode = me.editor.document.createElement('span');
  26744. me.editor.body.appendChild(tmpNode);
  26745. me.editor.body.style.height = Math.max(domUtils.getXY(tmpNode).y, me.editor.iframe.offsetHeight - 20) + 'px';
  26746. domUtils.remove(tmpNode)
  26747. }
  26748. }
  26749. });
  26750. function move(event) {
  26751. clearSelection();
  26752. var e = event || window.event;
  26753. pageX = e.pageX || (doc.documentElement.scrollLeft + e.clientX);
  26754. pageY = e.pageY || (doc.documentElement.scrollTop + e.clientY);
  26755. scaleWidth = pageX - position.x;
  26756. scaleHeight = pageY - position.y;
  26757. if (scaleWidth >= minEditorWidth) {
  26758. isMouseMove = true;
  26759. scalelayer.style.width = scaleWidth + 'px';
  26760. }
  26761. if (scaleHeight >= minEditorHeight) {
  26762. isMouseMove = true;
  26763. scalelayer.style.height = scaleHeight + "px";
  26764. }
  26765. }
  26766. function up() {
  26767. if (isMouseMove) {
  26768. isMouseMove = false;
  26769. editor.ui._actualFrameWidth = scalelayer.offsetWidth - 2;
  26770. editorHolder.style.width = editor.ui._actualFrameWidth + 'px';
  26771. editor.setHeight(scalelayer.offsetHeight - bottombar.offsetHeight - toolbarBox.offsetHeight - 2,true);
  26772. }
  26773. if (scalelayer) {
  26774. scalelayer.style.display = "none";
  26775. }
  26776. clearSelection();
  26777. domUtils.un(doc, "mousemove", move);
  26778. domUtils.un(editorDocument, "mouseup", up);
  26779. domUtils.un(doc, "mouseup", up);
  26780. }
  26781. function clearSelection() {
  26782. if (browser.ie)
  26783. doc.selection.clear();
  26784. else
  26785. window.getSelection().removeAllRanges();
  26786. }
  26787. this.enableScale = function () {
  26788. //trace:2868
  26789. if (editor.queryCommandState("source") == 1) return;
  26790. scale.style.display = "";
  26791. this.scaleEnabled = true;
  26792. domUtils.on(scale, "mousedown", down);
  26793. };
  26794. this.disableScale = function () {
  26795. scale.style.display = "none";
  26796. this.scaleEnabled = false;
  26797. domUtils.un(scale, "mousedown", down);
  26798. };
  26799. },
  26800. isFullScreen:function () {
  26801. return this._fullscreen;
  26802. },
  26803. postRender:function () {
  26804. UIBase.prototype.postRender.call(this);
  26805. for (var i = 0; i < this.toolbars.length; i++) {
  26806. this.toolbars[i].postRender();
  26807. }
  26808. var me = this;
  26809. var timerId,
  26810. domUtils = baidu.editor.dom.domUtils,
  26811. updateFullScreenTime = function () {
  26812. clearTimeout(timerId);
  26813. timerId = setTimeout(function () {
  26814. me._updateFullScreen();
  26815. });
  26816. };
  26817. domUtils.on(window, 'resize', updateFullScreenTime);
  26818. me.addListener('destroy', function () {
  26819. domUtils.un(window, 'resize', updateFullScreenTime);
  26820. clearTimeout(timerId);
  26821. })
  26822. },
  26823. showToolbarMsg:function (msg, flag) {
  26824. this.getDom('toolbarmsg_label').innerHTML = msg;
  26825. this.getDom('toolbarmsg').style.display = '';
  26826. //
  26827. if (!flag) {
  26828. var w = this.getDom('upload_dialog');
  26829. w.style.display = 'none';
  26830. }
  26831. },
  26832. hideToolbarMsg:function () {
  26833. this.getDom('toolbarmsg').style.display = 'none';
  26834. },
  26835. mapUrl:function (url) {
  26836. return url ? url.replace('~/', this.editor.options.UEDITOR_HOME_URL || '') : ''
  26837. },
  26838. triggerLayout:function () {
  26839. var dom = this.getDom();
  26840. if (dom.style.zoom == '1') {
  26841. dom.style.zoom = '100%';
  26842. } else {
  26843. dom.style.zoom = '1';
  26844. }
  26845. }
  26846. };
  26847. utils.inherits(EditorUI, baidu.editor.ui.UIBase);
  26848. var instances = {};
  26849. UE.ui.Editor = function (options) {
  26850. var editor = new UE.Editor(options);
  26851. editor.options.editor = editor;
  26852. utils.loadFile(document, {
  26853. href:editor.options.themePath + editor.options.theme + "/css/ueditor.css",
  26854. tag:"link",
  26855. type:"text/css",
  26856. rel:"stylesheet"
  26857. });
  26858. var oldRender = editor.render;
  26859. editor.render = function (holder) {
  26860. if (holder.constructor === String) {
  26861. editor.key = holder;
  26862. instances[holder] = editor;
  26863. }
  26864. utils.domReady(function () {
  26865. editor.langIsReady ? renderUI() : editor.addListener("langReady", renderUI);
  26866. function renderUI() {
  26867. editor.setOpt({
  26868. labelMap:editor.options.labelMap || editor.getLang('labelMap')
  26869. });
  26870. new EditorUI(editor.options);
  26871. if (holder) {
  26872. if (holder.constructor === String) {
  26873. holder = document.getElementById(holder);
  26874. }
  26875. holder && holder.getAttribute('name') && ( editor.options.textarea = holder.getAttribute('name'));
  26876. if (holder && /script|textarea/ig.test(holder.tagName)) {
  26877. var newDiv = document.createElement('div');
  26878. holder.parentNode.insertBefore(newDiv, holder);
  26879. var cont = holder.value || holder.innerHTML;
  26880. editor.options.initialContent = /^[\t\r\n ]*$/.test(cont) ? editor.options.initialContent :
  26881. cont.replace(/>[\n\r\t]+([ ]{4})+/g, '>')
  26882. .replace(/[\n\r\t]+([ ]{4})+</g, '<')
  26883. .replace(/>[\n\r\t]+</g, '><');
  26884. holder.className && (newDiv.className = holder.className);
  26885. holder.style.cssText && (newDiv.style.cssText = holder.style.cssText);
  26886. if (/textarea/i.test(holder.tagName)) {
  26887. editor.textarea = holder;
  26888. editor.textarea.style.display = 'none';
  26889. } else {
  26890. holder.parentNode.removeChild(holder);
  26891. }
  26892. if(holder.id){
  26893. newDiv.id = holder.id;
  26894. domUtils.removeAttributes(holder,'id');
  26895. }
  26896. holder = newDiv;
  26897. holder.innerHTML = '';
  26898. }
  26899. }
  26900. domUtils.addClass(holder, "edui-" + editor.options.theme);
  26901. editor.ui.render(holder);
  26902. var opt = editor.options;
  26903. //给实例添加一个编辑器的容器引用
  26904. editor.container = editor.ui.getDom();
  26905. var parents = domUtils.findParents(holder,true);
  26906. var displays = [];
  26907. for(var i = 0 ,ci;ci=parents[i];i++){
  26908. displays[i] = ci.style.display;
  26909. ci.style.display = 'block'
  26910. }
  26911. if (opt.initialFrameWidth) {
  26912. opt.minFrameWidth = opt.initialFrameWidth;
  26913. } else {
  26914. opt.minFrameWidth = opt.initialFrameWidth = holder.offsetWidth;
  26915. var styleWidth = holder.style.width;
  26916. if(/%$/.test(styleWidth)) {
  26917. opt.initialFrameWidth = styleWidth;
  26918. }
  26919. }
  26920. if (opt.initialFrameHeight) {
  26921. opt.minFrameHeight = opt.initialFrameHeight;
  26922. } else {
  26923. opt.initialFrameHeight = opt.minFrameHeight = holder.offsetHeight;
  26924. }
  26925. for(var i = 0 ,ci;ci=parents[i];i++){
  26926. ci.style.display = displays[i]
  26927. }
  26928. //编辑器最外容器设置了高度,会导致,编辑器不占位
  26929. //todo 先去掉,没有找到原因
  26930. if(holder.style.height){
  26931. holder.style.height = ''
  26932. }
  26933. editor.container.style.width = opt.initialFrameWidth + (/%$/.test(opt.initialFrameWidth) ? '' : 'px');
  26934. editor.container.style.zIndex = opt.zIndex;
  26935. oldRender.call(editor, editor.ui.getDom('iframeholder'));
  26936. editor.fireEvent("afteruiready");
  26937. }
  26938. })
  26939. };
  26940. return editor;
  26941. };
  26942. /**
  26943. * @file
  26944. * @name UE
  26945. * @short UE
  26946. * @desc UEditor的顶部命名空间
  26947. */
  26948. /**
  26949. * @name getEditor
  26950. * @since 1.2.4+
  26951. * @grammar UE.getEditor(id,[opt]) => Editor实例
  26952. * @desc 提供一个全局的方法得到编辑器实例
  26953. *
  26954. * * ''id'' 放置编辑器的容器id, 如果容器下的编辑器已经存在,就直接返回
  26955. * * ''opt'' 编辑器的可选参数
  26956. * @example
  26957. * UE.getEditor('containerId',{onready:function(){//创建一个编辑器实例
  26958. * this.setContent('hello')
  26959. * }});
  26960. * UE.getEditor('containerId'); //返回刚创建的实例
  26961. *
  26962. */
  26963. UE.getEditor = function (id, opt) {
  26964. var editor = instances[id];
  26965. if (!editor) {
  26966. editor = instances[id] = new UE.ui.Editor(opt);
  26967. editor.render(id);
  26968. }
  26969. return editor;
  26970. };
  26971. UE.delEditor = function (id) {
  26972. var editor;
  26973. if (editor = instances[id]) {
  26974. editor.key && editor.destroy();
  26975. delete instances[id]
  26976. }
  26977. };
  26978. UE.registerUI = function(uiName,fn,index,editorId){
  26979. utils.each(uiName.split(/\s+/), function (name) {
  26980. UE._customizeUI[name] = {
  26981. id : editorId,
  26982. execFn:fn,
  26983. index:index
  26984. };
  26985. })
  26986. }
  26987. })();
  26988. // adapter/message.js
  26989. UE.registerUI('message', function(editor) {
  26990. var editorui = baidu.editor.ui;
  26991. var Message = editorui.Message;
  26992. var holder;
  26993. var _messageItems = [];
  26994. var me = editor;
  26995. me.addListener('ready', function(){
  26996. holder = document.getElementById(me.ui.id + '_message_holder');
  26997. updateHolderPos();
  26998. // HaoChuan9421
  26999. // setTimeout(function(){
  27000. // updateHolderPos();
  27001. // }, 500);
  27002. });
  27003. me.addListener('showmessage', function(type, opt){
  27004. opt = utils.isString(opt) ? {
  27005. 'content': opt
  27006. } : opt;
  27007. var message = new Message({
  27008. 'timeout': opt.timeout,
  27009. 'type': opt.type,
  27010. 'content': opt.content,
  27011. 'keepshow': opt.keepshow,
  27012. 'editor': me
  27013. }),
  27014. mid = opt.id || ('msg_' + (+new Date()).toString(36));
  27015. message.render(holder);
  27016. _messageItems[mid] = message;
  27017. message.reset(opt);
  27018. updateHolderPos();
  27019. return mid;
  27020. });
  27021. me.addListener('updatemessage',function(type, id, opt){
  27022. opt = utils.isString(opt) ? {
  27023. 'content': opt
  27024. } : opt;
  27025. var message = _messageItems[id];
  27026. message.render(holder);
  27027. message && message.reset(opt);
  27028. });
  27029. me.addListener('hidemessage',function(type, id){
  27030. var message = _messageItems[id];
  27031. message && message.hide();
  27032. });
  27033. function updateHolderPos(){
  27034. var toolbarbox = me.ui.getDom('toolbarbox');
  27035. if (toolbarbox) {
  27036. holder.style.top = toolbarbox.offsetHeight + 3 + 'px';
  27037. }
  27038. holder.style.zIndex = Math.max(me.options.zIndex, me.iframe.style.zIndex) + 1;
  27039. }
  27040. });
  27041. // adapter/autosave.js
  27042. UE.registerUI('autosave', function(editor) {
  27043. var timer = null,uid = null;
  27044. editor.on('afterautosave',function(){
  27045. clearTimeout(timer);
  27046. timer = setTimeout(function(){
  27047. if(uid){
  27048. editor.trigger('hidemessage',uid);
  27049. }
  27050. uid = editor.trigger('showmessage',{
  27051. content : editor.getLang('autosave.success'),
  27052. timeout : 2000
  27053. });
  27054. },2000)
  27055. })
  27056. });
  27057. })();