12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119 |
- /*!
- * UEditor Mini版本
- * version: 1.2.2
- * build: Thu Dec 22 2016 16:33:28 GMT+0800 (CST)
- */
- (function ($) {
- UMEDITOR_CONFIG = window.UMEDITOR_CONFIG || {};
- window.UM = {
- list: {},
- plugins: {},
- commands: {},
- I18N: {},
- version: "1.2.2"
- };
- var dom = UM.dom = {};
- /**
- * 浏览器判断模块
- * @file
- * @module UE.browser
- * @since 1.2.6.1
- */
- /**
- * 提供浏览器检测的模块
- * @unfile
- * @module UE.browser
- */
- var browser = UM.browser = function () {
- var agent = navigator.userAgent.toLowerCase(),
- opera = window.opera,
- browser = {
- /**
- * @property {boolean} ie 检测当前浏览器是否为IE
- * @example
- * ```javascript
- * if ( UE.browser.ie ) {
- * console.log( '当前浏览器是IE' );
- * }
- * ```
- */
- ie: /(msie\s|trident.*rv:)([\w.]+)/.test(agent),
- /**
- * @property {boolean} opera 检测当前浏览器是否为Opera
- * @example
- * ```javascript
- * if ( UE.browser.opera ) {
- * console.log( '当前浏览器是Opera' );
- * }
- * ```
- */
- opera: (!!opera && opera.version),
- /**
- * @property {boolean} webkit 检测当前浏览器是否是webkit内核的浏览器
- * @example
- * ```javascript
- * if ( UE.browser.webkit ) {
- * console.log( '当前浏览器是webkit内核浏览器' );
- * }
- * ```
- */
- webkit: (agent.indexOf(' applewebkit/') > -1),
- /**
- * @property {boolean} mac 检测当前浏览器是否是运行在mac平台下
- * @example
- * ```javascript
- * if ( UE.browser.mac ) {
- * console.log( '当前浏览器运行在mac平台下' );
- * }
- * ```
- */
- mac: (agent.indexOf('macintosh') > -1),
- /**
- * @property {boolean} quirks 检测当前浏览器是否处于“怪异模式”下
- * @example
- * ```javascript
- * if ( UE.browser.quirks ) {
- * console.log( '当前浏览器运行处于“怪异模式”' );
- * }
- * ```
- */
- quirks: (document.compatMode == 'BackCompat')
- };
- /**
- * @property {boolean} gecko 检测当前浏览器内核是否是gecko内核
- * @example
- * ```javascript
- * if ( UE.browser.gecko ) {
- * console.log( '当前浏览器内核是gecko内核' );
- * }
- * ```
- */
- browser.gecko = (navigator.product == 'Gecko' && !browser.webkit && !browser.opera && !browser.ie);
- var version = 0;
- // Internet Explorer 6.0+
- if (browser.ie) {
- var v1 = agent.match(/(?:msie\s([\w.]+))/);
- var v2 = agent.match(/(?:trident.*rv:([\w.]+))/);
- if (v1 && v2 && v1[1] && v2[1]) {
- version = Math.max(v1[1] * 1, v2[1] * 1);
- } else if (v1 && v1[1]) {
- version = v1[1] * 1;
- } else if (v2 && v2[1]) {
- version = v2[1] * 1;
- } else {
- version = 0;
- }
- browser.ie11Compat = document.documentMode == 11;
- /**
- * @property { boolean } ie9Compat 检测浏览器模式是否为 IE9 兼容模式
- * @warning 如果浏览器不是IE, 则该值为undefined
- * @example
- * ```javascript
- * if ( UE.browser.ie9Compat ) {
- * console.log( '当前浏览器运行在IE9兼容模式下' );
- * }
- * ```
- */
- browser.ie9Compat = document.documentMode == 9;
- /**
- * @property { boolean } ie8 检测浏览器是否是IE8浏览器
- * @warning 如果浏览器不是IE, 则该值为undefined
- * @example
- * ```javascript
- * if ( UE.browser.ie8 ) {
- * console.log( '当前浏览器是IE8浏览器' );
- * }
- * ```
- */
- browser.ie8 = !!document.documentMode;
- /**
- * @property { boolean } ie8Compat 检测浏览器模式是否为 IE8 兼容模式
- * @warning 如果浏览器不是IE, 则该值为undefined
- * @example
- * ```javascript
- * if ( UE.browser.ie8Compat ) {
- * console.log( '当前浏览器运行在IE8兼容模式下' );
- * }
- * ```
- */
- browser.ie8Compat = document.documentMode == 8;
- /**
- * @property { boolean } ie7Compat 检测浏览器模式是否为 IE7 兼容模式
- * @warning 如果浏览器不是IE, 则该值为undefined
- * @example
- * ```javascript
- * if ( UE.browser.ie7Compat ) {
- * console.log( '当前浏览器运行在IE7兼容模式下' );
- * }
- * ```
- */
- browser.ie7Compat = ((version == 7 && !document.documentMode)
- || document.documentMode == 7);
- /**
- * @property { boolean } ie6Compat 检测浏览器模式是否为 IE6 模式 或者怪异模式
- * @warning 如果浏览器不是IE, 则该值为undefined
- * @example
- * ```javascript
- * if ( UE.browser.ie6Compat ) {
- * console.log( '当前浏览器运行在IE6模式或者怪异模式下' );
- * }
- * ```
- */
- browser.ie6Compat = (version < 7 || browser.quirks);
- browser.ie9above = version > 8;
- browser.ie9below = version < 9;
- }
- // Gecko.
- if (browser.gecko) {
- var geckoRelease = agent.match(/rv:([\d\.]+)/);
- if (geckoRelease) {
- geckoRelease = geckoRelease[1].split('.');
- version = geckoRelease[0] * 10000 + (geckoRelease[1] || 0) * 100 + (geckoRelease[2] || 0) * 1;
- }
- }
- /**
- * @property { Number } chrome 检测当前浏览器是否为Chrome, 如果是,则返回Chrome的大版本号
- * @warning 如果浏览器不是chrome, 则该值为undefined
- * @example
- * ```javascript
- * if ( UE.browser.chrome ) {
- * console.log( '当前浏览器是Chrome' );
- * }
- * ```
- */
- if (/chrome\/(\d+\.\d)/i.test(agent)) {
- browser.chrome = +RegExp['\x241'];
- }
- /**
- * @property { Number } safari 检测当前浏览器是否为Safari, 如果是,则返回Safari的大版本号
- * @warning 如果浏览器不是safari, 则该值为undefined
- * @example
- * ```javascript
- * if ( UE.browser.safari ) {
- * console.log( '当前浏览器是Safari' );
- * }
- * ```
- */
- if (/(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(agent) && !/chrome/i.test(agent)) {
- browser.safari = +(RegExp['\x241'] || RegExp['\x242']);
- }
- // Opera 9.50+
- if (browser.opera)
- version = parseFloat(opera.version());
- // WebKit 522+ (Safari 3+)
- if (browser.webkit)
- version = parseFloat(agent.match(/ applewebkit\/(\d+)/)[1]);
- /**
- * @property { Number } version 检测当前浏览器版本号
- * @remind
- * <ul>
- * <li>IE系列返回值为5,6,7,8,9,10等</li>
- * <li>gecko系列会返回10900,158900等</li>
- * <li>webkit系列会返回其build号 (如 522等)</li>
- * </ul>
- * @example
- * ```javascript
- * console.log( '当前浏览器版本号是: ' + UE.browser.version );
- * ```
- */
- browser.version = version;
- /**
- * @property { boolean } isCompatible 检测当前浏览器是否能够与UEditor良好兼容
- * @example
- * ```javascript
- * if ( UE.browser.isCompatible ) {
- * console.log( '浏览器与UEditor能够良好兼容' );
- * }
- * ```
- */
- browser.isCompatible =
- !browser.mobile && (
- (browser.ie && version >= 6) ||
- (browser.gecko && version >= 10801) ||
- (browser.opera && version >= 9.5) ||
- (browser.air && version >= 1) ||
- (browser.webkit && version >= 522) ||
- false);
- return browser;
- }();
- //快捷方式
- var ie = browser.ie,
- webkit = browser.webkit,
- gecko = browser.gecko,
- opera = browser.opera;
- /**
- * @file
- * @name UM.Utils
- * @short Utils
- * @desc UEditor封装使用的静态工具函数
- * @import editor.js
- */
- var utils = UM.utils = {
- /**
- * 遍历数组,对象,nodeList
- * @name each
- * @grammar UM.utils.each(obj,iterator,[context])
- * @since 1.2.4+
- * @desc
- * * obj 要遍历的对象
- * * iterator 遍历的方法,方法的第一个是遍历的值,第二个是索引,第三个是obj
- * * context iterator的上下文
- * @example
- * UM.utils.each([1,2],function(v,i){
- * console.log(v)//值
- * console.log(i)//索引
- * })
- * UM.utils.each(document.getElementsByTagName('*'),function(n){
- * console.log(n.tagName)
- * })
- */
- each: function (obj, iterator, context) {
- if (obj == null) return;
- if (obj.length === +obj.length) {
- for (var i = 0, l = obj.length; i < l; i++) {
- if (iterator.call(context, obj[i], i, obj) === false)
- return false;
- }
- } else {
- for (var key in obj) {
- if (obj.hasOwnProperty(key)) {
- if (iterator.call(context, obj[key], key, obj) === false)
- return false;
- }
- }
- }
- },
- makeInstance: function (obj) {
- var noop = new Function();
- noop.prototype = obj;
- obj = new noop;
- noop.prototype = null;
- return obj;
- },
- /**
- * 将source对象中的属性扩展到target对象上
- * @name extend
- * @grammar UM.utils.extend(target,source) => Object //覆盖扩展
- * @grammar UM.utils.extend(target,source,true) ==> Object //保留扩展
- */
- extend: function (t, s, b) {
- if (s) {
- for (var k in s) {
- if (!b || !t.hasOwnProperty(k)) {
- t[k] = s[k];
- }
- }
- }
- return t;
- },
- extend2: function (t) {
- var a = arguments;
- for (var i = 1; i < a.length; i++) {
- var x = a[i];
- for (var k in x) {
- if (!t.hasOwnProperty(k)) {
- t[k] = x[k];
- }
- }
- }
- return t;
- },
- /**
- * 模拟继承机制,subClass继承superClass
- * @name inherits
- * @grammar UM.utils.inherits(subClass,superClass) => subClass
- * @example
- * function SuperClass(){
- * this.name = "小李";
- * }
- * SuperClass.prototype = {
- * hello:function(str){
- * console.log(this.name + str);
- * }
- * }
- * function SubClass(){
- * this.name = "小张";
- * }
- * UM.utils.inherits(SubClass,SuperClass);
- * var sub = new SubClass();
- * sub.hello("早上好!"); ==> "小张早上好!"
- */
- inherits: function (subClass, superClass) {
- var oldP = subClass.prototype,
- newP = utils.makeInstance(superClass.prototype);
- utils.extend(newP, oldP, true);
- subClass.prototype = newP;
- return (newP.constructor = subClass);
- },
- /**
- * 用指定的context作为fn上下文,也就是this
- * @name bind
- * @grammar UM.utils.bind(fn,context) => fn
- */
- bind: function (fn, context) {
- return function () {
- return fn.apply(context, arguments);
- };
- },
- /**
- * 创建延迟delay执行的函数fn
- * @name defer
- * @grammar UM.utils.defer(fn,delay) =>fn //延迟delay毫秒执行fn,返回fn
- * @grammar UM.utils.defer(fn,delay,exclusion) =>fn //延迟delay毫秒执行fn,若exclusion为真,则互斥执行fn
- * @example
- * function test(){
- * console.log("延迟输出!");
- * }
- * //非互斥延迟执行
- * var testDefer = UM.utils.defer(test,1000);
- * testDefer(); => "延迟输出!";
- * testDefer(); => "延迟输出!";
- * //互斥延迟执行
- * var testDefer1 = UM.utils.defer(test,1000,true);
- * testDefer1(); => //本次不执行
- * testDefer1(); => "延迟输出!";
- */
- defer: function (fn, delay, exclusion) {
- var timerID;
- return function () {
- if (exclusion) {
- clearTimeout(timerID);
- }
- timerID = setTimeout(fn, delay);
- };
- },
- /**
- * 查找元素item在数组array中的索引, 若找不到返回-1
- * @name indexOf
- * @grammar UM.utils.indexOf(array,item) => index|-1 //默认从数组开头部开始搜索
- * @grammar UM.utils.indexOf(array,item,start) => index|-1 //start指定开始查找的位置
- */
- indexOf: function (array, item, start) {
- var index = -1;
- start = this.isNumber(start) ? start : 0;
- this.each(array, function (v, i) {
- if (i >= start && v === item) {
- index = i;
- return false;
- }
- });
- return index;
- },
- /**
- * 移除数组array中的元素item
- * @name removeItem
- * @grammar UM.utils.removeItem(array,item)
- */
- removeItem: function (array, item) {
- for (var i = 0, l = array.length; i < l; i++) {
- if (array[i] === item) {
- array.splice(i, 1);
- i--;
- }
- }
- },
- /**
- * 删除字符串str的首尾空格
- * @name trim
- * @grammar UM.utils.trim(str) => String
- */
- trim: function (str) {
- return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, '');
- },
- /**
- * 将字符串list(以','分隔)或者数组list转成哈希对象
- * @name listToMap
- * @grammar UM.utils.listToMap(list) => Object //Object形如{test:1,br:1,textarea:1}
- */
- listToMap: function (list) {
- if (!list) return {};
- list = utils.isArray(list) ? list : list.split(',');
- for (var i = 0, ci, obj = {}; ci = list[i++];) {
- obj[ci.toUpperCase()] = obj[ci] = 1;
- }
- return obj;
- },
- /**
- * 将str中的html符号转义,默认将转义''&<">''四个字符,可自定义reg来确定需要转义的字符
- * @name unhtml
- * @grammar UM.utils.unhtml(str); => String
- * @grammar UM.utils.unhtml(str,reg) => String
- * @example
- * var html = '<body>You say:"你好!Baidu & UEditor!"</body>';
- * UM.utils.unhtml(html); ==> <body>You say:"你好!Baidu & UEditor!"</body>
- * UM.utils.unhtml(html,/[<>]/g) ==> <body>You say:"你好!Baidu & UEditor!"</body>
- */
- unhtml: function (str, reg) {
- return str ? str.replace(reg || /[&<">'](?:(amp|lt|quot|gt|#39|nbsp);)?/g, function (a, b) {
- if (b) {
- return a;
- } else {
- return {
- '<': '<',
- '&': '&',
- '"': '"',
- '>': '>',
- "'": '''
- }[a]
- }
- }) : '';
- },
- /**
- * 将str中的转义字符还原成html字符
- * @name html
- * @grammar UM.utils.html(str) => String //详细参见<code><a href = '#unhtml'>unhtml</a></code>
- */
- html: function (str) {
- return str ? str.replace(/&((g|l|quo)t|amp|#39);/g, function (m) {
- return {
- '<': '<',
- '&': '&',
- '"': '"',
- '>': '>',
- ''': "'"
- }[m]
- }) : '';
- },
- /**
- * 将css样式转换为驼峰的形式。如font-size => fontSize
- * @name cssStyleToDomStyle
- * @grammar UM.utils.cssStyleToDomStyle(cssName) => String
- */
- cssStyleToDomStyle: function () {
- var test = document.createElement('div').style,
- cache = {
- 'float': test.cssFloat != undefined ? 'cssFloat' : test.styleFloat != undefined ? 'styleFloat' : 'float'
- };
- return function (cssName) {
- return cache[cssName] || (cache[cssName] = cssName.toLowerCase().replace(/-./g, function (match) {
- return match.charAt(1).toUpperCase();
- }));
- };
- }(),
- /**
- * 动态加载文件到doc中,并依据obj来设置属性,加载成功后执行回调函数fn
- * @name loadFile
- * @grammar UM.utils.loadFile(doc,obj)
- * @grammar UM.utils.loadFile(doc,obj,fn)
- * @example
- * //指定加载到当前document中一个script文件,加载成功后执行function
- * utils.loadFile( document, {
- * src:"test.js",
- * tag:"script",
- * type:"text/javascript",
- * defer:"defer"
- * }, function () {
- * console.log('加载成功!')
- * });
- */
- loadFile: function () {
- var tmpList = [];
- function getItem(doc, obj) {
- try {
- for (var i = 0, ci; ci = tmpList[i++];) {
- if (ci.doc === doc && ci.url == (obj.src || obj.href)) {
- return ci;
- }
- }
- } catch (e) {
- return null;
- }
- }
- return function (doc, obj, fn) {
- var item = getItem(doc, obj);
- if (item) {
- if (item.ready) {
- fn && fn();
- } else {
- item.funs.push(fn)
- }
- return;
- }
- tmpList.push({
- doc: doc,
- url: obj.src || obj.href,
- funs: [fn]
- });
- if (!doc.body) {
- var html = [];
- for (var p in obj) {
- if (p == 'tag') continue;
- html.push(p + '="' + obj[p] + '"')
- }
- doc.write('<' + obj.tag + ' ' + html.join(' ') + ' ></' + obj.tag + '>');
- return;
- }
- if (obj.id && doc.getElementById(obj.id)) {
- return;
- }
- var element = doc.createElement(obj.tag);
- delete obj.tag;
- for (var p in obj) {
- element.setAttribute(p, obj[p]);
- }
- element.onload = element.onreadystatechange = function () {
- if (!this.readyState || /loaded|complete/.test(this.readyState)) {
- item = getItem(doc, obj);
- if (item.funs.length > 0) {
- item.ready = 1;
- for (var fi; fi = item.funs.pop();) {
- fi();
- }
- }
- element.onload = element.onreadystatechange = null;
- }
- };
- element.onerror = function () {
- throw Error('The load ' + (obj.href || obj.src) + ' fails,check the url settings of file umeditor.config.js ')
- };
- doc.getElementsByTagName("head")[0].appendChild(element);
- }
- }(),
- /**
- * 判断obj对象是否为空
- * @name isEmptyObject
- * @grammar UM.utils.isEmptyObject(obj) => true|false
- * @example
- * UM.utils.isEmptyObject({}) ==>true
- * UM.utils.isEmptyObject([]) ==>true
- * UM.utils.isEmptyObject("") ==>true
- */
- isEmptyObject: function (obj) {
- if (obj == null) return true;
- if (this.isArray(obj) || this.isString(obj)) return obj.length === 0;
- for (var key in obj) if (obj.hasOwnProperty(key)) return false;
- return true;
- },
- /**
- * 统一将颜色值使用16进制形式表示
- * @name fixColor
- * @grammar UM.utils.fixColor(name,value) => value
- * @example
- * rgb(255,255,255) => "#ffffff"
- */
- fixColor: function (name, value) {
- if (/color/i.test(name) && /rgba?/.test(value)) {
- var array = value.split(",");
- if (array.length > 3)
- return "";
- value = "#";
- for (var i = 0, color; color = array[i++];) {
- color = parseInt(color.replace(/[^\d]/gi, ''), 10).toString(16);
- value += color.length == 1 ? "0" + color : color;
- }
- value = value.toUpperCase();
- }
- return value;
- },
- /**
- * 深度克隆对象,从source到target
- * @name clone
- * @grammar UM.utils.clone(source) => anthorObj 新的对象是完整的source的副本
- * @grammar UM.utils.clone(source,target) => target包含了source的所有内容,重名会覆盖
- */
- clone: function (source, target) {
- var tmp;
- target = target || {};
- for (var i in source) {
- if (source.hasOwnProperty(i)) {
- tmp = source[i];
- if (typeof tmp == 'object') {
- target[i] = utils.isArray(tmp) ? [] : {};
- utils.clone(source[i], target[i])
- } else {
- target[i] = tmp;
- }
- }
- }
- return target;
- },
- /**
- * 转换cm/pt到px
- * @name transUnitToPx
- * @grammar UM.utils.transUnitToPx('20pt') => '27px'
- * @grammar UM.utils.transUnitToPx('0pt') => '0'
- */
- transUnitToPx: function (val) {
- if (!/(pt|cm)/.test(val)) {
- return val
- }
- var unit;
- val.replace(/([\d.]+)(\w+)/, function (str, v, u) {
- val = v;
- unit = u;
- });
- switch (unit) {
- case 'cm':
- val = parseFloat(val) * 25;
- break;
- case 'pt':
- val = Math.round(parseFloat(val) * 96 / 72);
- }
- return val + (val ? 'px' : '');
- },
- /**
- * 动态添加css样式
- * @name cssRule
- * @grammar UM.utils.cssRule('添加的样式的节点名称',['样式','放到哪个document上'])
- * @grammar UM.utils.cssRule('body','body{background:#ccc}') => null //给body添加背景颜色
- * @grammar UM.utils.cssRule('body') =>样式的字符串 //取得key值为body的样式的内容,如果没有找到key值先关的样式将返回空,例如刚才那个背景颜色,将返回 body{background:#ccc}
- * @grammar UM.utils.cssRule('body','') =>null //清空给定的key值的背景颜色
- */
- cssRule: browser.ie && browser.version != 11 ? function (key, style, doc) {
- var indexList, index;
- doc = doc || document;
- if (doc.indexList) {
- indexList = doc.indexList;
- } else {
- indexList = doc.indexList = {};
- }
- var sheetStyle;
- if (!indexList[key]) {
- if (style === undefined) {
- return ''
- }
- sheetStyle = doc.createStyleSheet('', index = doc.styleSheets.length);
- indexList[key] = index;
- } else {
- sheetStyle = doc.styleSheets[indexList[key]];
- }
- if (style === undefined) {
- return sheetStyle.cssText
- }
- sheetStyle.cssText = style || ''
- } : function (key, style, doc) {
- doc = doc || document;
- var head = doc.getElementsByTagName('head')[0], node;
- if (!(node = doc.getElementById(key))) {
- if (style === undefined) {
- return ''
- }
- node = doc.createElement('style');
- node.id = key;
- head.appendChild(node)
- }
- if (style === undefined) {
- return node.innerHTML
- }
- if (style !== '') {
- node.innerHTML = style;
- } else {
- head.removeChild(node)
- }
- }
- };
- /**
- * 判断str是否为字符串
- * @name isString
- * @grammar UM.utils.isString(str) => true|false
- */
- /**
- * 判断array是否为数组
- * @name isArray
- * @grammar UM.utils.isArray(obj) => true|false
- */
- /**
- * 判断obj对象是否为方法
- * @name isFunction
- * @grammar UM.utils.isFunction(obj) => true|false
- */
- /**
- * 判断obj对象是否为数字
- * @name isNumber
- * @grammar UM.utils.isNumber(obj) => true|false
- */
- utils.each(['String', 'Function', 'Array', 'Number', 'RegExp', 'Object'], function (v) {
- UM.utils['is' + v] = function (obj) {
- return Object.prototype.toString.apply(obj) == '[object ' + v + ']';
- }
- });
- /**
- * @file
- * @name UM.EventBase
- * @short EventBase
- * @import editor.js,core/utils.js
- * @desc UE采用的事件基类,继承此类的对应类将获取addListener,removeListener,fireEvent方法。
- * 在UE中,Editor以及所有ui实例都继承了该类,故可以在对应的ui对象以及editor对象上使用上述方法。
- */
- var EventBase = UM.EventBase = function () {
- };
- EventBase.prototype = {
- /**
- * 注册事件监听器
- * @name addListener
- * @grammar editor.addListener(types,fn) //types为事件名称,多个可用空格分隔
- * @example
- * editor.addListener('selectionchange',function(){
- * console.log("选区已经变化!");
- * })
- * editor.addListener('beforegetcontent aftergetcontent',function(type){
- * if(type == 'beforegetcontent'){
- * //do something
- * }else{
- * //do something
- * }
- * console.log(this.getContent) // this是注册的事件的编辑器实例
- * })
- */
- addListener: function (types, listener) {
- types = utils.trim(types).split(' ');
- for (var i = 0, ti; ti = types[i++];) {
- getListener(this, ti, true).push(listener);
- }
- },
- /**
- * 移除事件监听器
- * @name removeListener
- * @grammar editor.removeListener(types,fn) //types为事件名称,多个可用空格分隔
- * @example
- * //changeCallback为方法体
- * editor.removeListener("selectionchange",changeCallback);
- */
- removeListener: function (types, listener) {
- types = utils.trim(types).split(' ');
- for (var i = 0, ti; ti = types[i++];) {
- utils.removeItem(getListener(this, ti) || [], listener);
- }
- },
- /**
- * 触发事件
- * @name fireEvent
- * @grammar editor.fireEvent(types) //types为事件名称,多个可用空格分隔
- * @example
- * editor.fireEvent("selectionchange");
- */
- fireEvent: function () {
- var types = arguments[0];
- types = utils.trim(types).split(' ');
- for (var i = 0, ti; ti = types[i++];) {
- var listeners = getListener(this, ti),
- r, t, k;
- if (listeners) {
- k = listeners.length;
- while (k--) {
- if (!listeners[k]) continue;
- t = listeners[k].apply(this, arguments);
- if (t === true) {
- return t;
- }
- if (t !== undefined) {
- r = t;
- }
- }
- }
- if (t = this['on' + ti.toLowerCase()]) {
- r = t.apply(this, arguments);
- }
- }
- return r;
- }
- };
- /**
- * 获得对象所拥有监听类型的所有监听器
- * @public
- * @function
- * @param {Object} obj 查询监听器的对象
- * @param {String} type 事件类型
- * @param {Boolean} force 为true且当前所有type类型的侦听器不存在时,创建一个空监听器数组
- * @returns {Array} 监听器数组
- */
- function getListener(obj, type, force) {
- var allListeners;
- type = type.toLowerCase();
- return ((allListeners = (obj.__allListeners || force && (obj.__allListeners = {})))
- && (allListeners[type] || force && (allListeners[type] = [])));
- }
- ///import editor.js
- ///import core/dom/dom.js
- ///import core/utils.js
- /**
- * dtd html语义化的体现类
- * @constructor
- * @namespace dtd
- */
- var dtd = dom.dtd = (function () {
- function _(s) {
- for (var k in s) {
- s[k.toUpperCase()] = s[k];
- }
- return s;
- }
- var X = utils.extend2;
- var A = _({isindex: 1, fieldset: 1}),
- B = _({input: 1, button: 1, select: 1, textarea: 1, label: 1}),
- C = X(_({a: 1}), B),
- D = X({iframe: 1}, C),
- 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}),
- F = _({ins: 1, del: 1, script: 1, style: 1}),
- 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),
- 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),
- I = X(_({p: 1}), H),
- J = X(_({iframe: 1}), H, B),
- 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
- }),
- L = X(_({a: 0}), J),//a不能被切开,所以把他
- M = _({tr: 1}),
- N = _({'#': 1}),
- O = X(_({param: 1}), K),
- P = X(_({form: 1}), A, D, E, I),
- Q = _({li: 1, ol: 1, ul: 1}),
- R = _({style: 1, script: 1}),
- S = _({base: 1, link: 1, meta: 1, title: 1}),
- T = X(S, R),
- U = _({head: 1, body: 1}),
- V = _({html: 1});
- 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}),
- 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});
- return _({
- // $ 表示自定的属性
- // body外的元素列表.
- $nonBodyContent: X(V, U, S),
- //块结构元素列表
- $block: block,
- //内联元素列表
- $inline: L,
- $inlineWithA: X(_({a: 1}), L),
- $body: X(_({script: 1, style: 1}), block),
- $cdata: _({script: 1, style: 1}),
- //自闭和元素
- $empty: empty,
- //不是自闭合,但不能让range选中里边
- $nonChild: _({iframe: 1, textarea: 1}),
- //列表元素列表
- $listItem: _({dd: 1, dt: 1, li: 1}),
- //列表根元素列表
- $list: _({ul: 1, ol: 1, dl: 1}),
- //不能认为是空的元素
- $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}),
- //如果没有子节点就可以删除的元素列表,像span,a
- $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}),
- $removeEmptyBlock: _({'p': 1, 'div': 1}),
- //在table元素里的元素列表
- $tableContent: _({caption: 1, col: 1, colgroup: 1, tbody: 1, td: 1, tfoot: 1, th: 1, thead: 1, tr: 1, table: 1}),
- //不转换的标签
- $notTransContent: _({pre: 1, script: 1, style: 1, textarea: 1}),
- html: U,
- head: T,
- style: N,
- script: N,
- body: P,
- base: {},
- link: {},
- meta: {},
- title: N,
- col: {},
- tr: _({td: 1, th: 1}),
- img: {},
- embed: {},
- colgroup: _({thead: 1, col: 1, tbody: 1, tr: 1, tfoot: 1}),
- noscript: P,
- td: P,
- br: {},
- th: P,
- center: P,
- kbd: L,
- button: X(I, E),
- basefont: {},
- h5: L,
- h4: L,
- samp: L,
- h6: L,
- ol: Q,
- h1: L,
- h3: L,
- option: N,
- h2: L,
- form: X(A, D, E, I),
- select: _({optgroup: 1, option: 1}),
- font: L,
- ins: L,
- menu: Q,
- abbr: L,
- label: L,
- table: _({thead: 1, col: 1, tbody: 1, tr: 1, colgroup: 1, caption: 1, tfoot: 1}),
- code: L,
- tfoot: M,
- cite: L,
- li: P,
- input: {},
- iframe: P,
- strong: L,
- textarea: N,
- noframes: P,
- big: L,
- small: L,
- //trace:
- span: _({'#': 1, br: 1, b: 1, strong: 1, u: 1, i: 1, em: 1, sub: 1, sup: 1, strike: 1, span: 1}),
- hr: L,
- dt: L,
- sub: L,
- optgroup: _({option: 1}),
- param: {},
- bdo: L,
- 'var': L,
- div: P,
- object: O,
- sup: L,
- dd: P,
- strike: L,
- area: {},
- dir: Q,
- map: X(_({area: 1, form: 1, p: 1}), A, F, E),
- applet: O,
- dl: _({dt: 1, dd: 1}),
- del: L,
- isindex: {},
- fieldset: X(_({legend: 1}), K),
- thead: M,
- ul: Q,
- acronym: L,
- b: L,
- a: X(_({a: 1}), J),
- blockquote: X(_({td: 1, tr: 1, tbody: 1, li: 1}), P),
- caption: L,
- i: L,
- u: L,
- tbody: M,
- s: L,
- address: X(D, I),
- tt: L,
- legend: L,
- q: L,
- pre: X(G, C),
- p: X(_({'a': 1}), L),
- em: L,
- dfn: L
- });
- })();
- /**
- * @file
- * @name UM.dom.domUtils
- * @short DomUtils
- * @import editor.js, core/utils.js,core/browser.js,core/dom/dtd.js
- * @desc UEditor封装的底层dom操作库
- */
- function getDomNode(node, start, ltr, startFromChild, fn, guard) {
- var tmpNode = startFromChild && node[start],
- parent;
- !tmpNode && (tmpNode = node[ltr]);
- while (!tmpNode && (parent = (parent || node).parentNode)) {
- if (parent.tagName == 'BODY' || guard && !guard(parent)) {
- return null;
- }
- tmpNode = parent[ltr];
- }
- if (tmpNode && fn && !fn(tmpNode)) {
- return getDomNode(tmpNode, start, ltr, false, fn);
- }
- return tmpNode;
- }
- var attrFix = ie && browser.version < 9 ? {
- tabindex: "tabIndex",
- readonly: "readOnly",
- "for": "htmlFor",
- "class": "className",
- maxlength: "maxLength",
- cellspacing: "cellSpacing",
- cellpadding: "cellPadding",
- rowspan: "rowSpan",
- colspan: "colSpan",
- usemap: "useMap",
- frameborder: "frameBorder"
- } : {
- tabindex: "tabIndex",
- readonly: "readOnly"
- },
- styleBlock = utils.listToMap([
- '-webkit-box', '-moz-box', 'block',
- 'list-item', 'table', 'table-row-group',
- 'table-header-group', 'table-footer-group',
- 'table-row', 'table-column-group', 'table-column',
- 'table-cell', 'table-caption'
- ]);
- var domUtils = dom.domUtils = {
- //节点常量
- NODE_ELEMENT: 1,
- NODE_DOCUMENT: 9,
- NODE_TEXT: 3,
- NODE_COMMENT: 8,
- NODE_DOCUMENT_FRAGMENT: 11,
- //位置关系
- POSITION_IDENTICAL: 0,
- POSITION_DISCONNECTED: 1,
- POSITION_FOLLOWING: 2,
- POSITION_PRECEDING: 4,
- POSITION_IS_CONTAINED: 8,
- POSITION_CONTAINS: 16,
- //ie6使用其他的会有一段空白出现
- fillChar: ie && browser.version == '6' ? '\ufeff' : '\u200B',
- //-------------------------Node部分--------------------------------
- keys: {
- /*Backspace*/ 8: 1, /*Delete*/ 46: 1,
- /*Shift*/ 16: 1, /*Ctrl*/ 17: 1, /*Alt*/ 18: 1,
- 37: 1, 38: 1, 39: 1, 40: 1,
- 13: 1 /*enter*/
- },
- breakParent: function (node, parent) {
- var tmpNode,
- parentClone = node,
- clone = node,
- leftNodes,
- rightNodes;
- do {
- parentClone = parentClone.parentNode;
- if (leftNodes) {
- tmpNode = parentClone.cloneNode(false);
- tmpNode.appendChild(leftNodes);
- leftNodes = tmpNode;
- tmpNode = parentClone.cloneNode(false);
- tmpNode.appendChild(rightNodes);
- rightNodes = tmpNode;
- } else {
- leftNodes = parentClone.cloneNode(false);
- rightNodes = leftNodes.cloneNode(false);
- }
- while (tmpNode = clone.previousSibling) {
- leftNodes.insertBefore(tmpNode, leftNodes.firstChild);
- }
- while (tmpNode = clone.nextSibling) {
- rightNodes.appendChild(tmpNode);
- }
- clone = parentClone;
- } while (parent !== parentClone);
- tmpNode = parent.parentNode;
- tmpNode.insertBefore(leftNodes, parent);
- tmpNode.insertBefore(rightNodes, parent);
- tmpNode.insertBefore(node, rightNodes);
- domUtils.remove(parent);
- return node;
- },
- trimWhiteTextNode: function (node) {
- function remove(dir) {
- var child;
- while ((child = node[dir]) && child.nodeType == 3 && domUtils.isWhitespace(child)) {
- node.removeChild(child);
- }
- }
- remove('firstChild');
- remove('lastChild');
- },
- /**
- * 获取节点A相对于节点B的位置关系
- * @name getPosition
- * @grammar UM.dom.domUtils.getPosition(nodeA,nodeB) => Number
- * @example
- * switch (returnValue) {
- * case 0: //相等,同一节点
- * case 1: //无关,节点不相连
- * case 2: //跟随,即节点A头部位于节点B头部的后面
- * case 4: //前置,即节点A头部位于节点B头部的前面
- * case 8: //被包含,即节点A被节点B包含
- * case 10://组合类型,即节点A满足跟随节点B且被节点B包含。实际上,如果被包含,必定跟随,所以returnValue事实上不会存在8的情况。
- * case 16://包含,即节点A包含节点B
- * case 20://组合类型,即节点A满足前置节点A且包含节点B。同样,如果包含,必定前置,所以returnValue事实上也不会存在16的情况
- * }
- */
- getPosition: function (nodeA, nodeB) {
- // 如果两个节点是同一个节点
- if (nodeA === nodeB) {
- // domUtils.POSITION_IDENTICAL
- return 0;
- }
- var node,
- parentsA = [nodeA],
- parentsB = [nodeB];
- node = nodeA;
- while (node = node.parentNode) {
- // 如果nodeB是nodeA的祖先节点
- if (node === nodeB) {
- // domUtils.POSITION_IS_CONTAINED + domUtils.POSITION_FOLLOWING
- return 10;
- }
- parentsA.push(node);
- }
- node = nodeB;
- while (node = node.parentNode) {
- // 如果nodeA是nodeB的祖先节点
- if (node === nodeA) {
- // domUtils.POSITION_CONTAINS + domUtils.POSITION_PRECEDING
- return 20;
- }
- parentsB.push(node);
- }
- parentsA.reverse();
- parentsB.reverse();
- if (parentsA[0] !== parentsB[0]) {
- // domUtils.POSITION_DISCONNECTED
- return 1;
- }
- var i = -1;
- while (i++, parentsA[i] === parentsB[i]) {
- }
- nodeA = parentsA[i];
- nodeB = parentsB[i];
- while (nodeA = nodeA.nextSibling) {
- if (nodeA === nodeB) {
- // domUtils.POSITION_PRECEDING
- return 4
- }
- }
- // domUtils.POSITION_FOLLOWING
- return 2;
- },
- /**
- * 返回节点node在父节点中的索引位置
- * @name getNodeIndex
- * @grammar UM.dom.domUtils.getNodeIndex(node) => Number //索引值从0开始
- */
- getNodeIndex: function (node, ignoreTextNode) {
- var preNode = node,
- i = 0;
- while (preNode = preNode.previousSibling) {
- if (ignoreTextNode && preNode.nodeType == 3) {
- if (preNode.nodeType != preNode.nextSibling.nodeType) {
- i++;
- }
- continue;
- }
- i++;
- }
- return i;
- },
- /**
- * 检测节点node是否在节点doc的树上,实质上是检测是否被doc包含
- * @name inDoc
- * @grammar UM.dom.domUtils.inDoc(node,doc) => true|false
- */
- inDoc: function (node, doc) {
- return domUtils.getPosition(node, doc) == 10;
- },
- /**
- * 查找node节点的祖先节点
- * @name findParent
- * @grammar UM.dom.domUtils.findParent(node) => Element // 直接返回node节点的父节点
- * @grammar UM.dom.domUtils.findParent(node,filterFn) => Element //filterFn为过滤函数,node作为参数,返回true时才会将node作为符合要求的节点返回
- * @grammar UM.dom.domUtils.findParent(node,filterFn,includeSelf) => Element //includeSelf指定是否包含自身
- */
- findParent: function (node, filterFn, includeSelf) {
- if (node && !domUtils.isBody(node)) {
- node = includeSelf ? node : node.parentNode;
- while (node) {
- if (!filterFn || filterFn(node) || domUtils.isBody(node)) {
- return filterFn && !filterFn(node) && domUtils.isBody(node) ? null : node;
- }
- node = node.parentNode;
- }
- }
- return null;
- },
- /**
- * 通过tagName查找node节点的祖先节点
- * @name findParentByTagName
- * @grammar UM.dom.domUtils.findParentByTagName(node,tagNames) => Element //tagNames支持数组,区分大小写
- * @grammar UM.dom.domUtils.findParentByTagName(node,tagNames,includeSelf) => Element //includeSelf指定是否包含自身
- * @grammar UM.dom.domUtils.findParentByTagName(node,tagNames,includeSelf,excludeFn) => Element //excludeFn指定例外过滤条件,返回true时忽略该节点
- */
- findParentByTagName: function (node, tagNames, includeSelf, excludeFn) {
- tagNames = utils.listToMap(utils.isArray(tagNames) ? tagNames : [tagNames]);
- return domUtils.findParent(node, function (node) {
- return tagNames[node.tagName] && !(excludeFn && excludeFn(node));
- }, includeSelf);
- },
- /**
- * 查找节点node的祖先节点集合
- * @name findParents
- * @grammar UM.dom.domUtils.findParents(node) => Array //返回一个祖先节点数组集合,不包含自身
- * @grammar UM.dom.domUtils.findParents(node,includeSelf) => Array //返回一个祖先节点数组集合,includeSelf指定是否包含自身
- * @grammar UM.dom.domUtils.findParents(node,includeSelf,filterFn) => Array //返回一个祖先节点数组集合,filterFn指定过滤条件,返回true的node将被选取
- * @grammar UM.dom.domUtils.findParents(node,includeSelf,filterFn,closerFirst) => Array //返回一个祖先节点数组集合,closerFirst为true的话,node的直接父亲节点是数组的第0个
- */
- findParents: function (node, includeSelf, filterFn, closerFirst) {
- var parents = includeSelf && (filterFn && filterFn(node) || !filterFn) ? [node] : [];
- while (node = domUtils.findParent(node, filterFn)) {
- parents.push(node);
- }
- return closerFirst ? parents : parents.reverse();
- },
- /**
- * 在节点node后面插入新节点newNode
- * @name insertAfter
- * @grammar UM.dom.domUtils.insertAfter(node,newNode) => newNode
- */
- insertAfter: function (node, newNode) {
- return node.parentNode.insertBefore(newNode, node.nextSibling);
- },
- /**
- * 删除节点node,并根据keepChildren指定是否保留子节点
- * @name remove
- * @grammar UM.dom.domUtils.remove(node) => node
- * @grammar UM.dom.domUtils.remove(node,keepChildren) => node
- */
- remove: function (node, keepChildren) {
- var parent = node.parentNode,
- child;
- if (parent) {
- if (keepChildren && node.hasChildNodes()) {
- while (child = node.firstChild) {
- parent.insertBefore(child, node);
- }
- }
- parent.removeChild(node);
- }
- return node;
- },
- /**
- * 取得node节点的下一个兄弟节点, 如果该节点其后没有兄弟节点, 则递归查找其父节点之后的第一个兄弟节点,
- * 直到找到满足条件的节点或者递归到BODY节点之后才会结束。
- * @method getNextDomNode
- * @param { Node } node 需要获取其后的兄弟节点的节点对象
- * @return { Node | NULL } 如果找满足条件的节点, 则返回该节点, 否则返回NULL
- * @example
- * ```html
- * <body>
- * <div id="test">
- * <span></span>
- * </div>
- * <i>xxx</i>
- * </body>
- * <script>
- *
- * //output: i节点
- * console.log( UE.dom.domUtils.getNextDomNode( document.getElementById( "test" ) ) );
- *
- * </script>
- * ```
- * @example
- * ```html
- * <body>
- * <div>
- * <span></span>
- * <i id="test">xxx</i>
- * </div>
- * <b>xxx</b>
- * </body>
- * <script>
- *
- * //由于id为test的i节点之后没有兄弟节点, 则查找其父节点(div)后面的兄弟节点
- * //output: b节点
- * console.log( UE.dom.domUtils.getNextDomNode( document.getElementById( "test" ) ) );
- *
- * </script>
- * ```
- */
- /**
- * 取得node节点的下一个兄弟节点, 如果startFromChild的值为ture,则先获取其子节点,
- * 如果有子节点则直接返回第一个子节点;如果没有子节点或者startFromChild的值为false,
- * 则执行<a href="#UE.dom.domUtils.getNextDomNode(Node)">getNextDomNode(Node node)</a>的查找过程。
- * @method getNextDomNode
- * @param { Node } node 需要获取其后的兄弟节点的节点对象
- * @param { Boolean } startFromChild 查找过程是否从其子节点开始
- * @return { Node | NULL } 如果找满足条件的节点, 则返回该节点, 否则返回NULL
- * @see UE.dom.domUtils.getNextDomNode(Node)
- */
- getNextDomNode: function (node, startFromChild, filterFn, guard) {
- return getDomNode(node, 'firstChild', 'nextSibling', startFromChild, filterFn, guard);
- },
- getPreDomNode: function (node, startFromChild, filterFn, guard) {
- return getDomNode(node, 'lastChild', 'previousSibling', startFromChild, filterFn, guard);
- },
- /**
- * 检测节点node是否属于bookmark节点
- * @name isBookmarkNode
- * @grammar UM.dom.domUtils.isBookmarkNode(node) => true|false
- */
- isBookmarkNode: function (node) {
- return node.nodeType == 1 && node.id && /^_baidu_bookmark_/i.test(node.id);
- },
- /**
- * 获取节点node所在的window对象
- * @name getWindow
- * @grammar UM.dom.domUtils.getWindow(node) => window对象
- */
- getWindow: function (node) {
- var doc = node.ownerDocument || node;
- return doc.defaultView || doc.parentWindow;
- },
- /**
- * 获取离nodeA与nodeB最近的公共的祖先节点
- * @method getCommonAncestor
- * @param { Node } nodeA 第一个节点
- * @param { Node } nodeB 第二个节点
- * @remind 如果给定的两个节点是同一个节点, 将直接返回该节点。
- * @return { Node | NULL } 如果未找到公共节点, 返回NULL, 否则返回最近的公共祖先节点。
- * @example
- * ```javascript
- * var commonAncestor = UE.dom.domUtils.getCommonAncestor( document.body, document.body.firstChild );
- * //output: true
- * console.log( commonAncestor.tagName.toLowerCase() === 'body' );
- * ```
- */
- getCommonAncestor: function (nodeA, nodeB) {
- if (nodeA === nodeB)
- return nodeA;
- var parentsA = [nodeA], parentsB = [nodeB], parent = nodeA, i = -1;
- while (parent = parent.parentNode) {
- if (parent === nodeB) {
- return parent;
- }
- parentsA.push(parent);
- }
- parent = nodeB;
- while (parent = parent.parentNode) {
- if (parent === nodeA)
- return parent;
- parentsB.push(parent);
- }
- parentsA.reverse();
- parentsB.reverse();
- while (i++, parentsA[i] === parentsB[i]) {
- }
- return i == 0 ? null : parentsA[i - 1];
- },
- /**
- * 清除node节点左右连续为空的兄弟inline节点
- * @method clearEmptySibling
- * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
- * 则这些兄弟节点将被删除
- * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext) //ignoreNext指定是否忽略右边空节点
- * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext,ignorePre) //ignorePre指定是否忽略左边空节点
- * @example
- * ```html
- * <body>
- * <div></div>
- * <span id="test"></span>
- * <i></i>
- * <b></b>
- * <em>xxx</em>
- * <span></span>
- * </body>
- * <script>
- *
- * UE.dom.domUtils.clearEmptySibling( document.getElementById( "test" ) );
- *
- * //output: <div></div><span id="test"></span><em>xxx</em><span></span>
- * console.log( document.body.innerHTML );
- *
- * </script>
- * ```
- */
- /**
- * 清除node节点左右连续为空的兄弟inline节点, 如果ignoreNext的值为true,
- * 则忽略对右边兄弟节点的操作。
- * @method clearEmptySibling
- * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
- * @param { Boolean } ignoreNext 是否忽略忽略对右边的兄弟节点的操作
- * 则这些兄弟节点将被删除
- * @see UE.dom.domUtils.clearEmptySibling(Node)
- */
- /**
- * 清除node节点左右连续为空的兄弟inline节点, 如果ignoreNext的值为true,
- * 则忽略对右边兄弟节点的操作, 如果ignorePre的值为true,则忽略对左边兄弟节点的操作。
- * @method clearEmptySibling
- * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
- * @param { Boolean } ignoreNext 是否忽略忽略对右边的兄弟节点的操作
- * @param { Boolean } ignorePre 是否忽略忽略对左边的兄弟节点的操作
- * 则这些兄弟节点将被删除
- * @see UE.dom.domUtils.clearEmptySibling(Node)
- */
- clearEmptySibling: function (node, ignoreNext, ignorePre) {
- function clear(next, dir) {
- var tmpNode;
- while (next && !domUtils.isBookmarkNode(next) && (domUtils.isEmptyInlineElement(next)
- //这里不能把空格算进来会吧空格干掉,出现文字间的空格丢掉了
- || !new RegExp('[^\t\n\r' + domUtils.fillChar + ']').test(next.nodeValue))) {
- tmpNode = next[dir];
- domUtils.remove(next);
- next = tmpNode;
- }
- }
- !ignoreNext && clear(node.nextSibling, 'nextSibling');
- !ignorePre && clear(node.previousSibling, 'previousSibling');
- },
- /**
- * 将一个文本节点node拆分成两个文本节点,offset指定拆分位置
- * @name split
- * @grammar UM.dom.domUtils.split(node,offset) => TextNode //返回从切分位置开始的后一个文本节点
- */
- split: function (node, offset) {
- var doc = node.ownerDocument;
- if (browser.ie && offset == node.nodeValue.length) {
- var next = doc.createTextNode('');
- return domUtils.insertAfter(node, next);
- }
- var retval = node.splitText(offset);
- //ie8下splitText不会跟新childNodes,我们手动触发他的更新
- if (browser.ie8) {
- var tmpNode = doc.createTextNode('');
- domUtils.insertAfter(retval, tmpNode);
- domUtils.remove(tmpNode);
- }
- return retval;
- },
- /**
- * 检测节点node是否为空节点(包括空格、换行、占位符等字符)
- * @name isWhitespace
- * @grammar UM.dom.domUtils.isWhitespace(node) => true|false
- */
- isWhitespace: function (node) {
- return !new RegExp('[^ \t\n\r' + domUtils.fillChar + ']').test(node.nodeValue);
- },
- /**
- * 获取元素element相对于viewport的位置坐标
- * @name getXY
- * @grammar UM.dom.domUtils.getXY(element) => Object //返回坐标对象{x:left,y:top}
- */
- getXY: function (element) {
- var x = 0, y = 0;
- while (element.offsetParent) {
- y += element.offsetTop;
- x += element.offsetLeft;
- element = element.offsetParent;
- }
- return {'x': x, 'y': y};
- },
- /**
- * 检查节点node是否是空inline节点
- * @name isEmptyInlineElement
- * @grammar UM.dom.domUtils.isEmptyInlineElement(node) => 1|0
- * @example
- * <b><i></i></b> => 1
- * <b><i></i><u></u></b> => 1
- * <b></b> => 1
- * <b>xx<i></i></b> => 0
- */
- isEmptyInlineElement: function (node) {
- if (node.nodeType != 1 || !dtd.$removeEmpty[node.tagName]) {
- return 0;
- }
- node = node.firstChild;
- while (node) {
- //如果是创建的bookmark就跳过
- if (domUtils.isBookmarkNode(node)) {
- return 0;
- }
- if (node.nodeType == 1 && !domUtils.isEmptyInlineElement(node) ||
- node.nodeType == 3 && !domUtils.isWhitespace(node)
- ) {
- return 0;
- }
- node = node.nextSibling;
- }
- return 1;
- },
- /**
- * 检查节点node是否为块元素
- * @name isBlockElm
- * @grammar UM.dom.domUtils.isBlockElm(node) => true|false
- */
- isBlockElm: function (node) {
- return node.nodeType == 1 && (dtd.$block[node.tagName] || styleBlock[domUtils.getComputedStyle(node, 'display')]) && !dtd.$nonChild[node.tagName];
- },
- /**
- * 原生方法getElementsByTagName的封装
- * @name getElementsByTagName
- * @grammar UM.dom.domUtils.getElementsByTagName(node,tagName) => Array //节点集合数组
- */
- getElementsByTagName: function (node, name, filter) {
- if (filter && utils.isString(filter)) {
- var className = filter;
- filter = function (node) {
- var result = false;
- $.each(utils.trim(className).replace(/[ ]{2,}/g, ' ').split(' '), function (i, v) {
- if ($(node).hasClass(v)) {
- result = true;
- return false;
- }
- })
- return result;
- }
- }
- name = utils.trim(name).replace(/[ ]{2,}/g, ' ').split(' ');
- var arr = [];
- for (var n = 0, ni; ni = name[n++];) {
- var list = node.getElementsByTagName(ni);
- for (var i = 0, ci; ci = list[i++];) {
- if (!filter || filter(ci))
- arr.push(ci);
- }
- }
- return arr;
- },
- /**
- * 设置节点node及其子节点不会被选中
- * @name unSelectable
- * @grammar UM.dom.domUtils.unSelectable(node)
- */
- unSelectable: ie && browser.ie9below || browser.opera ? function (node) {
- //for ie9
- node.onselectstart = function () {
- return false;
- };
- node.onclick = node.onkeyup = node.onkeydown = function () {
- return false;
- };
- node.unselectable = 'on';
- node.setAttribute("unselectable", "on");
- for (var i = 0, ci; ci = node.all[i++];) {
- switch (ci.tagName.toLowerCase()) {
- case 'iframe' :
- case 'textarea' :
- case 'input' :
- case 'select' :
- break;
- default :
- ci.unselectable = 'on';
- node.setAttribute("unselectable", "on");
- }
- }
- } : function (node) {
- node.style.MozUserSelect =
- node.style.webkitUserSelect =
- node.style.msUserSelect =
- node.style.KhtmlUserSelect = 'none';
- },
- /**
- * 删除节点node上的属性attrNames,attrNames为属性名称数组
- * @name removeAttributes
- * @grammar UM.dom.domUtils.removeAttributes(node,attrNames)
- * @example
- * //Before remove
- * <span style="font-size:14px;" id="test" name="followMe">xxxxx</span>
- * //Remove
- * UM.dom.domUtils.removeAttributes(node,["id","name"]);
- * //After remove
- * <span style="font-size:14px;">xxxxx</span>
- */
- removeAttributes: function (node, attrNames) {
- attrNames = utils.isArray(attrNames) ? attrNames : utils.trim(attrNames).replace(/[ ]{2,}/g, ' ').split(' ');
- for (var i = 0, ci; ci = attrNames[i++];) {
- ci = attrFix[ci] || ci;
- switch (ci) {
- case 'className':
- node[ci] = '';
- break;
- case 'style':
- node.style.cssText = '';
- !browser.ie && node.removeAttributeNode(node.getAttributeNode('style'))
- }
- node.removeAttribute(ci);
- }
- },
- /**
- * 在doc下创建一个标签名为tag,属性为attrs的元素
- * @name createElement
- * @grammar UM.dom.domUtils.createElement(doc,tag,attrs) => Node //返回创建的节点
- */
- createElement: function (doc, tag, attrs) {
- return domUtils.setAttributes(doc.createElement(tag), attrs)
- },
- /**
- * 为节点node添加属性attrs,attrs为属性键值对
- * @name setAttributes
- * @grammar UM.dom.domUtils.setAttributes(node,attrs) => node
- */
- setAttributes: function (node, attrs) {
- for (var attr in attrs) {
- if (attrs.hasOwnProperty(attr)) {
- var value = attrs[attr];
- switch (attr) {
- case 'class':
- //ie下要这样赋值,setAttribute不起作用
- node.className = value;
- break;
- case 'style' :
- node.style.cssText = node.style.cssText + ";" + value;
- break;
- case 'innerHTML':
- node[attr] = value;
- break;
- case 'value':
- node.value = value;
- break;
- default:
- node.setAttribute(attrFix[attr] || attr, value);
- }
- }
- }
- return node;
- },
- /**
- * 获取元素element的计算样式
- * @name getComputedStyle
- * @grammar UM.dom.domUtils.getComputedStyle(element,styleName) => String //返回对应样式名称的样式值
- * @example
- * getComputedStyle(document.body,"font-size") => "15px"
- * getComputedStyle(form,"color") => "#ffccdd"
- */
- getComputedStyle: function (element, styleName) {
- return utils.transUnitToPx(utils.fixColor(styleName, $(element).css(styleName)));
- },
- /**
- * 阻止事件默认行为
- * @param {Event} evt 需要组织的事件对象
- */
- preventDefault: function (evt) {
- evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
- },
- /**
- * 删除元素element指定的样式
- * @method removeStyle
- * @param { Element } element 需要删除样式的元素
- * @param { String } styleName 需要删除的样式名
- * @example
- * ```html
- * <span id="test" style="color: red; background: blue;"></span>
- *
- * <script>
- *
- * var testNode = document.getElementById("test");
- *
- * UE.dom.domUtils.removeStyle( testNode, 'color' );
- *
- * //output: background: blue;
- * console.log( testNode.style.cssText );
- *
- * </script>
- * ```
- */
- removeStyle: function (element, name) {
- if (browser.ie) {
- //针对color先单独处理一下
- if (name == 'color') {
- name = '(^|;)' + name;
- }
- element.style.cssText = element.style.cssText.replace(new RegExp(name + '[^:]*:[^;]+;?', 'ig'), '')
- } else {
- if (element.style.removeProperty) {
- element.style.removeProperty(name);
- } else {
- element.style.removeAttribute(utils.cssStyleToDomStyle(name));
- }
- }
- if (!element.style.cssText) {
- domUtils.removeAttributes(element, ['style']);
- }
- },
- /**
- * 获取元素element的某个样式值
- * @name getStyle
- * @grammar UM.dom.domUtils.getStyle(element,name) => String
- */
- getStyle: function (element, name) {
- var value = element.style[utils.cssStyleToDomStyle(name)];
- return utils.fixColor(name, value);
- },
- /**
- * 为元素element设置样式属性值
- * @name setStyle
- * @grammar UM.dom.domUtils.setStyle(element,name,value)
- */
- setStyle: function (element, name, value) {
- element.style[utils.cssStyleToDomStyle(name)] = value;
- if (!utils.trim(element.style.cssText)) {
- this.removeAttributes(element, 'style')
- }
- },
- /**
- * 删除_moz_dirty属性
- * @function
- */
- removeDirtyAttr: function (node) {
- for (var i = 0, ci, nodes = node.getElementsByTagName('*'); ci = nodes[i++];) {
- ci.removeAttribute('_moz_dirty');
- }
- node.removeAttribute('_moz_dirty');
- },
- /**
- * 返回子节点的数量
- * @function
- * @param {Node} node 父节点
- * @param {Function} fn 过滤子节点的规则,若为空,则得到所有子节点的数量
- * @return {Number} 符合条件子节点的数量
- */
- getChildCount: function (node, fn) {
- var count = 0, first = node.firstChild;
- fn = fn || function () {
- return 1;
- };
- while (first) {
- if (fn(first)) {
- count++;
- }
- first = first.nextSibling;
- }
- return count;
- },
- /**
- * 判断是否为空节点
- * @function
- * @param {Node} node 节点
- * @return {Boolean} 是否为空节点
- */
- isEmptyNode: function (node) {
- return !node.firstChild || domUtils.getChildCount(node, function (node) {
- return !domUtils.isBr(node) && !domUtils.isBookmarkNode(node) && !domUtils.isWhitespace(node)
- }) == 0
- },
- /**
- * 判断节点是否为br
- * @function
- * @param {Node} node 节点
- */
- isBr: function (node) {
- return node.nodeType == 1 && node.tagName == 'BR';
- },
- isEmptyBlock: function (node, reg) {
- if (node.nodeType != 1)
- return 0;
- reg = reg || new RegExp('[ \t\r\n' + domUtils.fillChar + ']', 'g');
- if (node[browser.ie ? 'innerText' : 'textContent'].replace(reg, '').length > 0) {
- return 0;
- }
- for (var n in dtd.$isNotEmpty) {
- if (node.getElementsByTagName(n).length) {
- return 0;
- }
- }
- return 1;
- },
- //判断是否是编辑器自定义的参数
- isCustomeNode: function (node) {
- return node.nodeType == 1 && node.getAttribute('_ue_custom_node_');
- },
- fillNode: function (doc, node) {
- var tmpNode = browser.ie ? doc.createTextNode(domUtils.fillChar) : doc.createElement('br');
- node.innerHTML = '';
- node.appendChild(tmpNode);
- },
- isBoundaryNode: function (node, dir) {
- var tmp;
- while (!domUtils.isBody(node)) {
- tmp = node;
- node = node.parentNode;
- if (tmp !== node[dir]) {
- return false;
- }
- }
- return true;
- },
- isFillChar: function (node, isInStart) {
- return node.nodeType == 3 && !node.nodeValue.replace(new RegExp((isInStart ? '^' : '') + domUtils.fillChar), '').length
- },
- isBody: function (node) {
- return $(node).hasClass('edui-body-container');
- }
- };
- var fillCharReg = new RegExp(domUtils.fillChar, 'g');
- ///import editor.js
- ///import core/utils.js
- ///import core/browser.js
- ///import core/dom/dom.js
- ///import core/dom/dtd.js
- ///import core/dom/domUtils.js
- /**
- * @file
- * @name UM.dom.Range
- * @anthor zhanyi
- * @short Range
- * @import editor.js,core/utils.js,core/browser.js,core/dom/domUtils.js,core/dom/dtd.js
- * @desc Range范围实现类,本类是UEditor底层核心类,统一w3cRange和ieRange之间的差异,包括接口和属性
- */
- (function () {
- var guid = 0,
- fillChar = domUtils.fillChar,
- fillData;
- /**
- * 更新range的collapse状态
- * @param {Range} range range对象
- */
- function updateCollapse(range) {
- range.collapsed =
- range.startContainer && range.endContainer &&
- range.startContainer === range.endContainer &&
- range.startOffset == range.endOffset;
- }
- function selectOneNode(rng) {
- return !rng.collapsed && rng.startContainer.nodeType == 1 && rng.startContainer === rng.endContainer && rng.endOffset - rng.startOffset == 1
- }
- function setEndPoint(toStart, node, offset, range) {
- //如果node是自闭合标签要处理
- if (node.nodeType == 1 && (dtd.$empty[node.tagName] || dtd.$nonChild[node.tagName])) {
- offset = domUtils.getNodeIndex(node) + (toStart ? 0 : 1);
- node = node.parentNode;
- }
- if (toStart) {
- range.startContainer = node;
- range.startOffset = offset;
- if (!range.endContainer) {
- range.collapse(true);
- }
- } else {
- range.endContainer = node;
- range.endOffset = offset;
- if (!range.startContainer) {
- range.collapse(false);
- }
- }
- updateCollapse(range);
- return range;
- }
- /**
- * @name Range
- * @grammar new UM.dom.Range(document) => Range 实例
- * @desc 创建一个跟document绑定的空的Range实例
- * - ***startContainer*** 开始边界的容器节点,可以是elementNode或者是textNode
- * - ***startOffset*** 容器节点中的偏移量,如果是elementNode就是childNodes中的第几个,如果是textNode就是nodeValue的第几个字符
- * - ***endContainer*** 结束边界的容器节点,可以是elementNode或者是textNode
- * - ***endOffset*** 容器节点中的偏移量,如果是elementNode就是childNodes中的第几个,如果是textNode就是nodeValue的第几个字符
- * - ***document*** 跟range关联的document对象
- * - ***collapsed*** 是否是闭合状态
- */
- var Range = dom.Range = function (document, body) {
- var me = this;
- me.startContainer =
- me.startOffset =
- me.endContainer =
- me.endOffset = null;
- me.document = document;
- me.collapsed = true;
- me.body = body;
- };
- /**
- * 删除fillData
- * @param doc
- * @param excludeNode
- */
- function removeFillData(doc, excludeNode) {
- try {
- if (fillData && domUtils.inDoc(fillData, doc)) {
- if (!fillData.nodeValue.replace(fillCharReg, '').length) {
- var tmpNode = fillData.parentNode;
- domUtils.remove(fillData);
- while (tmpNode && domUtils.isEmptyInlineElement(tmpNode) &&
- //safari的contains有bug
- (browser.safari ? !(domUtils.getPosition(tmpNode, excludeNode) & domUtils.POSITION_CONTAINS) : !tmpNode.contains(excludeNode))
- ) {
- fillData = tmpNode.parentNode;
- domUtils.remove(tmpNode);
- tmpNode = fillData;
- }
- } else {
- fillData.nodeValue = fillData.nodeValue.replace(fillCharReg, '');
- }
- }
- } catch (e) {
- }
- }
- /**
- *
- * @param node
- * @param dir
- */
- function mergeSibling(node, dir) {
- var tmpNode;
- node = node[dir];
- while (node && domUtils.isFillChar(node)) {
- tmpNode = node[dir];
- domUtils.remove(node);
- node = tmpNode;
- }
- }
- function execContentsAction(range, action) {
- //调整边界
- //range.includeBookmark();
- var start = range.startContainer,
- end = range.endContainer,
- startOffset = range.startOffset,
- endOffset = range.endOffset,
- doc = range.document,
- frag = doc.createDocumentFragment(),
- tmpStart, tmpEnd;
- if (start.nodeType == 1) {
- start = start.childNodes[startOffset] || (tmpStart = start.appendChild(doc.createTextNode('')));
- }
- if (end.nodeType == 1) {
- end = end.childNodes[endOffset] || (tmpEnd = end.appendChild(doc.createTextNode('')));
- }
- if (start === end && start.nodeType == 3) {
- frag.appendChild(doc.createTextNode(start.substringData(startOffset, endOffset - startOffset)));
- //is not clone
- if (action) {
- start.deleteData(startOffset, endOffset - startOffset);
- range.collapse(true);
- }
- return frag;
- }
- var current, currentLevel, clone = frag,
- startParents = domUtils.findParents(start, true), endParents = domUtils.findParents(end, true);
- for (var i = 0; startParents[i] == endParents[i];) {
- i++;
- }
- for (var j = i, si; si = startParents[j]; j++) {
- current = si.nextSibling;
- if (si == start) {
- if (!tmpStart) {
- if (range.startContainer.nodeType == 3) {
- clone.appendChild(doc.createTextNode(start.nodeValue.slice(startOffset)));
- //is not clone
- if (action) {
- start.deleteData(startOffset, start.nodeValue.length - startOffset);
- }
- } else {
- clone.appendChild(!action ? start.cloneNode(true) : start);
- }
- }
- } else {
- currentLevel = si.cloneNode(false);
- clone.appendChild(currentLevel);
- }
- while (current) {
- if (current === end || current === endParents[j]) {
- break;
- }
- si = current.nextSibling;
- clone.appendChild(!action ? current.cloneNode(true) : current);
- current = si;
- }
- clone = currentLevel;
- }
- clone = frag;
- if (!startParents[i]) {
- clone.appendChild(startParents[i - 1].cloneNode(false));
- clone = clone.firstChild;
- }
- for (var j = i, ei; ei = endParents[j]; j++) {
- current = ei.previousSibling;
- if (ei == end) {
- if (!tmpEnd && range.endContainer.nodeType == 3) {
- clone.appendChild(doc.createTextNode(end.substringData(0, endOffset)));
- //is not clone
- if (action) {
- end.deleteData(0, endOffset);
- }
- }
- } else {
- currentLevel = ei.cloneNode(false);
- clone.appendChild(currentLevel);
- }
- //如果两端同级,右边第一次已经被开始做了
- if (j != i || !startParents[i]) {
- while (current) {
- if (current === start) {
- break;
- }
- ei = current.previousSibling;
- clone.insertBefore(!action ? current.cloneNode(true) : current, clone.firstChild);
- current = ei;
- }
- }
- clone = currentLevel;
- }
- if (action) {
- range.setStartBefore(!endParents[i] ? endParents[i - 1] : !startParents[i] ? startParents[i - 1] : endParents[i]).collapse(true);
- }
- tmpStart && domUtils.remove(tmpStart);
- tmpEnd && domUtils.remove(tmpEnd);
- return frag;
- }
- Range.prototype = {
- /**
- * @name deleteContents
- * @grammar range.deleteContents() => Range
- * @desc 删除当前选区范围中的所有内容并返回range实例,这时的range已经变成了闭合状态
- * @example
- * DOM Element :
- * <b>x<i>x[x<i>xx]x</b>
- * //执行方法后
- * <b>x<i>x<i>|x</b>
- * 注意range改变了
- * range.startContainer => b
- * range.startOffset => 2
- * range.endContainer => b
- * range.endOffset => 2
- * range.collapsed => true
- */
- deleteContents: function () {
- var txt;
- if (!this.collapsed) {
- execContentsAction(this, 1);
- }
- if (browser.webkit) {
- txt = this.startContainer;
- if (txt.nodeType == 3 && !txt.nodeValue.length) {
- this.setStartBefore(txt).collapse(true);
- domUtils.remove(txt);
- }
- }
- return this;
- },
- inFillChar: function () {
- var start = this.startContainer;
- if (this.collapsed && start.nodeType == 3
- && start.nodeValue.replace(new RegExp('^' + domUtils.fillChar), '').length + 1 == start.nodeValue.length
- ) {
- return true;
- }
- return false;
- },
- /**
- * @name setStart
- * @grammar range.setStart(node,offset) => Range
- * @desc 设置range的开始位置位于node节点内,偏移量为offset
- * 如果node是elementNode那offset指的是childNodes中的第几个,如果是textNode那offset指的是nodeValue的第几个字符
- */
- setStart: function (node, offset) {
- return setEndPoint(true, node, offset, this);
- },
- /**
- * 设置range的结束位置位于node节点,偏移量为offset
- * 如果node是elementNode那offset指的是childNodes中的第几个,如果是textNode那offset指的是nodeValue的第几个字符
- * @name setEnd
- * @grammar range.setEnd(node,offset) => Range
- */
- setEnd: function (node, offset) {
- return setEndPoint(false, node, offset, this);
- },
- /**
- * 将Range开始位置设置到node节点之后
- * @name setStartAfter
- * @grammar range.setStartAfter(node) => Range
- * @example
- * <b>xx<i>x|x</i>x</b>
- * 执行setStartAfter(i)后
- * range.startContainer =>b
- * range.startOffset =>2
- */
- setStartAfter: function (node) {
- return this.setStart(node.parentNode, domUtils.getNodeIndex(node) + 1);
- },
- /**
- * 将Range开始位置设置到node节点之前
- * @name setStartBefore
- * @grammar range.setStartBefore(node) => Range
- * @example
- * <b>xx<i>x|x</i>x</b>
- * 执行setStartBefore(i)后
- * range.startContainer =>b
- * range.startOffset =>1
- */
- setStartBefore: function (node) {
- return this.setStart(node.parentNode, domUtils.getNodeIndex(node));
- },
- /**
- * 将Range结束位置设置到node节点之后
- * @name setEndAfter
- * @grammar range.setEndAfter(node) => Range
- * @example
- * <b>xx<i>x|x</i>x</b>
- * setEndAfter(i)后
- * range.endContainer =>b
- * range.endtOffset =>2
- */
- setEndAfter: function (node) {
- return this.setEnd(node.parentNode, domUtils.getNodeIndex(node) + 1);
- },
- /**
- * 将Range结束位置设置到node节点之前
- * @name setEndBefore
- * @grammar range.setEndBefore(node) => Range
- * @example
- * <b>xx<i>x|x</i>x</b>
- * 执行setEndBefore(i)后
- * range.endContainer =>b
- * range.endtOffset =>1
- */
- setEndBefore: function (node) {
- return this.setEnd(node.parentNode, domUtils.getNodeIndex(node));
- },
- /**
- * 将Range开始位置设置到node节点内的开始位置
- * @name setStartAtFirst
- * @grammar range.setStartAtFirst(node) => Range
- */
- setStartAtFirst: function (node) {
- return this.setStart(node, 0);
- },
- /**
- * 将Range开始位置设置到node节点内的结束位置
- * @name setStartAtLast
- * @grammar range.setStartAtLast(node) => Range
- */
- setStartAtLast: function (node) {
- return this.setStart(node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length);
- },
- /**
- * 将Range结束位置设置到node节点内的开始位置
- * @name setEndAtFirst
- * @grammar range.setEndAtFirst(node) => Range
- */
- setEndAtFirst: function (node) {
- return this.setEnd(node, 0);
- },
- /**
- * 将Range结束位置设置到node节点内的结束位置
- * @name setEndAtLast
- * @grammar range.setEndAtLast(node) => Range
- */
- setEndAtLast: function (node) {
- return this.setEnd(node, node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length);
- },
- /**
- * 选中完整的指定节点,并返回包含该节点的range
- * @name selectNode
- * @grammar range.selectNode(node) => Range
- */
- selectNode: function (node) {
- return this.setStartBefore(node).setEndAfter(node);
- },
- /**
- * 选中node内部的所有节点,并返回对应的range
- * @name selectNodeContents
- * @grammar range.selectNodeContents(node) => Range
- * @example
- * <b>xx[x<i>xxx</i>]xxx</b>
- * 执行后
- * <b>[xxx<i>xxx</i>xxx]</b>
- * range.startContainer =>b
- * range.startOffset =>0
- * range.endContainer =>b
- * range.endOffset =>3
- */
- selectNodeContents: function (node) {
- return this.setStart(node, 0).setEndAtLast(node);
- },
- /**
- * 克隆一个新的range对象
- * @name cloneRange
- * @grammar range.cloneRange() => Range
- */
- cloneRange: function () {
- var me = this;
- return new Range(me.document).setStart(me.startContainer, me.startOffset).setEnd(me.endContainer, me.endOffset);
- },
- /**
- * 让选区闭合到尾部,若toStart为真,则闭合到头部
- * @name collapse
- * @grammar range.collapse() => Range
- * @grammar range.collapse(true) => Range //闭合选区到头部
- */
- collapse: function (toStart) {
- var me = this;
- if (toStart) {
- me.endContainer = me.startContainer;
- me.endOffset = me.startOffset;
- } else {
- me.startContainer = me.endContainer;
- me.startOffset = me.endOffset;
- }
- me.collapsed = true;
- return me;
- },
- /**
- * 调整range的边界,使其"收缩"到最小的位置
- * @name shrinkBoundary
- * @grammar range.shrinkBoundary() => Range //range开始位置和结束位置都调整,参见<code><a href="#adjustmentboundary">adjustmentBoundary</a></code>
- * @grammar range.shrinkBoundary(true) => Range //仅调整开始位置,忽略结束位置
- * @example
- * <b>xx[</b>xxxxx] ==> <b>xx</b>[xxxxx]
- * <b>x[xx</b><i>]xxx</i> ==> <b>x[xx]</b><i>xxx</i>
- * [<b><i>xxxx</i>xxxxxxx</b>] ==> <b><i>[xxxx</i>xxxxxxx]</b>
- */
- shrinkBoundary: function (ignoreEnd) {
- var me = this, child,
- collapsed = me.collapsed;
- function check(node) {
- return node.nodeType == 1 && !domUtils.isBookmarkNode(node) && !dtd.$empty[node.tagName] && !dtd.$nonChild[node.tagName]
- }
- while (me.startContainer.nodeType == 1 //是element
- && (child = me.startContainer.childNodes[me.startOffset]) //子节点也是element
- && check(child)) {
- me.setStart(child, 0);
- }
- if (collapsed) {
- return me.collapse(true);
- }
- if (!ignoreEnd) {
- while (me.endContainer.nodeType == 1//是element
- && me.endOffset > 0 //如果是空元素就退出 endOffset=0那么endOffst-1为负值,childNodes[endOffset]报错
- && (child = me.endContainer.childNodes[me.endOffset - 1]) //子节点也是element
- && check(child)) {
- me.setEnd(child, child.childNodes.length);
- }
- }
- return me;
- },
- /**
- * 调整边界容器,如果是textNode,就调整到elementNode上
- * @name trimBoundary
- * @grammar range.trimBoundary([ignoreEnd]) => Range //true忽略结束边界
- * @example
- * DOM Element :
- * <b>|xxx</b>
- * startContainer = xxx; startOffset = 0
- * //执行后本方法后
- * startContainer = <b>; startOffset = 0
- * @example
- * Dom Element :
- * <b>xx|x</b>
- * startContainer = xxx; startOffset = 2
- * //执行本方法后,xxx被实实在在地切分成两个TextNode
- * startContainer = <b>; startOffset = 1
- */
- trimBoundary: function (ignoreEnd) {
- this.txtToElmBoundary();
- var start = this.startContainer,
- offset = this.startOffset,
- collapsed = this.collapsed,
- end = this.endContainer;
- if (start.nodeType == 3) {
- if (offset == 0) {
- this.setStartBefore(start);
- } else {
- if (offset >= start.nodeValue.length) {
- this.setStartAfter(start);
- } else {
- var textNode = domUtils.split(start, offset);
- //跟新结束边界
- if (start === end) {
- this.setEnd(textNode, this.endOffset - offset);
- } else if (start.parentNode === end) {
- this.endOffset += 1;
- }
- this.setStartBefore(textNode);
- }
- }
- if (collapsed) {
- return this.collapse(true);
- }
- }
- if (!ignoreEnd) {
- offset = this.endOffset;
- end = this.endContainer;
- if (end.nodeType == 3) {
- if (offset == 0) {
- this.setEndBefore(end);
- } else {
- offset < end.nodeValue.length && domUtils.split(end, offset);
- this.setEndAfter(end);
- }
- }
- }
- return this;
- },
- /**
- * 如果选区在文本的边界上,就扩展选区到文本的父节点上
- * @name txtToElmBoundary
- * @example
- * Dom Element :
- * <b> |xxx</b>
- * startContainer = xxx; startOffset = 0
- * //本方法执行后
- * startContainer = <b>; startOffset = 0
- * @example
- * Dom Element :
- * <b> xxx| </b>
- * startContainer = xxx; startOffset = 3
- * //本方法执行后
- * startContainer = <b>; startOffset = 1
- */
- txtToElmBoundary: function (ignoreCollapsed) {
- function adjust(r, c) {
- var container = r[c + 'Container'],
- offset = r[c + 'Offset'];
- if (container.nodeType == 3) {
- if (!offset) {
- r['set' + c.replace(/(\w)/, function (a) {
- return a.toUpperCase();
- }) + 'Before'](container);
- } else if (offset >= container.nodeValue.length) {
- r['set' + c.replace(/(\w)/, function (a) {
- return a.toUpperCase();
- }) + 'After'](container);
- }
- }
- }
- if (ignoreCollapsed || !this.collapsed) {
- adjust(this, 'start');
- adjust(this, 'end');
- }
- return this;
- },
- /**
- * 在当前选区的开始位置前插入一个节点或者fragment,range的开始位置会在插入节点的前边
- * @name insertNode
- * @grammar range.insertNode(node) => Range //node可以是textNode,elementNode,fragment
- * @example
- * Range :
- * xxx[x<p>xxxx</p>xxxx]x<p>sdfsdf</p>
- * 待插入Node :
- * <p>ssss</p>
- * 执行本方法后的Range :
- * xxx[<p>ssss</p>x<p>xxxx</p>xxxx]x<p>sdfsdf</p>
- */
- insertNode: function (node) {
- var first = node, length = 1;
- if (node.nodeType == 11) {
- first = node.firstChild;
- length = node.childNodes.length;
- }
- this.trimBoundary(true);
- var start = this.startContainer,
- offset = this.startOffset;
- var nextNode = start.childNodes[offset];
- if (nextNode) {
- start.insertBefore(node, nextNode);
- } else {
- start.appendChild(node);
- }
- if (first.parentNode === this.endContainer) {
- this.endOffset = this.endOffset + length;
- }
- return this.setStartBefore(first);
- },
- /**
- * 设置光标闭合位置,toEnd设置为true时光标将闭合到选区的结尾
- * @name setCursor
- * @grammar range.setCursor([toEnd]) => Range //toEnd为true时,光标闭合到选区的末尾
- */
- setCursor: function (toEnd, noFillData) {
- return this.collapse(!toEnd).select(noFillData);
- },
- /**
- * 创建当前range的一个书签,记录下当前range的位置,方便当dom树改变时,还能找回原来的选区位置
- * @name createBookmark
- * @grammar range.createBookmark([serialize]) => Object //{start:开始标记,end:结束标记,id:serialize} serialize为真时,开始结束标记是插入节点的id,否则是插入节点的引用
- */
- createBookmark: function (serialize, same) {
- var endNode,
- startNode = this.document.createElement('span');
- startNode.style.cssText = 'display:none;line-height:0px;';
- startNode.appendChild(this.document.createTextNode('\u200D'));
- startNode.id = '_baidu_bookmark_start_' + (same ? '' : guid++);
- if (!this.collapsed) {
- endNode = startNode.cloneNode(true);
- endNode.id = '_baidu_bookmark_end_' + (same ? '' : guid++);
- }
- this.insertNode(startNode);
- if (endNode) {
- this.collapse().insertNode(endNode).setEndBefore(endNode);
- }
- this.setStartAfter(startNode);
- return {
- start: serialize ? startNode.id : startNode,
- end: endNode ? serialize ? endNode.id : endNode : null,
- id: serialize
- }
- },
- /**
- * 移动边界到书签位置,并删除插入的书签节点
- * @name moveToBookmark
- * @grammar range.moveToBookmark(bookmark) => Range //让当前的range选到给定bookmark的位置,bookmark对象是由range.createBookmark创建的
- */
- moveToBookmark: function (bookmark) {
- var start = bookmark.id ? this.document.getElementById(bookmark.start) : bookmark.start,
- end = bookmark.end && bookmark.id ? this.document.getElementById(bookmark.end) : bookmark.end;
- this.setStartBefore(start);
- domUtils.remove(start);
- if (end) {
- this.setEndBefore(end);
- domUtils.remove(end);
- } else {
- this.collapse(true);
- }
- return this;
- },
- /**
- * 调整Range的边界,使其"缩小"到最合适的位置
- * @name adjustmentBoundary
- * @grammar range.adjustmentBoundary() => Range //参见<code><a href="#shrinkboundary">shrinkBoundary</a></code>
- * @example
- * <b>xx[</b>xxxxx] ==> <b>xx</b>[xxxxx]
- * <b>x[xx</b><i>]xxx</i> ==> <b>x[xx</b>]<i>xxx</i>
- */
- adjustmentBoundary: function () {
- if (!this.collapsed) {
- while (!domUtils.isBody(this.startContainer) &&
- this.startOffset == this.startContainer[this.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length &&
- this.startContainer[this.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length
- ) {
- this.setStartAfter(this.startContainer);
- }
- while (!domUtils.isBody(this.endContainer) && !this.endOffset &&
- this.endContainer[this.endContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'].length
- ) {
- this.setEndBefore(this.endContainer);
- }
- }
- return this;
- },
- /**
- * 得到一个自闭合的节点,常用于获取自闭和的节点,例如图片节点
- * @name getClosedNode
- * @grammar range.getClosedNode() => node|null
- * @example
- * <b>xxxx[<img />]xxx</b>
- */
- getClosedNode: function () {
- var node;
- if (!this.collapsed) {
- var range = this.cloneRange().adjustmentBoundary().shrinkBoundary();
- if (selectOneNode(range)) {
- var child = range.startContainer.childNodes[range.startOffset];
- if (child && child.nodeType == 1 && (dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName])) {
- node = child;
- }
- }
- }
- return node;
- },
- /**
- * 根据当前range选中内容节点(在页面上表现为反白显示)
- * @name select
- * @grammar range.select(); => Range
- */
- select: browser.ie ? function (noFillData, textRange) {
- var nativeRange;
- if (!this.collapsed)
- this.shrinkBoundary();
- var node = this.getClosedNode();
- if (node && !textRange) {
- try {
- nativeRange = this.document.body.createControlRange();
- nativeRange.addElement(node);
- nativeRange.select();
- } catch (e) {
- }
- return this;
- }
- var bookmark = this.createBookmark(),
- start = bookmark.start,
- end;
- nativeRange = this.document.body.createTextRange();
- nativeRange.moveToElementText(start);
- nativeRange.moveStart('character', 1);
- if (!this.collapsed) {
- var nativeRangeEnd = this.document.body.createTextRange();
- end = bookmark.end;
- nativeRangeEnd.moveToElementText(end);
- nativeRange.setEndPoint('EndToEnd', nativeRangeEnd);
- } else {
- if (!noFillData && this.startContainer.nodeType != 3) {
- //使用<span>|x<span>固定住光标
- var tmpText = this.document.createTextNode(fillChar),
- tmp = this.document.createElement('span');
- tmp.appendChild(this.document.createTextNode(fillChar));
- start.parentNode.insertBefore(tmp, start);
- start.parentNode.insertBefore(tmpText, start);
- //当点b,i,u时,不能清除i上边的b
- removeFillData(this.document, tmpText);
- fillData = tmpText;
- mergeSibling(tmp, 'previousSibling');
- mergeSibling(start, 'nextSibling');
- nativeRange.moveStart('character', -1);
- nativeRange.collapse(true);
- }
- }
- this.moveToBookmark(bookmark);
- tmp && domUtils.remove(tmp);
- //IE在隐藏状态下不支持range操作,catch一下
- try {
- nativeRange.select();
- } catch (e) {
- }
- return this;
- } : function (notInsertFillData) {
- function checkOffset(rng) {
- function check(node, offset, dir) {
- if (node.nodeType == 3 && node.nodeValue.length < offset) {
- rng[dir + 'Offset'] = node.nodeValue.length
- }
- }
- check(rng.startContainer, rng.startOffset, 'start');
- check(rng.endContainer, rng.endOffset, 'end');
- }
- var win = domUtils.getWindow(this.document),
- sel = win.getSelection(),
- txtNode;
- //FF下关闭自动长高时滚动条在关闭dialog时会跳
- //ff下如果不body.focus将不能定位闭合光标到编辑器内
- browser.gecko ? this.body.focus() : win.focus();
- if (sel) {
- sel.removeAllRanges();
- // trace:870 chrome/safari后边是br对于闭合得range不能定位 所以去掉了判断
- // this.startContainer.nodeType != 3 &&! ((child = this.startContainer.childNodes[this.startOffset]) && child.nodeType == 1 && child.tagName == 'BR'
- if (this.collapsed && !notInsertFillData) {
- // //opear如果没有节点接着,原生的不能够定位,不能在body的第一级插入空白节点
- // if (notInsertFillData && browser.opera && !domUtils.isBody(this.startContainer) && this.startContainer.nodeType == 1) {
- // var tmp = this.document.createTextNode('');
- // this.insertNode(tmp).setStart(tmp, 0).collapse(true);
- // }
- //
- //处理光标落在文本节点的情况
- //处理以下的情况
- //<b>|xxxx</b>
- //<b>xxxx</b>|xxxx
- //xxxx<b>|</b>
- var start = this.startContainer, child = start;
- if (start.nodeType == 1) {
- child = start.childNodes[this.startOffset];
- }
- if (!(start.nodeType == 3 && this.startOffset) &&
- (child ?
- (!child.previousSibling || child.previousSibling.nodeType != 3)
- :
- (!start.lastChild || start.lastChild.nodeType != 3)
- )
- ) {
- txtNode = this.document.createTextNode(fillChar);
- //跟着前边走
- this.insertNode(txtNode);
- removeFillData(this.document, txtNode);
- mergeSibling(txtNode, 'previousSibling');
- mergeSibling(txtNode, 'nextSibling');
- fillData = txtNode;
- this.setStart(txtNode, browser.webkit ? 1 : 0).collapse(true);
- }
- }
- var nativeRange = this.document.createRange();
- if (this.collapsed && browser.opera && this.startContainer.nodeType == 1) {
- var child = this.startContainer.childNodes[this.startOffset];
- if (!child) {
- //往前靠拢
- child = this.startContainer.lastChild;
- if (child && domUtils.isBr(child)) {
- this.setStartBefore(child).collapse(true);
- }
- } else {
- //向后靠拢
- while (child && domUtils.isBlockElm(child)) {
- if (child.nodeType == 1 && child.childNodes[0]) {
- child = child.childNodes[0]
- } else {
- break;
- }
- }
- child && this.setStartBefore(child).collapse(true)
- }
- }
- //是createAddress最后一位算的不准,现在这里进行微调
- checkOffset(this);
- nativeRange.setStart(this.startContainer, this.startOffset);
- nativeRange.setEnd(this.endContainer, this.endOffset);
- sel.addRange(nativeRange);
- }
- return this;
- },
- createAddress: function (ignoreEnd, ignoreTxt) {
- var addr = {}, me = this;
- function getAddress(isStart) {
- var node = isStart ? me.startContainer : me.endContainer;
- var parents = domUtils.findParents(node, true, function (node) {
- return !domUtils.isBody(node)
- }),
- addrs = [];
- for (var i = 0, ci; ci = parents[i++];) {
- addrs.push(domUtils.getNodeIndex(ci, ignoreTxt));
- }
- var firstIndex = 0;
- if (ignoreTxt) {
- if (node.nodeType == 3) {
- var tmpNode = node.previousSibling;
- while (tmpNode && tmpNode.nodeType == 3) {
- firstIndex += tmpNode.nodeValue.replace(fillCharReg, '').length;
- tmpNode = tmpNode.previousSibling;
- }
- firstIndex += (isStart ? me.startOffset : me.endOffset)// - (fillCharReg.test(node.nodeValue) ? 1 : 0 )
- } else {
- node = node.childNodes[isStart ? me.startOffset : me.endOffset];
- if (node) {
- firstIndex = domUtils.getNodeIndex(node, ignoreTxt);
- } else {
- node = isStart ? me.startContainer : me.endContainer;
- var first = node.firstChild;
- while (first) {
- if (domUtils.isFillChar(first)) {
- first = first.nextSibling;
- continue;
- }
- firstIndex++;
- if (first.nodeType == 3) {
- while (first && first.nodeType == 3) {
- first = first.nextSibling;
- }
- } else {
- first = first.nextSibling;
- }
- }
- }
- }
- } else {
- firstIndex = isStart ? domUtils.isFillChar(node) ? 0 : me.startOffset : me.endOffset
- }
- if (firstIndex < 0) {
- firstIndex = 0;
- }
- addrs.push(firstIndex);
- return addrs;
- }
- addr.startAddress = getAddress(true);
- if (!ignoreEnd) {
- addr.endAddress = me.collapsed ? [].concat(addr.startAddress) : getAddress();
- }
- return addr;
- },
- moveToAddress: function (addr, ignoreEnd) {
- var me = this;
- function getNode(address, isStart) {
- var tmpNode = me.body,
- parentNode, offset;
- for (var i = 0, ci, l = address.length; i < l; i++) {
- ci = address[i];
- parentNode = tmpNode;
- tmpNode = tmpNode.childNodes[ci];
- if (!tmpNode) {
- offset = ci;
- break;
- }
- }
- if (isStart) {
- if (tmpNode) {
- me.setStartBefore(tmpNode)
- } else {
- me.setStart(parentNode, offset)
- }
- } else {
- if (tmpNode) {
- me.setEndBefore(tmpNode)
- } else {
- me.setEnd(parentNode, offset)
- }
- }
- }
- getNode(addr.startAddress, true);
- !ignoreEnd && addr.endAddress && getNode(addr.endAddress);
- return me;
- },
- equals: function (rng) {
- for (var p in this) {
- if (this.hasOwnProperty(p)) {
- if (this[p] !== rng[p])
- return false
- }
- }
- return true;
- },
- scrollIntoView: function () {
- var $span = $('<span style="padding:0;margin:0;display:block;border:0"> </span>');
- this.cloneRange().insertNode($span.get(0));
- var winScrollTop = $(window).scrollTop(),
- winHeight = $(window).height(),
- spanTop = $span.offset().top;
- if (spanTop < winScrollTop - winHeight || spanTop > winScrollTop + winHeight) {
- if (spanTop > winScrollTop + winHeight) {
- window.scrollTo(0, spanTop - winHeight + $span.height())
- } else {
- window.scrollTo(0, winScrollTop - spanTop)
- }
- }
- $span.remove();
- },
- getOffset: function () {
- var bk = this.createBookmark();
- var offset = $(bk.start).css('display', 'inline-block').offset();
- this.moveToBookmark(bk);
- return offset
- }
- };
- })();
- ///import editor.js
- ///import core/browser.js
- ///import core/dom/dom.js
- ///import core/dom/dtd.js
- ///import core/dom/domUtils.js
- ///import core/dom/Range.js
- /**
- * @class UM.dom.Selection Selection类
- */
- (function () {
- function getBoundaryInformation(range, start) {
- var getIndex = domUtils.getNodeIndex;
- range = range.duplicate();
- range.collapse(start);
- var parent = range.parentElement();
- //如果节点里没有子节点,直接退出
- if (!parent.hasChildNodes()) {
- return {container: parent, offset: 0};
- }
- var siblings = parent.children,
- child,
- testRange = range.duplicate(),
- startIndex = 0, endIndex = siblings.length - 1, index = -1,
- distance;
- while (startIndex <= endIndex) {
- index = Math.floor((startIndex + endIndex) / 2);
- child = siblings[index];
- testRange.moveToElementText(child);
- var position = testRange.compareEndPoints('StartToStart', range);
- if (position > 0) {
- endIndex = index - 1;
- } else if (position < 0) {
- startIndex = index + 1;
- } else {
- //trace:1043
- return {container: parent, offset: getIndex(child)};
- }
- }
- if (index == -1) {
- testRange.moveToElementText(parent);
- testRange.setEndPoint('StartToStart', range);
- distance = testRange.text.replace(/(\r\n|\r)/g, '\n').length;
- siblings = parent.childNodes;
- if (!distance) {
- child = siblings[siblings.length - 1];
- return {container: child, offset: child.nodeValue.length};
- }
- var i = siblings.length;
- while (distance > 0) {
- distance -= siblings[--i].nodeValue.length;
- }
- return {container: siblings[i], offset: -distance};
- }
- testRange.collapse(position > 0);
- testRange.setEndPoint(position > 0 ? 'StartToStart' : 'EndToStart', range);
- distance = testRange.text.replace(/(\r\n|\r)/g, '\n').length;
- if (!distance) {
- return dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName] ?
- {container: parent, offset: getIndex(child) + (position > 0 ? 0 : 1)} :
- {container: child, offset: position > 0 ? 0 : child.childNodes.length}
- }
- while (distance > 0) {
- try {
- var pre = child;
- child = child[position > 0 ? 'previousSibling' : 'nextSibling'];
- distance -= child.nodeValue.length;
- } catch (e) {
- return {container: parent, offset: getIndex(pre)};
- }
- }
- return {container: child, offset: position > 0 ? -distance : child.nodeValue.length + distance}
- }
- /**
- * 将ieRange转换为Range对象
- * @param {Range} ieRange ieRange对象
- * @param {Range} range Range对象
- * @return {Range} range 返回转换后的Range对象
- */
- function transformIERangeToRange(ieRange, range) {
- if (ieRange.item) {
- range.selectNode(ieRange.item(0));
- } else {
- var bi = getBoundaryInformation(ieRange, true);
- range.setStart(bi.container, bi.offset);
- if (ieRange.compareEndPoints('StartToEnd', ieRange) != 0) {
- bi = getBoundaryInformation(ieRange, false);
- range.setEnd(bi.container, bi.offset);
- }
- }
- return range;
- }
- /**
- * 获得ieRange
- * @param {Selection} sel Selection对象
- * @return {ieRange} 得到ieRange
- */
- function _getIERange(sel, txtRange) {
- var ieRange;
- //ie下有可能报错
- try {
- ieRange = sel.getNative(txtRange).createRange();
- } catch (e) {
- return null;
- }
- var el = ieRange.item ? ieRange.item(0) : ieRange.parentElement();
- if ((el.ownerDocument || el) === sel.document) {
- return ieRange;
- }
- return null;
- }
- var Selection = dom.Selection = function (doc, body) {
- var me = this;
- me.document = doc;
- me.body = body;
- if (browser.ie9below) {
- $(body).on('beforedeactivate', function () {
- me._bakIERange = me.getIERange();
- }).on('activate', function () {
- try {
- var ieNativRng = _getIERange(me);
- if ((!ieNativRng || !me.rangeInBody(ieNativRng)) && me._bakIERange) {
- me._bakIERange.select();
- }
- } catch (ex) {
- }
- me._bakIERange = null;
- });
- }
- };
- Selection.prototype = {
- hasNativeRange: function () {
- var rng;
- if (!browser.ie || browser.ie9above) {
- var nativeSel = this.getNative();
- if (!nativeSel.rangeCount) {
- return false;
- }
- rng = nativeSel.getRangeAt(0);
- } else {
- rng = _getIERange(this);
- }
- return this.rangeInBody(rng);
- },
- /**
- * 获取原生seleciton对象
- * @public
- * @function
- * @name UM.dom.Selection.getNative
- * @return {Selection} 获得selection对象
- */
- getNative: function (txtRange) {
- var doc = this.document;
- try {
- return !doc ? null : browser.ie9below || txtRange ? doc.selection : domUtils.getWindow(doc).getSelection();
- } catch (e) {
- return null;
- }
- },
- /**
- * 获得ieRange
- * @public
- * @function
- * @name UM.dom.Selection.getIERange
- * @return {ieRange} 返回ie原生的Range
- */
- getIERange: function (txtRange) {
- var ieRange = _getIERange(this, txtRange);
- if (!ieRange || !this.rangeInBody(ieRange, txtRange)) {
- if (this._bakIERange) {
- return this._bakIERange;
- }
- }
- return ieRange;
- },
- rangeInBody: function (rng, txtRange) {
- var node = browser.ie9below || txtRange ? rng.item ? rng.item() : rng.parentElement() : rng.startContainer;
- return node === this.body || domUtils.inDoc(node, this.body);
- },
- /**
- * 缓存当前选区的range和选区的开始节点
- * @public
- * @function
- * @name UM.dom.Selection.cache
- */
- cache: function () {
- this.clear();
- this._cachedRange = this.getRange();
- this._cachedStartElement = this.getStart();
- this._cachedStartElementPath = this.getStartElementPath();
- },
- getStartElementPath: function () {
- if (this._cachedStartElementPath) {
- return this._cachedStartElementPath;
- }
- var start = this.getStart();
- if (start) {
- return domUtils.findParents(start, true, null, true)
- }
- return [];
- },
- /**
- * 清空缓存
- * @public
- * @function
- * @name UM.dom.Selection.clear
- */
- clear: function () {
- this._cachedStartElementPath = this._cachedRange = this._cachedStartElement = null;
- },
- /**
- * 编辑器是否得到了选区
- */
- isFocus: function () {
- return this.hasNativeRange()
- },
- /**
- * 获取选区对应的Range
- * @public
- * @function
- * @name UM.dom.Selection.getRange
- * @returns {UM.dom.Range} 得到Range对象
- */
- getRange: function () {
- var me = this;
- function optimze(range) {
- var child = me.body.firstChild,
- collapsed = range.collapsed;
- while (child && child.firstChild) {
- range.setStart(child, 0);
- child = child.firstChild;
- }
- if (!range.startContainer) {
- range.setStart(me.body, 0)
- }
- if (collapsed) {
- range.collapse(true);
- }
- }
- if (me._cachedRange != null) {
- return this._cachedRange;
- }
- var range = new dom.Range(me.document, me.body);
- if (browser.ie9below) {
- var nativeRange = me.getIERange();
- if (nativeRange && this.rangeInBody(nativeRange)) {
- try {
- transformIERangeToRange(nativeRange, range);
- } catch (e) {
- optimze(range);
- }
- } else {
- optimze(range);
- }
- } else {
- var sel = me.getNative();
- if (sel && sel.rangeCount && me.rangeInBody(sel.getRangeAt(0))) {
- var firstRange = sel.getRangeAt(0);
- var lastRange = sel.getRangeAt(sel.rangeCount - 1);
- range.setStart(firstRange.startContainer, firstRange.startOffset).setEnd(lastRange.endContainer, lastRange.endOffset);
- if (range.collapsed && domUtils.isBody(range.startContainer) && !range.startOffset) {
- optimze(range);
- }
- } else {
- //trace:1734 有可能已经不在dom树上了,标识的节点
- if (this._bakRange && (this._bakRange.startContainer === this.body || domUtils.inDoc(this._bakRange.startContainer, this.body))) {
- return this._bakRange;
- }
- optimze(range);
- }
- }
- return this._bakRange = range;
- },
- /**
- * 获取开始元素,用于状态反射
- * @public
- * @function
- * @name UM.dom.Selection.getStart
- * @return {Element} 获得开始元素
- */
- getStart: function () {
- if (this._cachedStartElement) {
- return this._cachedStartElement;
- }
- var range = browser.ie9below ? this.getIERange() : this.getRange(),
- tmpRange,
- start, tmp, parent;
- if (browser.ie9below) {
- if (!range) {
- //todo 给第一个值可能会有问题
- return this.document.body.firstChild;
- }
- //control元素
- if (range.item) {
- return range.item(0);
- }
- tmpRange = range.duplicate();
- //修正ie下<b>x</b>[xx] 闭合后 <b>x|</b>xx
- tmpRange.text.length > 0 && tmpRange.moveStart('character', 1);
- tmpRange.collapse(1);
- start = tmpRange.parentElement();
- parent = tmp = range.parentElement();
- while (tmp = tmp.parentNode) {
- if (tmp == start) {
- start = parent;
- break;
- }
- }
- } else {
- start = range.startContainer;
- if (start.nodeType == 1 && start.hasChildNodes()) {
- start = start.childNodes[Math.min(start.childNodes.length - 1, range.startOffset)];
- }
- if (start.nodeType == 3) {
- return start.parentNode;
- }
- }
- return start;
- },
- /**
- * 得到选区中的文本
- * @public
- * @function
- * @name UM.dom.Selection.getText
- * @return {String} 选区中包含的文本
- */
- getText: function () {
- var nativeSel, nativeRange;
- if (this.isFocus() && (nativeSel = this.getNative())) {
- nativeRange = browser.ie9below ? nativeSel.createRange() : nativeSel.getRangeAt(0);
- return browser.ie9below ? nativeRange.text : nativeRange.toString();
- }
- return '';
- }
- };
- })();
- /**
- * @file
- * @name UM.Editor
- * @short Editor
- * @import editor.js,core/utils.js,core/EventBase.js,core/browser.js,core/dom/dtd.js,core/dom/domUtils.js,core/dom/Range.js,core/dom/Selection.js,plugins/serialize.js
- * @desc 编辑器主类,包含编辑器提供的大部分公用接口
- */
- (function () {
- var uid = 0, _selectionChangeTimer;
- /**
- * @private
- * @ignore
- * @param form 编辑器所在的form元素
- * @param editor 编辑器实例对象
- */
- function setValue(form, editor) {
- var textarea;
- if (editor.textarea) {
- if (utils.isString(editor.textarea)) {
- for (var i = 0, ti, tis = domUtils.getElementsByTagName(form, 'textarea'); ti = tis[i++];) {
- if (ti.id == 'umeditor_textarea_' + editor.options.textarea) {
- textarea = ti;
- break;
- }
- }
- } else {
- textarea = editor.textarea;
- }
- }
- if (!textarea) {
- form.appendChild(textarea = domUtils.createElement(document, 'textarea', {
- 'name': editor.options.textarea,
- 'id': 'umeditor_textarea_' + editor.options.textarea,
- 'style': "display:none"
- }));
- //不要产生多个textarea
- editor.textarea = textarea;
- }
- textarea.value = editor.hasContents() ?
- (editor.options.allHtmlEnabled ? editor.getAllHtml() : editor.getContent(null, null, true)) :
- ''
- }
- function loadPlugins(me) {
- //初始化插件
- for (var pi in UM.plugins) {
- if (me.options.excludePlugins.indexOf(pi) == -1) {
- UM.plugins[pi].call(me);
- me.plugins[pi] = 1;
- }
- }
- me.langIsReady = true;
- me.fireEvent("langReady");
- }
- function checkCurLang(I18N) {
- for (var lang in I18N) {
- return lang
- }
- }
- /**
- * UEditor编辑器类
- * @name Editor
- * @desc 创建一个跟编辑器实例
- * - ***container*** 编辑器容器对象
- * - ***iframe*** 编辑区域所在的iframe对象
- * - ***window*** 编辑区域所在的window
- * - ***document*** 编辑区域所在的document对象
- * - ***body*** 编辑区域所在的body对象
- * - ***selection*** 编辑区域的选区对象
- */
- var Editor = UM.Editor = function (options) {
- var me = this;
- me.uid = uid++;
- EventBase.call(me);
- me.commands = {};
- me.options = utils.extend(utils.clone(options || {}), UMEDITOR_CONFIG, true);
- me.shortcutkeys = {};
- me.inputRules = [];
- me.outputRules = [];
- //设置默认的常用属性
- me.setOpt({
- isShow: true,
- initialContent: '',
- initialStyle: '',
- autoClearinitialContent: false,
- textarea: 'editorValue',
- focus: false,
- focusInEnd: true,
- autoClearEmptyNode: true,
- fullscreen: false,
- readonly: false,
- zIndex: 999,
- enterTag: 'p',
- lang: 'zh-cn',
- langPath: me.options.UMEDITOR_HOME_URL + 'lang/',
- theme: 'default',
- themePath: me.options.UMEDITOR_HOME_URL + 'themes/',
- allHtmlEnabled: false,
- autoSyncData: true,
- autoHeightEnabled: true,
- excludePlugins: ''
- });
- me.plugins = {};
- if (!utils.isEmptyObject(UM.I18N)) {
- //修改默认的语言类型
- me.options.lang = checkCurLang(UM.I18N);
- loadPlugins(me)
- } else {
- utils.loadFile(document, {
- src: me.options.langPath + me.options.lang + "/" + me.options.lang + ".js",
- tag: "script",
- type: "text/javascript",
- defer: "defer"
- }, function () {
- loadPlugins(me)
- });
- }
- };
- Editor.prototype = {
- /**
- * 当编辑器ready后执行传入的fn,如果编辑器已经完成ready,就马上执行fn,fn的中的this是编辑器实例。
- * 大部分的实例接口都需要放在该方法内部执行,否则在IE下可能会报错。
- * @name ready
- * @grammar editor.ready(fn) fn是当编辑器渲染好后执行的function
- * @example
- * var editor = new UM.ui.Editor();
- * editor.render("myEditor");
- * editor.ready(function(){
- * editor.setContent("欢迎使用UEditor!");
- * })
- */
- ready: function (fn) {
- var me = this;
- if (fn) {
- me.isReady ? fn.apply(me) : me.addListener('ready', fn);
- }
- },
- /**
- * 为编辑器设置默认参数值。若用户配置为空,则以默认配置为准
- * @grammar editor.setOpt(key,value); //传入一个键、值对
- * @grammar editor.setOpt({ key:value}); //传入一个json对象
- */
- setOpt: function (key, val) {
- var obj = {};
- if (utils.isString(key)) {
- obj[key] = val
- } else {
- obj = key;
- }
- utils.extend(this.options, obj, true);
- },
- getOpt: function (key) {
- return this.options[key] || ''
- },
- /**
- * 销毁编辑器实例对象
- * @name destroy
- * @grammar editor.destroy();
- */
- destroy: function () {
- var me = this;
- me.fireEvent('destroy');
- var container = me.container.parentNode;
- if (container === document.body) {
- container = me.container;
- }
- var textarea = me.textarea;
- if (!textarea) {
- textarea = document.createElement('textarea');
- container.parentNode.insertBefore(textarea, container);
- } else {
- textarea.style.display = ''
- }
- textarea.style.width = me.body.offsetWidth + 'px';
- textarea.style.height = me.body.offsetHeight + 'px';
- textarea.value = me.getContent();
- textarea.id = me.key;
- if (container.contains(textarea)) {
- $(textarea).insertBefore(container);
- }
- container.innerHTML = '';
- domUtils.remove(container);
- UM.clearCache(me.id);
- //trace:2004
- for (var p in me) {
- if (me.hasOwnProperty(p)) {
- delete this[p];
- }
- }
- },
- initialCont: function (holder) {
- if (holder) {
- holder.getAttribute('name') && (this.options.textarea = holder.getAttribute('name'));
- if (holder && /script|textarea/ig.test(holder.tagName)) {
- var newDiv = document.createElement('div');
- holder.parentNode.insertBefore(newDiv, holder);
- this.options.initialContent = UM.htmlparser(holder.value || holder.innerHTML || this.options.initialContent).toHtml();
- holder.className && (newDiv.className = holder.className);
- holder.style.cssText && (newDiv.style.cssText = holder.style.cssText);
- if (/textarea/i.test(holder.tagName)) {
- this.textarea = holder;
- this.textarea.style.display = 'none';
- } else {
- holder.parentNode.removeChild(holder);
- holder.id && (newDiv.id = holder.id);
- }
- holder = newDiv;
- holder.innerHTML = '';
- }
- return holder;
- } else {
- return null;
- }
- },
- /**
- * 渲染编辑器的DOM到指定容器,必须且只能调用一次
- * @name render
- * @grammar editor.render(containerId); //可以指定一个容器ID
- * @grammar editor.render(containerDom); //也可以直接指定容器对象
- */
- render: function (container) {
- var me = this,
- options = me.options,
- getStyleValue = function (attr) {
- return parseInt($(container).css(attr));
- };
- if (utils.isString(container)) {
- container = document.getElementById(container);
- }
- if (container) {
- this.id = container.getAttribute('id');
- UM.setEditor(this);
- utils.cssRule('edui-style-body', me.options.initialStyle, document);
- container = this.initialCont(container);
- container.className += ' edui-body-container';
- if (options.initialFrameWidth) {
- options.minFrameWidth = options.initialFrameWidth
- } else {
- //都没给值,先写死了
- options.minFrameWidth = options.initialFrameWidth = $(container).width() || UM.defaultWidth;
- }
- if (options.initialFrameHeight) {
- options.minFrameHeight = options.initialFrameHeight
- } else {
- options.initialFrameHeight = options.minFrameHeight = $(container).height() || UM.defaultHeight;
- }
- container.style.width = /%$/.test(options.initialFrameWidth) ? '100%' : options.initialFrameWidth -
- getStyleValue("padding-left") -
- getStyleValue("padding-right") + 'px';
- var height = /%$/.test(options.initialFrameHeight) ? '100%' : (options.initialFrameHeight - getStyleValue("padding-top") - getStyleValue("padding-bottom"));
- if (this.options.autoHeightEnabled) {
- container.style.minHeight = height + 'px';
- container.style.height = '';
- if (browser.ie && browser.version <= 6) {
- container.style.height = height;
- container.style.setExpression('height', 'this.scrollHeight <= ' + height + ' ? "' + height + 'px" : "auto"');
- }
- } else {
- $(container).height(height)
- }
- container.style.zIndex = options.zIndex;
- this._setup(container);
- }
- },
- /**
- * 编辑器初始化
- * @private
- * @ignore
- * @param {Element} doc 编辑器Iframe中的文档对象
- */
- _setup: function (cont) {
- var me = this,
- options = me.options;
- cont.contentEditable = true;
- document.body.spellcheck = false;
- me.document = document;
- me.window = document.defaultView || document.parentWindow;
- me.body = cont;
- me.$body = $(cont);
- me.selection = new dom.Selection(document, me.body);
- me._isEnabled = false;
- //gecko初始化就能得到range,无法判断isFocus了
- var geckoSel;
- if (browser.gecko && (geckoSel = this.selection.getNative())) {
- geckoSel.removeAllRanges();
- }
- this._initEvents();
- //为form提交提供一个隐藏的textarea
- for (var form = cont.parentNode; form && !domUtils.isBody(form); form = form.parentNode) {
- if (form.tagName == 'FORM') {
- me.form = form;
- if (me.options.autoSyncData) {
- $(cont).on('blur', function () {
- setValue(form, me);
- })
- } else {
- $(form).on('submit', function () {
- setValue(this, me);
- })
- }
- break;
- }
- }
- if (options.initialContent) {
- if (options.autoClearinitialContent) {
- var oldExecCommand = me.execCommand;
- me.execCommand = function () {
- me.fireEvent('firstBeforeExecCommand');
- return oldExecCommand.apply(me, arguments);
- };
- this._setDefaultContent(options.initialContent);
- } else
- this.setContent(options.initialContent, false, true);
- }
- //编辑器不能为空内容
- if (domUtils.isEmptyNode(me.body)) {
- me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
- }
- //如果要求focus, 就把光标定位到内容开始
- if (options.focus) {
- setTimeout(function () {
- me.focus(me.options.focusInEnd);
- //如果自动清除开着,就不需要做selectionchange;
- !me.options.autoClearinitialContent && me._selectionChange();
- }, 0);
- }
- if (!me.container) {
- me.container = cont.parentNode;
- }
- me._bindshortcutKeys();
- me.isReady = 1;
- me.fireEvent('ready');
- options.onready && options.onready.call(me);
- if (!browser.ie || browser.ie9above) {
- $(me.body).on('blur focus', function (e) {
- var nSel = me.selection.getNative();
- //chrome下会出现alt+tab切换时,导致选区位置不对
- if (e.type == 'blur') {
- if (nSel.rangeCount > 0) {
- me._bakRange = nSel.getRangeAt(0);
- }
- } else {
- try {
- me._bakRange && nSel.addRange(me._bakRange)
- } catch (e) {
- }
- me._bakRange = null;
- }
- });
- }
- !options.isShow && me.setHide();
- options.readonly && me.setDisabled();
- },
- /**
- * 同步编辑器的数据,为提交数据做准备,主要用于你是手动提交的情况
- * @name sync
- * @grammar editor.sync(); //从编辑器的容器向上查找,如果找到就同步数据
- * @grammar editor.sync(formID); //formID制定一个要同步数据的form的id,编辑器的数据会同步到你指定form下
- * @desc
- * 后台取得数据得键值使用你容器上得''name''属性,如果没有就使用参数传入的''textarea''
- * @example
- * editor.sync();
- * form.sumbit(); //form变量已经指向了form元素
- *
- */
- sync: function (formId) {
- var me = this,
- form = formId ? document.getElementById(formId) :
- domUtils.findParent(me.body.parentNode, function (node) {
- return node.tagName == 'FORM'
- }, true);
- form && setValue(form, me);
- },
- /**
- * 设置编辑器高度
- * @name setHeight
- * @grammar editor.setHeight(number); //纯数值,不带单位
- */
- setHeight: function (height, notSetHeight) {
- !notSetHeight && (this.options.initialFrameHeight = height);
- if (this.options.autoHeightEnabled) {
- $(this.body).css({
- 'min-height': height + 'px'
- });
- if (browser.ie && browser.version <= 6 && this.container) {
- this.container.style.height = height;
- this.container.style.setExpression('height', 'this.scrollHeight <= ' + height + ' ? "' + height + 'px" : "auto"');
- }
- } else {
- $(this.body).height(height)
- }
- this.fireEvent('resize');
- },
- /**
- * 设置编辑器宽度
- * @name setWidth
- * @grammar editor.setWidth(number); //纯数值,不带单位
- */
- setWidth: function (width) {
- this.$container && this.$container.width(width);
- $(this.body).width(width - $(this.body).css('padding-left').replace('px', '') * 1 - $(this.body).css('padding-right').replace('px', '') * 1);
- this.fireEvent('resize');
- },
- addshortcutkey: function (cmd, keys) {
- var obj = {};
- if (keys) {
- obj[cmd] = keys
- } else {
- obj = cmd;
- }
- utils.extend(this.shortcutkeys, obj)
- },
- _bindshortcutKeys: function () {
- var me = this, shortcutkeys = this.shortcutkeys;
- me.addListener('keydown', function (type, e) {
- var keyCode = e.keyCode || e.which;
- for (var i in shortcutkeys) {
- var tmp = shortcutkeys[i].split(',');
- for (var t = 0, ti; ti = tmp[t++];) {
- ti = ti.split(':');
- var key = ti[0], param = ti[1];
- if (/^(ctrl)(\+shift)?\+(\d+)$/.test(key.toLowerCase()) || /^(\d+)$/.test(key)) {
- if (((RegExp.$1 == 'ctrl' ? (e.ctrlKey || e.metaKey) : 0)
- && (RegExp.$2 != "" ? e[RegExp.$2.slice(1) + "Key"] : 1)
- && keyCode == RegExp.$3
- ) ||
- keyCode == RegExp.$1
- ) {
- if (me.queryCommandState(i, param) != -1)
- me.execCommand(i, param);
- domUtils.preventDefault(e);
- }
- }
- }
- }
- });
- },
- /**
- * 获取编辑器内容
- * @name getContent
- * @grammar editor.getContent() => String //若编辑器中只包含字符"<p><br /></p/>"会返回空。
- * @grammar editor.getContent(fn) => String
- * @example
- * getContent默认是会现调用hasContents来判断编辑器是否为空,如果是,就直接返回空字符串
- * 你也可以传入一个fn来接替hasContents的工作,定制判断的规则
- * editor.getContent(function(){
- * return false //编辑器没有内容 ,getContent直接返回空
- * })
- */
- getContent: function (cmd, fn, notSetCursor, ignoreBlank, formatter) {
- var me = this;
- if (cmd && utils.isFunction(cmd)) {
- fn = cmd;
- cmd = '';
- }
- if (fn ? !fn() : !this.hasContents()) {
- return '';
- }
- me.fireEvent('beforegetcontent');
- var root = UM.htmlparser(me.body.innerHTML, ignoreBlank);
- me.filterOutputRule(root);
- me.fireEvent('aftergetcontent', root);
- return root.toHtml(formatter);
- },
- /**
- * 取得完整的html代码,可以直接显示成完整的html文档
- * @name getAllHtml
- * @grammar editor.getAllHtml() => String
- */
- getAllHtml: function () {
- var me = this,
- headHtml = [],
- html = '';
- me.fireEvent('getAllHtml', headHtml);
- if (browser.ie && browser.version > 8) {
- var headHtmlForIE9 = '';
- utils.each(me.document.styleSheets, function (si) {
- headHtmlForIE9 += (si.href ? '<link rel="stylesheet" type="text/css" href="' + si.href + '" />' : '<style>' + si.cssText + '</style>');
- });
- utils.each(me.document.getElementsByTagName('script'), function (si) {
- headHtmlForIE9 += si.outerHTML;
- });
- }
- return '<html><head>' + (me.options.charset ? '<meta http-equiv="Content-Type" content="text/html; charset=' + me.options.charset + '"/>' : '')
- + (headHtmlForIE9 || me.document.getElementsByTagName('head')[0].innerHTML) + headHtml.join('\n') + '</head>'
- + '<body ' + (ie && browser.version < 9 ? 'class="view"' : '') + '>' + me.getContent(null, null, true) + '</body></html>';
- },
- /**
- * 得到编辑器的纯文本内容,但会保留段落格式
- * @name getPlainTxt
- * @grammar editor.getPlainTxt() => String
- */
- getPlainTxt: function () {
- var reg = new RegExp(domUtils.fillChar, 'g'),
- html = this.body.innerHTML.replace(/[\n\r]/g, '');//ie要先去了\n在处理
- html = html.replace(/<(p|div)[^>]*>(<br\/?>| )<\/\1>/gi, '\n')
- .replace(/<br\/?>/gi, '\n')
- .replace(/<[^>/]+>/g, '')
- .replace(/(\n)?<\/([^>]+)>/g, function (a, b, c) {
- return dtd.$block[c] ? '\n' : b ? b : '';
- });
- //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
- return html.replace(reg, '').replace(/\u00a0/g, ' ').replace(/ /g, ' ');
- },
- /**
- * 获取编辑器中的纯文本内容,没有段落格式
- * @name getContentTxt
- * @grammar editor.getContentTxt() => String
- */
- getContentTxt: function () {
- var reg = new RegExp(domUtils.fillChar, 'g');
- //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
- return this.body[browser.ie ? 'innerText' : 'textContent'].replace(reg, '').replace(/\u00a0/g, ' ');
- },
- /**
- * 将html设置到编辑器中, 如果是用于初始化时给编辑器赋初值,则必须放在ready方法内部执行
- * @name setContent
- * @grammar editor.setContent(html)
- * @example
- * var editor = new UM.ui.Editor()
- * editor.ready(function(){
- * //需要ready后执行,否则可能报错
- * editor.setContent("欢迎使用UEditor!");
- * })
- */
- setContent: function (html, isAppendTo, notFireSelectionchange) {
- var me = this;
- me.fireEvent('beforesetcontent', html);
- var root = UM.htmlparser(html);
- me.filterInputRule(root);
- html = root.toHtml();
- me.body.innerHTML = (isAppendTo ? me.body.innerHTML : '') + html;
- function isCdataDiv(node) {
- return node.tagName == 'DIV' && node.getAttribute('cdata_tag');
- }
- //给文本或者inline节点套p标签
- if (me.options.enterTag == 'p') {
- var child = this.body.firstChild, tmpNode;
- if (!child || child.nodeType == 1 &&
- (dtd.$cdata[child.tagName] || isCdataDiv(child) ||
- domUtils.isCustomeNode(child)
- )
- && child === this.body.lastChild) {
- this.body.innerHTML = '<p>' + (browser.ie ? ' ' : '<br/>') + '</p>' + this.body.innerHTML;
- } else {
- var p = me.document.createElement('p');
- while (child) {
- while (child && (child.nodeType == 3 || child.nodeType == 1 && dtd.p[child.tagName] && !dtd.$cdata[child.tagName])) {
- tmpNode = child.nextSibling;
- p.appendChild(child);
- child = tmpNode;
- }
- if (p.firstChild) {
- if (!child) {
- me.body.appendChild(p);
- break;
- } else {
- child.parentNode.insertBefore(p, child);
- p = me.document.createElement('p');
- }
- }
- child = child.nextSibling;
- }
- }
- }
- me.fireEvent('aftersetcontent');
- me.fireEvent('contentchange');
- !notFireSelectionchange && me._selectionChange();
- //清除保存的选区
- me._bakRange = me._bakIERange = me._bakNativeRange = null;
- //trace:1742 setContent后gecko能得到焦点问题
- var geckoSel;
- if (browser.gecko && (geckoSel = this.selection.getNative())) {
- geckoSel.removeAllRanges();
- }
- if (me.options.autoSyncData) {
- me.form && setValue(me.form, me);
- }
- },
- /**
- * 让编辑器获得焦点,toEnd确定focus位置
- * @name focus
- * @grammar editor.focus([toEnd]) //默认focus到编辑器头部,toEnd为true时focus到内容尾部
- */
- focus: function (toEnd) {
- try {
- var me = this,
- rng = me.selection.getRange();
- if (toEnd) {
- rng.setStartAtLast(me.body.lastChild).setCursor(false, true);
- } else {
- rng.select(true);
- }
- this.fireEvent('focus');
- } catch (e) {
- }
- },
- /**
- * 使编辑区域失去焦点
- */
- blur: function () {
- var sel = this.selection.getNative();
- sel.empty ? sel.empty() : sel.removeAllRanges();
- this.fireEvent('blur')
- },
- /**
- * 判断编辑器当前是否获得了焦点
- */
- isFocus: function () {
- if (this.fireEvent('isfocus') === true) {
- return true;
- }
- return this.selection.isFocus();
- },
- /**
- * 初始化UE事件及部分事件代理
- * @private
- * @ignore
- */
- _initEvents: function () {
- var me = this,
- cont = me.body,
- _proxyDomEvent = function () {
- me._proxyDomEvent.apply(me, arguments);
- };
- $(cont)
- .on('click contextmenu mousedown keydown keyup keypress mouseup mouseover mouseout selectstart', _proxyDomEvent)
- .on('focus blur', _proxyDomEvent)
- .on('mouseup keydown', function (evt) {
- //特殊键不触发selectionchange
- if (evt.type == 'keydown' && (evt.ctrlKey || evt.metaKey || evt.shiftKey || evt.altKey)) {
- return;
- }
- if (evt.button == 2) return;
- me._selectionChange(250, evt);
- });
- },
- /**
- * 触发事件代理
- * @private
- * @ignore
- */
- _proxyDomEvent: function (evt) {
- return this.fireEvent(evt.type.replace(/^on/, ''), evt);
- },
- /**
- * 变化选区
- * @private
- * @ignore
- */
- _selectionChange: function (delay, evt) {
- var me = this;
- //有光标才做selectionchange 为了解决未focus时点击source不能触发更改工具栏状态的问题(source命令notNeedUndo=1)
- // if ( !me.selection.isFocus() ){
- // return;
- // }
- var hackForMouseUp = false;
- var mouseX, mouseY;
- if (browser.ie && browser.version < 9 && evt && evt.type == 'mouseup') {
- var range = this.selection.getRange();
- if (!range.collapsed) {
- hackForMouseUp = true;
- mouseX = evt.clientX;
- mouseY = evt.clientY;
- }
- }
- clearTimeout(_selectionChangeTimer);
- _selectionChangeTimer = setTimeout(function () {
- if (!me.selection.getNative()) {
- return;
- }
- //修复一个IE下的bug: 鼠标点击一段已选择的文本中间时,可能在mouseup后的一段时间内取到的range是在selection的type为None下的错误值.
- //IE下如果用户是拖拽一段已选择文本,则不会触发mouseup事件,所以这里的特殊处理不会对其有影响
- var ieRange;
- if (hackForMouseUp && me.selection.getNative().type == 'None') {
- ieRange = me.document.body.createTextRange();
- try {
- ieRange.moveToPoint(mouseX, mouseY);
- } catch (ex) {
- ieRange = null;
- }
- }
- var bakGetIERange;
- if (ieRange) {
- bakGetIERange = me.selection.getIERange;
- me.selection.getIERange = function () {
- return ieRange;
- };
- }
- me.selection.cache();
- if (bakGetIERange) {
- me.selection.getIERange = bakGetIERange;
- }
- if (me.selection._cachedRange && me.selection._cachedStartElement) {
- me.fireEvent('beforeselectionchange');
- // 第二个参数causeByUi为true代表由用户交互造成的selectionchange.
- me.fireEvent('selectionchange', !!evt);
- me.fireEvent('afterselectionchange');
- me.selection.clear();
- }
- }, delay || 50);
- },
- _callCmdFn: function (fnName, args) {
- args = Array.prototype.slice.call(args, 0);
- var cmdName = args.shift().toLowerCase(),
- cmd, cmdFn;
- cmd = this.commands[cmdName] || UM.commands[cmdName];
- cmdFn = cmd && cmd[fnName];
- //没有querycommandstate或者没有command的都默认返回0
- if ((!cmd || !cmdFn) && fnName == 'queryCommandState') {
- return 0;
- } else if (cmdFn) {
- return cmdFn.apply(this, [cmdName].concat(args));
- }
- },
- /**
- * 执行编辑命令cmdName,完成富文本编辑效果
- * @name execCommand
- * @grammar editor.execCommand(cmdName) => {*}
- */
- execCommand: function (cmdName) {
- if (!this.isFocus()) {
- var bakRange = this.selection._bakRange;
- if (bakRange) {
- bakRange.select()
- } else {
- this.focus(true)
- }
- }
- cmdName = cmdName.toLowerCase();
- var me = this,
- result,
- cmd = me.commands[cmdName] || UM.commands[cmdName];
- if (!cmd || !cmd.execCommand) {
- return null;
- }
- if (!cmd.notNeedUndo && !me.__hasEnterExecCommand) {
- me.__hasEnterExecCommand = true;
- if (me.queryCommandState.apply(me, arguments) != -1) {
- me.fireEvent('saveScene');
- me.fireEvent('beforeexeccommand', cmdName);
- result = this._callCmdFn('execCommand', arguments);
- (!cmd.ignoreContentChange && !me._ignoreContentChange) && me.fireEvent('contentchange');
- me.fireEvent('afterexeccommand', cmdName);
- me.fireEvent('saveScene');
- }
- me.__hasEnterExecCommand = false;
- } else {
- result = this._callCmdFn('execCommand', arguments);
- (!me.__hasEnterExecCommand && !cmd.ignoreContentChange && !me._ignoreContentChange) && me.fireEvent('contentchange')
- }
- (!me.__hasEnterExecCommand && !cmd.ignoreContentChange && !me._ignoreContentChange) && me._selectionChange();
- return result;
- },
- /**
- * 根据传入的command命令,查选编辑器当前的选区,返回命令的状态
- * @name queryCommandState
- * @grammar editor.queryCommandState(cmdName) => (-1|0|1)
- * @desc
- * * ''-1'' 当前命令不可用
- * * ''0'' 当前命令可用
- * * ''1'' 当前命令已经执行过了
- */
- queryCommandState: function (cmdName) {
- try {
- return this._callCmdFn('queryCommandState', arguments);
- } catch (e) {
- return 0
- }
- },
- /**
- * 根据传入的command命令,查选编辑器当前的选区,根据命令返回相关的值
- * @name queryCommandValue
- * @grammar editor.queryCommandValue(cmdName) => {*}
- */
- queryCommandValue: function (cmdName) {
- try {
- return this._callCmdFn('queryCommandValue', arguments);
- } catch (e) {
- return null
- }
- },
- /**
- * 检查编辑区域中是否有内容,若包含tags中的节点类型,直接返回true
- * @name hasContents
- * @desc
- * 默认有文本内容,或者有以下节点都不认为是空
- * <code>{table:1,ul:1,ol:1,dl:1,iframe:1,area:1,base:1,col:1,hr:1,img:1,embed:1,input:1,link:1,meta:1,param:1}</code>
- * @grammar editor.hasContents() => (true|false)
- * @grammar editor.hasContents(tags) => (true|false) //若文档中包含tags数组里对应的tag,直接返回true
- * @example
- * editor.hasContents(['span']) //如果编辑器里有这些,不认为是空
- */
- hasContents: function (tags) {
- if (tags) {
- for (var i = 0, ci; ci = tags[i++];) {
- if (this.body.getElementsByTagName(ci).length > 0) {
- return true;
- }
- }
- }
- if (!domUtils.isEmptyBlock(this.body)) {
- return true
- }
- //随时添加,定义的特殊标签如果存在,不能认为是空
- tags = ['div'];
- for (i = 0; ci = tags[i++];) {
- var nodes = domUtils.getElementsByTagName(this.body, ci);
- for (var n = 0, cn; cn = nodes[n++];) {
- if (domUtils.isCustomeNode(cn)) {
- return true;
- }
- }
- }
- return false;
- },
- /**
- * 重置编辑器,可用来做多个tab使用同一个编辑器实例
- * @name reset
- * @desc
- * * 清空编辑器内容
- * * 清空回退列表
- * @grammar editor.reset()
- */
- reset: function () {
- this.fireEvent('reset');
- },
- isEnabled: function () {
- return this._isEnabled != true;
- },
- setEnabled: function () {
- var me = this, range;
- me.body.contentEditable = true;
- /* 恢复选区 */
- if (me.lastBk) {
- range = me.selection.getRange();
- try {
- range.moveToBookmark(me.lastBk);
- delete me.lastBk
- } catch (e) {
- range.setStartAtFirst(me.body).collapse(true)
- }
- range.select(true);
- }
- /* 恢复query函数 */
- if (me.bkqueryCommandState) {
- me.queryCommandState = me.bkqueryCommandState;
- delete me.bkqueryCommandState;
- }
- /* 恢复原生事件 */
- if (me._bkproxyDomEvent) {
- me._proxyDomEvent = me._bkproxyDomEvent;
- delete me._bkproxyDomEvent;
- }
- /* 触发事件 */
- me.fireEvent('setEnabled');
- },
- /**
- * 设置当前编辑区域可以编辑
- * @name enable
- * @grammar editor.enable()
- */
- enable: function () {
- return this.setEnabled();
- },
- setDisabled: function (except, keepDomEvent) {
- var me = this;
- me.body.contentEditable = false;
- me._except = except ? utils.isArray(except) ? except : [except] : [];
- /* 备份最后的选区 */
- if (!me.lastBk) {
- me.lastBk = me.selection.getRange().createBookmark(true);
- }
- /* 备份并重置query函数 */
- if (!me.bkqueryCommandState) {
- me.bkqueryCommandState = me.queryCommandState;
- me.queryCommandState = function (type) {
- if (utils.indexOf(me._except, type) != -1) {
- return me.bkqueryCommandState.apply(me, arguments);
- }
- return -1;
- };
- }
- /* 备份并墙原生事件 */
- if (!keepDomEvent && !me._bkproxyDomEvent) {
- me._bkproxyDomEvent = me._proxyDomEvent;
- me._proxyDomEvent = function () {
- return false;
- };
- }
- /* 触发事件 */
- me.fireEvent('selectionchange');
- me.fireEvent('setDisabled', me._except);
- },
- /** 设置当前编辑区域不可编辑,except中的命令除外
- * @name disable
- * @grammar editor.disable()
- * @grammar editor.disable(except) //例外的命令,也即即使设置了disable,此处配置的命令仍然可以执行
- * @example
- * //禁用工具栏中除加粗和插入图片之外的所有功能
- * editor.disable(['bold','insertimage']);//可以是单一的String,也可以是Array
- */
- disable: function (except) {
- return this.setDisabled(except);
- },
- /**
- * 设置默认内容
- * @ignore
- * @private
- * @param {String} cont 要存入的内容
- */
- _setDefaultContent: function () {
- function clear() {
- var me = this;
- if (me.document.getElementById('initContent')) {
- me.body.innerHTML = '<p>' + (ie ? '' : '<br/>') + '</p>';
- me.removeListener('firstBeforeExecCommand focus', clear);
- setTimeout(function () {
- me.focus();
- me._selectionChange();
- }, 0)
- }
- }
- return function (cont) {
- var me = this;
- me.body.innerHTML = '<p id="initContent">' + cont + '</p>';
- me.addListener('firstBeforeExecCommand focus', clear);
- }
- }(),
- /**
- * show方法的兼容版本
- * @private
- * @ignore
- */
- setShow: function () {
- var me = this, range = me.selection.getRange();
- if (me.container.style.display == 'none') {
- //有可能内容丢失了
- try {
- range.moveToBookmark(me.lastBk);
- delete me.lastBk
- } catch (e) {
- range.setStartAtFirst(me.body).collapse(true)
- }
- //ie下focus实效,所以做了个延迟
- setTimeout(function () {
- range.select(true);
- }, 100);
- me.container.style.display = '';
- }
- },
- /**
- * 显示编辑器
- * @name show
- * @grammar editor.show()
- */
- show: function () {
- return this.setShow();
- },
- /**
- * hide方法的兼容版本
- * @private
- * @ignore
- */
- setHide: function () {
- var me = this;
- if (!me.lastBk) {
- me.lastBk = me.selection.getRange().createBookmark(true);
- }
- me.container.style.display = 'none'
- },
- /**
- * 隐藏编辑器
- * @name hide
- * @grammar editor.hide()
- */
- hide: function () {
- return this.setHide();
- },
- /**
- * 根据制定的路径,获取对应的语言资源
- * @name getLang
- * @grammar editor.getLang(path) => (JSON|String) 路径根据的是lang目录下的语言文件的路径结构
- * @example
- * editor.getLang('contextMenu.delete') //如果当前是中文,那返回是的是删除
- */
- getLang: function (path) {
- var lang = UM.I18N[this.options.lang];
- if (!lang) {
- throw Error("not import language file");
- }
- path = (path || "").split(".");
- for (var i = 0, ci; ci = path[i++];) {
- lang = lang[ci];
- if (!lang) break;
- }
- return lang;
- },
- /**
- * 计算编辑器当前内容的长度
- * @name getContentLength
- * @grammar editor.getContentLength(ingoneHtml,tagNames) =>
- * @example
- * editor.getLang(true)
- */
- getContentLength: function (ingoneHtml, tagNames) {
- var count = this.getContent(false, false, true).length;
- if (ingoneHtml) {
- tagNames = (tagNames || []).concat(['hr', 'img', 'iframe']);
- count = this.getContentTxt().replace(/[\t\r\n]+/g, '').length;
- for (var i = 0, ci; ci = tagNames[i++];) {
- count += this.body.getElementsByTagName(ci).length;
- }
- }
- return count;
- },
- addInputRule: function (rule, ignoreUndo) {
- rule.ignoreUndo = ignoreUndo;
- this.inputRules.push(rule);
- },
- filterInputRule: function (root, isUndoLoad) {
- for (var i = 0, ci; ci = this.inputRules[i++];) {
- if (isUndoLoad && ci.ignoreUndo) {
- continue;
- }
- ci.call(this, root)
- }
- },
- addOutputRule: function (rule, ignoreUndo) {
- rule.ignoreUndo = ignoreUndo;
- this.outputRules.push(rule)
- },
- filterOutputRule: function (root, isUndoLoad) {
- for (var i = 0, ci; ci = this.outputRules[i++];) {
- if (isUndoLoad && ci.ignoreUndo) {
- continue;
- }
- ci.call(this, root)
- }
- }
- };
- utils.inherits(Editor, EventBase);
- })();
- /**
- * @file
- * @name UM.filterWord
- * @short filterWord
- * @desc 用来过滤word粘贴过来的字符串
- * @import editor.js,core/utils.js
- * @anthor zhanyi
- */
- var filterWord = UM.filterWord = function () {
- //是否是word过来的内容
- function isWordDocument(str) {
- return /(class="?Mso|style="[^"]*\bmso\-|w:WordDocument|<(v|o):|lang=)/ig.test(str);
- }
- //去掉小数
- function transUnit(v) {
- v = v.replace(/[\d.]+\w+/g, function (m) {
- return utils.transUnitToPx(m);
- });
- return v;
- }
- function filterPasteWord(str) {
- return str.replace(/[\t\r\n]+/g, ' ')
- .replace(/<!--[\s\S]*?-->/ig, "")
- //转换图片
- .replace(/<v:shape [^>]*>[\s\S]*?.<\/v:shape>/gi, function (str) {
- //opera能自己解析出image所这里直接返回空
- if (browser.opera) {
- return '';
- }
- try {
- //有可能是bitmap占为图,无用,直接过滤掉,主要体现在粘贴excel表格中
- if (/Bitmap/i.test(str)) {
- return '';
- }
- var width = str.match(/width:([ \d.]*p[tx])/i)[1],
- height = str.match(/height:([ \d.]*p[tx])/i)[1],
- src = str.match(/src=\s*"([^"]*)"/i)[1];
- return '<img width="' + transUnit(width) + '" height="' + transUnit(height) + '" src="' + src + '" />';
- } catch (e) {
- return '';
- }
- })
- //针对wps添加的多余标签处理
- .replace(/<\/?div[^>]*>/g, '')
- //去掉多余的属性
- .replace(/v:\w+=(["']?)[^'"]+\1/g, '')
- .replace(/<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|xml|meta|link|style|\w+:\w+)(?=[\s\/>]))[^>]*>/gi, "")
- .replace(/<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi, "<p><strong>$1</strong></p>")
- //去掉多余的属性
- .replace(/\s+(class|lang|align)\s*=\s*(['"]?)([\w-]+)\2/ig, function (str, name, marks, val) {
- //保留list的标示
- return name == 'class' && val == 'MsoListParagraph' ? str : ''
- })
- //清除多余的font/span不能匹配 有可能是空格
- .replace(/<(font|span)[^>]*>(\s*)<\/\1>/gi, function (a, b, c) {
- return c.replace(/[\t\r\n ]+/g, ' ')
- })
- //处理style的问题
- .replace(/(<[a-z][^>]*)\sstyle=(["'])([^\2]*?)\2/gi, function (str, tag, tmp, style) {
- var n = [],
- s = style.replace(/^\s+|\s+$/, '')
- .replace(/'/g, '\'')
- .replace(/"/gi, "'")
- .split(/;\s*/g);
- for (var i = 0, v; v = s[i]; i++) {
- var name, value,
- parts = v.split(":");
- if (parts.length == 2) {
- name = parts[0].toLowerCase();
- value = parts[1].toLowerCase();
- if (/^(background)\w*/.test(name) && value.replace(/(initial|\s)/g, '').length == 0
- ||
- /^(margin)\w*/.test(name) && /^0\w+$/.test(value)
- ) {
- continue;
- }
- switch (name) {
- case "mso-padding-alt":
- case "mso-padding-top-alt":
- case "mso-padding-right-alt":
- case "mso-padding-bottom-alt":
- case "mso-padding-left-alt":
- case "mso-margin-alt":
- case "mso-margin-top-alt":
- case "mso-margin-right-alt":
- case "mso-margin-bottom-alt":
- case "mso-margin-left-alt":
- //ie下会出现挤到一起的情况
- //case "mso-table-layout-alt":
- case "mso-height":
- case "mso-width":
- case "mso-vertical-align-alt":
- //trace:1819 ff下会解析出padding在table上
- if (!/<table/.test(tag))
- n[i] = name.replace(/^mso-|-alt$/g, "") + ":" + transUnit(value);
- continue;
- case "horiz-align":
- n[i] = "text-align:" + value;
- continue;
- case "vert-align":
- n[i] = "vertical-align:" + value;
- continue;
- case "font-color":
- case "mso-foreground":
- n[i] = "color:" + value;
- continue;
- case "mso-background":
- case "mso-highlight":
- n[i] = "background:" + value;
- continue;
- case "mso-default-height":
- n[i] = "min-height:" + transUnit(value);
- continue;
- case "mso-default-width":
- n[i] = "min-width:" + transUnit(value);
- continue;
- case "mso-padding-between-alt":
- n[i] = "border-collapse:separate;border-spacing:" + transUnit(value);
- continue;
- case "text-line-through":
- if ((value == "single") || (value == "double")) {
- n[i] = "text-decoration:line-through";
- }
- continue;
- case "mso-zero-height":
- if (value == "yes") {
- n[i] = "display:none";
- }
- continue;
- // case 'background':
- // break;
- case 'margin':
- if (!/[1-9]/.test(value)) {
- continue;
- }
- }
- 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)
- ||
- /text\-indent|padding|margin/.test(name) && /\-[\d.]+/.test(value)
- ) {
- continue;
- }
- n[i] = name + ":" + parts[1];
- }
- }
- return tag + (n.length ? ' style="' + n.join(';').replace(/;{2,}/g, ';') + '"' : '');
- })
- .replace(/[\d.]+(cm|pt)/g, function (str) {
- return utils.transUnitToPx(str)
- })
- }
- return function (html) {
- return (isWordDocument(html) ? filterPasteWord(html) : html);
- };
- }();
- ///import editor.js
- ///import core/utils.js
- ///import core/dom/dom.js
- ///import core/dom/dtd.js
- ///import core/htmlparser.js
- //模拟的节点类
- //by zhanyi
- (function () {
- var uNode = UM.uNode = function (obj) {
- this.type = obj.type;
- this.data = obj.data;
- this.tagName = obj.tagName;
- this.parentNode = obj.parentNode;
- this.attrs = obj.attrs || {};
- this.children = obj.children;
- };
- var notTransAttrs = {
- 'href': 1,
- 'src': 1,
- '_src': 1,
- '_href': 1,
- 'cdata_data': 1
- };
- var notTransTagName = {
- style: 1,
- script: 1
- };
- var indentChar = ' ',
- breakChar = '\n';
- function insertLine(arr, current, begin) {
- arr.push(breakChar);
- return current + (begin ? 1 : -1);
- }
- function insertIndent(arr, current) {
- //插入缩进
- for (var i = 0; i < current; i++) {
- arr.push(indentChar);
- }
- }
- //创建uNode的静态方法
- //支持标签和html
- uNode.createElement = function (html) {
- if (/[<>]/.test(html)) {
- return UM.htmlparser(html).children[0]
- } else {
- return new uNode({
- type: 'element',
- children: [],
- tagName: html
- })
- }
- };
- uNode.createText = function (data, noTrans) {
- return new UM.uNode({
- type: 'text',
- 'data': noTrans ? data : utils.unhtml(data || '')
- })
- };
- function nodeToHtml(node, arr, formatter, current) {
- switch (node.type) {
- case 'root':
- for (var i = 0, ci; ci = node.children[i++];) {
- //插入新行
- if (formatter && ci.type == 'element' && !dtd.$inlineWithA[ci.tagName] && i > 1) {
- insertLine(arr, current, true);
- insertIndent(arr, current)
- }
- nodeToHtml(ci, arr, formatter, current)
- }
- break;
- case 'text':
- isText(node, arr);
- break;
- case 'element':
- isElement(node, arr, formatter, current);
- break;
- case 'comment':
- isComment(node, arr, formatter);
- }
- return arr;
- }
- function isText(node, arr) {
- if (node.parentNode.tagName == 'pre') {
- //源码模式下输入html标签,不能做转换处理,直接输出
- arr.push(node.data)
- } else {
- arr.push(notTransTagName[node.parentNode.tagName] ? utils.html(node.data) : node.data.replace(/[ ]{2}/g, ' '))
- }
- }
- function isElement(node, arr, formatter, current) {
- var attrhtml = '';
- if (node.attrs) {
- attrhtml = [];
- var attrs = node.attrs;
- for (var a in attrs) {
- //这里就针对
- //<p>'<img src='http://nsclick.baidu.com/u.gif?&asdf=\"sdf&asdfasdfs;asdf'></p>
- //这里边的\"做转换,要不用innerHTML直接被截断了,属性src
- //有可能做的不够
- attrhtml.push(a + (attrs[a] !== undefined ? '="' + (notTransAttrs[a] ? utils.html(attrs[a]).replace(/["]/g, function (a) {
- return '"'
- }) : utils.unhtml(attrs[a])) + '"' : ''))
- }
- attrhtml = attrhtml.join(' ');
- }
- arr.push('<' + node.tagName +
- (attrhtml ? ' ' + attrhtml : '') +
- (dtd.$empty[node.tagName] ? '\/' : '') + '>'
- );
- //插入新行
- if (formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != 'pre') {
- if (node.children && node.children.length) {
- current = insertLine(arr, current, true);
- insertIndent(arr, current)
- }
- }
- if (node.children && node.children.length) {
- for (var i = 0, ci; ci = node.children[i++];) {
- if (formatter && ci.type == 'element' && !dtd.$inlineWithA[ci.tagName] && i > 1) {
- insertLine(arr, current);
- insertIndent(arr, current)
- }
- nodeToHtml(ci, arr, formatter, current)
- }
- }
- if (!dtd.$empty[node.tagName]) {
- if (formatter && !dtd.$inlineWithA[node.tagName] && node.tagName != 'pre') {
- if (node.children && node.children.length) {
- current = insertLine(arr, current);
- insertIndent(arr, current)
- }
- }
- arr.push('<\/' + node.tagName + '>');
- }
- }
- function isComment(node, arr) {
- arr.push('<!--' + node.data + '-->');
- }
- function getNodeById(root, id) {
- var node;
- if (root.type == 'element' && root.getAttr('id') == id) {
- return root;
- }
- if (root.children && root.children.length) {
- for (var i = 0, ci; ci = root.children[i++];) {
- if (node = getNodeById(ci, id)) {
- return node;
- }
- }
- }
- }
- function getNodesByTagName(node, tagName, arr) {
- if (node.type == 'element' && node.tagName == tagName) {
- arr.push(node);
- }
- if (node.children && node.children.length) {
- for (var i = 0, ci; ci = node.children[i++];) {
- getNodesByTagName(ci, tagName, arr)
- }
- }
- }
- function nodeTraversal(root, fn) {
- if (root.children && root.children.length) {
- for (var i = 0, ci; ci = root.children[i];) {
- nodeTraversal(ci, fn);
- //ci被替换的情况,这里就不再走 fn了
- if (ci.parentNode) {
- if (ci.children && ci.children.length) {
- fn(ci)
- }
- if (ci.parentNode) i++
- }
- }
- } else {
- fn(root)
- }
- }
- uNode.prototype = {
- /**
- * 当前节点对象,转换成html文本
- * @method toHtml
- * @return { String } 返回转换后的html字符串
- * @example
- * ```javascript
- * node.toHtml();
- * ```
- */
- /**
- * 当前节点对象,转换成html文本
- * @method toHtml
- * @param { Boolean } formatter 是否格式化返回值
- * @return { String } 返回转换后的html字符串
- * @example
- * ```javascript
- * node.toHtml( true );
- * ```
- */
- toHtml: function (formatter) {
- var arr = [];
- nodeToHtml(this, arr, formatter, 0);
- return arr.join('')
- },
- /**
- * 获取节点的html内容
- * @method innerHTML
- * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
- * @return { String } 返回节点的html内容
- * @example
- * ```javascript
- * var htmlstr = node.innerHTML();
- * ```
- */
- /**
- * 设置节点的html内容
- * @method innerHTML
- * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
- * @param { String } htmlstr 传入要设置的html内容
- * @return { UM.uNode } 返回节点本身
- * @example
- * ```javascript
- * node.innerHTML('<span>text</span>');
- * ```
- */
- innerHTML: function (htmlstr) {
- if (this.type != 'element' || dtd.$empty[this.tagName]) {
- return this;
- }
- if (utils.isString(htmlstr)) {
- if (this.children) {
- for (var i = 0, ci; ci = this.children[i++];) {
- ci.parentNode = null;
- }
- }
- this.children = [];
- var tmpRoot = UM.htmlparser(htmlstr);
- for (var i = 0, ci; ci = tmpRoot.children[i++];) {
- this.children.push(ci);
- ci.parentNode = this;
- }
- return this;
- } else {
- var tmpRoot = new UM.uNode({
- type: 'root',
- children: this.children
- });
- return tmpRoot.toHtml();
- }
- },
- /**
- * 获取节点的纯文本内容
- * @method innerText
- * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
- * @return { String } 返回节点的存文本内容
- * @example
- * ```javascript
- * var textStr = node.innerText();
- * ```
- */
- /**
- * 设置节点的纯文本内容
- * @method innerText
- * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
- * @param { String } textStr 传入要设置的文本内容
- * @return { UM.uNode } 返回节点本身
- * @example
- * ```javascript
- * node.innerText('<span>text</span>');
- * ```
- */
- innerText: function (textStr, noTrans) {
- if (this.type != 'element' || dtd.$empty[this.tagName]) {
- return this;
- }
- if (textStr) {
- if (this.children) {
- for (var i = 0, ci; ci = this.children[i++];) {
- ci.parentNode = null;
- }
- }
- this.children = [];
- this.appendChild(uNode.createText(textStr, noTrans));
- return this;
- } else {
- return this.toHtml().replace(/<[^>]+>/g, '');
- }
- },
- /**
- * 获取当前对象的data属性
- * @method getData
- * @return { Object } 若节点的type值是elemenet,返回空字符串,否则返回节点的data属性
- * @example
- * ```javascript
- * node.getData();
- * ```
- */
- getData: function () {
- if (this.type == 'element')
- return '';
- return this.data
- },
- /**
- * 获取当前节点下的第一个子节点
- * @method firstChild
- * @return { UM.uNode } 返回第一个子节点
- * @example
- * ```javascript
- * node.firstChild(); //返回第一个子节点
- * ```
- */
- firstChild: function () {
- // if (this.type != 'element' || dtd.$empty[this.tagName]) {
- // return this;
- // }
- return this.children ? this.children[0] : null;
- },
- /**
- * 获取当前节点下的最后一个子节点
- * @method lastChild
- * @return { UM.uNode } 返回最后一个子节点
- * @example
- * ```javascript
- * node.lastChild(); //返回最后一个子节点
- * ```
- */
- lastChild: function () {
- // if (this.type != 'element' || dtd.$empty[this.tagName] ) {
- // return this;
- // }
- return this.children ? this.children[this.children.length - 1] : null;
- },
- /**
- * 获取和当前节点有相同父亲节点的前一个节点
- * @method previousSibling
- * @return { UM.uNode } 返回前一个节点
- * @example
- * ```javascript
- * node.children[2].previousSibling(); //返回子节点node.children[1]
- * ```
- */
- previousSibling: function () {
- var parent = this.parentNode;
- for (var i = 0, ci; ci = parent.children[i]; i++) {
- if (ci === this) {
- return i == 0 ? null : parent.children[i - 1];
- }
- }
- },
- /**
- * 获取和当前节点有相同父亲节点的后一个节点
- * @method nextSibling
- * @return { UM.uNode } 返回后一个节点,找不到返回null
- * @example
- * ```javascript
- * node.children[2].nextSibling(); //如果有,返回子节点node.children[3]
- * ```
- */
- nextSibling: function () {
- var parent = this.parentNode;
- for (var i = 0, ci; ci = parent.children[i++];) {
- if (ci === this) {
- return parent.children[i];
- }
- }
- },
- /**
- * 用新的节点替换当前节点
- * @method replaceChild
- * @param { UM.uNode } target 要替换成该节点参数
- * @param { UM.uNode } source 要被替换掉的节点
- * @return { UM.uNode } 返回替换之后的节点对象
- * @example
- * ```javascript
- * node.replaceChild(newNode, childNode); //用newNode替换childNode,childNode是node的子节点
- * ```
- */
- replaceChild: function (target, source) {
- if (this.children) {
- if (target.parentNode) {
- target.parentNode.removeChild(target);
- }
- for (var i = 0, ci; ci = this.children[i]; i++) {
- if (ci === source) {
- this.children.splice(i, 1, target);
- source.parentNode = null;
- target.parentNode = this;
- return target;
- }
- }
- }
- },
- /**
- * 在节点的子节点列表最后位置插入一个节点
- * @method appendChild
- * @param { UM.uNode } node 要插入的节点
- * @return { UM.uNode } 返回刚插入的子节点
- * @example
- * ```javascript
- * node.appendChild( newNode ); //在node内插入子节点newNode
- * ```
- */
- appendChild: function (node) {
- if (this.type == 'root' || (this.type == 'element' && !dtd.$empty[this.tagName])) {
- if (!this.children) {
- this.children = []
- }
- if (node.parentNode) {
- node.parentNode.removeChild(node);
- }
- for (var i = 0, ci; ci = this.children[i]; i++) {
- if (ci === node) {
- this.children.splice(i, 1);
- break;
- }
- }
- this.children.push(node);
- node.parentNode = this;
- return node;
- }
- },
- /**
- * 在传入节点的前面插入一个节点
- * @method insertBefore
- * @param { UM.uNode } target 要插入的节点
- * @param { UM.uNode } source 在该参数节点前面插入
- * @return { UM.uNode } 返回刚插入的子节点
- * @example
- * ```javascript
- * node.parentNode.insertBefore(newNode, node); //在node节点后面插入newNode
- * ```
- */
- insertBefore: function (target, source) {
- if (this.children) {
- if (target.parentNode) {
- target.parentNode.removeChild(target);
- }
- for (var i = 0, ci; ci = this.children[i]; i++) {
- if (ci === source) {
- this.children.splice(i, 0, target);
- target.parentNode = this;
- return target;
- }
- }
- }
- },
- /**
- * 在传入节点的后面插入一个节点
- * @method insertAfter
- * @param { UM.uNode } target 要插入的节点
- * @param { UM.uNode } source 在该参数节点后面插入
- * @return { UM.uNode } 返回刚插入的子节点
- * @example
- * ```javascript
- * node.parentNode.insertAfter(newNode, node); //在node节点后面插入newNode
- * ```
- */
- insertAfter: function (target, source) {
- if (this.children) {
- if (target.parentNode) {
- target.parentNode.removeChild(target);
- }
- for (var i = 0, ci; ci = this.children[i]; i++) {
- if (ci === source) {
- this.children.splice(i + 1, 0, target);
- target.parentNode = this;
- return target;
- }
- }
- }
- },
- /**
- * 从当前节点的子节点列表中,移除节点
- * @method removeChild
- * @param { UM.uNode } node 要移除的节点引用
- * @param { Boolean } keepChildren 是否保留移除节点的子节点,若传入true,自动把移除节点的子节点插入到移除的位置
- * @return { * } 返回刚移除的子节点
- * @example
- * ```javascript
- * node.removeChild(childNode,true); //在node的子节点列表中移除child节点,并且吧child的子节点插入到移除的位置
- * ```
- */
- removeChild: function (node, keepChildren) {
- if (this.children) {
- for (var i = 0, ci; ci = this.children[i]; i++) {
- if (ci === node) {
- this.children.splice(i, 1);
- ci.parentNode = null;
- if (keepChildren && ci.children && ci.children.length) {
- for (var j = 0, cj; cj = ci.children[j]; j++) {
- this.children.splice(i + j, 0, cj);
- cj.parentNode = this;
- }
- }
- return ci;
- }
- }
- }
- },
- /**
- * 获取当前节点所代表的元素属性,即获取attrs对象下的属性值
- * @method getAttr
- * @param { String } attrName 要获取的属性名称
- * @return { * } 返回attrs对象下的属性值
- * @example
- * ```javascript
- * node.getAttr('title');
- * ```
- */
- getAttr: function (attrName) {
- return this.attrs && this.attrs[attrName.toLowerCase()]
- },
- /**
- * 设置当前节点所代表的元素属性,即设置attrs对象下的属性值
- * @method setAttr
- * @param { String } attrName 要设置的属性名称
- * @param { * } attrVal 要设置的属性值,类型视设置的属性而定
- * @return { * } 返回attrs对象下的属性值
- * @example
- * ```javascript
- * node.setAttr('title','标题');
- * ```
- */
- setAttr: function (attrName, attrVal) {
- if (!attrName) {
- delete this.attrs;
- return;
- }
- if (!this.attrs) {
- this.attrs = {};
- }
- if (utils.isObject(attrName)) {
- for (var a in attrName) {
- if (!attrName[a]) {
- delete this.attrs[a]
- } else {
- this.attrs[a.toLowerCase()] = attrName[a];
- }
- }
- } else {
- if (!attrVal) {
- delete this.attrs[attrName]
- } else {
- this.attrs[attrName.toLowerCase()] = attrVal;
- }
- }
- },
- hasAttr: function (attrName) {
- var attrVal = this.getAttr(attrName);
- return (attrVal !== null) && (attrVal !== undefined);
- },
- /**
- * 获取当前节点在父节点下的位置索引
- * @method getIndex
- * @return { Number } 返回索引数值,如果没有父节点,返回-1
- * @example
- * ```javascript
- * node.getIndex();
- * ```
- */
- getIndex: function () {
- var parent = this.parentNode;
- for (var i = 0, ci; ci = parent.children[i]; i++) {
- if (ci === this) {
- return i;
- }
- }
- return -1;
- },
- /**
- * 在当前节点下,根据id查找节点
- * @method getNodeById
- * @param { String } id 要查找的id
- * @return { UM.uNode } 返回找到的节点
- * @example
- * ```javascript
- * node.getNodeById('textId');
- * ```
- */
- getNodeById: function (id) {
- var node;
- if (this.children && this.children.length) {
- for (var i = 0, ci; ci = this.children[i++];) {
- if (node = getNodeById(ci, id)) {
- return node;
- }
- }
- }
- },
- /**
- * 在当前节点下,根据元素名称查找节点列表
- * @method getNodesByTagName
- * @param { String } tagNames 要查找的元素名称
- * @return { Array } 返回找到的节点列表
- * @example
- * ```javascript
- * node.getNodesByTagName('span');
- * ```
- */
- getNodesByTagName: function (tagNames) {
- tagNames = utils.trim(tagNames).replace(/[ ]{2,}/g, ' ').split(' ');
- var arr = [], me = this;
- utils.each(tagNames, function (tagName) {
- if (me.children && me.children.length) {
- for (var i = 0, ci; ci = me.children[i++];) {
- getNodesByTagName(ci, tagName, arr)
- }
- }
- });
- return arr;
- },
- /**
- * 根据样式名称,获取节点的样式值
- * @method getStyle
- * @param { String } name 要获取的样式名称
- * @return { String } 返回样式值
- * @example
- * ```javascript
- * node.getStyle('font-size');
- * ```
- */
- getStyle: function (name) {
- var cssStyle = this.getAttr('style');
- if (!cssStyle) {
- return ''
- }
- var reg = new RegExp('(^|;)\\s*' + name + ':([^;]+)', 'i');
- var match = cssStyle.match(reg);
- if (match && match[0]) {
- return match[2]
- }
- return '';
- },
- /**
- * 给节点设置样式
- * @method setStyle
- * @param { String } name 要设置的的样式名称
- * @param { String } val 要设置的的样值
- * @example
- * ```javascript
- * node.setStyle('font-size', '12px');
- * ```
- */
- setStyle: function (name, val) {
- function exec(name, val) {
- var reg = new RegExp('(^|;)\\s*' + name + ':([^;]+;?)', 'gi');
- cssStyle = cssStyle.replace(reg, '$1');
- if (val) {
- cssStyle = name + ':' + utils.unhtml(val) + ';' + cssStyle
- }
- }
- var cssStyle = this.getAttr('style');
- if (!cssStyle) {
- cssStyle = '';
- }
- if (utils.isObject(name)) {
- for (var a in name) {
- exec(a, name[a])
- }
- } else {
- exec(name, val)
- }
- this.setAttr('style', utils.trim(cssStyle))
- },
- hasClass: function (className) {
- if (this.hasAttr('class')) {
- var classNames = this.getAttr('class').split(/\s+/),
- hasClass = false;
- $.each(classNames, function (key, item) {
- if (item === className) {
- hasClass = true;
- }
- });
- return hasClass;
- } else {
- return false;
- }
- },
- addClass: function (className) {
- var classes = null,
- hasClass = false;
- if (this.hasAttr('class')) {
- classes = this.getAttr('class');
- classes = classes.split(/\s+/);
- classes.forEach(function (item) {
- if (item === className) {
- hasClass = true;
- return;
- }
- });
- !hasClass && classes.push(className);
- this.setAttr('class', classes.join(" "));
- } else {
- this.setAttr('class', className);
- }
- },
- removeClass: function (className) {
- if (this.hasAttr('class')) {
- var cl = this.getAttr('class');
- cl = cl.replace(new RegExp('\\b' + className + '\\b', 'g'), '');
- this.setAttr('class', utils.trim(cl).replace(/[ ]{2,}/g, ' '));
- }
- },
- /**
- * 传入一个函数,递归遍历当前节点下的所有节点
- * @method traversal
- * @param { Function } fn 遍历到节点的时,传入节点作为参数,运行此函数
- * @example
- * ```javascript
- * traversal(node, function(){
- * console.log(node.type);
- * });
- * ```
- */
- traversal: function (fn) {
- if (this.children && this.children.length) {
- nodeTraversal(this, fn);
- }
- return this;
- }
- }
- })();
- //html字符串转换成uNode节点
- //by zhanyi
- var htmlparser = UM.htmlparser = function (htmlstr, ignoreBlank) {
- //todo 原来的方式 [^"'<>\/] 有\/就不能配对上 <TD vAlign=top background=../AAA.JPG> 这样的标签了
- //先去掉了,加上的原因忘了,这里先记录
- var re_tag = /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g,
- re_attr = /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g;
- //ie下取得的html可能会有\n存在,要去掉,在处理replace(/[\t\r\n]*/g,'');代码高量的\n不能去除
- var allowEmptyTags = {
- b: 1, code: 1, i: 1, u: 1, strike: 1, s: 1, tt: 1, strong: 1, q: 1, samp: 1, em: 1, span: 1,
- sub: 1, img: 1, sup: 1, font: 1, big: 1, small: 1, iframe: 1, a: 1, br: 1, pre: 1
- };
- htmlstr = htmlstr.replace(new RegExp(domUtils.fillChar, 'g'), '');
- if (!ignoreBlank) {
- htmlstr = htmlstr.replace(new RegExp('[\\r\\t\\n' + (ignoreBlank ? '' : ' ') + ']*<\/?(\\w+)\\s*(?:[^>]*)>[\\r\\t\\n' + (ignoreBlank ? '' : ' ') + ']*', 'g'), function (a, b) {
- //br暂时单独处理
- if (b && allowEmptyTags[b.toLowerCase()]) {
- return a.replace(/(^[\n\r]+)|([\n\r]+$)/g, '');
- }
- return a.replace(new RegExp('^[\\r\\n' + (ignoreBlank ? '' : ' ') + ']+'), '').replace(new RegExp('[\\r\\n' + (ignoreBlank ? '' : ' ') + ']+$'), '');
- });
- }
- var notTransAttrs = {
- 'href': 1,
- 'src': 1
- };
- var uNode = UM.uNode,
- needParentNode = {
- 'td': 'tr',
- 'tr': ['tbody', 'thead', 'tfoot'],
- 'tbody': 'table',
- 'th': 'tr',
- 'thead': 'table',
- 'tfoot': 'table',
- 'caption': 'table',
- 'li': ['ul', 'ol'],
- 'dt': 'dl',
- 'dd': 'dl',
- 'option': 'select'
- },
- needChild = {
- 'ol': 'li',
- 'ul': 'li'
- };
- function text(parent, data) {
- if (needChild[parent.tagName]) {
- var tmpNode = uNode.createElement(needChild[parent.tagName]);
- parent.appendChild(tmpNode);
- tmpNode.appendChild(uNode.createText(data));
- parent = tmpNode;
- } else {
- parent.appendChild(uNode.createText(data));
- }
- }
- function element(parent, tagName, htmlattr) {
- var needParentTag;
- if (needParentTag = needParentNode[tagName]) {
- var tmpParent = parent, hasParent;
- while (tmpParent.type != 'root') {
- if (utils.isArray(needParentTag) ? utils.indexOf(needParentTag, tmpParent.tagName) != -1 : needParentTag == tmpParent.tagName) {
- parent = tmpParent;
- hasParent = true;
- break;
- }
- tmpParent = tmpParent.parentNode;
- }
- if (!hasParent) {
- parent = element(parent, utils.isArray(needParentTag) ? needParentTag[0] : needParentTag)
- }
- }
- //按dtd处理嵌套
- // if(parent.type != 'root' && !dtd[parent.tagName][tagName])
- // parent = parent.parentNode;
- var elm = new uNode({
- parentNode: parent,
- type: 'element',
- tagName: tagName.toLowerCase(),
- //是自闭合的处理一下
- children: dtd.$empty[tagName] ? null : []
- });
- //如果属性存在,处理属性
- if (htmlattr) {
- var attrs = {}, match;
- while (match = re_attr.exec(htmlattr)) {
- attrs[match[1].toLowerCase()] = notTransAttrs[match[1].toLowerCase()] ? (match[2] || match[3] || match[4]) : utils.unhtml(match[2] || match[3] || match[4])
- }
- elm.attrs = attrs;
- }
- parent.children.push(elm);
- //如果是自闭合节点返回父亲节点
- return dtd.$empty[tagName] ? parent : elm
- }
- function comment(parent, data) {
- parent.children.push(new uNode({
- type: 'comment',
- data: data,
- parentNode: parent
- }));
- }
- var match, currentIndex = 0, nextIndex = 0;
- //设置根节点
- var root = new uNode({
- type: 'root',
- children: []
- });
- var currentParent = root;
- while (match = re_tag.exec(htmlstr)) {
- currentIndex = match.index;
- try {
- if (currentIndex > nextIndex) {
- //text node
- text(currentParent, htmlstr.slice(nextIndex, currentIndex));
- }
- if (match[3]) {
- if (dtd.$cdata[currentParent.tagName]) {
- text(currentParent, match[0]);
- } else {
- //start tag
- currentParent = element(currentParent, match[3].toLowerCase(), match[4]);
- }
- } else if (match[1]) {
- if (currentParent.type != 'root') {
- if (dtd.$cdata[currentParent.tagName] && !dtd.$cdata[match[1]]) {
- text(currentParent, match[0]);
- } else {
- var tmpParent = currentParent;
- while (currentParent.type == 'element' && currentParent.tagName != match[1].toLowerCase()) {
- currentParent = currentParent.parentNode;
- if (currentParent.type == 'root') {
- currentParent = tmpParent;
- throw 'break'
- }
- }
- //end tag
- currentParent = currentParent.parentNode;
- }
- }
- } else if (match[2]) {
- //comment
- comment(currentParent, match[2])
- }
- } catch (e) {
- }
- nextIndex = re_tag.lastIndex;
- }
- //如果结束是文本,就有可能丢掉,所以这里手动判断一下
- //例如 <li>sdfsdfsdf<li>sdfsdfsdfsdf
- if (nextIndex < htmlstr.length) {
- text(currentParent, htmlstr.slice(nextIndex));
- }
- return root;
- };
- /**
- * @file
- * @name UM.filterNode
- * @short filterNode
- * @desc 根据给定的规则过滤节点
- * @import editor.js,core/utils.js
- * @anthor zhanyi
- */
- var filterNode = UM.filterNode = function () {
- function filterNode(node, rules) {
- switch (node.type) {
- case 'text':
- break;
- case 'element':
- var val;
- if (val = rules[node.tagName]) {
- if (val === '-') {
- node.parentNode.removeChild(node)
- } else if (utils.isFunction(val)) {
- var parentNode = node.parentNode,
- index = node.getIndex();
- val(node);
- if (node.parentNode) {
- if (node.children) {
- for (var i = 0, ci; ci = node.children[i];) {
- filterNode(ci, rules);
- if (ci.parentNode) {
- i++;
- }
- }
- }
- } else {
- for (var i = index, ci; ci = parentNode.children[i];) {
- filterNode(ci, rules);
- if (ci.parentNode) {
- i++;
- }
- }
- }
- } else {
- var attrs = val['$'];
- if (attrs && node.attrs) {
- var tmpAttrs = {}, tmpVal;
- for (var a in attrs) {
- tmpVal = node.getAttr(a);
- //todo 只先对style单独处理
- if (a == 'style' && utils.isArray(attrs[a])) {
- var tmpCssStyle = [];
- utils.each(attrs[a], function (v) {
- var tmp;
- if (tmp = node.getStyle(v)) {
- tmpCssStyle.push(v + ':' + tmp);
- }
- });
- tmpVal = tmpCssStyle.join(';')
- }
- if (tmpVal) {
- tmpAttrs[a] = tmpVal;
- }
- }
- node.attrs = tmpAttrs;
- }
- if (node.children) {
- for (var i = 0, ci; ci = node.children[i];) {
- filterNode(ci, rules);
- if (ci.parentNode) {
- i++;
- }
- }
- }
- }
- } else {
- //如果不在名单里扣出子节点并删除该节点,cdata除外
- if (dtd.$cdata[node.tagName]) {
- node.parentNode.removeChild(node)
- } else {
- var parentNode = node.parentNode,
- index = node.getIndex();
- node.parentNode.removeChild(node, true);
- for (var i = index, ci; ci = parentNode.children[i];) {
- filterNode(ci, rules);
- if (ci.parentNode) {
- i++;
- }
- }
- }
- }
- break;
- case 'comment':
- node.parentNode.removeChild(node)
- }
- }
- return function (root, rules) {
- if (utils.isEmptyObject(rules)) {
- return root;
- }
- var val;
- if (val = rules['-']) {
- utils.each(val.split(' '), function (k) {
- rules[k] = '-'
- })
- }
- for (var i = 0, ci; ci = root.children[i];) {
- filterNode(ci, rules);
- if (ci.parentNode) {
- i++;
- }
- }
- return root;
- }
- }();
- ///import core
- /**
- * @description 插入内容
- * @name baidu.editor.execCommand
- * @param {String} cmdName inserthtml插入内容的命令
- * @param {String} html 要插入的内容
- * @author zhanyi
- */
- UM.commands['inserthtml'] = {
- execCommand: function (command, html, notNeedFilter) {
- var me = this,
- range,
- div;
- if (!html) {
- return;
- }
- if (me.fireEvent('beforeinserthtml', html) === true) {
- return;
- }
- range = me.selection.getRange();
- div = range.document.createElement('div');
- div.style.display = 'inline';
- if (!notNeedFilter) {
- var root = UM.htmlparser(html);
- //如果给了过滤规则就先进行过滤
- if (me.options.filterRules) {
- UM.filterNode(root, me.options.filterRules);
- }
- //执行默认的处理
- me.filterInputRule(root);
- html = root.toHtml()
- }
- div.innerHTML = utils.trim(html);
- if (!range.collapsed) {
- var tmpNode = range.startContainer;
- if (domUtils.isFillChar(tmpNode)) {
- range.setStartBefore(tmpNode)
- }
- tmpNode = range.endContainer;
- if (domUtils.isFillChar(tmpNode)) {
- range.setEndAfter(tmpNode)
- }
- range.txtToElmBoundary();
- //结束边界可能放到了br的前边,要把br包含进来
- // x[xxx]<br/>
- if (range.endContainer && range.endContainer.nodeType == 1) {
- tmpNode = range.endContainer.childNodes[range.endOffset];
- if (tmpNode && domUtils.isBr(tmpNode)) {
- range.setEndAfter(tmpNode);
- }
- }
- if (range.startOffset == 0) {
- tmpNode = range.startContainer;
- if (domUtils.isBoundaryNode(tmpNode, 'firstChild')) {
- tmpNode = range.endContainer;
- if (range.endOffset == (tmpNode.nodeType == 3 ? tmpNode.nodeValue.length : tmpNode.childNodes.length) && domUtils.isBoundaryNode(tmpNode, 'lastChild')) {
- me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
- range.setStart(me.body.firstChild, 0).collapse(true)
- }
- }
- }
- !range.collapsed && range.deleteContents();
- if (range.startContainer.nodeType == 1) {
- var child = range.startContainer.childNodes[range.startOffset], pre;
- if (child && domUtils.isBlockElm(child) && (pre = child.previousSibling) && domUtils.isBlockElm(pre)) {
- range.setEnd(pre, pre.childNodes.length).collapse();
- while (child.firstChild) {
- pre.appendChild(child.firstChild);
- }
- domUtils.remove(child);
- }
- }
- }
- var child, parent, pre, tmp, hadBreak = 0, nextNode;
- //如果当前位置选中了fillchar要干掉,要不会产生空行
- if (range.inFillChar()) {
- child = range.startContainer;
- if (domUtils.isFillChar(child)) {
- range.setStartBefore(child).collapse(true);
- domUtils.remove(child);
- } else if (domUtils.isFillChar(child, true)) {
- child.nodeValue = child.nodeValue.replace(fillCharReg, '');
- range.startOffset--;
- range.collapsed && range.collapse(true)
- }
- }
- while (child = div.firstChild) {
- if (hadBreak) {
- var p = me.document.createElement('p');
- while (child && (child.nodeType == 3 || !dtd.$block[child.tagName])) {
- nextNode = child.nextSibling;
- p.appendChild(child);
- child = nextNode;
- }
- if (p.firstChild) {
- child = p
- }
- }
- range.insertNode(child);
- nextNode = child.nextSibling;
- if (!hadBreak && child.nodeType == domUtils.NODE_ELEMENT && domUtils.isBlockElm(child)) {
- parent = domUtils.findParent(child, function (node) {
- return domUtils.isBlockElm(node);
- });
- if (parent && parent.tagName.toLowerCase() != 'body' && !(dtd[parent.tagName][child.nodeName] && child.parentNode === parent)) {
- if (!dtd[parent.tagName][child.nodeName]) {
- pre = parent;
- } else {
- tmp = child.parentNode;
- while (tmp !== parent) {
- pre = tmp;
- tmp = tmp.parentNode;
- }
- }
- domUtils.breakParent(child, pre || tmp);
- //去掉break后前一个多余的节点 <p>|<[p> ==> <p></p><div></div><p>|</p>
- var pre = child.previousSibling;
- domUtils.trimWhiteTextNode(pre);
- if (!pre.childNodes.length) {
- domUtils.remove(pre);
- }
- //trace:2012,在非ie的情况,切开后剩下的节点有可能不能点入光标添加br占位
- if (!browser.ie &&
- (next = child.nextSibling) &&
- domUtils.isBlockElm(next) &&
- next.lastChild &&
- !domUtils.isBr(next.lastChild)) {
- next.appendChild(me.document.createElement('br'));
- }
- hadBreak = 1;
- }
- }
- var next = child.nextSibling;
- if (!div.firstChild && next && domUtils.isBlockElm(next)) {
- range.setStart(next, 0).collapse(true);
- break;
- }
- range.setEndAfter(child).collapse();
- }
- child = range.startContainer;
- if (nextNode && domUtils.isBr(nextNode)) {
- domUtils.remove(nextNode)
- }
- //用chrome可能有空白展位符
- if (domUtils.isBlockElm(child) && domUtils.isEmptyNode(child)) {
- if (nextNode = child.nextSibling) {
- domUtils.remove(child);
- if (nextNode.nodeType == 1 && dtd.$block[nextNode.tagName]) {
- range.setStart(nextNode, 0).collapse(true).shrinkBoundary()
- }
- } else {
- try {
- child.innerHTML = browser.ie ? domUtils.fillChar : '<br/>';
- } catch (e) {
- range.setStartBefore(child);
- domUtils.remove(child)
- }
- }
- }
- //加上true因为在删除表情等时会删两次,第一次是删的fillData
- try {
- if (browser.ie9below && range.startContainer.nodeType == 1 && !range.startContainer.childNodes[range.startOffset]) {
- var start = range.startContainer, pre = start.childNodes[range.startOffset - 1];
- if (pre && pre.nodeType == 1 && dtd.$empty[pre.tagName]) {
- var txt = this.document.createTextNode(domUtils.fillChar);
- range.insertNode(txt).setStart(txt, 0).collapse(true);
- }
- }
- setTimeout(function () {
- range.select(true);
- })
- } catch (e) {
- }
- setTimeout(function () {
- range = me.selection.getRange();
- range.scrollIntoView();
- me.fireEvent('afterinserthtml');
- }, 200);
- }
- };
- ///import core
- ///import plugins\inserthtml.js
- ///commands 插入图片,操作图片的对齐方式
- ///commandsName InsertImage,ImageNone,ImageLeft,ImageRight,ImageCenter
- ///commandsTitle 图片,默认,居左,居右,居中
- ///commandsDialog dialogs\image
- /**
- * Created by .
- * User: zhanyi
- * for image
- */
- UM.commands['insertimage'] = {
- execCommand: function (cmd, opt) {
- opt = utils.isArray(opt) ? opt : [opt];
- if (!opt.length) {
- return;
- }
- var me = this;
- var html = [], str = '', ci;
- ci = opt[0];
- if (opt.length == 1) {
- str = '<img src="' + ci.src + '" ' + (ci._src ? ' _src="' + ci._src + '" ' : '') +
- (ci.width ? 'width="' + ci.width + '" ' : '') +
- (ci.height ? ' height="' + ci.height + '" ' : '') +
- (ci['floatStyle'] == 'left' || ci['floatStyle'] == 'right' ? ' style="float:' + ci['floatStyle'] + ';"' : '') +
- (ci.title && ci.title != "" ? ' title="' + ci.title + '"' : '') +
- (ci.border && ci.border != "0" ? ' border="' + ci.border + '"' : '') +
- (ci.alt && ci.alt != "" ? ' alt="' + ci.alt + '"' : '') +
- (ci.hspace && ci.hspace != "0" ? ' hspace = "' + ci.hspace + '"' : '') +
- (ci.vspace && ci.vspace != "0" ? ' vspace = "' + ci.vspace + '"' : '') + '/>';
- if (ci['floatStyle'] == 'center') {
- str = '<p style="text-align: center">' + str + '</p>';
- }
- html.push(str);
- } else {
- for (var i = 0; ci = opt[i++];) {
- str = '<p ' + (ci['floatStyle'] == 'center' ? 'style="text-align: center" ' : '') + '><img src="' + ci.src + '" ' +
- (ci.width ? 'width="' + ci.width + '" ' : '') + (ci._src ? ' _src="' + ci._src + '" ' : '') +
- (ci.height ? ' height="' + ci.height + '" ' : '') +
- ' style="' + (ci['floatStyle'] && ci['floatStyle'] != 'center' ? 'float:' + ci['floatStyle'] + ';' : '') +
- (ci.border || '') + '" ' +
- (ci.title ? ' title="' + ci.title + '"' : '') + ' /></p>';
- html.push(str);
- }
- }
- me.execCommand('insertHtml', html.join(''), true);
- }
- };
- ///import core
- ///commands 段落格式,居左,居右,居中,两端对齐
- ///commandsName JustifyLeft,JustifyCenter,JustifyRight,JustifyJustify
- ///commandsTitle 居左对齐,居中对齐,居右对齐,两端对齐
- /**
- * @description 居左右中
- * @name UM.execCommand
- * @param {String} cmdName justify执行对齐方式的命令
- * @param {String} align 对齐方式:left居左,right居右,center居中,justify两端对齐
- * @author zhanyi
- */
- UM.plugins['justify'] = function () {
- var me = this;
- $.each('justifyleft justifyright justifycenter justifyfull'.split(' '), function (i, cmdName) {
- me.commands[cmdName] = {
- execCommand: function (cmdName) {
- return this.document.execCommand(cmdName);
- },
- queryCommandValue: function (cmdName) {
- var val = this.document.queryCommandValue(cmdName);
- return val === true || val === 'true' ? cmdName.replace(/justify/, '') : '';
- },
- queryCommandState: function (cmdName) {
- return this.document.queryCommandState(cmdName) ? 1 : 0
- }
- };
- })
- };
- ///import core
- ///import plugins\removeformat.js
- ///commands 字体颜色,背景色,字号,字体,下划线,删除线
- ///commandsName ForeColor,BackColor,FontSize,FontFamily,Underline,StrikeThrough
- ///commandsTitle 字体颜色,背景色,字号,字体,下划线,删除线
- /**
- * @description 字体
- * @name UM.execCommand
- * @param {String} cmdName 执行的功能名称
- * @param {String} value 传入的值
- */
- UM.plugins['font'] = function () {
- var me = this,
- fonts = {
- 'forecolor': 'forecolor',
- 'backcolor': 'backcolor',
- 'fontsize': 'fontsize',
- 'fontfamily': 'fontname'
- },
- cmdNameToStyle = {
- 'forecolor': 'color',
- 'backcolor': 'background-color',
- 'fontsize': 'font-size',
- 'fontfamily': 'font-family'
- },
- cmdNameToAttr = {
- 'forecolor': 'color',
- 'fontsize': 'size',
- 'fontfamily': 'face'
- };
- me.setOpt({
- 'fontfamily': [
- {name: 'songti', val: '宋体,SimSun'},
- {name: 'yahei', val: '微软雅黑,Microsoft YaHei'},
- {name: 'kaiti', val: '楷体,楷体_GB2312, SimKai'},
- {name: 'heiti', val: '黑体, SimHei'},
- {name: 'lishu', val: '隶书, SimLi'},
- {name: 'andaleMono', val: 'andale mono'},
- {name: 'arial', val: 'arial, helvetica,sans-serif'},
- {name: 'arialBlack', val: 'arial black,avant garde'},
- {name: 'comicSansMs', val: 'comic sans ms'},
- {name: 'impact', val: 'impact,chicago'},
- {name: 'timesNewRoman', val: 'times new roman'},
- {name: 'sans-serif', val: 'sans-serif'}
- ],
- 'fontsize': [10, 12, 16, 18, 24, 32, 48]
- });
- me.addOutputRule(function (root) {
- utils.each(root.getNodesByTagName('font'), function (node) {
- if (node.tagName == 'font') {
- var cssStyle = [];
- for (var p in node.attrs) {
- switch (p) {
- case 'size':
- var val = node.attrs[p];
- $.each({
- '10': '1',
- '12': '2',
- '16': '3',
- '18': '4',
- '24': '5',
- '32': '6',
- '48': '7'
- }, function (k, v) {
- if (v == val) {
- val = k;
- return false;
- }
- });
- cssStyle.push('font-size:' + val + 'px');
- break;
- case 'color':
- cssStyle.push('color:' + node.attrs[p]);
- break;
- case 'face':
- cssStyle.push('font-family:' + node.attrs[p]);
- break;
- case 'style':
- cssStyle.push(node.attrs[p]);
- }
- }
- node.attrs = {
- 'style': cssStyle.join(';')
- };
- }
- node.tagName = 'span';
- if (node.parentNode.tagName == 'span' && node.parentNode.children.length == 1) {
- $.each(node.attrs, function (k, v) {
- node.parentNode.attrs[k] = k == 'style' ? node.parentNode.attrs[k] + v : v;
- })
- node.parentNode.removeChild(node, true);
- }
- });
- });
- for (var p in fonts) {
- (function (cmd) {
- me.commands[cmd] = {
- execCommand: function (cmdName, value) {
- if (value == 'transparent') {
- return;
- }
- var rng = this.selection.getRange();
- if (rng.collapsed) {
- var span = $('<span></span>').css(cmdNameToStyle[cmdName], value)[0];
- rng.insertNode(span).setStart(span, 0).setCursor();
- } else {
- if (cmdName == 'fontsize') {
- value = {
- '10': '1',
- '12': '2',
- '16': '3',
- '18': '4',
- '24': '5',
- '32': '6',
- '48': '7'
- }[(value + "").replace(/px/, '')]
- }
- this.document.execCommand(fonts[cmdName], false, value);
- if (browser.gecko) {
- $.each(this.$body.find('a'), function (i, a) {
- var parent = a.parentNode;
- if (parent.lastChild === parent.firstChild && /FONT|SPAN/.test(parent.tagName)) {
- var cloneNode = parent.cloneNode(false);
- cloneNode.innerHTML = a.innerHTML;
- $(a).html('').append(cloneNode).insertBefore(parent);
- $(parent).remove();
- }
- });
- }
- if (!browser.ie) {
- var nativeRange = this.selection.getNative().getRangeAt(0);
- var common = nativeRange.commonAncestorContainer;
- var rng = this.selection.getRange(),
- bk = rng.createBookmark(true);
- $(common).find('a').each(function (i, n) {
- var parent = n.parentNode;
- if (parent.nodeName == 'FONT') {
- var font = parent.cloneNode(false);
- font.innerHTML = n.innerHTML;
- $(n).html('').append(font);
- }
- });
- rng.moveToBookmark(bk).select()
- }
- return true
- }
- },
- queryCommandValue: function (cmdName) {
- var start = me.selection.getStart();
- var val = $(start).css(cmdNameToStyle[cmdName]);
- if (val === undefined) {
- val = $(start).attr(cmdNameToAttr[cmdName])
- }
- return val ? utils.fixColor(cmdName, val).replace(/px/, '') : '';
- },
- queryCommandState: function (cmdName) {
- return this.queryCommandValue(cmdName)
- }
- };
- })(p);
- }
- };
- ///import core
- ///commands 超链接,取消链接
- ///commandsName Link,Unlink
- ///commandsTitle 超链接,取消链接
- ///commandsDialog dialogs\link
- /**
- * 超链接
- * @function
- * @name UM.execCommand
- * @param {String} cmdName link插入超链接
- * @param {Object} options url地址,title标题,target是否打开新页
- * @author zhanyi
- */
- /**
- * 取消链接
- * @function
- * @name UM.execCommand
- * @param {String} cmdName unlink取消链接
- * @author zhanyi
- */
- UM.plugins['link'] = function () {
- var me = this;
- me.setOpt('autourldetectinie', false);
- //在ie下禁用autolink
- if (browser.ie && this.options.autourldetectinie === false) {
- this.addListener('keyup', function (cmd, evt) {
- var me = this, keyCode = evt.keyCode;
- if (keyCode == 13 || keyCode == 32) {
- var rng = me.selection.getRange();
- var start = rng.startContainer;
- if (keyCode == 13) {
- if (start.nodeName == 'P') {
- var pre = start.previousSibling;
- if (pre && pre.nodeType == 1) {
- var pre = pre.lastChild;
- if (pre && pre.nodeName == 'A' && !pre.getAttribute('_href')) {
- domUtils.remove(pre, true);
- }
- }
- }
- } else if (keyCode == 32) {
- if (start.nodeType == 3 && /^\s$/.test(start.nodeValue)) {
- start = start.previousSibling;
- if (start && start.nodeName == 'A' && !start.getAttribute('_href')) {
- domUtils.remove(start, true);
- }
- }
- }
- }
- });
- }
- this.addOutputRule(function (root) {
- $.each(root.getNodesByTagName('a'), function (i, a) {
- var _href = a.getAttr('href');
- if (!/^(ftp|https?|\/|file)/.test(_href)) {
- _href = 'http://' + _href;
- }
- if (_href != 'http://undefined') a.setAttr('href', _href);
- a.setAttr('href', _href);
- a.setAttr('_href')
- if (a.getAttr('title') == '') {
- a.setAttr('title')
- }
- })
- });
- this.addInputRule(function (root) {
- $.each(root.getNodesByTagName('a'), function (i, a) {
- a.setAttr('_href', a.getAttr('href'));
- })
- });
- me.commands['link'] = {
- execCommand: function (cmdName, opt) {
- var me = this;
- var rng = me.selection.getRange();
- opt._href && (opt._href = utils.unhtml(opt._href, /[<">'](?:(amp|lt|quot|gt|#39|nbsp);)?/g));
- opt.href && (opt.href = utils.unhtml(opt.href, /[<">'](?:(amp|lt|quot|gt|#39|nbsp);)?/g));
- if (rng.collapsed) {
- var start = rng.startContainer;
- if (start = domUtils.findParentByTagName(start, 'a', true)) {
- $(start).attr(opt);
- rng.selectNode(start).select()
- } else {
- rng.insertNode($('<a>' + opt.href + '</a>').attr(opt)[0]).select()
- }
- } else {
- me.document.execCommand('createlink', false, '_umeditor_link');
- utils.each(domUtils.getElementsByTagName(me.body, 'a', function (n) {
- return n.getAttribute('href') == '_umeditor_link'
- }), function (l) {
- if ($(l).text() == '_umeditor_link') {
- $(l).text(opt.href);
- }
- domUtils.setAttributes(l, opt);
- rng.selectNode(l).select()
- })
- }
- },
- queryCommandState: function () {
- return this.queryCommandValue('link') ? 1 : 0;
- },
- queryCommandValue: function () {
- var path = this.selection.getStartElementPath();
- var result;
- $.each(path, function (i, n) {
- if (n.nodeName == "A") {
- result = n;
- return false;
- }
- })
- return result;
- }
- };
- me.commands['unlink'] = {
- execCommand: function () {
- this.document.execCommand('unlink');
- }
- };
- };
- ///import core
- ///commands 打印
- ///commandsName Print
- ///commandsTitle 打印
- /**
- * @description 打印
- * @name baidu.editor.execCommand
- * @param {String} cmdName print打印编辑器内容
- * @author zhanyi
- */
- UM.commands['print'] = {
- execCommand: function () {
- var me = this,
- id = 'editor_print_' + +new Date();
- $('<iframe src="" id="' + id + '" name="' + id + '" frameborder="0"></iframe>').attr('id', id)
- .css({
- width: '0px',
- height: '0px',
- 'overflow': 'hidden',
- 'float': 'left',
- 'position': 'absolute',
- top: '-10000px',
- left: '-10000px'
- })
- .appendTo(me.$container.find('.edui-dialog-container'));
- var w = window.open('', id, ''),
- d = w.document;
- d.open();
- d.write('<html><head></head><body><div>' + this.getContent(null, null, true) + '</div><script>' +
- "setTimeout(function(){" +
- "window.print();" +
- "setTimeout(function(){" +
- "window.parent.$('#" + id + "').remove();" +
- "},100);" +
- "},200);" +
- '</script></body></html>');
- d.close();
- },
- notNeedUndo: 1
- };
- ///import core
- ///commands 格式
- ///commandsName Paragraph
- ///commandsTitle 段落格式
- /**
- * 段落样式
- * @function
- * @name UM.execCommand
- * @param {String} cmdName paragraph插入段落执行命令
- * @param {String} style 标签值为:'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
- * @param {String} attrs 标签的属性
- * @author zhanyi
- */
- UM.plugins['paragraph'] = function () {
- var me = this;
- me.setOpt('paragraph', {'p': '', 'h1': '', 'h2': '', 'h3': '', 'h4': '', 'h5': '', 'h6': ''});
- me.commands['paragraph'] = {
- execCommand: function (cmdName, style) {
- return this.document.execCommand('formatBlock', false, '<' + style + '>');
- },
- queryCommandValue: function () {
- try {
- var val = this.document.queryCommandValue('formatBlock')
- } catch (e) {
- }
- return val;
- }
- };
- };
- ///import core
- ///import plugins\inserthtml.js
- ///commands 分割线
- ///commandsName Horizontal
- ///commandsTitle 分隔线
- /**
- * 分割线
- * @function
- * @name UM.execCommand
- * @param {String} cmdName horizontal插入分割线
- */
- UM.plugins['horizontal'] = function () {
- var me = this;
- me.commands['horizontal'] = {
- execCommand: function () {
- this.document.execCommand('insertHorizontalRule');
- var rng = me.selection.getRange().txtToElmBoundary(true),
- start = rng.startContainer;
- if (domUtils.isBody(rng.startContainer)) {
- var next = rng.startContainer.childNodes[rng.startOffset];
- if (!next) {
- next = $('<p></p>').appendTo(rng.startContainer).html(browser.ie ? ' ' : '<br/>')[0]
- }
- rng.setStart(next, 0).setCursor()
- } else {
- while (dtd.$inline[start.tagName] && start.lastChild === start.firstChild) {
- var parent = start.parentNode;
- parent.appendChild(start.firstChild);
- parent.removeChild(start);
- start = parent;
- }
- while (dtd.$inline[start.tagName]) {
- start = start.parentNode;
- }
- if (start.childNodes.length == 1 && start.lastChild.nodeName == 'HR') {
- var hr = start.lastChild;
- $(hr).insertBefore(start);
- rng.setStart(start, 0).setCursor();
- } else {
- hr = $('hr', start)[0];
- domUtils.breakParent(hr, start);
- var pre = hr.previousSibling;
- if (pre && domUtils.isEmptyBlock(pre)) {
- $(pre).remove()
- }
- rng.setStart(hr.nextSibling, 0).setCursor();
- }
- }
- }
- };
- };
- ///import core
- ///commands 清空文档
- ///commandsName ClearDoc
- ///commandsTitle 清空文档
- /**
- *
- * 清空文档
- * @function
- * @name UM.execCommand
- * @param {String} cmdName cleardoc清空文档
- */
- UM.commands['cleardoc'] = {
- execCommand: function () {
- var me = this,
- range = me.selection.getRange();
- me.body.innerHTML = "<p>" + (ie ? "" : "<br/>") + "</p>";
- range.setStart(me.body.firstChild, 0).setCursor(false, true);
- setTimeout(function () {
- me.fireEvent("clearDoc");
- }, 0);
- }
- };
- ///import core
- ///commands 撤销和重做
- ///commandsName Undo,Redo
- ///commandsTitle 撤销,重做
- /**
- * @description 回退
- * @author zhanyi
- */
- UM.plugins['undo'] = function () {
- var saveSceneTimer;
- var me = this,
- maxUndoCount = me.options.maxUndoCount || 20,
- maxInputCount = me.options.maxInputCount || 20,
- fillchar = new RegExp(domUtils.fillChar + '|<\/hr>', 'gi');// ie会产生多余的</hr>
- var noNeedFillCharTags = {
- ol: 1, ul: 1, table: 1, tbody: 1, tr: 1, body: 1
- };
- var orgState = me.options.autoClearEmptyNode;
- function compareAddr(indexA, indexB) {
- if (indexA.length != indexB.length)
- return 0;
- for (var i = 0, l = indexA.length; i < l; i++) {
- if (indexA[i] != indexB[i])
- return 0
- }
- return 1;
- }
- function compareRangeAddress(rngAddrA, rngAddrB) {
- if (rngAddrA.collapsed != rngAddrB.collapsed) {
- return 0;
- }
- if (!compareAddr(rngAddrA.startAddress, rngAddrB.startAddress) || !compareAddr(rngAddrA.endAddress, rngAddrB.endAddress)) {
- return 0;
- }
- return 1;
- }
- function UndoManager() {
- this.list = [];
- this.index = 0;
- this.hasUndo = false;
- this.hasRedo = false;
- this.undo = function () {
- if (this.hasUndo) {
- if (!this.list[this.index - 1] && this.list.length == 1) {
- this.reset();
- return;
- }
- while (this.list[this.index].content == this.list[this.index - 1].content) {
- this.index--;
- if (this.index == 0) {
- return this.restore(0);
- }
- }
- this.restore(--this.index);
- }
- };
- this.redo = function () {
- if (this.hasRedo) {
- while (this.list[this.index].content == this.list[this.index + 1].content) {
- this.index++;
- if (this.index == this.list.length - 1) {
- return this.restore(this.index);
- }
- }
- this.restore(++this.index);
- }
- };
- this.restore = function () {
- var me = this.editor;
- var scene = this.list[this.index];
- var root = UM.htmlparser(scene.content.replace(fillchar, ''));
- me.options.autoClearEmptyNode = false;
- me.filterInputRule(root, true);
- me.options.autoClearEmptyNode = orgState;
- //trace:873
- //去掉展位符
- me.body.innerHTML = root.toHtml();
- me.fireEvent('afterscencerestore');
- //处理undo后空格不展位的问题
- if (browser.ie) {
- utils.each(domUtils.getElementsByTagName(me.document, 'td th caption p'), function (node) {
- if (domUtils.isEmptyNode(node)) {
- domUtils.fillNode(me.document, node);
- }
- })
- }
- try {
- var rng = new dom.Range(me.document, me.body).moveToAddress(scene.address);
- if (browser.ie && rng.collapsed && rng.startContainer.nodeType == 1) {
- var tmpNode = rng.startContainer.childNodes[rng.startOffset];
- if (!tmpNode || tmpNode.nodeType == 1 && dtd.$empty[tmpNode]) {
- rng.insertNode(me.document.createTextNode(' ')).collapse(true);
- }
- }
- rng.select(noNeedFillCharTags[rng.startContainer.nodeName.toLowerCase()]);
- } catch (e) {
- }
- this.update();
- this.clearKey();
- //不能把自己reset了
- me.fireEvent('reset', true);
- };
- this.getScene = function () {
- var me = this.editor;
- var rng = me.selection.getRange(),
- rngAddress = rng.createAddress(false, true);
- me.fireEvent('beforegetscene');
- var root = UM.htmlparser(me.body.innerHTML, true);
- me.options.autoClearEmptyNode = false;
- me.filterOutputRule(root, true);
- me.options.autoClearEmptyNode = orgState;
- var cont = root.toHtml();
- browser.ie && (cont = cont.replace(/> </g, '><').replace(/\s*</g, '<').replace(/>\s*/g, '>'));
- me.fireEvent('aftergetscene');
- return {
- address: rngAddress,
- content: cont
- }
- };
- this.save = function (notCompareRange, notSetCursor) {
- clearTimeout(saveSceneTimer);
- var currentScene = this.getScene(notSetCursor),
- lastScene = this.list[this.index];
- //内容相同位置相同不存
- if (lastScene && lastScene.content == currentScene.content &&
- (notCompareRange ? 1 : compareRangeAddress(lastScene.address, currentScene.address))
- ) {
- return;
- }
- this.list = this.list.slice(0, this.index + 1);
- this.list.push(currentScene);
- //如果大于最大数量了,就把最前的剔除
- if (this.list.length > maxUndoCount) {
- this.list.shift();
- }
- this.index = this.list.length - 1;
- this.clearKey();
- //跟新undo/redo状态
- this.update();
- };
- this.update = function () {
- this.hasRedo = !!this.list[this.index + 1];
- this.hasUndo = !!this.list[this.index - 1];
- };
- this.reset = function () {
- this.list = [];
- this.index = 0;
- this.hasUndo = false;
- this.hasRedo = false;
- this.clearKey();
- };
- this.clearKey = function () {
- keycont = 0;
- lastKeyCode = null;
- };
- }
- me.undoManger = new UndoManager();
- me.undoManger.editor = me;
- function saveScene() {
- this.undoManger.save();
- }
- me.addListener('saveScene', function () {
- var args = Array.prototype.splice.call(arguments, 1);
- this.undoManger.save.apply(this.undoManger, args);
- });
- me.addListener('beforeexeccommand', saveScene);
- me.addListener('afterexeccommand', saveScene);
- me.addListener('reset', function (type, exclude) {
- if (!exclude) {
- this.undoManger.reset();
- }
- });
- me.commands['redo'] = me.commands['undo'] = {
- execCommand: function (cmdName) {
- this.undoManger[cmdName]();
- },
- queryCommandState: function (cmdName) {
- return this.undoManger['has' + (cmdName.toLowerCase() == 'undo' ? 'Undo' : 'Redo')] ? 0 : -1;
- },
- notNeedUndo: 1
- };
- var keys = {
- // /*Backspace*/ 8:1, /*Delete*/ 46:1,
- /*Shift*/ 16: 1, /*Ctrl*/ 17: 1, /*Alt*/ 18: 1,
- 37: 1, 38: 1, 39: 1, 40: 1
- },
- keycont = 0,
- lastKeyCode;
- //输入法状态下不计算字符数
- var inputType = false;
- me.addListener('ready', function () {
- $(this.body).on('compositionstart', function () {
- inputType = true;
- }).on('compositionend', function () {
- inputType = false;
- })
- });
- //快捷键
- me.addshortcutkey({
- "Undo": "ctrl+90", //undo
- "Redo": "ctrl+89,shift+ctrl+z" //redo
- });
- var isCollapsed = true;
- me.addListener('keydown', function (type, evt) {
- var me = this;
- var keyCode = evt.keyCode || evt.which;
- if (!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
- if (inputType)
- return;
- if (!me.selection.getRange().collapsed) {
- me.undoManger.save(false, true);
- isCollapsed = false;
- return;
- }
- if (me.undoManger.list.length == 0) {
- me.undoManger.save(true);
- }
- clearTimeout(saveSceneTimer);
- function save(cont) {
- if (cont.selection.getRange().collapsed)
- cont.fireEvent('contentchange');
- cont.undoManger.save(false, true);
- cont.fireEvent('selectionchange');
- }
- saveSceneTimer = setTimeout(function () {
- if (inputType) {
- var interalTimer = setInterval(function () {
- if (!inputType) {
- save(me);
- clearInterval(interalTimer)
- }
- }, 300)
- return;
- }
- save(me);
- }, 200);
- lastKeyCode = keyCode;
- keycont++;
- if (keycont >= maxInputCount) {
- save(me)
- }
- }
- });
- me.addListener('keyup', function (type, evt) {
- var keyCode = evt.keyCode || evt.which;
- if (!keys[keyCode] && !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
- if (inputType)
- return;
- if (!isCollapsed) {
- this.undoManger.save(false, true);
- isCollapsed = true;
- }
- }
- });
- };
- ///import core
- ///import plugins/inserthtml.js
- ///import plugins/undo.js
- ///import plugins/serialize.js
- ///commands 粘贴
- ///commandsName PastePlain
- ///commandsTitle 纯文本粘贴模式
- /**
- * @description 粘贴
- * @author zhanyi
- */
- UM.plugins['paste'] = function () {
- function getClipboardData(callback) {
- var doc = this.document;
- if (doc.getElementById('baidu_pastebin')) {
- return;
- }
- var range = this.selection.getRange(),
- bk = range.createBookmark(),
- //创建剪贴的容器div
- pastebin = doc.createElement('div');
- pastebin.id = 'baidu_pastebin';
- // Safari 要求div必须有内容,才能粘贴内容进来
- browser.webkit && pastebin.appendChild(doc.createTextNode(domUtils.fillChar + domUtils.fillChar));
- this.body.appendChild(pastebin);
- //trace:717 隐藏的span不能得到top
- //bk.start.innerHTML = ' ';
- bk.start.style.display = '';
- pastebin.style.cssText = "position:absolute;width:1px;height:1px;overflow:hidden;left:-1000px;white-space:nowrap;top:" +
- //要在现在光标平行的位置加入,否则会出现跳动的问题
- $(bk.start).position().top + 'px';
- range.selectNodeContents(pastebin).select(true);
- setTimeout(function () {
- if (browser.webkit) {
- for (var i = 0, pastebins = doc.querySelectorAll('#baidu_pastebin'), pi; pi = pastebins[i++];) {
- if (domUtils.isEmptyNode(pi)) {
- domUtils.remove(pi);
- } else {
- pastebin = pi;
- break;
- }
- }
- }
- try {
- pastebin.parentNode.removeChild(pastebin);
- } catch (e) {
- }
- range.moveToBookmark(bk).select(true);
- callback(pastebin);
- }, 0);
- }
- var me = this;
- function filter(div) {
- var html;
- if (div.firstChild) {
- //去掉cut中添加的边界值
- var nodes = domUtils.getElementsByTagName(div, 'span');
- for (var i = 0, ni; ni = nodes[i++];) {
- if (ni.id == '_baidu_cut_start' || ni.id == '_baidu_cut_end') {
- domUtils.remove(ni);
- }
- }
- if (browser.webkit) {
- var brs = div.querySelectorAll('div br');
- for (var i = 0, bi; bi = brs[i++];) {
- var pN = bi.parentNode;
- if (pN.tagName == 'DIV' && pN.childNodes.length == 1) {
- pN.innerHTML = '<p><br/></p>';
- domUtils.remove(pN);
- }
- }
- var divs = div.querySelectorAll('#baidu_pastebin');
- for (var i = 0, di; di = divs[i++];) {
- var tmpP = me.document.createElement('p');
- di.parentNode.insertBefore(tmpP, di);
- while (di.firstChild) {
- tmpP.appendChild(di.firstChild);
- }
- domUtils.remove(di);
- }
- var metas = div.querySelectorAll('meta');
- for (var i = 0, ci; ci = metas[i++];) {
- domUtils.remove(ci);
- }
- var brs = div.querySelectorAll('br');
- for (i = 0; ci = brs[i++];) {
- if (/^apple-/i.test(ci.className)) {
- domUtils.remove(ci);
- }
- }
- }
- if (browser.gecko) {
- var dirtyNodes = div.querySelectorAll('[_moz_dirty]');
- for (i = 0; ci = dirtyNodes[i++];) {
- ci.removeAttribute('_moz_dirty');
- }
- }
- if (!browser.ie) {
- var spans = div.querySelectorAll('span.Apple-style-span');
- for (var i = 0, ci; ci = spans[i++];) {
- domUtils.remove(ci, true);
- }
- }
- //ie下使用innerHTML会产生多余的\r\n字符,也会产生 这里过滤掉
- html = div.innerHTML;//.replace(/>(?:(\s| )*?)</g,'><');
- //过滤word粘贴过来的冗余属性
- html = UM.filterWord(html);
- //取消了忽略空白的第二个参数,粘贴过来的有些是有空白的,会被套上相关的标签
- var root = UM.htmlparser(html);
- //如果给了过滤规则就先进行过滤
- if (me.options.filterRules) {
- UM.filterNode(root, me.options.filterRules);
- }
- //执行默认的处理
- me.filterInputRule(root);
- //针对chrome的处理
- if (browser.webkit) {
- var br = root.lastChild();
- if (br && br.type == 'element' && br.tagName == 'br') {
- root.removeChild(br)
- }
- utils.each(me.body.querySelectorAll('div'), function (node) {
- if (domUtils.isEmptyBlock(node)) {
- domUtils.remove(node)
- }
- })
- }
- html = {'html': root.toHtml()};
- me.fireEvent('beforepaste', html, root);
- //抢了默认的粘贴,那后边的内容就不执行了,比如表格粘贴
- if (!html.html) {
- return;
- }
- me.execCommand('insertHtml', html.html, true);
- me.fireEvent("afterpaste", html);
- }
- }
- me.addListener('ready', function () {
- $(me.body).on('cut', function () {
- var range = me.selection.getRange();
- if (!range.collapsed && me.undoManger) {
- me.undoManger.save();
- }
- }).on(browser.ie || browser.opera ? 'keydown' : 'paste', function (e) {
- //ie下beforepaste在点击右键时也会触发,所以用监控键盘才处理
- if ((browser.ie || browser.opera) && ((!e.ctrlKey && !e.metaKey) || e.keyCode != '86')) {
- return;
- }
- getClipboardData.call(me, function (div) {
- filter(div);
- });
- });
- });
- };
- ///import core
- ///commands 有序列表,无序列表
- ///commandsName InsertOrderedList,InsertUnorderedList
- ///commandsTitle 有序列表,无序列表
- /**
- * 有序列表
- * @function
- * @name UM.execCommand
- * @param {String} cmdName insertorderlist插入有序列表
- * @param {String} style 值为:decimal,lower-alpha,lower-roman,upper-alpha,upper-roman
- * @author zhanyi
- */
- /**
- * 无序链接
- * @function
- * @name UM.execCommand
- * @param {String} cmdName insertunorderlist插入无序列表
- * * @param {String} style 值为:circle,disc,square
- * @author zhanyi
- */
- UM.plugins['list'] = function () {
- var me = this;
- me.setOpt({
- 'insertorderedlist': {
- 'decimal': '',
- 'lower-alpha': '',
- 'lower-roman': '',
- 'upper-alpha': '',
- 'upper-roman': ''
- },
- 'insertunorderedlist': {
- 'circle': '',
- 'disc': '',
- 'square': ''
- }
- });
- this.addInputRule(function (root) {
- utils.each(root.getNodesByTagName('li'), function (node) {
- if (node.children.length == 0) {
- node.parentNode.removeChild(node);
- }
- })
- });
- me.commands['insertorderedlist'] =
- me.commands['insertunorderedlist'] = {
- execCommand: function (cmdName) {
- this.document.execCommand(cmdName);
- var rng = this.selection.getRange(),
- bk = rng.createBookmark(true);
- this.$body.find('ol,ul').each(function (i, n) {
- var parent = n.parentNode;
- if (parent.tagName == 'P' && parent.lastChild === parent.firstChild) {
- $(n).children().each(function (j, li) {
- var p = parent.cloneNode(false);
- $(p).append(li.innerHTML);
- $(li).html('').append(p);
- });
- $(n).insertBefore(parent);
- $(parent).remove();
- }
- if (dtd.$inline[parent.tagName]) {
- if (parent.tagName == 'SPAN') {
- $(n).children().each(function (k, li) {
- var span = parent.cloneNode(false);
- if (li.firstChild.nodeName != 'P') {
- while (li.firstChild) {
- span.appendChild(li.firstChild)
- }
- ;
- $('<p></p>').appendTo(li).append(span);
- } else {
- while (li.firstChild) {
- span.appendChild(li.firstChild)
- }
- ;
- $(li.firstChild).append(span);
- }
- })
- }
- domUtils.remove(parent, true)
- }
- });
- rng.moveToBookmark(bk).select();
- return true;
- },
- queryCommandState: function (cmdName) {
- return this.document.queryCommandState(cmdName);
- }
- };
- };
- ///import core
- ///import plugins/serialize.js
- ///import plugins/undo.js
- ///commands 查看源码
- ///commandsName Source
- ///commandsTitle 查看源码
- (function () {
- var sourceEditors = {
- textarea: function (editor, holder) {
- var textarea = holder.ownerDocument.createElement('textarea');
- textarea.style.cssText = 'resize:none;border:0;padding:0;margin:0;overflow-y:auto;outline:0';
- // todo: IE下只有onresize属性可用... 很纠结
- if (browser.ie && browser.version < 8) {
- textarea.style.width = holder.offsetWidth + 'px';
- textarea.style.height = holder.offsetHeight + 'px';
- holder.onresize = function () {
- textarea.style.width = holder.offsetWidth + 'px';
- textarea.style.height = holder.offsetHeight + 'px';
- };
- }
- holder.appendChild(textarea);
- return {
- container: textarea,
- setContent: function (content) {
- textarea.value = content;
- },
- getContent: function () {
- return textarea.value;
- },
- select: function () {
- var range;
- if (browser.ie) {
- range = textarea.createTextRange();
- range.collapse(true);
- range.select();
- } else {
- //todo: chrome下无法设置焦点
- textarea.setSelectionRange(0, 0);
- textarea.focus();
- }
- },
- dispose: function () {
- holder.removeChild(textarea);
- // todo
- holder.onresize = null;
- textarea = null;
- holder = null;
- }
- };
- }
- };
- UM.plugins['source'] = function () {
- var me = this;
- var opt = this.options;
- var sourceMode = false;
- var sourceEditor;
- opt.sourceEditor = 'textarea';
- me.setOpt({
- sourceEditorFirst: false
- });
- function createSourceEditor(holder) {
- return sourceEditors.textarea(me, holder);
- }
- var bakCssText;
- //解决在源码模式下getContent不能得到最新的内容问题
- var oldGetContent = me.getContent,
- bakAddress;
- me.commands['source'] = {
- execCommand: function () {
- sourceMode = !sourceMode;
- if (sourceMode) {
- bakAddress = me.selection.getRange().createAddress(false, true);
- me.undoManger && me.undoManger.save(true);
- if (browser.gecko) {
- me.body.contentEditable = false;
- }
- // bakCssText = me.body.style.cssText;
- me.body.style.cssText += ';position:absolute;left:-32768px;top:-32768px;';
- me.fireEvent('beforegetcontent');
- var root = UM.htmlparser(me.body.innerHTML);
- me.filterOutputRule(root);
- root.traversal(function (node) {
- if (node.type == 'element') {
- switch (node.tagName) {
- case 'td':
- case 'th':
- case 'caption':
- if (node.children && node.children.length == 1) {
- if (node.firstChild().tagName == 'br') {
- node.removeChild(node.firstChild())
- }
- }
- ;
- break;
- case 'pre':
- node.innerText(node.innerText().replace(/ /g, ' '))
- }
- }
- });
- me.fireEvent('aftergetcontent');
- var content = root.toHtml(true);
- sourceEditor = createSourceEditor(me.body.parentNode);
- sourceEditor.setContent(content);
- var getStyleValue = function (attr) {
- return parseInt($(me.body).css(attr));
- };
- $(sourceEditor.container).width($(me.body).width() + getStyleValue("padding-left") + getStyleValue("padding-right"))
- .height($(me.body).height());
- setTimeout(function () {
- sourceEditor.select();
- });
- //重置getContent,源码模式下取值也能是最新的数据
- me.getContent = function () {
- return sourceEditor.getContent() || '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
- };
- } else {
- me.$body.css({
- 'position': '',
- 'left': '',
- 'top': ''
- });
- // me.body.style.cssText = bakCssText;
- var cont = sourceEditor.getContent() || '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
- //处理掉block节点前后的空格,有可能会误命中,暂时不考虑
- cont = cont.replace(new RegExp('[\\r\\t\\n ]*<\/?(\\w+)\\s*(?:[^>]*)>', 'g'), function (a, b) {
- if (b && !dtd.$inlineWithA[b.toLowerCase()]) {
- return a.replace(/(^[\n\r\t ]*)|([\n\r\t ]*$)/g, '');
- }
- return a.replace(/(^[\n\r\t]*)|([\n\r\t]*$)/g, '')
- });
- me.setContent(cont);
- sourceEditor.dispose();
- sourceEditor = null;
- //还原getContent方法
- me.getContent = oldGetContent;
- var first = me.body.firstChild;
- //trace:1106 都删除空了,下边会报错,所以补充一个p占位
- if (!first) {
- me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
- }
- //要在ifm为显示时ff才能取到selection,否则报错
- //这里不能比较位置了
- me.undoManger && me.undoManger.save(true);
- if (browser.gecko) {
- me.body.contentEditable = true;
- }
- try {
- me.selection.getRange().moveToAddress(bakAddress).select();
- } catch (e) {
- }
- }
- this.fireEvent('sourcemodechanged', sourceMode);
- },
- queryCommandState: function () {
- return sourceMode | 0;
- },
- notNeedUndo: 1
- };
- var oldQueryCommandState = me.queryCommandState;
- me.queryCommandState = function (cmdName) {
- cmdName = cmdName.toLowerCase();
- if (sourceMode) {
- //源码模式下可以开启的命令
- return cmdName in {
- 'source': 1,
- 'fullscreen': 1
- } ? oldQueryCommandState.apply(this, arguments) : -1
- }
- return oldQueryCommandState.apply(this, arguments);
- };
- };
- })();
- ///import core
- ///import plugins/undo.js
- ///commands 设置回车标签p或br
- ///commandsName EnterKey
- ///commandsTitle 设置回车标签p或br
- /**
- * @description 处理回车
- * @author zhanyi
- */
- UM.plugins['enterkey'] = function () {
- var hTag,
- me = this,
- tag = me.options.enterTag;
- me.addListener('keyup', function (type, evt) {
- var keyCode = evt.keyCode || evt.which;
- if (keyCode == 13) {
- var range = me.selection.getRange(),
- start = range.startContainer,
- doSave;
- //修正在h1-h6里边回车后不能嵌套p的问题
- if (!browser.ie) {
- if (/h\d/i.test(hTag)) {
- if (browser.gecko) {
- var h = domUtils.findParentByTagName(start, ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'caption', 'table'], true);
- if (!h) {
- me.document.execCommand('formatBlock', false, '<p>');
- doSave = 1;
- }
- } else {
- //chrome remove div
- if (start.nodeType == 1) {
- var tmp = me.document.createTextNode(''), div;
- range.insertNode(tmp);
- div = domUtils.findParentByTagName(tmp, 'div', true);
- if (div) {
- var p = me.document.createElement('p');
- while (div.firstChild) {
- p.appendChild(div.firstChild);
- }
- div.parentNode.insertBefore(p, div);
- domUtils.remove(div);
- range.setStartBefore(tmp).setCursor();
- doSave = 1;
- }
- domUtils.remove(tmp);
- }
- }
- if (me.undoManger && doSave) {
- me.undoManger.save();
- }
- }
- //没有站位符,会出现多行的问题
- browser.opera && range.select();
- } else {
- me.fireEvent('saveScene', true, true)
- }
- }
- });
- me.addListener('keydown', function (type, evt) {
- var keyCode = evt.keyCode || evt.which;
- if (keyCode == 13) {//回车
- if (me.fireEvent('beforeenterkeydown')) {
- domUtils.preventDefault(evt);
- return;
- }
- me.fireEvent('saveScene', true, true);
- hTag = '';
- var range = me.selection.getRange();
- if (!range.collapsed) {
- //跨td不能删
- var start = range.startContainer,
- end = range.endContainer,
- startTd = domUtils.findParentByTagName(start, 'td', true),
- endTd = domUtils.findParentByTagName(end, 'td', true);
- if (startTd && endTd && startTd !== endTd || !startTd && endTd || startTd && !endTd) {
- evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false);
- return;
- }
- }
- if (tag == 'p') {
- if (!browser.ie) {
- start = domUtils.findParentByTagName(range.startContainer, ['ol', 'ul', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'caption'], true);
- //opera下执行formatblock会在table的场景下有问题,回车在opera原生支持很好,所以暂时在opera去掉调用这个原生的command
- //trace:2431
- if (!start && !browser.opera) {
- me.document.execCommand('formatBlock', false, '<p>');
- if (browser.gecko) {
- range = me.selection.getRange();
- start = domUtils.findParentByTagName(range.startContainer, 'p', true);
- start && domUtils.removeDirtyAttr(start);
- }
- } else {
- hTag = start.tagName;
- start.tagName.toLowerCase() == 'p' && browser.gecko && domUtils.removeDirtyAttr(start);
- }
- }
- }
- }
- });
- browser.ie && me.addListener('setDisabled', function () {
- $(me.body).find('p').each(function (i, p) {
- if (domUtils.isEmptyBlock(p)) {
- p.innerHTML = ' '
- }
- })
- })
- };
- ///import core
- ///commands 预览
- ///commandsName Preview
- ///commandsTitle 预览
- /**
- * 预览
- * @function
- * @name UM.execCommand
- * @param {String} cmdName preview预览编辑器内容
- */
- UM.commands['preview'] = {
- execCommand: function () {
- var w = window.open('', '_blank', ''),
- d = w.document,
- c = this.getContent(null, null, true),
- path = this.getOpt('UMEDITOR_HOME_URL'),
- formula = c.indexOf('mathquill-embedded-latex') != -1 ?
- '<link rel="stylesheet" href="' + path + 'third-party/mathquill/mathquill.css"/>' +
- '<script src="' + path + 'third-party/jquery.min.js"></script>' +
- '<script src="' + path + 'third-party/mathquill/mathquill.min.js"></script>' : '';
- d.open();
- d.write('<html><head>' + formula + '</head><body><div>' + c + '</div></body></html>');
- d.close();
- },
- notNeedUndo: 1
- };
- ///import core
- ///commands 加粗,斜体,上标,下标
- ///commandsName Bold,Italic,Subscript,Superscript
- ///commandsTitle 加粗,加斜,下标,上标
- /**
- * b u i等基础功能实现
- * @function
- * @name UM.execCommands
- * @param {String} cmdName bold加粗。italic斜体。subscript上标。superscript下标。
- */
- UM.plugins['basestyle'] = function () {
- var basestyles = ['bold', 'underline', 'superscript', 'subscript', 'italic', 'strikethrough'],
- me = this;
- //添加快捷键
- me.addshortcutkey({
- "Bold": "ctrl+66",//^B
- "Italic": "ctrl+73", //^I
- "Underline": "ctrl+shift+85",//^U
- "strikeThrough": 'ctrl+shift+83' //^s
- });
- //过滤最后的产出数据
- me.addOutputRule(function (root) {
- $.each(root.getNodesByTagName('b i u strike s'), function (i, node) {
- switch (node.tagName) {
- case 'b':
- node.tagName = 'strong';
- break;
- case 'i':
- node.tagName = 'em';
- break;
- case 'u':
- node.tagName = 'span';
- node.setStyle('text-decoration', 'underline');
- break;
- case 's':
- case 'strike':
- node.tagName = 'span';
- node.setStyle('text-decoration', 'line-through')
- }
- });
- });
- $.each(basestyles, function (i, cmd) {
- me.commands[cmd] = {
- execCommand: function (cmdName) {
- var rng = this.selection.getRange();
- if (rng.collapsed && this.queryCommandState(cmdName) != 1) {
- var node = this.document.createElement({
- 'bold': 'strong',
- 'underline': 'u',
- 'superscript': 'sup',
- 'subscript': 'sub',
- 'italic': 'em',
- 'strikethrough': 'strike'
- }[cmdName]);
- rng.insertNode(node).setStart(node, 0).setCursor(false);
- return true;
- } else {
- return this.document.execCommand(cmdName)
- }
- },
- queryCommandState: function (cmdName) {
- if (browser.gecko) {
- return this.document.queryCommandState(cmdName)
- }
- var path = this.selection.getStartElementPath(), result = false;
- $.each(path, function (i, n) {
- switch (cmdName) {
- case 'bold':
- if (n.nodeName == 'STRONG' || n.nodeName == 'B') {
- result = 1;
- return false;
- }
- break;
- case 'underline':
- if (n.nodeName == 'U' || n.nodeName == 'SPAN' && $(n).css('text-decoration') == 'underline') {
- result = 1;
- return false;
- }
- break;
- case 'superscript':
- if (n.nodeName == 'SUP') {
- result = 1;
- return false;
- }
- break;
- case 'subscript':
- if (n.nodeName == 'SUB') {
- result = 1;
- return false;
- }
- break;
- case 'italic':
- if (n.nodeName == 'EM' || n.nodeName == 'I') {
- result = 1;
- return false;
- }
- break;
- case 'strikethrough':
- if (n.nodeName == 'S' || n.nodeName == 'STRIKE' || n.nodeName == 'SPAN' && $(n).css('text-decoration') == 'line-through') {
- result = 1;
- return false;
- }
- break;
- }
- })
- return result
- }
- };
- })
- };
- ///import core
- ///import plugins/inserthtml.js
- ///commands 视频
- ///commandsName InsertVideo
- ///commandsTitle 插入视频
- ///commandsDialog dialogs\video
- UM.plugins['video'] = function () {
- var me = this,
- div;
- /**
- * 创建插入视频字符窜
- * @param url 视频地址
- * @param width 视频宽度
- * @param height 视频高度
- * @param align 视频对齐
- * @param toEmbed 是否以flash代替显示
- * @param addParagraph 是否需要添加P 标签
- */
- function creatInsertStr(url, width, height, id, align, toEmbed) {
- return !toEmbed ?
- '<img ' + (id ? 'id="' + id + '"' : '') + ' width="' + width + '" height="' + height + '" _url="' + url + '" class="edui-faked-video"' +
- ' src="' + me.options.UMEDITOR_HOME_URL + 'themes/default/images/spacer.gif" style="background:url(' + me.options.UMEDITOR_HOME_URL + 'themes/default/images/videologo.gif) no-repeat center center; border:1px solid gray;' + (align ? 'float:' + align + ';' : '') + '" />'
- :
- '<video class="edui-faked-video" ' +
- ' src="' + url + '" width="' + width + '" height="' + height + '"' + (align ? ' style="float:' + align + '"' : '') +
- ' controls autoplay preload="auto"></video>';
- }
- function switchImgAndEmbed(root, img2embed) {
- utils.each(root.getNodesByTagName(img2embed ? 'img' : 'embed'), function (node) {
- if (node.getAttr('class') == 'edui-faked-video') {
- var html = creatInsertStr(img2embed ? node.getAttr('_url') : node.getAttr('src'), node.getAttr('width'), node.getAttr('height'), null, node.getStyle('float') || '', img2embed);
- node.parentNode.replaceChild(UM.uNode.createElement(html), node)
- }
- })
- }
- me.addOutputRule(function (root) {
- switchImgAndEmbed(root, true)
- });
- me.addInputRule(function (root) {
- switchImgAndEmbed(root)
- });
- me.commands["insertvideo"] = {
- execCommand: function (cmd, videoObjs) {
- videoObjs = utils.isArray(videoObjs) ? videoObjs : [videoObjs];
- var html = [], id = 'tmpVedio';
- for (var i = 0, vi, len = videoObjs.length; i < len; i++) {
- vi = videoObjs[i];
- vi.url = utils.unhtml(vi.url, /[<">'](?:(amp|lt|quot|gt|#39|nbsp);)?/g);
- html.push(creatInsertStr(vi.url, vi.width || 420, vi.height || 280, id + i, vi.align, false));
- }
- me.execCommand("inserthtml", html.join(""), true);
- },
- queryCommandState: function () {
- var img = me.selection.getRange().getClosedNode(),
- flag = img && (img.className == "edui-faked-video");
- return flag ? 1 : 0;
- }
- };
- };
- ///import core
- ///commands 全选
- ///commandsName SelectAll
- ///commandsTitle 全选
- /**
- * 选中所有
- * @function
- * @name UM.execCommand
- * @param {String} cmdName selectall选中编辑器里的所有内容
- * @author zhanyi
- */
- UM.plugins['selectall'] = function () {
- var me = this;
- me.commands['selectall'] = {
- execCommand: function () {
- //去掉了原生的selectAll,因为会出现报错和当内容为空时,不能出现闭合状态的光标
- var me = this, body = me.body,
- range = me.selection.getRange();
- range.selectNodeContents(body);
- if (domUtils.isEmptyBlock(body)) {
- //opera不能自动合并到元素的里边,要手动处理一下
- if (browser.opera && body.firstChild && body.firstChild.nodeType == 1) {
- range.setStartAtFirst(body.firstChild);
- }
- range.collapse(true);
- }
- range.select(true);
- },
- notNeedUndo: 1
- };
- //快捷键
- me.addshortcutkey({
- "selectAll": "ctrl+65"
- });
- };
- //UM.plugins['removeformat'] = function () {
- // var me = this;
- // me.commands['removeformat'] = {
- // execCommand: function () {
- // me.document.execCommand('removeformat');
- //
- // /* 处理ie8和firefox选区有链接时,清除格式的bug */
- // if (browser.gecko || browser.ie8 || browser.webkit) {
- // var nativeRange = this.selection.getNative().getRangeAt(0),
- // common = nativeRange.commonAncestorContainer,
- // rng = me.selection.getRange(),
- // bk = rng.createBookmark();
- //
- // function isEleInBookmark(node, bk){
- // if ( (domUtils.getPosition(node, bk.start) & domUtils.POSITION_FOLLOWING) &&
- // (domUtils.getPosition(bk.end, node) & domUtils.POSITION_FOLLOWING) ) {
- // return true;
- // } else if ( (domUtils.getPosition(node, bk.start) & domUtils.POSITION_CONTAINS) ||
- // (domUtils.getPosition(node, bk.end) & domUtils.POSITION_CONTAINS) ) {
- // return true;
- // }
- // return false;
- // }
- //
- // $(common).find('a').each(function (k, a) {
- // if ( isEleInBookmark(a, bk) ) {
- // a.removeAttribute('style');
- // }
- // });
- //
- // }
- // }
- // };
- //
- //};
- //
- UM.plugins['removeformat'] = function () {
- var me = this;
- me.setOpt({
- 'removeFormatTags': 'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var',
- 'removeFormatAttributes': 'class,style,lang,width,height,align,hspace,valign'
- });
- me.commands['removeformat'] = {
- execCommand: function (cmdName, tags, style, attrs, notIncludeA) {
- var tagReg = new RegExp('^(?:' + (tags || this.options.removeFormatTags).replace(/,/g, '|') + ')$', 'i'),
- removeFormatAttributes = style ? [] : (attrs || this.options.removeFormatAttributes).split(','),
- range = new dom.Range(this.document),
- bookmark, node, parent,
- filter = function (node) {
- return node.nodeType == 1;
- };
- function isRedundantSpan(node) {
- if (node.nodeType == 3 || node.tagName.toLowerCase() != 'span') {
- return 0;
- }
- if (browser.ie) {
- //ie 下判断实效,所以只能简单用style来判断
- //return node.style.cssText == '' ? 1 : 0;
- var attrs = node.attributes;
- if (attrs.length) {
- for (var i = 0, l = attrs.length; i < l; i++) {
- if (attrs[i].specified) {
- return 0;
- }
- }
- return 1;
- }
- }
- return !node.attributes.length;
- }
- function doRemove(range) {
- var bookmark1 = range.createBookmark();
- if (range.collapsed) {
- range.enlarge(true);
- }
- //不能把a标签切了
- if (!notIncludeA) {
- var aNode = domUtils.findParentByTagName(range.startContainer, 'a', true);
- if (aNode) {
- range.setStartBefore(aNode);
- }
- aNode = domUtils.findParentByTagName(range.endContainer, 'a', true);
- if (aNode) {
- range.setEndAfter(aNode);
- }
- }
- bookmark = range.createBookmark();
- node = bookmark.start;
- //切开始
- while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
- domUtils.breakParent(node, parent);
- domUtils.clearEmptySibling(node);
- }
- if (bookmark.end) {
- //切结束
- node = bookmark.end;
- while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
- domUtils.breakParent(node, parent);
- domUtils.clearEmptySibling(node);
- }
- //开始去除样式
- var current = domUtils.getNextDomNode(bookmark.start, false, filter),
- next;
- while (current) {
- if (current == bookmark.end) {
- break;
- }
- next = domUtils.getNextDomNode(current, true, filter);
- if (!dtd.$empty[current.tagName.toLowerCase()] && !domUtils.isBookmarkNode(current)) {
- if (tagReg.test(current.tagName)) {
- if (style) {
- domUtils.removeStyle(current, style);
- if (isRedundantSpan(current) && style != 'text-decoration') {
- domUtils.remove(current, true);
- }
- } else {
- domUtils.remove(current, true);
- }
- } else {
- //trace:939 不能把list上的样式去掉
- if (!dtd.$tableContent[current.tagName] && !dtd.$list[current.tagName]) {
- domUtils.removeAttributes(current, removeFormatAttributes);
- if (isRedundantSpan(current)) {
- domUtils.remove(current, true);
- }
- }
- }
- }
- current = next;
- }
- }
- //trace:1035
- //trace:1096 不能把td上的样式去掉,比如边框
- var pN = bookmark.start.parentNode;
- if (domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName] && !dtd.$list[pN.tagName]) {
- var remove_check = pN.getAttribute('class'); //新增
- if (remove_check && remove_check.indexOf('edui-body-container') > -1) {
- } else {
- domUtils.removeAttributes(pN, removeFormatAttributes);
- }
- }
- pN = bookmark.end.parentNode;
- if (bookmark.end && domUtils.isBlockElm(pN) && !dtd.$tableContent[pN.tagName] && !dtd.$list[pN.tagName]) {
- var remove_check = pN.getAttribute('class'); //新增
- if (remove_check && remove_check.indexOf('edui-body-container') > -1) {
- } else {
- domUtils.removeAttributes(pN, removeFormatAttributes);
- }
- }
- range.moveToBookmark(bookmark).moveToBookmark(bookmark1);
- //清除冗余的代码 <b><bookmark></b>
- var node = range.startContainer,
- tmp,
- collapsed = range.collapsed;
- console.log(node);
- while (node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]) {
- tmp = node.parentNode;
- range.setStartBefore(node);
- //trace:937
- //更新结束边界
- if (range.startContainer === range.endContainer) {
- range.endOffset--;
- }
- domUtils.remove(node);
- node = tmp;
- }
- if (!collapsed) {
- node = range.endContainer;
- while (node.nodeType == 1 && domUtils.isEmptyNode(node) && dtd.$removeEmpty[node.tagName]) {
- tmp = node.parentNode;
- range.setEndBefore(node);
- domUtils.remove(node);
- node = tmp;
- }
- }
- }
- range = this.selection.getRange();
- if (!range.collapsed) {
- doRemove(range);
- range.select();
- }
- }
- };
- };
- /*
- * 处理特殊键的兼容性问题
- */
- UM.plugins['keystrokes'] = function () {
- var me = this;
- var collapsed = true;
- me.addListener('keydown', function (type, evt) {
- var keyCode = evt.keyCode || evt.which,
- rng = me.selection.getRange();
- //处理全选的情况
- if (!rng.collapsed && !(evt.ctrlKey || evt.shiftKey || evt.altKey || evt.metaKey) && (keyCode >= 65 && keyCode <= 90
- || keyCode >= 48 && keyCode <= 57 ||
- keyCode >= 96 && keyCode <= 111 || {
- 13: 1,
- 8: 1,
- 46: 1
- }[keyCode])
- ) {
- var tmpNode = rng.startContainer;
- if (domUtils.isFillChar(tmpNode)) {
- rng.setStartBefore(tmpNode)
- }
- tmpNode = rng.endContainer;
- if (domUtils.isFillChar(tmpNode)) {
- rng.setEndAfter(tmpNode)
- }
- rng.txtToElmBoundary();
- //结束边界可能放到了br的前边,要把br包含进来
- // x[xxx]<br/>
- if (rng.endContainer && rng.endContainer.nodeType == 1) {
- tmpNode = rng.endContainer.childNodes[rng.endOffset];
- if (tmpNode && domUtils.isBr(tmpNode)) {
- rng.setEndAfter(tmpNode);
- }
- }
- if (rng.startOffset == 0) {
- tmpNode = rng.startContainer;
- if (domUtils.isBoundaryNode(tmpNode, 'firstChild')) {
- tmpNode = rng.endContainer;
- if (rng.endOffset == (tmpNode.nodeType == 3 ? tmpNode.nodeValue.length : tmpNode.childNodes.length) && domUtils.isBoundaryNode(tmpNode, 'lastChild')) {
- me.fireEvent('saveScene');
- me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>';
- rng.setStart(me.body.firstChild, 0).setCursor(false, true);
- me._selectionChange();
- return;
- }
- }
- }
- }
- //处理backspace
- if (keyCode == 8) {
- rng = me.selection.getRange();
- collapsed = rng.collapsed;
- if (me.fireEvent('delkeydown', evt)) {
- return;
- }
- var start, end;
- //避免按两次删除才能生效的问题
- if (rng.collapsed && rng.inFillChar()) {
- start = rng.startContainer;
- if (domUtils.isFillChar(start)) {
- rng.setStartBefore(start).shrinkBoundary(true).collapse(true);
- domUtils.remove(start)
- } else {
- start.nodeValue = start.nodeValue.replace(new RegExp('^' + domUtils.fillChar), '');
- rng.startOffset--;
- rng.collapse(true).select(true)
- }
- }
- //解决选中control元素不能删除的问题
- if (start = rng.getClosedNode()) {
- me.fireEvent('saveScene');
- rng.setStartBefore(start);
- domUtils.remove(start);
- rng.setCursor();
- me.fireEvent('saveScene');
- domUtils.preventDefault(evt);
- return;
- }
- //阻止在table上的删除
- if (!browser.ie) {
- start = domUtils.findParentByTagName(rng.startContainer, 'table', true);
- end = domUtils.findParentByTagName(rng.endContainer, 'table', true);
- if (start && !end || !start && end || start !== end) {
- evt.preventDefault();
- return;
- }
- }
- start = rng.startContainer;
- if (rng.collapsed && start.nodeType == 1) {
- var currentNode = start.childNodes[rng.startOffset - 1];
- if (currentNode && currentNode.nodeType == 1 && currentNode.tagName == 'BR') {
- me.fireEvent('saveScene');
- rng.setStartBefore(currentNode).collapse(true);
- domUtils.remove(currentNode);
- rng.select();
- me.fireEvent('saveScene');
- }
- }
- //trace:3613
- if (browser.chrome) {
- if (rng.collapsed) {
- while (rng.startOffset == 0 && !domUtils.isEmptyBlock(rng.startContainer)) {
- rng.setStartBefore(rng.startContainer)
- }
- var pre = rng.startContainer.childNodes[rng.startOffset - 1];
- if (pre && pre.nodeName == 'BR') {
- rng.setStartBefore(pre);
- me.fireEvent('saveScene');
- $(pre).remove();
- rng.setCursor();
- me.fireEvent('saveScene');
- }
- }
- }
- }
- //trace:1634
- //ff的del键在容器空的时候,也会删除
- if (browser.gecko && keyCode == 46) {
- var range = me.selection.getRange();
- if (range.collapsed) {
- start = range.startContainer;
- if (domUtils.isEmptyBlock(start)) {
- var parent = start.parentNode;
- while (domUtils.getChildCount(parent) == 1 && !domUtils.isBody(parent)) {
- start = parent;
- parent = parent.parentNode;
- }
- if (start === parent.lastChild)
- evt.preventDefault();
- return;
- }
- }
- }
- });
- me.addListener('keyup', function (type, evt) {
- var keyCode = evt.keyCode || evt.which,
- rng, me = this;
- if (keyCode == 8) {
- if (me.fireEvent('delkeyup')) {
- return;
- }
- rng = me.selection.getRange();
- if (rng.collapsed) {
- var tmpNode,
- autoClearTagName = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
- if (tmpNode = domUtils.findParentByTagName(rng.startContainer, autoClearTagName, true)) {
- if (domUtils.isEmptyBlock(tmpNode)) {
- var pre = tmpNode.previousSibling;
- if (pre && pre.nodeName != 'TABLE') {
- domUtils.remove(tmpNode);
- rng.setStartAtLast(pre).setCursor(false, true);
- return;
- } else {
- var next = tmpNode.nextSibling;
- if (next && next.nodeName != 'TABLE') {
- domUtils.remove(tmpNode);
- rng.setStartAtFirst(next).setCursor(false, true);
- return;
- }
- }
- }
- }
- //处理当删除到body时,要重新给p标签展位
- if (domUtils.isBody(rng.startContainer)) {
- var tmpNode = domUtils.createElement(me.document, 'p', {
- 'innerHTML': browser.ie ? domUtils.fillChar : '<br/>'
- });
- rng.insertNode(tmpNode).setStart(tmpNode, 0).setCursor(false, true);
- }
- }
- //chrome下如果删除了inline标签,浏览器会有记忆,在输入文字还是会套上刚才删除的标签,所以这里再选一次就不会了
- if (!collapsed && (rng.startContainer.nodeType == 3 || rng.startContainer.nodeType == 1 && domUtils.isEmptyBlock(rng.startContainer))) {
- if (browser.ie) {
- var span = rng.document.createElement('span');
- rng.insertNode(span).setStartBefore(span).collapse(true);
- rng.select();
- domUtils.remove(span)
- } else {
- rng.select()
- }
- }
- }
- })
- };
- /**
- * 自动保存草稿
- */
- UM.plugins['autosave'] = function () {
- var me = this,
- //无限循环保护
- lastSaveTime = new Date(),
- //最小保存间隔时间
- MIN_TIME = 20,
- //auto save key
- saveKey = null;
- //默认间隔时间
- me.setOpt('saveInterval', 500);
- //存储媒介封装
- var LocalStorage = UM.LocalStorage = (function () {
- var storage = window.localStorage || getUserData() || null,
- LOCAL_FILE = "localStorage";
- return {
- saveLocalData: function (key, data) {
- if (storage && data) {
- storage.setItem(key, data);
- return true;
- }
- return false;
- },
- getLocalData: function (key) {
- if (storage) {
- return storage.getItem(key);
- }
- return null;
- },
- removeItem: function (key) {
- storage && storage.removeItem(key);
- }
- };
- function getUserData() {
- var container = document.createElement("div");
- container.style.display = "none";
- if (!container.addBehavior) {
- return null;
- }
- container.addBehavior("#default#userdata");
- return {
- getItem: function (key) {
- var result = null;
- try {
- document.body.appendChild(container);
- container.load(LOCAL_FILE);
- result = container.getAttribute(key);
- document.body.removeChild(container);
- } catch (e) {
- }
- return result;
- },
- setItem: function (key, value) {
- document.body.appendChild(container);
- container.setAttribute(key, value);
- container.save(LOCAL_FILE);
- document.body.removeChild(container);
- },
- // 暂时没有用到
- // clear: function () {
- //
- // var expiresTime = new Date();
- // expiresTime.setFullYear( expiresTime.getFullYear() - 1 );
- // document.body.appendChild( container );
- // container.expires = expiresTime.toUTCString();
- // container.save( LOCAL_FILE );
- // document.body.removeChild( container );
- //
- // },
- removeItem: function (key) {
- document.body.appendChild(container);
- container.removeAttribute(key);
- container.save(LOCAL_FILE);
- document.body.removeChild(container);
- }
- };
- }
- })();
- function save(editor) {
- var saveData = null;
- if (new Date() - lastSaveTime < MIN_TIME) {
- return;
- }
- if (!editor.hasContents()) {
- //这里不能调用命令来删除, 会造成事件死循环
- saveKey && LocalStorage.removeItem(saveKey);
- return;
- }
- lastSaveTime = new Date();
- editor._saveFlag = null;
- saveData = me.body.innerHTML;
- if (editor.fireEvent("beforeautosave", {
- content: saveData
- }) === false) {
- return;
- }
- LocalStorage.saveLocalData(saveKey, saveData);
- editor.fireEvent("afterautosave", {
- content: saveData
- });
- }
- me.addListener('ready', function () {
- var _suffix = "-drafts-data",
- key = null;
- if (me.key) {
- key = me.key + _suffix;
- } else {
- key = (me.container.parentNode.id || 'ue-common') + _suffix;
- }
- //页面地址+编辑器ID 保持唯一
- saveKey = (location.protocol + location.host + location.pathname).replace(/[.:\/]/g, '_') + key;
- });
- me.addListener('contentchange', function () {
- if (!saveKey) {
- return;
- }
- if (me._saveFlag) {
- window.clearTimeout(me._saveFlag);
- }
- if (me.options.saveInterval > 0) {
- me._saveFlag = window.setTimeout(function () {
- save(me);
- }, me.options.saveInterval);
- } else {
- save(me);
- }
- })
- me.commands['clearlocaldata'] = {
- execCommand: function (cmd, name) {
- if (saveKey && LocalStorage.getLocalData(saveKey)) {
- LocalStorage.removeItem(saveKey)
- }
- },
- notNeedUndo: true,
- ignoreContentChange: true
- };
- me.commands['getlocaldata'] = {
- execCommand: function (cmd, name) {
- return saveKey ? LocalStorage.getLocalData(saveKey) || '' : '';
- },
- notNeedUndo: true,
- ignoreContentChange: true
- };
- me.commands['drafts'] = {
- execCommand: function (cmd, name) {
- if (saveKey) {
- me.body.innerHTML = LocalStorage.getLocalData(saveKey) || '<p>' + (browser.ie ? ' ' : '<br/>') + '</p>';
- me.focus(true);
- }
- },
- queryCommandState: function () {
- return saveKey ? (LocalStorage.getLocalData(saveKey) === null ? -1 : 0) : -1;
- },
- notNeedUndo: true,
- ignoreContentChange: true
- }
- };
- /**
- * @description
- * 1.拖放文件到编辑区域,自动上传并插入到选区
- * 2.插入粘贴板的图片,自动上传并插入到选区
- * @author Jinqn
- * @date 2013-10-14
- */
- UM.plugins['autoupload'] = function () {
- var me = this;
- me.setOpt('pasteImageEnabled', true);
- me.setOpt('dropFileEnabled', true);
- var sendAndInsertImage = function (file, editor) {
- //模拟数据
- var fd = new FormData();
- fd.append(editor.options.imageFieldName || 'upfile', file, file.name || ('blob.' + file.type.substr('image/'.length)));
- fd.append('type', 'ajax');
- var xhr = new XMLHttpRequest();
- xhr.open("post", me.options.imageUrl, true);
- xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
- xhr.addEventListener('load', function (e) {
- try {
- var json = eval('(' + e.target.response + ')'),
- link = json.url,
- picLink = me.options.imagePath + link;
- editor.execCommand('insertimage', {
- src: picLink,
- _src: picLink
- });
- } catch (er) {
- }
- });
- xhr.send(fd);
- };
- function getPasteImage(e) {
- return e.clipboardData && e.clipboardData.items && e.clipboardData.items.length == 1 && /^image\//.test(e.clipboardData.items[0].type) ? e.clipboardData.items : null;
- }
- function getDropImage(e) {
- return e.dataTransfer && e.dataTransfer.files ? e.dataTransfer.files : null;
- }
- me.addListener('ready', function () {
- if (window.FormData && window.FileReader) {
- var autoUploadHandler = function (e) {
- var hasImg = false,
- items;
- //获取粘贴板文件列表或者拖放文件列表
- items = e.type == 'paste' ? getPasteImage(e.originalEvent) : getDropImage(e.originalEvent);
- if (items) {
- var len = items.length,
- file;
- while (len--) {
- file = items[len];
- if (file.getAsFile) file = file.getAsFile();
- if (file && file.size > 0 && /image\/\w+/i.test(file.type)) {
- sendAndInsertImage(file, me);
- hasImg = true;
- }
- }
- if (hasImg) return false;
- }
- };
- me.getOpt('pasteImageEnabled') && me.$body.on('paste', autoUploadHandler);
- me.getOpt('dropFileEnabled') && me.$body.on('drop', autoUploadHandler);
- //取消拖放图片时出现的文字光标位置提示
- me.$body.on('dragover', function (e) {
- if (e.originalEvent.dataTransfer.types[0] == 'Files') {
- return false;
- }
- });
- }
- });
- };
- /**
- * 公式插件
- */
- UM.plugins['formula'] = function () {
- var me = this;
- function getActiveIframe() {
- return me.$body.find('iframe.edui-formula-active')[0] || null;
- }
- function blurActiveIframe() {
- var iframe = getActiveIframe();
- iframe && iframe.contentWindow.formula.blur();
- }
- me.addInputRule(function (root) {
- $.each(root.getNodesByTagName('span'), function (i, node) {
- if (node.hasClass('mathquill-embedded-latex')) {
- var firstChild, latex = '';
- while (firstChild = node.firstChild()) {
- latex += firstChild.data;
- node.removeChild(firstChild);
- }
- node.tagName = 'iframe';
- node.setAttr({
- 'frameborder': '0',
- 'src': me.getOpt('UMEDITOR_HOME_URL') + 'dialogs/formula/formula.html',
- 'data-latex': utils.unhtml(latex)
- });
- }
- });
- });
- me.addOutputRule(function (root) {
- $.each(root.getNodesByTagName('iframe'), function (i, node) {
- if (node.hasClass('mathquill-embedded-latex')) {
- node.tagName = 'span';
- node.appendChild(UM.uNode.createText(node.getAttr('data-latex')));
- node.setAttr({
- 'frameborder': '',
- 'src': '',
- 'data-latex': ''
- });
- }
- });
- });
- me.addListener('click', function () {
- blurActiveIframe();
- });
- me.addListener('afterexeccommand', function (type, cmd) {
- if (cmd != 'formula') {
- blurActiveIframe();
- }
- });
- me.commands['formula'] = {
- execCommand: function (cmd, latex) {
- var iframe = getActiveIframe();
- if (iframe) {
- iframe.contentWindow.formula.insertLatex(latex);
- } else {
- me.execCommand('inserthtml', '<span class="mathquill-embedded-latex">' + latex + '</span>');
- browser.ie && browser.ie9below && setTimeout(function () {
- var rng = me.selection.getRange(),
- startContainer = rng.startContainer;
- if (startContainer.nodeType == 1 && !startContainer.childNodes[rng.startOffset]) {
- rng.insertNode(me.document.createTextNode(' '));
- rng.setCursor()
- }
- }, 100)
- }
- },
- queryCommandState: function (cmd) {
- return 0;
- },
- queryCommandValue: function (cmd) {
- var iframe = getActiveIframe();
- return iframe && iframe.contentWindow.formula.getLatex();
- }
- }
- };
- /**
- * @file xssFilter.js
- * @desc xss过滤器
- * @author robbenmu
- */
- UM.plugins.xssFilter = function () {
- var config = UMEDITOR_CONFIG;
- var whiteList = config.whiteList;
- function filter(node) {
- var tagName = node.tagName;
- var attrs = node.attrs;
- if (!whiteList.hasOwnProperty(tagName)) {
- node.parentNode.removeChild(node);
- return false;
- }
- UM.utils.each(attrs, function (val, key) {
- if (whiteList[tagName].indexOf(key) === -1) {
- node.setAttr(key);
- }
- });
- }
- // 添加inserthtml\paste等操作用的过滤规则
- if (whiteList && config.xssFilterRules) {
- this.options.filterRules = function () {
- var result = {};
- UM.utils.each(whiteList, function (val, key) {
- result[key] = function (node) {
- return filter(node);
- };
- });
- return result;
- }();
- }
- var tagList = [];
- UM.utils.each(whiteList, function (val, key) {
- tagList.push(key);
- });
- // 添加input过滤规则
- //
- if (whiteList && config.inputXssFilter) {
- this.addInputRule(function (root) {
- root.traversal(function (node) {
- if (node.type !== 'element') {
- return false;
- }
- filter(node);
- });
- });
- }
- // 添加output过滤规则
- //
- if (whiteList && config.outputXssFilter) {
- this.addOutputRule(function (root) {
- root.traversal(function (node) {
- if (node.type !== 'element') {
- return false;
- }
- filter(node);
- });
- });
- }
- };
- (function ($) {
- //对jquery的扩展
- $.parseTmpl = function parse(str, data) {
- var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' + 'with(obj||{}){__p.push(\'' + str.replace(/\\/g, '\\\\').replace(/'/g, "\\'").replace(/<%=([\s\S]+?)%>/g, function (match, code) {
- return "'," + code.replace(/\\'/g, "'") + ",'";
- }).replace(/<%([\s\S]+?)%>/g, function (match, code) {
- return "');" + code.replace(/\\'/g, "'").replace(/[\r\n\t]/g, ' ') + "__p.push('";
- }).replace(/\r/g, '\\r').replace(/\n/g, '\\n').replace(/\t/g, '\\t') + "');}return __p.join('');";
- var func = new Function('obj', tmpl);
- return data ? func(data) : func;
- };
- $.extend2 = function (t, s) {
- var a = arguments,
- notCover = $.type(a[a.length - 1]) == 'boolean' ? a[a.length - 1] : false,
- len = $.type(a[a.length - 1]) == 'boolean' ? a.length - 1 : a.length;
- for (var i = 1; i < len; i++) {
- var x = a[i];
- for (var k in x) {
- if (!notCover || !t.hasOwnProperty(k)) {
- t[k] = x[k];
- }
- }
- }
- return t;
- };
- $.IE6 = !!window.ActiveXObject && parseFloat(navigator.userAgent.match(/msie (\d+)/i)[1]) == 6;
- //所有ui的基类
- var _eventHandler = [];
- var _widget = function () {
- };
- var _prefix = 'edui';
- _widget.prototype = {
- on: function (ev, cb) {
- this.root().on(ev, $.proxy(cb, this));
- return this;
- },
- off: function (ev, cb) {
- this.root().off(ev, $.proxy(cb, this));
- return this;
- },
- trigger: function (ev, data) {
- return this.root().trigger(ev, data) === false ? false : this;
- },
- root: function ($el) {
- return this._$el || (this._$el = $el);
- },
- destroy: function () {
- },
- data: function (key, val) {
- if (val !== undefined) {
- this.root().data(_prefix + key, val);
- return this;
- } else {
- return this.root().data(_prefix + key)
- }
- },
- register: function (eventName, $el, fn) {
- _eventHandler.push({
- 'evtname': eventName,
- '$els': $.isArray($el) ? $el : [$el],
- handler: $.proxy(fn, $el)
- })
- }
- };
- //从jq实例上拿到绑定的widget实例
- $.fn.edui = function (obj) {
- return obj ? this.data('eduiwidget', obj) : this.data('eduiwidget');
- };
- function _createClass(ClassObj, properties, supperClass) {
- ClassObj.prototype = $.extend2(
- $.extend({}, properties),
- (UM.ui[supperClass] || _widget).prototype,
- true
- );
- ClassObj.prototype.supper = (UM.ui[supperClass] || _widget).prototype;
- //父class的defaultOpt 合并
- if (UM.ui[supperClass] && UM.ui[supperClass].prototype.defaultOpt) {
- var parentDefaultOptions = UM.ui[supperClass].prototype.defaultOpt,
- subDefaultOptions = ClassObj.prototype.defaultOpt;
- ClassObj.prototype.defaultOpt = $.extend({}, parentDefaultOptions, subDefaultOptions || {});
- }
- return ClassObj
- }
- var _guid = 1;
- function mergeToJQ(ClassObj, className) {
- $[_prefix + className] = ClassObj;
- $.fn[_prefix + className] = function (opt) {
- var result, args = Array.prototype.slice.call(arguments, 1);
- this.each(function (i, el) {
- var $this = $(el);
- var obj = $this.edui();
- if (!obj) {
- ClassObj(!opt || !$.isPlainObject(opt) ? {} : opt, $this);
- $this.edui(obj)
- }
- if ($.type(opt) == 'string') {
- if (opt == 'this') {
- result = obj;
- } else {
- result = obj[opt].apply(obj, args);
- if (result !== obj && result !== undefined) {
- return false;
- }
- result = null;
- }
- }
- });
- return result !== null ? result : this;
- }
- }
- UM.ui = {
- define: function (className, properties, supperClass) {
- var ClassObj = UM.ui[className] = _createClass(function (options, $el) {
- var _obj = function () {
- };
- $.extend(_obj.prototype, ClassObj.prototype, {
- guid: className + _guid++,
- widgetName: className
- }
- );
- var obj = new _obj;
- if ($.type(options) == 'string') {
- obj.init && obj.init({});
- obj.root().edui(obj);
- obj.root().find('a').click(function (evt) {
- evt.preventDefault()
- });
- return obj.root()[_prefix + className].apply(obj.root(), arguments)
- } else {
- $el && obj.root($el);
- obj.init && obj.init(!options || $.isPlainObject(options) ? $.extend2(options || {}, obj.defaultOpt || {}, true) : options);
- try {
- obj.root().find('a').click(function (evt) {
- evt.preventDefault()
- });
- } catch (e) {
- }
- return obj.root().edui(obj);
- }
- }, properties, supperClass);
- mergeToJQ(ClassObj, className);
- }
- };
- $(function () {
- $(document).on('click mouseup mousedown dblclick mouseover', function (evt) {
- $.each(_eventHandler, function (i, obj) {
- if (obj.evtname == evt.type) {
- $.each(obj.$els, function (i, $el) {
- if ($el[0] !== evt.target && !$.contains($el[0], evt.target)) {
- obj.handler(evt);
- }
- })
- }
- })
- })
- })
- })(jQuery);
- //button 类
- UM.ui.define('button', {
- tpl: '<<%if(!texttype){%>div class="edui-btn edui-btn-<%=icon%> <%if(name){%>edui-btn-name-<%=name%><%}%>" unselectable="on" onmousedown="return false" <%}else{%>a class="edui-text-btn"<%}%><% if(title) {%> data-original-title="<%=title%>" <%};%>> ' +
- '<% if(icon) {%><div unselectable="on" class="edui-icon-<%=icon%> edui-icon"></div><% }; %><%if(text) {%><span unselectable="on" onmousedown="return false" class="edui-button-label"><%=text%></span><%}%>' +
- '<%if(caret && text){%><span class="edui-button-spacing"></span><%}%>' +
- '<% if(caret) {%><span unselectable="on" onmousedown="return false" class="edui-caret"></span><% };%></<%if(!texttype){%>div<%}else{%>a<%}%>>',
- defaultOpt: {
- text: '',
- title: '',
- icon: '',
- width: '',
- caret: false,
- texttype: false,
- click: function () {
- }
- },
- init: function (options) {
- var me = this;
- me.root($($.parseTmpl(me.tpl, options)))
- .click(function (evt) {
- me.wrapclick(options.click, evt)
- });
- me.root().hover(function () {
- if (!me.root().hasClass("edui-disabled")) {
- me.root().toggleClass('edui-hover')
- }
- })
- return me;
- },
- wrapclick: function (fn, evt) {
- if (!this.disabled()) {
- this.root().trigger('wrapclick');
- $.proxy(fn, this, evt)()
- }
- return this;
- },
- label: function (text) {
- if (text === undefined) {
- return this.root().find('.edui-button-label').text();
- } else {
- this.root().find('.edui-button-label').text(text);
- return this;
- }
- },
- disabled: function (state) {
- if (state === undefined) {
- return this.root().hasClass('edui-disabled')
- }
- this.root().toggleClass('edui-disabled', state);
- if (this.root().hasClass('edui-disabled')) {
- this.root().removeClass('edui-hover')
- }
- return this;
- },
- active: function (state) {
- if (state === undefined) {
- return this.root().hasClass('edui-active')
- }
- this.root().toggleClass('edui-active', state)
- return this;
- },
- mergeWith: function ($obj) {
- var me = this;
- me.data('$mergeObj', $obj);
- $obj.edui().data('$mergeObj', me.root());
- if (!$.contains(document.body, $obj[0])) {
- $obj.appendTo(me.root());
- }
- me.on('click', function () {
- me.wrapclick(function () {
- $obj.edui().show();
- })
- }).register('click', me.root(), function (evt) {
- $obj.hide()
- });
- }
- });
- //toolbar 类
- (function () {
- UM.ui.define('toolbar', {
- tpl: '<div class="edui-toolbar" ><div class="edui-btn-toolbar" unselectable="on" onmousedown="return false" ></div></div>'
- ,
- init: function () {
- var $root = this.root($(this.tpl));
- this.data('$btnToolbar', $root.find('.edui-btn-toolbar'))
- },
- appendToBtnmenu: function (data) {
- var $cont = this.data('$btnToolbar');
- data = $.isArray(data) ? data : [data];
- $.each(data, function (i, $item) {
- $cont.append($item)
- })
- }
- });
- })();
- //menu 类
- UM.ui.define('menu', {
- show: function ($obj, dir, fnname, topOffset, leftOffset) {
- fnname = fnname || 'position';
- if (this.trigger('beforeshow') === false) {
- return;
- } else {
- this.root().css($.extend({display: 'block'}, $obj ? {
- top: $obj[fnname]().top + (dir == 'right' ? 0 : $obj.outerHeight()) - (topOffset || 0),
- left: $obj[fnname]().left + (dir == 'right' ? $obj.outerWidth() : 0) - (leftOffset || 0)
- } : {}))
- this.trigger('aftershow');
- }
- },
- hide: function (all) {
- var $parentmenu;
- if (this.trigger('beforehide') === false) {
- return;
- } else {
- if ($parentmenu = this.root().data('parentmenu')) {
- if ($parentmenu.data('parentmenu') || all)
- $parentmenu.edui().hide();
- }
- this.root().css('display', 'none');
- this.trigger('afterhide');
- }
- },
- attachTo: function ($obj) {
- var me = this;
- if (!$obj.data('$mergeObj')) {
- $obj.data('$mergeObj', me.root());
- $obj.on('wrapclick', function (evt) {
- me.show()
- });
- me.register('click', $obj, function (evt) {
- me.hide()
- });
- me.data('$mergeObj', $obj)
- }
- }
- });
- //dropmenu 类
- UM.ui.define('dropmenu', {
- tmpl: '<ul class="edui-dropdown-menu" aria-labelledby="dropdownMenu" >' +
- '<%for(var i=0,ci;ci=data[i++];){%>' +
- '<%if(ci.divider){%><li class="edui-divider"></li><%}else{%>' +
- '<li <%if(ci.active||ci.disabled){%>class="<%= ci.active|| \'\' %> <%=ci.disabled||\'\' %>" <%}%> data-value="<%= ci.value%>">' +
- '<a href="#" tabindex="-1"><em class="edui-dropmenu-checkbox"><i class="edui-icon-ok"></i></em><%= ci.label%></a>' +
- '</li><%}%>' +
- '<%}%>' +
- '</ul>',
- defaultOpt: {
- data: [],
- click: function () {
- }
- },
- init: function (options) {
- var me = this;
- var eventName = {
- click: 1,
- mouseover: 1,
- mouseout: 1
- };
- this.root($($.parseTmpl(this.tmpl, options))).on('click', 'li[class!="edui-disabled edui-divider edui-dropdown-submenu"]', function (evt) {
- $.proxy(options.click, me, evt, $(this).data('value'), $(this))()
- }).find('li').each(function (i, el) {
- var $this = $(this);
- if (!$this.hasClass("edui-disabled edui-divider edui-dropdown-submenu")) {
- var data = options.data[i];
- $.each(eventName, function (k) {
- data[k] && $this[k](function (evt) {
- $.proxy(data[k], el)(evt, data, me.root)
- })
- })
- }
- })
- },
- disabled: function (cb) {
- $('li[class!=edui-divider]', this.root()).each(function () {
- var $el = $(this);
- if (cb === true) {
- $el.addClass('edui-disabled')
- } else if ($.isFunction(cb)) {
- $el.toggleClass('edui-disabled', cb(li))
- } else {
- $el.removeClass('edui-disabled')
- }
- });
- },
- val: function (val) {
- var currentVal;
- $('li[class!="edui-divider edui-disabled edui-dropdown-submenu"]', this.root()).each(function () {
- var $el = $(this);
- if (val === undefined) {
- if ($el.find('em.edui-dropmenu-checked').length) {
- currentVal = $el.data('value');
- return false
- }
- } else {
- $el.find('em').toggleClass('edui-dropmenu-checked', $el.data('value') == val)
- }
- });
- if (val === undefined) {
- return currentVal
- }
- },
- addSubmenu: function (label, menu, index) {
- index = index || 0;
- var $list = $('li[class!=edui-divider]', this.root());
- var $node = $('<li class="edui-dropdown-submenu"><a tabindex="-1" href="#">' + label + '</a></li>').append(menu);
- if (index >= 0 && index < $list.length) {
- $node.insertBefore($list[index]);
- } else if (index < 0) {
- $node.insertBefore($list[0]);
- } else if (index >= $list.length) {
- $node.appendTo($list);
- }
- }
- }, 'menu');
- //splitbutton 类
- ///import button
- UM.ui.define('splitbutton', {
- tpl: '<div class="edui-splitbutton <%if (name){%>edui-splitbutton-<%= name %><%}%>" unselectable="on" <%if(title){%>data-original-title="<%=title%>"<%}%>><div class="edui-btn" unselectable="on" ><%if(icon){%><div unselectable="on" class="edui-icon-<%=icon%> edui-icon"></div><%}%><%if(text){%><%=text%><%}%></div>' +
- '<div unselectable="on" class="edui-btn edui-dropdown-toggle" >' +
- '<div unselectable="on" class="edui-caret"><\/div>' +
- '</div>' +
- '</div>',
- defaultOpt: {
- text: '',
- title: '',
- click: function () {
- }
- },
- init: function (options) {
- var me = this;
- me.root($($.parseTmpl(me.tpl, options)));
- me.root().find('.edui-btn:first').click(function (evt) {
- if (!me.disabled()) {
- $.proxy(options.click, me)();
- }
- });
- me.root().find('.edui-dropdown-toggle').click(function () {
- if (!me.disabled()) {
- me.trigger('arrowclick')
- }
- });
- me.root().hover(function () {
- if (!me.root().hasClass("edui-disabled")) {
- me.root().toggleClass('edui-hover')
- }
- });
- return me;
- },
- wrapclick: function (fn, evt) {
- if (!this.disabled()) {
- $.proxy(fn, this, evt)()
- }
- return this;
- },
- disabled: function (state) {
- if (state === undefined) {
- return this.root().hasClass('edui-disabled')
- }
- this.root().toggleClass('edui-disabled', state).find('.edui-btn').toggleClass('edui-disabled', state);
- return this;
- },
- active: function (state) {
- if (state === undefined) {
- return this.root().hasClass('edui-active')
- }
- this.root().toggleClass('edui-active', state).find('.edui-btn:first').toggleClass('edui-active', state);
- return this;
- },
- mergeWith: function ($obj) {
- var me = this;
- me.data('$mergeObj', $obj);
- $obj.edui().data('$mergeObj', me.root());
- if (!$.contains(document.body, $obj[0])) {
- $obj.appendTo(me.root());
- }
- me.root().delegate('.edui-dropdown-toggle', 'click', function () {
- me.wrapclick(function () {
- $obj.edui().show();
- })
- });
- me.register('click', me.root().find('.edui-dropdown-toggle'), function (evt) {
- $obj.hide()
- });
- }
- });
- /**
- * Created with JetBrains PhpStorm.
- * User: hn
- * Date: 13-7-10
- * Time: 下午3:07
- * To change this template use File | Settings | File Templates.
- */
- UM.ui.define('colorsplitbutton', {
- tpl: '<div class="edui-splitbutton <%if (name){%>edui-splitbutton-<%= name %><%}%>" unselectable="on" <%if(title){%>data-original-title="<%=title%>"<%}%>><div class="edui-btn" unselectable="on" ><%if(icon){%><div unselectable="on" class="edui-icon-<%=icon%> edui-icon"></div><%}%><div class="edui-splitbutton-color-label" <%if (color) {%>style="background: <%=color%>"<%}%>></div><%if(text){%><%=text%><%}%></div>' +
- '<div unselectable="on" class="edui-btn edui-dropdown-toggle" >' +
- '<div unselectable="on" class="edui-caret"><\/div>' +
- '</div>' +
- '</div>',
- defaultOpt: {
- color: ''
- },
- init: function (options) {
- var me = this;
- me.supper.init.call(me, options);
- },
- colorLabel: function () {
- return this.root().find('.edui-splitbutton-color-label');
- }
- }, 'splitbutton');
- //popup 类
- UM.ui.define('popup', {
- tpl: '<div class="edui-dropdown-menu edui-popup"' +
- '<%if(!<%=stopprop%>){%>onmousedown="return false"<%}%>' +
- '><div class="edui-popup-body" unselectable="on" onmousedown="return false"><%=subtpl%></div>' +
- '<div class="edui-popup-caret"></div>' +
- '</div>',
- defaultOpt: {
- stopprop: false,
- subtpl: '',
- width: '',
- height: ''
- },
- init: function (options) {
- this.root($($.parseTmpl(this.tpl, options)));
- return this;
- },
- mergeTpl: function (data) {
- return $.parseTmpl(this.tpl, {subtpl: data});
- },
- show: function ($obj, posObj) {
- if (!posObj) posObj = {};
- var fnname = posObj.fnname || 'position';
- if (this.trigger('beforeshow') === false) {
- return;
- } else {
- this.root().css($.extend({display: 'block'}, $obj ? {
- top: $obj[fnname]().top + (posObj.dir == 'right' ? 0 : $obj.outerHeight()) - (posObj.offsetTop || 0),
- left: $obj[fnname]().left + (posObj.dir == 'right' ? $obj.outerWidth() : 0) - (posObj.offsetLeft || 0),
- position: 'absolute'
- } : {}));
- this.root().find('.edui-popup-caret').css({
- top: posObj.caretTop || 0,
- left: posObj.caretLeft || 0,
- position: 'absolute'
- }).addClass(posObj.caretDir || "up")
- }
- this.trigger("aftershow");
- },
- hide: function () {
- this.root().css('display', 'none');
- this.trigger('afterhide')
- },
- attachTo: function ($obj, posObj) {
- var me = this
- if (!$obj.data('$mergeObj')) {
- $obj.data('$mergeObj', me.root());
- $obj.on('wrapclick', function (evt) {
- me.show($obj, posObj)
- });
- me.register('click', $obj, function (evt) {
- me.hide()
- });
- me.data('$mergeObj', $obj)
- }
- },
- getBodyContainer: function () {
- return this.root().find(".edui-popup-body");
- }
- });
- //scale 类
- UM.ui.define('scale', {
- tpl: '<div class="edui-scale" unselectable="on">' +
- '<span class="edui-scale-hand0"></span>' +
- '<span class="edui-scale-hand1"></span>' +
- '<span class="edui-scale-hand2"></span>' +
- '<span class="edui-scale-hand3"></span>' +
- '<span class="edui-scale-hand4"></span>' +
- '<span class="edui-scale-hand5"></span>' +
- '<span class="edui-scale-hand6"></span>' +
- '<span class="edui-scale-hand7"></span>' +
- '</div>',
- defaultOpt: {
- $doc: $(document),
- $wrap: $(document)
- },
- init: function (options) {
- if (options.$doc) this.defaultOpt.$doc = options.$doc;
- if (options.$wrap) this.defaultOpt.$wrap = options.$wrap;
- this.root($($.parseTmpl(this.tpl, options)));
- this.initStyle();
- this.startPos = this.prePos = {x: 0, y: 0};
- this.dragId = -1;
- return this;
- },
- initStyle: function () {
- utils.cssRule('edui-style-scale', '.edui-scale{display:none;position:absolute;border:1px solid #38B2CE;cursor:hand;}' +
- '.edui-scale span{position:absolute;left:0;top:0;width:7px;height:7px;overflow:hidden;font-size:0px;display:block;background-color:#3C9DD0;}'
- + '.edui-scale .edui-scale-hand0{cursor:nw-resize;top:0;margin-top:-4px;left:0;margin-left:-4px;}'
- + '.edui-scale .edui-scale-hand1{cursor:n-resize;top:0;margin-top:-4px;left:50%;margin-left:-4px;}'
- + '.edui-scale .edui-scale-hand2{cursor:ne-resize;top:0;margin-top:-4px;left:100%;margin-left:-3px;}'
- + '.edui-scale .edui-scale-hand3{cursor:w-resize;top:50%;margin-top:-4px;left:0;margin-left:-4px;}'
- + '.edui-scale .edui-scale-hand4{cursor:e-resize;top:50%;margin-top:-4px;left:100%;margin-left:-3px;}'
- + '.edui-scale .edui-scale-hand5{cursor:sw-resize;top:100%;margin-top:-3px;left:0;margin-left:-4px;}'
- + '.edui-scale .edui-scale-hand6{cursor:s-resize;top:100%;margin-top:-3px;left:50%;margin-left:-4px;}'
- + '.edui-scale .edui-scale-hand7{cursor:se-resize;top:100%;margin-top:-3px;left:100%;margin-left:-3px;}');
- },
- _eventHandler: function (e) {
- var me = this,
- $doc = me.defaultOpt.$doc;
- switch (e.type) {
- case 'mousedown':
- var hand = e.target || e.srcElement, hand;
- if (hand.className.indexOf('edui-scale-hand') != -1) {
- me.dragId = hand.className.slice(-1);
- me.startPos.x = me.prePos.x = e.clientX;
- me.startPos.y = me.prePos.y = e.clientY;
- $doc.bind('mousemove', $.proxy(me._eventHandler, me));
- }
- break;
- case 'mousemove':
- if (me.dragId != -1) {
- me.updateContainerStyle(me.dragId, {x: e.clientX - me.prePos.x, y: e.clientY - me.prePos.y});
- me.prePos.x = e.clientX;
- me.prePos.y = e.clientY;
- me.updateTargetElement();
- }
- break;
- case 'mouseup':
- if (me.dragId != -1) {
- me.dragId = -1;
- me.updateTargetElement();
- var $target = me.data('$scaleTarget');
- if ($target.parent()) me.attachTo(me.data('$scaleTarget'));
- }
- $doc.unbind('mousemove', $.proxy(me._eventHandler, me));
- break;
- default:
- break;
- }
- },
- updateTargetElement: function () {
- var me = this,
- $root = me.root(),
- $target = me.data('$scaleTarget');
- $target.css({width: $root.width(), height: $root.height()});
- me.attachTo($target);
- },
- updateContainerStyle: function (dir, offset) {
- var me = this,
- $dom = me.root(),
- tmp,
- rect = [
- //[left, top, width, height]
- [0, 0, -1, -1],
- [0, 0, 0, -1],
- [0, 0, 1, -1],
- [0, 0, -1, 0],
- [0, 0, 1, 0],
- [0, 0, -1, 1],
- [0, 0, 0, 1],
- [0, 0, 1, 1]
- ];
- if (rect[dir][0] != 0) {
- tmp = parseInt($dom.offset().left) + offset.x;
- $dom.css('left', me._validScaledProp('left', tmp));
- }
- if (rect[dir][1] != 0) {
- tmp = parseInt($dom.offset().top) + offset.y;
- $dom.css('top', me._validScaledProp('top', tmp));
- }
- if (rect[dir][2] != 0) {
- tmp = $dom.width() + rect[dir][2] * offset.x;
- $dom.css('width', me._validScaledProp('width', tmp));
- }
- if (rect[dir][3] != 0) {
- tmp = $dom.height() + rect[dir][3] * offset.y;
- $dom.css('height', me._validScaledProp('height', tmp));
- }
- },
- _validScaledProp: function (prop, value) {
- var $ele = this.root(),
- $wrap = this.defaultOpt.$doc,
- calc = function (val, a, b) {
- return (val + a) > b ? b - a : value;
- };
- value = isNaN(value) ? 0 : value;
- switch (prop) {
- case 'left':
- return value < 0 ? 0 : calc(value, $ele.width(), $wrap.width());
- case 'top':
- return value < 0 ? 0 : calc(value, $ele.height(), $wrap.height());
- case 'width':
- return value <= 0 ? 1 : calc(value, $ele.offset().left, $wrap.width());
- case 'height':
- return value <= 0 ? 1 : calc(value, $ele.offset().top, $wrap.height());
- }
- },
- show: function ($obj) {
- var me = this;
- if ($obj) me.attachTo($obj);
- me.root().bind('mousedown', $.proxy(me._eventHandler, me));
- me.defaultOpt.$doc.bind('mouseup', $.proxy(me._eventHandler, me));
- me.root().show();
- me.trigger("aftershow");
- },
- hide: function () {
- var me = this;
- me.root().unbind('mousedown', $.proxy(me._eventHandler, me));
- me.defaultOpt.$doc.unbind('mouseup', $.proxy(me._eventHandler, me));
- me.root().hide();
- me.trigger('afterhide')
- },
- attachTo: function ($obj) {
- var me = this,
- imgPos = $obj.offset(),
- $root = me.root(),
- $wrap = me.defaultOpt.$wrap,
- posObj = $wrap.offset();
- me.data('$scaleTarget', $obj);
- me.root().css({
- position: 'absolute',
- width: $obj.width(),
- height: $obj.height(),
- left: imgPos.left - posObj.left - parseInt($wrap.css('border-left-width')) - parseInt($root.css('border-left-width')),
- top: imgPos.top - posObj.top - parseInt($wrap.css('border-top-width')) - parseInt($root.css('border-top-width'))
- });
- },
- getScaleTarget: function () {
- return this.data('$scaleTarget')[0];
- }
- });
- //colorpicker 类
- UM.ui.define('colorpicker', {
- tpl: function (opt) {
- var COLORS = (
- 'ffffff,000000,eeece1,1f497d,4f81bd,c0504d,9bbb59,8064a2,4bacc6,f79646,' +
- 'f2f2f2,7f7f7f,ddd9c3,c6d9f0,dbe5f1,f2dcdb,ebf1dd,e5e0ec,dbeef3,fdeada,' +
- 'd8d8d8,595959,c4bd97,8db3e2,b8cce4,e5b9b7,d7e3bc,ccc1d9,b7dde8,fbd5b5,' +
- 'bfbfbf,3f3f3f,938953,548dd4,95b3d7,d99694,c3d69b,b2a2c7,92cddc,fac08f,' +
- 'a5a5a5,262626,494429,17365d,366092,953734,76923c,5f497a,31859b,e36c09,' +
- '7f7f7f,0c0c0c,1d1b10,0f243e,244061,632423,4f6128,3f3151,205867,974806,' +
- 'c00000,ff0000,ffc000,ffff00,92d050,00b050,00b0f0,0070c0,002060,7030a0,').split(',');
- var html = '<div unselectable="on" onmousedown="return false" class="edui-colorpicker<%if (name){%> edui-colorpicker-<%=name%><%}%>" >' +
- '<table unselectable="on" onmousedown="return false">' +
- '<tr><td colspan="10">' + opt.lang_themeColor + '</td> </tr>' +
- '<tr class="edui-colorpicker-firstrow" >';
- for (var i = 0; i < COLORS.length; i++) {
- if (i && i % 10 === 0) {
- html += '</tr>' + (i == 60 ? '<tr><td colspan="10">' + opt.lang_standardColor + '</td></tr>' : '') + '<tr' + (i == 60 ? ' class="edui-colorpicker-firstrow"' : '') + '>';
- }
- html += i < 70 ? '<td><a unselectable="on" onmousedown="return false" title="' + COLORS[i] + '" class="edui-colorpicker-colorcell"' +
- ' data-color="#' + COLORS[i] + '"' +
- ' style="background-color:#' + COLORS[i] + ';border:solid #ccc;' +
- (i < 10 || i >= 60 ? 'border-width:1px;' :
- i >= 10 && i < 20 ? 'border-width:1px 1px 0 1px;' :
- 'border-width:0 1px 0 1px;') +
- '"' +
- '></a></td>' : '';
- }
- html += '</tr></table></div>';
- return html;
- },
- init: function (options) {
- var me = this;
- me.root($($.parseTmpl(me.supper.mergeTpl(me.tpl(options)), options)));
- me.root().on("click", function (e) {
- me.trigger('pickcolor', $(e.target).data('color'));
- });
- }
- }, 'popup');
- /**
- * Created with JetBrains PhpStorm.
- * User: hn
- * Date: 13-5-29
- * Time: 下午8:01
- * To change this template use File | Settings | File Templates.
- */
- (function () {
- var widgetName = 'combobox',
- itemClassName = 'edui-combobox-item',
- HOVER_CLASS = 'edui-combobox-item-hover',
- ICON_CLASS = 'edui-combobox-checked-icon',
- labelClassName = 'edui-combobox-item-label';
- UM.ui.define(widgetName, (function () {
- return {
- tpl: "<ul class=\"dropdown-menu edui-combobox-menu<%if (comboboxName!=='') {%> edui-combobox-<%=comboboxName%><%}%>\" unselectable=\"on\" onmousedown=\"return false\" role=\"menu\" aria-labelledby=\"dropdownMenu\">" +
- "<%if(autoRecord) {%>" +
- "<%for( var i=0, len = recordStack.length; i<len; i++ ) {%>" +
- "<%var index = recordStack[i];%>" +
- "<li class=\"<%=itemClassName%><%if( selected == index ) {%> edui-combobox-checked<%}%>\" data-item-index=\"<%=index%>\" unselectable=\"on\" onmousedown=\"return false\">" +
- "<span class=\"edui-combobox-icon\" unselectable=\"on\" onmousedown=\"return false\"></span>" +
- "<label class=\"<%=labelClassName%>\" style=\"<%=itemStyles[ index ]%>\" unselectable=\"on\" onmousedown=\"return false\"><%=items[index]%></label>" +
- "</li>" +
- "<%}%>" +
- "<%if( i ) {%>" +
- "<li class=\"edui-combobox-item-separator\"></li>" +
- "<%}%>" +
- "<%}%>" +
- "<%for( var i=0, label; label = items[i]; i++ ) {%>" +
- "<li class=\"<%=itemClassName%><%if( selected == i ) {%> edui-combobox-checked<%}%> edui-combobox-item-<%=i%>\" data-item-index=\"<%=i%>\" unselectable=\"on\" onmousedown=\"return false\">" +
- "<span class=\"edui-combobox-icon\" unselectable=\"on\" onmousedown=\"return false\"></span>" +
- "<label class=\"<%=labelClassName%>\" style=\"<%=itemStyles[ i ]%>\" unselectable=\"on\" onmousedown=\"return false\"><%=label%></label>" +
- "</li>" +
- "<%}%>" +
- "</ul>",
- defaultOpt: {
- //记录栈初始列表
- recordStack: [],
- //可用项列表
- items: [],
- //item对应的值列表
- value: [],
- comboboxName: '',
- selected: '',
- //自动记录
- autoRecord: true,
- //最多记录条数
- recordCount: 5
- },
- init: function (options) {
- var me = this;
- $.extend(me._optionAdaptation(options), me._createItemMapping(options.recordStack, options.items), {
- itemClassName: itemClassName,
- iconClass: ICON_CLASS,
- labelClassName: labelClassName
- });
- this._transStack(options);
- me.root($($.parseTmpl(me.tpl, options)));
- this.data('options', options).initEvent();
- },
- initEvent: function () {
- var me = this;
- me.initSelectItem();
- this.initItemActive();
- },
- /**
- * 初始化选择项
- */
- initSelectItem: function () {
- var me = this,
- labelClass = "." + labelClassName;
- me.root().delegate('.' + itemClassName, 'click', function () {
- var $li = $(this),
- index = $li.attr('data-item-index');
- me.trigger('comboboxselect', {
- index: index,
- label: $li.find(labelClass).text(),
- value: me.data('options').value[index]
- }).select(index);
- me.hide();
- return false;
- });
- },
- initItemActive: function () {
- var fn = {
- mouseenter: 'addClass',
- mouseleave: 'removeClass'
- };
- if ($.IE6) {
- this.root().delegate('.' + itemClassName, 'mouseenter mouseleave', function (evt) {
- $(this)[fn[evt.type]](HOVER_CLASS);
- }).one('afterhide', function () {
- });
- }
- },
- /**
- * 选择给定索引的项
- * @param index 项索引
- * @returns {*} 如果存在对应索引的项,则返回该项;否则返回null
- */
- select: function (index) {
- var itemCount = this.data('options').itemCount,
- items = this.data('options').autowidthitem;
- if (items && !items.length) {
- items = this.data('options').items;
- }
- if (itemCount == 0) {
- return null;
- }
- if (index < 0) {
- index = itemCount + index % itemCount;
- } else if (index >= itemCount) {
- index = itemCount - 1;
- }
- this.trigger('changebefore', items[index]);
- this._update(index);
- this.trigger('changeafter', items[index]);
- return null;
- },
- selectItemByLabel: function (label) {
- var itemMapping = this.data('options').itemMapping,
- me = this,
- index = null;
- !$.isArray(label) && (label = [label]);
- $.each(label, function (i, item) {
- index = itemMapping[item];
- if (index !== undefined) {
- me.select(index);
- return false;
- }
- });
- },
- /**
- * 转换记录栈
- */
- _transStack: function (options) {
- var temp = [],
- itemIndex = -1,
- selected = -1;
- $.each(options.recordStack, function (index, item) {
- itemIndex = options.itemMapping[item];
- if ($.isNumeric(itemIndex)) {
- temp.push(itemIndex);
- //selected的合法性检测
- if (item == options.selected) {
- selected = itemIndex;
- }
- }
- });
- options.recordStack = temp;
- options.selected = selected;
- temp = null;
- },
- _optionAdaptation: function (options) {
- if (!('itemStyles' in options)) {
- options.itemStyles = [];
- for (var i = 0, len = options.items.length; i < len; i++) {
- options.itemStyles.push('');
- }
- }
- options.autowidthitem = options.autowidthitem || options.items;
- options.itemCount = options.items.length;
- return options;
- },
- _createItemMapping: function (stackItem, items) {
- var temp = {},
- result = {
- recordStack: [],
- mapping: {}
- };
- $.each(items, function (index, item) {
- temp[item] = index;
- });
- result.itemMapping = temp;
- $.each(stackItem, function (index, item) {
- if (temp[item] !== undefined) {
- result.recordStack.push(temp[item]);
- result.mapping[item] = temp[item];
- }
- });
- return result;
- },
- _update: function (index) {
- var options = this.data("options"),
- newStack = [],
- newChilds = null;
- $.each(options.recordStack, function (i, item) {
- if (item != index) {
- newStack.push(item);
- }
- });
- //压入最新的记录
- newStack.unshift(index);
- if (newStack.length > options.recordCount) {
- newStack.length = options.recordCount;
- }
- options.recordStack = newStack;
- options.selected = index;
- newChilds = $($.parseTmpl(this.tpl, options));
- //重新渲染
- this.root().html(newChilds.html());
- newChilds = null;
- newStack = null;
- }
- };
- })(), 'menu');
- })();
- /**
- * Combox 抽象基类
- * User: hn
- * Date: 13-5-29
- * Time: 下午8:01
- * To change this template use File | Settings | File Templates.
- */
- (function () {
- var widgetName = 'buttoncombobox';
- UM.ui.define(widgetName, (function () {
- return {
- defaultOpt: {
- //按钮初始文字
- label: '',
- title: ''
- },
- init: function (options) {
- var me = this;
- var btnWidget = $.eduibutton({
- caret: true,
- name: options.comboboxName,
- title: options.title,
- text: options.label,
- click: function () {
- me.show(this.root());
- }
- });
- me.supper.init.call(me, options);
- //监听change, 改变button显示内容
- me.on('changebefore', function (e, label) {
- btnWidget.eduibutton('label', label);
- });
- me.data('button', btnWidget);
- me.attachTo(btnWidget)
- },
- button: function () {
- return this.data('button');
- }
- }
- })(), 'combobox');
- })();
- /*modal 类*/
- UM.ui.define('modal', {
- tpl: '<div class="edui-modal" tabindex="-1" >' +
- '<div class="edui-modal-header">' +
- '<div class="edui-close" data-hide="modal"></div>' +
- '<h3 class="edui-title"><%=title%></h3>' +
- '</div>' +
- '<div class="edui-modal-body" style="<%if(width){%>width:<%=width%>px;<%}%>' +
- '<%if(height){%>height:<%=height%>px;<%}%>">' +
- ' </div>' +
- '<% if(cancellabel || oklabel) {%>' +
- '<div class="edui-modal-footer">' +
- '<div class="edui-modal-tip"></div>' +
- '<%if(oklabel){%><div class="edui-btn edui-btn-primary" data-ok="modal"><%=oklabel%></div><%}%>' +
- '<%if(cancellabel){%><div class="edui-btn" data-hide="modal"><%=cancellabel%></div><%}%>' +
- '</div>' +
- '<%}%></div>',
- defaultOpt: {
- title: "",
- cancellabel: "",
- oklabel: "",
- width: '',
- height: '',
- backdrop: true,
- keyboard: true
- },
- init: function (options) {
- var me = this;
- me.root($($.parseTmpl(me.tpl, options || {})));
- me.data("options", options);
- if (options.okFn) {
- me.on('ok', $.proxy(options.okFn, me))
- }
- if (options.cancelFn) {
- me.on('beforehide', $.proxy(options.cancelFn, me))
- }
- me.root().delegate('[data-hide="modal"]', 'click', $.proxy(me.hide, me))
- .delegate('[data-ok="modal"]', 'click', $.proxy(me.ok, me));
- $('[data-hide="modal"],[data-ok="modal"]', me.root()).hover(function () {
- $(this).toggleClass('edui-hover')
- });
- },
- toggle: function () {
- var me = this;
- return me[!me.data("isShown") ? 'show' : 'hide']();
- },
- show: function () {
- var me = this;
- me.trigger("beforeshow");
- if (me.data("isShown")) return;
- me.data("isShown", true);
- me.escape();
- me.backdrop(function () {
- me.autoCenter();
- me.root()
- .show()
- .focus()
- .trigger('aftershow');
- })
- },
- showTip: function (text) {
- $('.edui-modal-tip', this.root()).html(text).fadeIn();
- },
- hideTip: function (text) {
- $('.edui-modal-tip', this.root()).fadeOut(function () {
- $(this).html('');
- });
- },
- autoCenter: function () {
- //ie6下不用处理了
- !$.IE6 && this.root().css("margin-left", -(this.root().width() / 2));
- },
- hide: function () {
- var me = this;
- me.trigger("beforehide");
- if (!me.data("isShown")) return;
- me.data("isShown", false);
- me.escape();
- me.hideModal();
- },
- escape: function () {
- var me = this;
- if (me.data("isShown") && me.data("options").keyboard) {
- me.root().on('keyup', function (e) {
- e.which == 27 && me.hide();
- })
- } else if (!me.data("isShown")) {
- me.root().off('keyup');
- }
- },
- hideModal: function () {
- var me = this;
- me.root().hide();
- me.backdrop(function () {
- me.removeBackdrop();
- me.trigger('afterhide');
- })
- },
- removeBackdrop: function () {
- this.$backdrop && this.$backdrop.remove();
- this.$backdrop = null;
- },
- backdrop: function (callback) {
- var me = this;
- if (me.data("isShown") && me.data("options").backdrop) {
- me.$backdrop = $('<div class="edui-modal-backdrop" />').click(
- me.data("options").backdrop == 'static' ?
- $.proxy(me.root()[0].focus, me.root()[0])
- : $.proxy(me.hide, me)
- )
- }
- me.trigger('afterbackdrop');
- callback && callback();
- },
- attachTo: function ($obj) {
- var me = this
- if (!$obj.data('$mergeObj')) {
- $obj.data('$mergeObj', me.root());
- $obj.on('click', function () {
- me.toggle($obj)
- });
- me.data('$mergeObj', $obj)
- }
- },
- ok: function () {
- var me = this;
- me.trigger('beforeok');
- if (me.trigger("ok", me) === false) {
- return;
- }
- me.hide();
- },
- getBodyContainer: function () {
- return this.root().find('.edui-modal-body')
- }
- });
- /*tooltip 类*/
- UM.ui.define('tooltip', {
- tpl: '<div class="edui-tooltip" unselectable="on" onmousedown="return false">' +
- '<div class="edui-tooltip-arrow" unselectable="on" onmousedown="return false"></div>' +
- '<div class="edui-tooltip-inner" unselectable="on" onmousedown="return false"></div>' +
- '</div>',
- init: function (options) {
- var me = this;
- me.root($($.parseTmpl(me.tpl, options || {})));
- },
- content: function (e) {
- var me = this,
- title = $(e.currentTarget).attr("data-original-title");
- me.root().find('.edui-tooltip-inner')['text'](title);
- },
- position: function (e) {
- var me = this,
- $obj = $(e.currentTarget);
- me.root().css($.extend({display: 'block'}, $obj ? {
- top: $obj.outerHeight(),
- left: (($obj.outerWidth() - me.root().outerWidth()) / 2)
- } : {}))
- },
- show: function (e) {
- if ($(e.currentTarget).hasClass('edui-disabled')) return;
- var me = this;
- me.content(e);
- me.root().appendTo($(e.currentTarget));
- me.position(e);
- me.root().css('display', 'block');
- },
- hide: function () {
- var me = this;
- me.root().css('display', 'none')
- },
- attachTo: function ($obj) {
- var me = this;
- function tmp($obj) {
- var me = this;
- if (!$.contains(document.body, me.root()[0])) {
- me.root().appendTo($obj);
- }
- me.data('tooltip', me.root());
- $obj.each(function () {
- if ($(this).attr("data-original-title")) {
- $(this).on('mouseenter', $.proxy(me.show, me))
- .on('mouseleave click', $.proxy(me.hide, me))
- }
- });
- }
- if ($.type($obj) === "undefined") {
- $("[data-original-title]").each(function (i, el) {
- tmp.call(me, $(el));
- })
- } else {
- if (!$obj.data('tooltip')) {
- tmp.call(me, $obj);
- }
- }
- }
- });
- /*tab 类*/
- UM.ui.define('tab', {
- init: function (options) {
- var me = this,
- slr = options.selector;
- if ($.type(slr)) {
- me.root($(slr, options.context));
- me.data("context", options.context);
- $(slr, me.data("context")).on('click', function (e) {
- me.show(e);
- });
- }
- },
- show: function (e) {
- var me = this,
- $cur = $(e.target),
- $ul = $cur.closest('ul'),
- selector,
- previous,
- $target,
- e;
- selector = $cur.attr('data-context');
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '');
- var $tmp = $cur.parent('li');
- if (!$tmp.length || $tmp.hasClass('edui-active')) return;
- previous = $ul.find('.edui-active:last a')[0];
- e = $.Event('beforeshow', {
- target: $cur[0],
- relatedTarget: previous
- });
- me.trigger(e);
- if (e.isDefaultPrevented()) return;
- $target = $(selector, me.data("context"));
- me.activate($cur.parent('li'), $ul);
- me.activate($target, $target.parent(), function () {
- me.trigger({
- type: 'aftershow', relatedTarget: previous
- })
- });
- },
- activate: function (element, container, callback) {
- if (element === undefined) {
- return $(".edui-tab-item.edui-active", this.root()).index();
- }
- var $active = container.find('> .edui-active');
- $active.removeClass('edui-active');
- element.addClass('edui-active');
- callback && callback();
- }
- });
- //button 类
- UM.ui.define('separator', {
- tpl: '<div class="edui-separator" unselectable="on" onmousedown="return false" ></div>',
- init: function (options) {
- var me = this;
- me.root($($.parseTmpl(me.tpl, options)));
- return me;
- }
- });
- /**
- * @file adapter.js
- * @desc adapt ui to editor
- * @import core/Editor.js, core/utils.js
- */
- (function () {
- var _editorUI = {},
- _editors = {},
- _readyFn = [],
- _activeWidget = null,
- _widgetData = {},
- _widgetCallBack = {},
- _cacheUI = {},
- _maxZIndex = null;
- utils.extend(UM, {
- defaultWidth: 500,
- defaultHeight: 500,
- registerUI: function (name, fn) {
- utils.each(name.split(/\s+/), function (uiname) {
- _editorUI[uiname] = fn;
- })
- },
- setEditor: function (editor) {
- !_editors[editor.id] && (_editors[editor.id] = editor);
- },
- registerWidget: function (name, pro, cb) {
- _widgetData[name] = $.extend2(pro, {
- $root: '',
- _preventDefault: false,
- root: function ($el) {
- return this.$root || (this.$root = $el);
- },
- preventDefault: function () {
- this._preventDefault = true;
- },
- clear: false
- });
- if (cb) {
- _widgetCallBack[name] = cb;
- }
- },
- getWidgetData: function (name) {
- return _widgetData[name]
- },
- setWidgetBody: function (name, $widget, editor) {
- if (!editor._widgetData) {
- utils.extend(editor, {
- _widgetData: {},
- getWidgetData: function (name) {
- return this._widgetData[name];
- },
- getWidgetCallback: function (widgetName) {
- var me = this;
- return function () {
- return _widgetCallBack[widgetName].apply(me, [me, $widget].concat(Array.prototype.slice.call(arguments, 0)))
- }
- }
- })
- }
- var pro = _widgetData[name];
- if (!pro) {
- return null;
- }
- pro = editor._widgetData[name];
- if (!pro) {
- pro = _widgetData[name];
- pro = editor._widgetData[name] = $.type(pro) == 'function' ? pro : utils.clone(pro);
- }
- pro.root($widget.edui().getBodyContainer());
- pro.initContent(editor, $widget);
- if (!pro._preventDefault) {
- pro.initEvent(editor, $widget);
- }
- pro.width && $widget.width(pro.width);
- },
- setActiveWidget: function ($widget) {
- _activeWidget = $widget;
- },
- getEditor: function (id, options) {
- var editor = _editors[id] || (_editors[id] = this.createEditor(id, options));
- _maxZIndex = _maxZIndex ? Math.max(editor.getOpt('zIndex'), _maxZIndex) : editor.getOpt('zIndex');
- return editor;
- },
- setTopEditor: function (editor) {
- $.each(_editors, function (i, o) {
- if (editor == o) {
- editor.$container && editor.$container.css('zIndex', _maxZIndex + 1);
- } else {
- o.$container && o.$container.css('zIndex', o.getOpt('zIndex'));
- }
- });
- },
- clearCache: function (id) {
- if (_editors[id]) {
- delete _editors[id]
- }
- },
- delEditor: function (id) {
- var editor;
- if (editor = _editors[id]) {
- editor.destroy();
- }
- },
- ready: function (fn) {
- _readyFn.push(fn);
- },
- createEditor: function (id, opt) {
- var editor = new UM.Editor(opt);
- var T = this;
- editor.langIsReady ? $.proxy(renderUI, T)() : editor.addListener("langReady", $.proxy(renderUI, T));
- function renderUI() {
- var $container = this.createUI('#' + id, editor);
- editor.key = id;
- editor.ready(function () {
- $.each(_readyFn, function (index, fn) {
- $.proxy(fn, editor)();
- });
- });
- var options = editor.options;
- if (options.initialFrameWidth) {
- options.minFrameWidth = options.initialFrameWidth
- } else {
- options.minFrameWidth = options.initialFrameWidth = editor.$body.width() || UM.defaultWidth;
- }
- $container.css({
- width: options.initialFrameWidth,
- zIndex: editor.getOpt('zIndex')
- });
- //ie6下缓存图片
- UM.browser.ie && UM.browser.version === 6 && document.execCommand("BackgroundImageCache", false, true);
- editor.render(id);
- //添加tooltip;
- $.eduitooltip && $.eduitooltip('attachTo', $("[data-original-title]", $container)).css('z-index', editor.getOpt('zIndex') + 1);
- $container.find('a').click(function (evt) {
- evt.preventDefault()
- });
- editor.fireEvent("afteruiready");
- }
- return editor;
- },
- createUI: function (id, editor) {
- var $editorCont = $(id),
- $container = $('<div class="edui-container"><div class="edui-editor-body"></div></div>').insertBefore($editorCont);
- editor.$container = $container;
- editor.container = $container[0];
- editor.$body = $editorCont;
- //修正在ie9+以上的版本中,自动长高收起时的,残影问题
- if (browser.ie && browser.ie9above) {
- var $span = $('<span style="padding:0;margin:0;height:0;width:0"></span>');
- $span.insertAfter($container);
- }
- //初始化注册的ui组件
- $.each(_editorUI, function (n, v) {
- var widget = v.call(editor, n);
- if (widget) {
- _cacheUI[n] = widget;
- }
- });
- $container.find('.edui-editor-body').append($editorCont).before(this.createToolbar(editor.options, editor));
- $container.find('.edui-toolbar').append($('<div class="edui-dialog-container"></div>'));
- return $container;
- },
- createToolbar: function (options, editor) {
- var $toolbar = $.eduitoolbar(), toolbar = $toolbar.edui();
- //创建下来菜单列表
- if (options.toolbar && options.toolbar.length) {
- var btns = [];
- $.each(options.toolbar, function (i, uiNames) {
- $.each(uiNames.split(/\s+/), function (index, name) {
- if (name == '|') {
- $.eduiseparator && btns.push($.eduiseparator());
- } else {
- var ui = _cacheUI[name];
- if (name == "fullscreen") {
- ui && btns.unshift(ui);
- } else {
- ui && btns.push(ui);
- }
- }
- });
- btns.length && toolbar.appendToBtnmenu(btns);
- });
- } else {
- $toolbar.find('.edui-btn-toolbar').remove()
- }
- return $toolbar;
- }
- })
- })();
- UM.registerUI('bold italic redo undo underline strikethrough superscript subscript insertorderedlist insertunorderedlist ' +
- 'cleardoc selectall link unlink print preview justifyleft justifycenter justifyright justifyfull removeformat horizontal drafts',
- function (name) {
- var me = this;
- var $btn = $.eduibutton({
- icon: name,
- click: function () {
- me.execCommand(name);
- },
- title: this.getLang('labelMap')[name] || ''
- });
- this.addListener('selectionchange', function () {
- var state = this.queryCommandState(name);
- $btn.edui().disabled(state == -1).active(state == 1)
- });
- return $btn;
- }
- );
- /**
- * 全屏组件
- */
- (function () {
- //状态缓存
- var STATUS_CACHE = {},
- //状态值列表
- STATUS_LIST = ['width', 'height', 'position', 'top', 'left', 'margin', 'padding', 'overflowX', 'overflowY'],
- CONTENT_AREA_STATUS = {},
- //页面状态
- DOCUMENT_STATUS = {},
- DOCUMENT_ELEMENT_STATUS = {},
- FULLSCREENS = {};
- UM.registerUI('fullscreen', function (name) {
- var me = this,
- $button = $.eduibutton({
- 'icon': 'fullscreen',
- 'title': (me.options.labelMap && me.options.labelMap[name]) || me.getLang("labelMap." + name),
- 'click': function () {
- //切换
- me.execCommand(name);
- UM.setTopEditor(me);
- }
- });
- me.addListener("selectionchange", function () {
- var state = this.queryCommandState(name);
- $button.edui().disabled(state == -1).active(state == 1);
- });
- //切换至全屏
- me.addListener('ready', function () {
- me.options.fullscreen && Fullscreen.getInstance(me).toggle();
- });
- return $button;
- });
- UM.commands['fullscreen'] = {
- execCommand: function (cmdName) {
- Fullscreen.getInstance(this).toggle();
- },
- queryCommandState: function (cmdName) {
- return this._edui_fullscreen_status;
- },
- notNeedUndo: 1
- };
- function Fullscreen(editor) {
- var me = this;
- if (!editor) {
- throw new Error('invalid params, notfound editor');
- }
- me.editor = editor;
- //记录初始化的全屏组件
- FULLSCREENS[editor.uid] = this;
- editor.addListener('destroy', function () {
- delete FULLSCREENS[editor.uid];
- me.editor = null;
- });
- }
- Fullscreen.prototype = {
- /**
- * 全屏状态切换
- */
- toggle: function () {
- var editor = this.editor,
- //当前编辑器的缩放状态
- _edui_fullscreen_status = this.isFullState();
- editor.fireEvent('beforefullscreenchange', !_edui_fullscreen_status);
- //更新状态
- this.update(!_edui_fullscreen_status);
- !_edui_fullscreen_status ? this.enlarge() : this.revert();
- editor.fireEvent('afterfullscreenchange', !_edui_fullscreen_status);
- if (editor.body.contentEditable === 'true') {
- editor.fireEvent('fullscreenchanged', !_edui_fullscreen_status);
- }
- editor.fireEvent('selectionchange');
- },
- /**
- * 执行放大
- */
- enlarge: function () {
- this.saveSataus();
- this.setDocumentStatus();
- this.resize();
- },
- /**
- * 全屏还原
- */
- revert: function () {
- //还原CSS表达式
- var options = this.editor.options,
- height = /%$/.test(options.initialFrameHeight) ? '100%' : (options.initialFrameHeight - this.getStyleValue("padding-top") - this.getStyleValue("padding-bottom") - this.getStyleValue('border-width'));
- $.IE6 && this.getEditorHolder().style.setExpression('height', 'this.scrollHeight <= ' + height + ' ? "' + height + 'px" : "auto"');
- //还原容器状态
- this.revertContainerStatus();
- this.revertContentAreaStatus();
- this.revertDocumentStatus();
- },
- /**
- * 更新状态
- * @param isFull 当前状态是否是全屏状态
- */
- update: function (isFull) {
- this.editor._edui_fullscreen_status = isFull;
- },
- /**
- * 调整当前编辑器的大小, 如果当前编辑器不处于全屏状态, 则不做调整
- */
- resize: function () {
- var $win = null,
- height = 0,
- width = 0,
- borderWidth = 0,
- paddingWidth = 0,
- editor = this.editor,
- me = this,
- bound = null,
- editorBody = null;
- if (!this.isFullState()) {
- return;
- }
- $win = $(window);
- width = $win.width();
- height = $win.height();
- editorBody = this.getEditorHolder();
- //文本编辑区border宽度
- borderWidth = parseInt(domUtils.getComputedStyle(editorBody, 'border-width'), 10) || 0;
- //容器border宽度
- borderWidth += parseInt(domUtils.getComputedStyle(editor.container, 'border-width'), 10) || 0;
- //容器padding
- paddingWidth += parseInt(domUtils.getComputedStyle(editorBody, 'padding-left'), 10) + parseInt(domUtils.getComputedStyle(editorBody, 'padding-right'), 10) || 0;
- //干掉css表达式
- $.IE6 && editorBody.style.setExpression('height', null);
- bound = this.getBound();
- $(editor.container).css({
- width: width + 'px',
- height: height + 'px',
- position: !$.IE6 ? 'fixed' : 'absolute',
- top: bound.top,
- left: bound.left,
- margin: 0,
- padding: 0,
- overflowX: 'hidden',
- overflowY: 'hidden'
- });
- $(editorBody).css({
- width: width - 2 * borderWidth - paddingWidth + 'px',
- height: height - 2 * borderWidth - (editor.options.withoutToolbar ? 0 : $('.edui-toolbar', editor.container).outerHeight()) - $('.edui-bottombar', editor.container).outerHeight() + 'px',
- overflowX: 'hidden',
- overflowY: 'auto'
- });
- },
- /**
- * 保存状态
- */
- saveSataus: function () {
- var styles = this.editor.container.style,
- tmp = null,
- cache = {};
- for (var i = 0, len = STATUS_LIST.length; i < len; i++) {
- tmp = STATUS_LIST[i];
- cache[tmp] = styles[tmp];
- }
- STATUS_CACHE[this.editor.uid] = cache;
- this.saveContentAreaStatus();
- this.saveDocumentStatus();
- },
- saveContentAreaStatus: function () {
- var $holder = $(this.getEditorHolder());
- CONTENT_AREA_STATUS[this.editor.uid] = {
- width: $holder.css("width"),
- overflowX: $holder.css("overflowX"),
- overflowY: $holder.css("overflowY"),
- height: $holder.css("height")
- };
- },
- /**
- * 保存与指定editor相关的页面的状态
- */
- saveDocumentStatus: function () {
- var $doc = $(this.getEditorDocumentBody());
- DOCUMENT_STATUS[this.editor.uid] = {
- overflowX: $doc.css('overflowX'),
- overflowY: $doc.css('overflowY')
- };
- DOCUMENT_ELEMENT_STATUS[this.editor.uid] = {
- overflowX: $(this.getEditorDocumentElement()).css('overflowX'),
- overflowY: $(this.getEditorDocumentElement()).css('overflowY')
- };
- },
- /**
- * 恢复容器状态
- */
- revertContainerStatus: function () {
- $(this.editor.container).css(this.getEditorStatus());
- },
- /**
- * 恢复编辑区状态
- */
- revertContentAreaStatus: function () {
- var holder = this.getEditorHolder(),
- state = this.getContentAreaStatus();
- if (this.supportMin()) {
- delete state.height;
- holder.style.height = null;
- }
- $(holder).css(state);
- },
- /**
- * 恢复页面状态
- */
- revertDocumentStatus: function () {
- var status = this.getDocumentStatus();
- $(this.getEditorDocumentBody()).css({overflowX: status.body.overflowX, overflowY: status.body.overflowY});
- $(this.getEditorDocumentElement()).css({overflowX: status.html.overflowX, overflowY: status.html.overflowY});
- },
- setDocumentStatus: function () {
- $(this.getEditorDocumentBody()).css({
- overflowX: 'hidden',
- overflowY: 'hidden'
- });
- $(this.getEditorDocumentElement()).css({
- overflowX: 'hidden',
- overflowY: 'hidden'
- });
- },
- /**
- * 检测当前编辑器是否处于全屏状态全屏状态
- * @returns {boolean} 是否处于全屏状态
- */
- isFullState: function () {
- return !!this.editor._edui_fullscreen_status;
- },
- /**
- * 获取编辑器状态
- */
- getEditorStatus: function () {
- return STATUS_CACHE[this.editor.uid];
- },
- getContentAreaStatus: function () {
- return CONTENT_AREA_STATUS[this.editor.uid];
- },
- getEditorDocumentElement: function () {
- return this.editor.container.ownerDocument.documentElement;
- },
- getEditorDocumentBody: function () {
- return this.editor.container.ownerDocument.body;
- },
- /**
- * 获取编辑区包裹对象
- */
- getEditorHolder: function () {
- return this.editor.body;
- },
- /**
- * 获取编辑器状态
- * @returns {*}
- */
- getDocumentStatus: function () {
- return {
- 'body': DOCUMENT_STATUS[this.editor.uid],
- 'html': DOCUMENT_ELEMENT_STATUS[this.editor.uid]
- };
- },
- supportMin: function () {
- var node = null;
- if (!this._support) {
- node = document.createElement("div");
- this._support = "minWidth" in node.style;
- node = null;
- }
- return this._support;
- },
- getBound: function () {
- var tags = {
- html: true,
- body: true
- },
- result = {
- top: 0,
- left: 0
- },
- offsetParent = null;
- if (!$.IE6) {
- return result;
- }
- offsetParent = this.editor.container.offsetParent;
- if (offsetParent && !tags[offsetParent.nodeName.toLowerCase()]) {
- tags = offsetParent.getBoundingClientRect();
- result.top = -tags.top;
- result.left = -tags.left;
- }
- return result;
- },
- getStyleValue: function (attr) {
- return parseInt(domUtils.getComputedStyle(this.getEditorHolder(), attr));
- }
- };
- $.extend(Fullscreen, {
- /**
- * 监听resize
- */
- listen: function () {
- var timer = null;
- if (Fullscreen._hasFullscreenListener) {
- return;
- }
- Fullscreen._hasFullscreenListener = true;
- $(window).on('resize', function () {
- if (timer !== null) {
- window.clearTimeout(timer);
- timer = null;
- }
- timer = window.setTimeout(function () {
- for (var key in FULLSCREENS) {
- FULLSCREENS[key].resize();
- }
- timer = null;
- }, 50);
- });
- },
- getInstance: function (editor) {
- if (!FULLSCREENS[editor.uid]) {
- new Fullscreen(editor);
- }
- return FULLSCREENS[editor.uid];
- }
- });
- //开始监听
- Fullscreen.listen();
- })();
- UM.registerUI('link image video map formula', function (name) {
- var me = this, currentRange, $dialog,
- opt = {
- title: (me.options.labelMap && me.options.labelMap[name]) || me.getLang("labelMap." + name),
- url: me.options.UMEDITOR_HOME_URL + 'dialogs/' + name + '/' + name + '.js'
- };
- var $btn = $.eduibutton({
- icon: name,
- title: this.getLang('labelMap')[name] || ''
- });
- //加载模版数据
- utils.loadFile(document, {
- src: opt.url,
- tag: "script",
- type: "text/javascript",
- defer: "defer"
- }, function () {
- //调整数据
- var data = UM.getWidgetData(name);
- if (!data) return;
- if (data.buttons) {
- var ok = data.buttons.ok;
- if (ok) {
- opt.oklabel = ok.label || me.getLang('ok');
- if (ok.exec) {
- opt.okFn = function () {
- return $.proxy(ok.exec, null, me, $dialog)()
- }
- }
- }
- var cancel = data.buttons.cancel;
- if (cancel) {
- opt.cancellabel = cancel.label || me.getLang('cancel');
- if (cancel.exec) {
- opt.cancelFn = function () {
- return $.proxy(cancel.exec, null, me, $dialog)()
- }
- }
- }
- }
- data.width && (opt.width = data.width);
- data.height && (opt.height = data.height);
- $dialog = $.eduimodal(opt);
- $dialog.attr('id', 'edui-dialog-' + name).addClass('edui-dialog-' + name)
- .find('.edui-modal-body').addClass('edui-dialog-' + name + '-body');
- $dialog.edui().on('beforehide', function () {
- var rng = me.selection.getRange();
- if (rng.equals(currentRange)) {
- rng.select()
- }
- }).on('beforeshow', function () {
- var $root = this.root(),
- win = null,
- offset = null;
- currentRange = me.selection.getRange();
- if (!$root.parent()[0]) {
- me.$container.find('.edui-dialog-container').append($root);
- }
- //IE6下 特殊处理, 通过计算进行定位
- if ($.IE6) {
- win = {
- width: $(window).width(),
- height: $(window).height()
- };
- offset = $root.parents(".edui-toolbar")[0].getBoundingClientRect();
- $root.css({
- position: 'absolute',
- margin: 0,
- left: (win.width - $root.width()) / 2 - offset.left,
- top: 100 - offset.top
- });
- }
- UM.setWidgetBody(name, $dialog, me);
- UM.setTopEditor(me);
- }).on('afterbackdrop', function () {
- this.$backdrop.css('zIndex', me.getOpt('zIndex') + 1).appendTo(me.$container.find('.edui-dialog-container'))
- $dialog.css('zIndex', me.getOpt('zIndex') + 2)
- }).on('beforeok', function () {
- try {
- currentRange.select()
- } catch (e) {
- }
- }).attachTo($btn)
- });
- me.addListener('selectionchange', function () {
- var state = this.queryCommandState(name);
- $btn.edui().disabled(state == -1).active(state == 1)
- });
- return $btn;
- });
- UM.registerUI('emotion formula', function (name) {
- var me = this,
- url = me.options.UMEDITOR_HOME_URL + 'dialogs/' + name + '/' + name + '.js';
- var $btn = $.eduibutton({
- icon: name,
- title: this.getLang('labelMap')[name] || ''
- });
- //加载模版数据
- utils.loadFile(document, {
- src: url,
- tag: "script",
- type: "text/javascript",
- defer: "defer"
- }, function () {
- var opt = {
- url: url
- };
- //调整数据
- var data = UM.getWidgetData(name);
- data.width && (opt.width = data.width);
- data.height && (opt.height = data.height);
- $.eduipopup(opt).css('zIndex', me.options.zIndex + 1)
- .addClass('edui-popup-' + name)
- .edui()
- .on('beforeshow', function () {
- var $root = this.root();
- if (!$root.parent().length) {
- me.$container.find('.edui-dialog-container').append($root);
- }
- UM.setWidgetBody(name, $root, me);
- UM.setTopEditor(me);
- }).attachTo($btn, {
- offsetTop: -5,
- offsetLeft: 10,
- caretLeft: 11,
- caretTop: -8
- });
- me.addListener('selectionchange', function () {
- var state = this.queryCommandState(name);
- $btn.edui().disabled(state == -1).active(state == 1);
- });
- });
- return $btn;
- });
- UM.registerUI('imagescale', function () {
- var me = this,
- $imagescale;
- me.setOpt('imageScaleEnabled', true);
- if (browser.webkit && me.getOpt('imageScaleEnabled')) {
- me.addListener('click', function (type, e) {
- var range = me.selection.getRange(),
- img = range.getClosedNode(),
- target = e.target;
- /* 点击第一个图片的后面,八个角不消失 fix:3652 */
- if (img && img.tagName == 'IMG' && target == img) {
- if (!$imagescale) {
- $imagescale = $.eduiscale({'$wrap': me.$container}).css('zIndex', me.options.zIndex);
- me.$container.append($imagescale);
- var _keyDownHandler = function () {
- $imagescale.edui().hide();
- }, _mouseDownHandler = function (e) {
- var ele = e.target || e.srcElement;
- if (ele && ele.className.indexOf('edui-scale') == -1) {
- _keyDownHandler(e);
- }
- }, timer;
- $imagescale.edui()
- .on('aftershow', function () {
- $(document).bind('keydown', _keyDownHandler);
- $(document).bind('mousedown', _mouseDownHandler);
- me.selection.getNative().removeAllRanges();
- })
- .on('afterhide', function () {
- $(document).unbind('keydown', _keyDownHandler);
- $(document).unbind('mousedown', _mouseDownHandler);
- var target = $imagescale.edui().getScaleTarget();
- if (target.parentNode) {
- me.selection.getRange().selectNode(target).select();
- }
- })
- .on('mousedown', function (e) {
- me.selection.getNative().removeAllRanges();
- var ele = e.target || e.srcElement;
- if (ele && ele.className.indexOf('edui-scale-hand') == -1) {
- timer = setTimeout(function () {
- $imagescale.edui().hide();
- }, 200);
- }
- })
- .on('mouseup', function (e) {
- var ele = e.target || e.srcElement;
- if (ele && ele.className.indexOf('edui-scale-hand') == -1) {
- clearTimeout(timer);
- }
- });
- }
- $imagescale.edui().show($(img));
- } else {
- if ($imagescale && $imagescale.css('display') != 'none') $imagescale.edui().hide();
- }
- });
- me.addListener('click', function (type, e) {
- if (e.target.tagName == 'IMG') {
- var range = new dom.Range(me.document, me.body);
- range.selectNode(e.target).select();
- }
- });
- }
- });
- UM.registerUI('autofloat', function () {
- var me = this,
- lang = me.getLang();
- me.setOpt({
- autoFloatEnabled: true,
- topOffset: 0
- });
- var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false,
- topOffset = me.options.topOffset;
- //如果不固定toolbar的位置,则直接退出
- if (!optsAutoFloatEnabled) {
- return;
- }
- me.ready(function () {
- var LteIE6 = browser.ie && browser.version <= 6,
- quirks = browser.quirks;
- function checkHasUI() {
- if (!UM.ui) {
- alert(lang.autofloatMsg);
- return 0;
- }
- return 1;
- }
- function fixIE6FixedPos() {
- var docStyle = document.body.style;
- docStyle.backgroundImage = 'url("about:blank")';
- docStyle.backgroundAttachment = 'fixed';
- }
- var bakCssText,
- placeHolder = document.createElement('div'),
- toolbarBox, orgTop,
- getPosition = function (element) {
- var bcr;
- //trace IE6下在控制编辑器显隐时可能会报错,catch一下
- try {
- bcr = element.getBoundingClientRect();
- } catch (e) {
- bcr = {left: 0, top: 0, height: 0, width: 0}
- }
- var rect = {
- left: Math.round(bcr.left),
- top: Math.round(bcr.top),
- height: Math.round(bcr.bottom - bcr.top),
- width: Math.round(bcr.right - bcr.left)
- };
- var doc;
- while ((doc = element.ownerDocument) !== document &&
- (element = domUtils.getWindow(doc).frameElement)) {
- bcr = element.getBoundingClientRect();
- rect.left += bcr.left;
- rect.top += bcr.top;
- }
- rect.bottom = rect.top + rect.height;
- rect.right = rect.left + rect.width;
- return rect;
- };
- var isFullScreening = false;
- function setFloating() {
- if (isFullScreening) {
- return;
- }
- var toobarBoxPos = domUtils.getXY(toolbarBox),
- origalFloat = domUtils.getComputedStyle(toolbarBox, 'position'),
- origalLeft = domUtils.getComputedStyle(toolbarBox, 'left');
- toolbarBox.style.width = toolbarBox.offsetWidth + 'px';
- toolbarBox.style.zIndex = me.options.zIndex * 1 + 1;
- toolbarBox.parentNode.insertBefore(placeHolder, toolbarBox);
- if (LteIE6 || (quirks && browser.ie)) {
- if (toolbarBox.style.position != 'absolute') {
- toolbarBox.style.position = 'absolute';
- }
- toolbarBox.style.top = (document.body.scrollTop || document.documentElement.scrollTop) - orgTop + topOffset + 'px';
- } else {
- if (toolbarBox.style.position != 'fixed') {
- toolbarBox.style.position = 'fixed';
- toolbarBox.style.top = topOffset + "px";
- ((origalFloat == 'absolute' || origalFloat == 'relative') && parseFloat(origalLeft)) && (toolbarBox.style.left = toobarBoxPos.x + 'px');
- }
- }
- }
- function unsetFloating() {
- if (placeHolder.parentNode) {
- placeHolder.parentNode.removeChild(placeHolder);
- }
- toolbarBox.style.cssText = bakCssText;
- }
- function updateFloating() {
- var rect3 = getPosition(me.container);
- var offset = me.options.toolbarTopOffset || 0;
- if (rect3.top < 0 && rect3.bottom - toolbarBox.offsetHeight > offset) {
- setFloating();
- } else {
- unsetFloating();
- }
- }
- var defer_updateFloating = utils.defer(function () {
- updateFloating();
- }, browser.ie ? 200 : 100, true);
- me.addListener('destroy', function () {
- $(window).off('scroll resize', updateFloating);
- me.removeListener('keydown', defer_updateFloating);
- });
- if (checkHasUI(me)) {
- toolbarBox = $('.edui-toolbar', me.container)[0];
- me.addListener("afteruiready", function () {
- setTimeout(function () {
- orgTop = $(toolbarBox).offset().top;
- }, 100);
- });
- bakCssText = toolbarBox.style.cssText;
- placeHolder.style.height = toolbarBox.offsetHeight + 'px';
- if (LteIE6) {
- fixIE6FixedPos();
- }
- $(window).on('scroll resize', updateFloating);
- me.addListener('keydown', defer_updateFloating);
- me.addListener('resize', function () {
- unsetFloating();
- placeHolder.style.height = toolbarBox.offsetHeight + 'px';
- updateFloating();
- });
- me.addListener('beforefullscreenchange', function (t, enabled) {
- if (enabled) {
- unsetFloating();
- isFullScreening = enabled;
- }
- });
- me.addListener('fullscreenchanged', function (t, enabled) {
- if (!enabled) {
- updateFloating();
- }
- isFullScreening = enabled;
- });
- me.addListener('sourcemodechanged', function (t, enabled) {
- setTimeout(function () {
- updateFloating();
- }, 0);
- });
- me.addListener("clearDoc", function () {
- setTimeout(function () {
- updateFloating();
- }, 0);
- })
- }
- })
- });
- UM.registerUI('source', function (name) {
- var me = this;
- me.addListener('fullscreenchanged', function () {
- me.$container.find('textarea').width(me.$body.width() - 10).height(me.$body.height())
- });
- var $btn = $.eduibutton({
- icon: name,
- click: function () {
- me.execCommand(name);
- UM.setTopEditor(me);
- },
- title: this.getLang('labelMap')[name] || ''
- });
- this.addListener('selectionchange', function () {
- var state = this.queryCommandState(name);
- $btn.edui().disabled(state == -1).active(state == 1)
- });
- return $btn;
- });
- UM.registerUI('paragraph fontfamily fontsize', function (name) {
- var me = this,
- label = (me.options.labelMap && me.options.labelMap[name]) || me.getLang("labelMap." + name),
- options = {
- label: label,
- title: label,
- comboboxName: name,
- items: me.options[name] || [],
- itemStyles: [],
- value: [],
- autowidthitem: []
- },
- $combox = null,
- comboboxWidget = null;
- if (options.items.length == 0) {
- return null;
- }
- switch (name) {
- case 'paragraph':
- options = transForParagraph(options);
- break;
- case 'fontfamily':
- options = transForFontfamily(options);
- break;
- case 'fontsize':
- options = transForFontsize(options);
- break;
- }
- //实例化
- $combox = $.eduibuttoncombobox(options).css('zIndex', me.getOpt('zIndex') + 1);
- comboboxWidget = $combox.edui();
- comboboxWidget.on('comboboxselect', function (evt, res) {
- me.execCommand(name, res.value);
- }).on("beforeshow", function () {
- if ($combox.parent().length === 0) {
- $combox.appendTo(me.$container.find('.edui-dialog-container'));
- }
- UM.setTopEditor(me);
- });
- //状态反射
- this.addListener('selectionchange', function (evt) {
- var state = this.queryCommandState(name),
- value = this.queryCommandValue(name);
- //设置按钮状态
- comboboxWidget.button().edui().disabled(state == -1).active(state == 1);
- if (value) {
- //设置label
- value = value.replace(/['"]/g, '').toLowerCase().split(/['|"]?\s*,\s*[\1]?/);
- comboboxWidget.selectItemByLabel(value);
- }
- });
- return comboboxWidget.button().addClass('edui-combobox');
- /**
- * 宽度自适应工具函数
- * @param word 单词内容
- * @param hasSuffix 是否含有后缀
- */
- function wordCountAdaptive(word, hasSuffix) {
- var $tmpNode = $('<span>').html(word).css({
- display: 'inline',
- position: 'absolute',
- top: -10000000,
- left: -100000
- }).appendTo(document.body),
- width = $tmpNode.width();
- $tmpNode.remove();
- $tmpNode = null;
- if (width < 50) {
- return word;
- } else {
- word = word.slice(0, hasSuffix ? -4 : -1);
- if (!word.length) {
- return '...';
- }
- return wordCountAdaptive(word + '...', true);
- }
- }
- //段落参数转换
- function transForParagraph(options) {
- var tempItems = [];
- for (var key in options.items) {
- options.value.push(key);
- tempItems.push(key);
- options.autowidthitem.push(wordCountAdaptive(key));
- }
- options.items = tempItems;
- options.autoRecord = false;
- return options;
- }
- //字体参数转换
- function transForFontfamily(options) {
- var temp = null,
- tempItems = [];
- for (var i = 0, len = options.items.length; i < len; i++) {
- temp = options.items[i].val;
- tempItems.push(temp.split(/\s*,\s*/)[0]);
- options.itemStyles.push('font-family: ' + temp);
- options.value.push(temp);
- options.autowidthitem.push(wordCountAdaptive(tempItems[i]));
- }
- options.items = tempItems;
- return options;
- }
- //字体大小参数转换
- function transForFontsize(options) {
- var temp = null,
- tempItems = [];
- options.itemStyles = [];
- options.value = [];
- for (var i = 0, len = options.items.length; i < len; i++) {
- temp = options.items[i];
- tempItems.push(temp);
- options.itemStyles.push('font-size: ' + temp + 'px');
- }
- options.value = options.items;
- options.items = tempItems;
- options.autoRecord = false;
- return options;
- }
- });
- UM.registerUI('forecolor backcolor', function (name) {
- function getCurrentColor() {
- return domUtils.getComputedStyle($colorLabel[0], 'background-color');
- }
- var me = this,
- $colorPickerWidget = null,
- $colorLabel = null,
- $btn = null;
- //querycommand
- this.addListener('selectionchange', function () {
- var state = this.queryCommandState(name);
- $btn.edui().disabled(state == -1).active(state == 1);
- });
- $btn = $.eduicolorsplitbutton({
- icon: name,
- caret: true,
- name: name,
- title: me.getLang("labelMap")[name],
- click: function () {
- me.execCommand(name, getCurrentColor());
- }
- });
- $colorLabel = $btn.edui().colorLabel();
- $colorPickerWidget = $.eduicolorpicker({
- name: name,
- lang_clearColor: me.getLang('clearColor') || '',
- lang_themeColor: me.getLang('themeColor') || '',
- lang_standardColor: me.getLang('standardColor') || ''
- })
- .on('pickcolor', function (evt, color) {
- window.setTimeout(function () {
- $colorLabel.css("backgroundColor", color);
- me.execCommand(name, color);
- }, 0);
- })
- .on('show', function () {
- UM.setActiveWidget(colorPickerWidget.root());
- }).css('zIndex', me.getOpt('zIndex') + 1);
- $btn.edui().on('arrowclick', function () {
- if (!$colorPickerWidget.parent().length) {
- me.$container.find('.edui-dialog-container').append($colorPickerWidget);
- }
- $colorPickerWidget.edui().show($btn, {
- caretDir: "down",
- offsetTop: -5,
- offsetLeft: 8,
- caretLeft: 11,
- caretTop: -8
- });
- UM.setTopEditor(me);
- }).register('click', $btn, function () {
- $colorPickerWidget.edui().hide()
- });
- return $btn;
- });
- })(jQuery)
|