ueditor.all.min.js 1.0 MB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837288382883928840288412884228843288442884528846288472884828849288502885128852288532885428855288562885728858288592886028861288622886328864288652886628867288682886928870288712887228873288742887528876288772887828879288802888128882288832888428885288862888728888288892889028891288922889328894288952889628897288982889928900289012890228903289042890528906289072890828909289102891128912289132891428915289162891728918289192892028921289222892328924289252892628927289282892928930289312893228933289342893528936289372893828939289402894128942289432894428945289462894728948289492895028951289522895328954289552895628957289582895928960289612896228963289642896528966289672896828969289702897128972289732897428975289762897728978289792898028981289822898328984289852898628987289882898928990289912899228993289942899528996289972899828999290002900129002290032900429005290062900729008290092901029011290122901329014290152901629017290182901929020290212902229023290242902529026290272902829029290302903129032290332903429035290362903729038290392904029041290422904329044290452904629047290482904929050290512905229053290542905529056290572905829059290602906129062290632906429065290662906729068290692907029071290722907329074290752907629077290782907929080290812908229083290842908529086290872908829089290902909129092290932909429095290962909729098290992910029101291022910329104291052910629107291082910929110291112911229113291142911529116291172911829119291202912129122291232912429125291262912729128291292913029131291322913329134291352913629137291382913929140291412914229143291442914529146291472914829149291502915129152291532915429155291562915729158291592916029161291622916329164291652916629167291682916929170291712917229173291742917529176291772917829179291802918129182291832918429185291862918729188291892919029191291922919329194291952919629197291982919929200292012920229203292042920529206292072920829209292102921129212292132921429215292162921729218292192922029221292222922329224292252922629227292282922929230292312923229233292342923529236292372923829239292402924129242292432924429245292462924729248292492925029251292522925329254292552925629257292582925929260292612926229263292642926529266292672926829269292702927129272292732927429275292762927729278292792928029281292822928329284292852928629287292882928929290292912929229293292942929529296292972929829299293002930129302293032930429305293062930729308293092931029311293122931329314293152931629317293182931929320293212932229323293242932529326293272932829329293302933129332293332933429335293362933729338293392934029341293422934329344293452934629347293482934929350293512935229353293542935529356293572935829359293602936129362293632936429365293662936729368293692937029371293722937329374293752937629377293782937929380293812938229383293842938529386293872938829389293902939129392293932939429395293962939729398293992940029401294022940329404294052940629407294082940929410294112941229413294142941529416294172941829419294202942129422294232942429425294262942729428294292943029431294322943329434294352943629437294382943929440294412944229443294442944529446294472944829449294502945129452294532945429455294562945729458294592946029461294622946329464294652946629467294682946929470294712947229473294742947529476294772947829479294802948129482294832948429485294862948729488294892949029491294922949329494294952949629497294982949929500295012950229503295042950529506295072950829509295102951129512295132951429515295162951729518295192952029521295222952329524295252952629527295282952929530295312953229533295342953529536295372953829539295402954129542295432954429545295462954729548295492955029551295522955329554295552955629557295582955929560295612956229563295642956529566295672956829569295702957129572295732957429575295762957729578295792958029581295822958329584295852958629587295882958929590295912959229593295942959529596295972959829599296002960129602296032960429605296062960729608296092961029611296122961329614296152961629617296182961929620296212962229623296242962529626296272962829629296302963129632296332963429635296362963729638296392964029641296422964329644296452964629647296482964929650296512965229653296542965529656296572965829659296602966129662296632966429665296662966729668296692967029671296722967329674296752967629677296782967929680296812968229683296842968529686296872968829689296902969129692296932969429695296962969729698296992970029701297022970329704297052970629707297082970929710297112971229713297142971529716297172971829719297202972129722297232972429725297262972729728297292973029731297322973329734297352973629737297382973929740297412974229743297442974529746297472974829749297502975129752297532975429755297562975729758297592976029761297622976329764297652976629767297682976929770297712977229773297742977529776297772977829779297802978129782297832978429785297862978729788297892979029791297922979329794297952979629797297982979929800298012980229803298042980529806298072980829809298102981129812298132981429815298162981729818298192982029821298222982329824298252982629827298282982929830298312983229833298342983529836298372983829839298402984129842298432984429845298462984729848298492985029851298522985329854298552985629857298582985929860298612986229863298642986529866298672986829869298702987129872298732987429875298762987729878298792988029881298822988329884298852988629887298882988929890298912989229893298942989529896298972989829899299002990129902299032990429905299062990729908299092991029911299122991329914299152991629917299182991929920299212992229923299242992529926299272992829929299302993129932299332993429935299362993729938299392994029941299422994329944299452994629947299482994929950299512995229953299542995529956299572995829959299602996129962299632996429965299662996729968299692997029971299722997329974299752997629977299782997929980299812998229983299842998529986299872998829989299902999129992299932999429995299962999729998299993000030001300023000330004300053000630007300083000930010300113001230013300143001530016300173001830019300203002130022300233002430025300263002730028300293003030031300323003330034300353003630037300383003930040300413004230043300443004530046300473004830049300503005130052300533005430055300563005730058300593006030061300623006330064300653006630067300683006930070300713007230073300743007530076300773007830079300803008130082300833008430085300863008730088300893009030091300923009330094300953009630097300983009930100301013010230103301043010530106301073010830109301103011130112301133011430115301163011730118301193012030121301223012330124301253012630127301283012930130301313013230133301343013530136301373013830139301403014130142301433014430145301463014730148301493015030151301523015330154301553015630157301583015930160301613016230163301643016530166301673016830169301703017130172301733017430175301763017730178301793018030181301823018330184301853018630187301883018930190301913019230193301943019530196301973019830199302003020130202302033020430205302063020730208302093021030211302123021330214302153021630217302183021930220302213022230223302243022530226302273022830229302303023130232302333023430235302363023730238302393024030241302423024330244302453024630247302483024930250302513025230253302543025530256302573025830259302603026130262302633026430265302663026730268302693027030271302723027330274302753027630277302783027930280302813028230283302843028530286302873028830289302903029130292302933029430295302963029730298302993030030301303023030330304303053030630307303083030930310303113031230313303143031530316303173031830319303203032130322303233032430325303263032730328303293033030331303323033330334303353033630337303383033930340303413034230343303443034530346303473034830349303503035130352303533035430355303563035730358303593036030361303623036330364303653036630367303683036930370303713037230373303743037530376303773037830379303803038130382303833038430385303863038730388303893039030391303923039330394303953039630397303983039930400304013040230403304043040530406304073040830409304103041130412304133041430415304163041730418304193042030421304223042330424304253042630427304283042930430304313043230433304343043530436304373043830439304403044130442304433044430445304463044730448304493045030451304523045330454304553045630457304583045930460304613046230463304643046530466304673046830469304703047130472304733047430475304763047730478304793048030481304823048330484304853048630487304883048930490304913049230493304943049530496304973049830499305003050130502305033050430505305063050730508305093051030511305123051330514305153051630517305183051930520305213052230523305243052530526305273052830529305303053130532305333053430535305363053730538305393054030541305423054330544305453054630547305483054930550305513055230553305543055530556305573055830559305603056130562305633056430565305663056730568305693057030571305723057330574305753057630577305783057930580305813058230583305843058530586305873058830589305903059130592305933059430595305963059730598305993060030601306023060330604306053060630607306083060930610306113061230613306143061530616306173061830619306203062130622306233062430625306263062730628306293063030631306323063330634306353063630637306383063930640306413064230643306443064530646306473064830649306503065130652306533065430655306563065730658306593066030661306623066330664306653066630667306683066930670306713067230673306743067530676306773067830679306803068130682306833068430685306863068730688306893069030691306923069330694306953069630697306983069930700307013070230703307043070530706307073070830709307103071130712307133071430715307163071730718307193072030721307223072330724307253072630727307283072930730307313073230733307343073530736307373073830739307403074130742307433074430745307463074730748307493075030751307523075330754307553075630757307583075930760307613076230763307643076530766307673076830769307703077130772307733077430775307763077730778307793078030781307823078330784307853078630787307883078930790307913079230793307943079530796307973079830799308003080130802308033080430805308063080730808308093081030811308123081330814308153081630817308183081930820308213082230823308243082530826308273082830829308303083130832308333083430835308363083730838308393084030841308423084330844308453084630847308483084930850308513085230853308543085530856308573085830859308603086130862308633086430865308663086730868308693087030871308723087330874308753087630877308783087930880308813088230883308843088530886308873088830889308903089130892308933089430895308963089730898308993090030901309023090330904309053090630907309083090930910309113091230913309143091530916309173091830919309203092130922309233092430925309263092730928309293093030931309323093330934309353093630937309383093930940309413094230943309443094530946309473094830949309503095130952309533095430955309563095730958309593096030961309623096330964309653096630967309683096930970309713097230973309743097530976309773097830979309803098130982309833098430985309863098730988309893099030991309923099330994309953099630997309983099931000310013100231003310043100531006310073100831009310103101131012310133101431015310163101731018310193102031021310223102331024310253102631027310283102931030310313103231033310343103531036310373103831039310403104131042310433104431045310463104731048310493105031051310523105331054310553105631057310583105931060310613106231063310643106531066310673106831069310703107131072310733107431075310763107731078310793108031081310823108331084310853108631087310883108931090310913109231093310943109531096310973109831099311003110131102311033110431105311063110731108311093111031111311123111331114311153111631117311183111931120311213112231123311243112531126311273112831129311303113131132311333113431135311363113731138311393114031141311423114331144311453114631147311483114931150311513115231153311543115531156311573115831159311603116131162311633116431165311663116731168311693117031171311723117331174311753117631177311783117931180311813118231183311843118531186311873118831189311903119131192311933119431195311963119731198311993120031201312023120331204312053120631207312083120931210312113121231213312143121531216312173121831219312203122131222312233122431225312263122731228312293123031231312323123331234312353123631237312383123931240312413124231243312443124531246312473124831249312503125131252312533125431255312563125731258312593126031261312623126331264312653126631267312683126931270312713127231273312743127531276312773127831279312803128131282312833128431285312863128731288312893129031291312923129331294312953129631297312983129931300313013130231303313043130531306313073130831309313103131131312313133131431315313163131731318313193132031321313223132331324313253132631327313283132931330313313133231333313343133531336313373133831339313403134131342313433134431345313463134731348313493135031351313523135331354313553135631357313583135931360313613136231363313643136531366313673136831369313703137131372313733137431375313763137731378313793138031381313823138331384313853138631387313883138931390313913139231393313943139531396313973139831399314003140131402314033140431405314063140731408314093141031411314123141331414314153141631417314183141931420314213142231423314243142531426314273142831429314303143131432314333143431435314363143731438314393144031441314423144331444314453144631447314483144931450314513145231453314543145531456314573145831459314603146131462314633146431465314663146731468314693147031471314723147331474314753147631477314783147931480314813148231483314843148531486314873148831489314903149131492314933149431495314963149731498314993150031501315023150331504315053150631507315083150931510315113151231513315143151531516315173151831519315203152131522315233152431525315263152731528315293153031531315323153331534315353153631537315383153931540315413154231543315443154531546315473154831549315503155131552315533155431555315563155731558315593156031561315623156331564315653156631567315683156931570315713157231573315743157531576315773157831579315803158131582315833158431585315863158731588315893159031591315923159331594315953159631597315983159931600316013160231603316043160531606316073160831609316103161131612316133161431615316163161731618316193162031621316223162331624316253162631627316283162931630316313163231633316343163531636316373163831639316403164131642316433164431645316463164731648316493165031651316523165331654316553165631657316583165931660316613166231663316643166531666316673166831669316703167131672316733167431675316763167731678316793168031681316823168331684316853168631687316883168931690316913169231693316943169531696316973169831699317003170131702317033170431705317063170731708317093171031711317123171331714317153171631717317183171931720317213172231723317243172531726317273172831729317303173131732317333173431735317363173731738317393174031741317423174331744317453174631747317483174931750317513175231753317543175531756317573175831759317603176131762317633176431765317663176731768317693177031771317723177331774317753177631777317783177931780317813178231783317843178531786317873178831789317903179131792317933179431795317963179731798317993180031801318023180331804318053180631807318083180931810318113181231813318143181531816318173181831819318203182131822318233182431825318263182731828318293183031831318323183331834318353183631837318383183931840318413184231843318443184531846318473184831849318503185131852318533185431855318563185731858318593186031861318623186331864318653186631867318683186931870318713187231873318743187531876318773187831879318803188131882318833188431885318863188731888318893189031891318923189331894318953189631897318983189931900319013190231903319043190531906319073190831909319103191131912319133191431915319163191731918319193192031921319223192331924319253192631927319283192931930319313193231933319343193531936319373193831939319403194131942319433194431945319463194731948319493195031951319523195331954319553195631957319583195931960319613196231963319643196531966319673196831969319703197131972319733197431975319763197731978319793198031981319823198331984319853198631987319883198931990319913199231993319943199531996319973199831999320003200132002320033200432005320063200732008320093201032011320123201332014320153201632017320183201932020320213202232023320243202532026320273202832029320303203132032320333203432035320363203732038320393204032041320423204332044320453204632047320483204932050320513205232053320543205532056320573205832059320603206132062320633206432065320663206732068320693207032071320723207332074320753207632077320783207932080320813208232083320843208532086320873208832089320903209132092320933209432095320963209732098320993210032101321023210332104321053210632107321083210932110321113211232113321143211532116321173211832119321203212132122321233212432125321263212732128321293213032131321323213332134321353213632137321383213932140321413214232143321443214532146321473214832149321503215132152321533215432155321563215732158321593216032161321623216332164321653216632167321683216932170321713217232173321743217532176321773217832179321803218132182321833218432185321863218732188321893219032191321923219332194321953219632197321983219932200322013220232203322043220532206322073220832209322103221132212322133221432215322163221732218322193222032221322223222332224322253222632227322283222932230322313223232233322343223532236322373223832239322403224132242322433224432245322463224732248322493225032251322523225332254322553225632257322583225932260322613226232263322643226532266322673226832269322703227132272322733227432275322763227732278322793228032281322823228332284322853228632287322883228932290322913229232293322943229532296322973229832299323003230132302323033230432305323063230732308323093231032311323123231332314323153231632317323183231932320323213232232323323243232532326323273232832329323303233132332323333233432335323363233732338323393234032341323423234332344323453234632347323483234932350323513235232353323543235532356323573235832359323603236132362323633236432365323663236732368323693237032371323723237332374323753237632377323783237932380323813238232383323843238532386323873238832389323903239132392323933239432395323963239732398323993240032401324023240332404324053240632407324083240932410324113241232413324143241532416324173241832419324203242132422324233242432425324263242732428324293243032431324323243332434324353243632437324383243932440324413244232443324443244532446324473244832449324503245132452324533245432455324563245732458324593246032461324623246332464324653246632467324683246932470324713247232473324743247532476324773247832479324803248132482324833248432485324863248732488324893249032491324923249332494324953249632497324983249932500325013250232503325043250532506325073250832509325103251132512325133251432515325163251732518325193252032521325223252332524325253252632527325283252932530325313253232533325343253532536325373253832539325403254132542325433254432545325463254732548325493255032551325523255332554325553255632557325583255932560325613256232563325643256532566325673256832569325703257132572325733257432575325763257732578325793258032581325823258332584325853258632587325883258932590325913259232593325943259532596325973259832599326003260132602326033260432605326063260732608326093261032611326123261332614326153261632617326183261932620326213262232623326243262532626326273262832629326303263132632326333263432635326363263732638326393264032641326423264332644326453264632647326483264932650326513265232653326543265532656326573265832659326603266132662326633266432665326663266732668326693267032671326723267332674326753267632677326783267932680326813268232683326843268532686326873268832689326903269132692326933269432695326963269732698326993270032701327023270332704327053270632707327083270932710327113271232713327143271532716327173271832719327203272132722327233272432725327263272732728327293273032731327323273332734327353273632737327383273932740327413274232743327443274532746327473274832749327503275132752327533275432755327563275732758327593276032761327623276332764327653276632767327683276932770327713277232773327743277532776327773277832779327803278132782327833278432785327863278732788327893279032791327923279332794327953279632797327983279932800328013280232803328043280532806328073280832809328103281132812328133281432815328163281732818328193282032821328223282332824328253282632827328283282932830328313283232833328343283532836328373283832839328403284132842328433284432845328463284732848328493285032851328523285332854328553285632857328583285932860328613286232863328643286532866328673286832869328703287132872328733287432875328763287732878328793288032881328823288332884328853288632887328883288932890328913289232893328943289532896328973289832899329003290132902329033290432905329063290732908329093291032911329123291332914329153291632917329183291932920329213292232923329243292532926329273292832929329303293132932329333293432935329363293732938329393294032941329423294332944329453294632947329483294932950329513295232953329543295532956329573295832959329603296132962329633296432965329663296732968329693297032971329723297332974329753297632977329783297932980329813298232983329843298532986329873298832989329903299132992329933299432995329963299732998329993300033001330023300333004330053300633007330083300933010330113301233013330143301533016330173301833019330203302133022330233302433025330263302733028330293303033031330323303333034330353303633037330383303933040330413304233043330443304533046330473304833049330503305133052330533305433055330563305733058330593306033061330623306333064330653306633067330683306933070330713307233073330743307533076330773307833079330803308133082330833308433085330863308733088330893309033091330923309333094330953309633097330983309933100331013310233103331043310533106331073310833109331103311133112331133311433115331163311733118331193312033121331223312333124331253312633127331283312933130331313313233133331343313533136331373313833139331403314133142331433314433145331463314733148331493315033151331523315333154331553315633157331583315933160331613316233163331643316533166331673316833169331703317133172331733317433175331763317733178331793318033181331823318333184331853318633187331883318933190331913319233193331943319533196331973319833199332003320133202332033320433205332063320733208332093321033211332123321333214332153321633217332183321933220332213322233223332243322533226332273322833229332303323133232332333323433235332363323733238332393324033241332423324333244
  1. /*!
  2. * UEditor
  3. * version: ueditor
  4. * build: Wed Dec 26 2018 17:25:05 GMT+0800 (CST)
  5. */
  6. ;(function () {
  7. // editor.js
  8. UEDITOR_CONFIG = window.UEDITOR_CONFIG || {}
  9. var baidu = window.baidu || {}
  10. window.baidu = baidu
  11. window.UE = baidu.editor = window.UE || {}
  12. UE.plugins = {}
  13. UE.commands = {}
  14. UE.instants = {}
  15. UE.I18N = {}
  16. UE._customizeUI = {}
  17. UE.version = '1.4.3'
  18. var dom = (UE.dom = {})
  19. // core/browser.js
  20. /**
  21. * 浏览器判断模块
  22. * @file
  23. * @module UE.browser
  24. * @since 1.2.6.1
  25. */
  26. /**
  27. * 提供浏览器检测的模块
  28. * @unfile
  29. * @module UE.browser
  30. */
  31. var browser = (UE.browser = (function () {
  32. var agent = navigator.userAgent.toLowerCase(),
  33. opera = window.opera,
  34. browser = {
  35. /**
  36. * @property {boolean} ie 检测当前浏览器是否为IE
  37. * @example
  38. * ```javascript
  39. * if ( UE.browser.ie ) {
  40. * console.log( '当前浏览器是IE' );
  41. * }
  42. * ```
  43. */
  44. ie: /(msie\s|trident.*rv:)([\w.]+)/.test(agent),
  45. /**
  46. * @property {boolean} opera 检测当前浏览器是否为Opera
  47. * @example
  48. * ```javascript
  49. * if ( UE.browser.opera ) {
  50. * console.log( '当前浏览器是Opera' );
  51. * }
  52. * ```
  53. */
  54. opera: !!opera && opera.version,
  55. /**
  56. * @property {boolean} webkit 检测当前浏览器是否是webkit内核的浏览器
  57. * @example
  58. * ```javascript
  59. * if ( UE.browser.webkit ) {
  60. * console.log( '当前浏览器是webkit内核浏览器' );
  61. * }
  62. * ```
  63. */
  64. webkit: agent.indexOf(' applewebkit/') > -1,
  65. /**
  66. * @property {boolean} mac 检测当前浏览器是否是运行在mac平台下
  67. * @example
  68. * ```javascript
  69. * if ( UE.browser.mac ) {
  70. * console.log( '当前浏览器运行在mac平台下' );
  71. * }
  72. * ```
  73. */
  74. mac: agent.indexOf('macintosh') > -1,
  75. /**
  76. * @property {boolean} quirks 检测当前浏览器是否处于“怪异模式”下
  77. * @example
  78. * ```javascript
  79. * if ( UE.browser.quirks ) {
  80. * console.log( '当前浏览器运行处于“怪异模式”' );
  81. * }
  82. * ```
  83. */
  84. quirks: document.compatMode == 'BackCompat',
  85. }
  86. /**
  87. * @property {boolean} gecko 检测当前浏览器内核是否是gecko内核
  88. * @example
  89. * ```javascript
  90. * if ( UE.browser.gecko ) {
  91. * console.log( '当前浏览器内核是gecko内核' );
  92. * }
  93. * ```
  94. */
  95. browser.gecko =
  96. navigator.product == 'Gecko' &&
  97. !browser.webkit &&
  98. !browser.opera &&
  99. !browser.ie
  100. var version = 0
  101. // Internet Explorer 6.0+
  102. if (browser.ie) {
  103. var v1 = agent.match(/(?:msie\s([\w.]+))/)
  104. var v2 = agent.match(/(?:trident.*rv:([\w.]+))/)
  105. if (v1 && v2 && v1[1] && v2[1]) {
  106. version = Math.max(v1[1] * 1, v2[1] * 1)
  107. } else if (v1 && v1[1]) {
  108. version = v1[1] * 1
  109. } else if (v2 && v2[1]) {
  110. version = v2[1] * 1
  111. } else {
  112. version = 0
  113. }
  114. browser.ie11Compat = document.documentMode == 11
  115. /**
  116. * @property { boolean } ie9Compat 检测浏览器模式是否为 IE9 兼容模式
  117. * @warning 如果浏览器不是IE, 则该值为undefined
  118. * @example
  119. * ```javascript
  120. * if ( UE.browser.ie9Compat ) {
  121. * console.log( '当前浏览器运行在IE9兼容模式下' );
  122. * }
  123. * ```
  124. */
  125. browser.ie9Compat = document.documentMode == 9
  126. /**
  127. * @property { boolean } ie8 检测浏览器是否是IE8浏览器
  128. * @warning 如果浏览器不是IE, 则该值为undefined
  129. * @example
  130. * ```javascript
  131. * if ( UE.browser.ie8 ) {
  132. * console.log( '当前浏览器是IE8浏览器' );
  133. * }
  134. * ```
  135. */
  136. browser.ie8 = !!document.documentMode
  137. /**
  138. * @property { boolean } ie8Compat 检测浏览器模式是否为 IE8 兼容模式
  139. * @warning 如果浏览器不是IE, 则该值为undefined
  140. * @example
  141. * ```javascript
  142. * if ( UE.browser.ie8Compat ) {
  143. * console.log( '当前浏览器运行在IE8兼容模式下' );
  144. * }
  145. * ```
  146. */
  147. browser.ie8Compat = document.documentMode == 8
  148. /**
  149. * @property { boolean } ie7Compat 检测浏览器模式是否为 IE7 兼容模式
  150. * @warning 如果浏览器不是IE, 则该值为undefined
  151. * @example
  152. * ```javascript
  153. * if ( UE.browser.ie7Compat ) {
  154. * console.log( '当前浏览器运行在IE7兼容模式下' );
  155. * }
  156. * ```
  157. */
  158. browser.ie7Compat =
  159. (version == 7 && !document.documentMode) || document.documentMode == 7
  160. /**
  161. * @property { boolean } ie6Compat 检测浏览器模式是否为 IE6 模式 或者怪异模式
  162. * @warning 如果浏览器不是IE, 则该值为undefined
  163. * @example
  164. * ```javascript
  165. * if ( UE.browser.ie6Compat ) {
  166. * console.log( '当前浏览器运行在IE6模式或者怪异模式下' );
  167. * }
  168. * ```
  169. */
  170. browser.ie6Compat = version < 7 || browser.quirks
  171. browser.ie9above = version > 8
  172. browser.ie9below = version < 9
  173. browser.ie11above = version > 10
  174. browser.ie11below = version < 11
  175. }
  176. // Gecko.
  177. if (browser.gecko) {
  178. var geckoRelease = agent.match(/rv:([\d\.]+)/)
  179. if (geckoRelease) {
  180. geckoRelease = geckoRelease[1].split('.')
  181. version =
  182. geckoRelease[0] * 10000 +
  183. (geckoRelease[1] || 0) * 100 +
  184. (geckoRelease[2] || 0) * 1
  185. }
  186. }
  187. /**
  188. * @property { Number } chrome 检测当前浏览器是否为Chrome, 如果是,则返回Chrome的大版本号
  189. * @warning 如果浏览器不是chrome, 则该值为undefined
  190. * @example
  191. * ```javascript
  192. * if ( UE.browser.chrome ) {
  193. * console.log( '当前浏览器是Chrome' );
  194. * }
  195. * ```
  196. */
  197. if (/chrome\/(\d+\.\d)/i.test(agent)) {
  198. browser.chrome = +RegExp['\x241']
  199. }
  200. /**
  201. * @property { Number } safari 检测当前浏览器是否为Safari, 如果是,则返回Safari的大版本号
  202. * @warning 如果浏览器不是safari, 则该值为undefined
  203. * @example
  204. * ```javascript
  205. * if ( UE.browser.safari ) {
  206. * console.log( '当前浏览器是Safari' );
  207. * }
  208. * ```
  209. */
  210. if (
  211. /(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(agent) &&
  212. !/chrome/i.test(agent)
  213. ) {
  214. browser.safari = +(RegExp['\x241'] || RegExp['\x242'])
  215. }
  216. // Opera 9.50+
  217. if (browser.opera) version = parseFloat(opera.version())
  218. // WebKit 522+ (Safari 3+)
  219. if (browser.webkit)
  220. version = parseFloat(agent.match(/ applewebkit\/(\d+)/)[1])
  221. /**
  222. * @property { Number } version 检测当前浏览器版本号
  223. * @remind
  224. * <ul>
  225. * <li>IE系列返回值为5,6,7,8,9,10等</li>
  226. * <li>gecko系列会返回10900,158900等</li>
  227. * <li>webkit系列会返回其build号 (如 522等)</li>
  228. * </ul>
  229. * @example
  230. * ```javascript
  231. * console.log( '当前浏览器版本号是: ' + UE.browser.version );
  232. * ```
  233. */
  234. browser.version = version
  235. /**
  236. * @property { boolean } isCompatible 检测当前浏览器是否能够与UEditor良好兼容
  237. * @example
  238. * ```javascript
  239. * if ( UE.browser.isCompatible ) {
  240. * console.log( '浏览器与UEditor能够良好兼容' );
  241. * }
  242. * ```
  243. */
  244. browser.isCompatible =
  245. !browser.mobile &&
  246. ((browser.ie && version >= 6) ||
  247. (browser.gecko && version >= 10801) ||
  248. (browser.opera && version >= 9.5) ||
  249. (browser.air && version >= 1) ||
  250. (browser.webkit && version >= 522) ||
  251. false)
  252. return browser
  253. })())
  254. //快捷方式
  255. var ie = browser.ie,
  256. webkit = browser.webkit,
  257. gecko = browser.gecko,
  258. opera = browser.opera
  259. // core/utils.js
  260. /**
  261. * 工具函数包
  262. * @file
  263. * @module UE.utils
  264. * @since 1.2.6.1
  265. */
  266. /**
  267. * UEditor封装使用的静态工具函数
  268. * @module UE.utils
  269. * @unfile
  270. */
  271. var utils = (UE.utils = {
  272. /**
  273. * 用给定的迭代器遍历对象
  274. * @method each
  275. * @param { Object } obj 需要遍历的对象
  276. * @param { Function } iterator 迭代器, 该方法接受两个参数, 第一个参数是当前所处理的value, 第二个参数是当前遍历对象的key
  277. * @example
  278. * ```javascript
  279. * var demoObj = {
  280. * key1: 1,
  281. * key2: 2
  282. * };
  283. *
  284. * //output: key1: 1, key2: 2
  285. * UE.utils.each( demoObj, funciton ( value, key ) {
  286. *
  287. * console.log( key + ":" + value );
  288. *
  289. * } );
  290. * ```
  291. */
  292. /**
  293. * 用给定的迭代器遍历数组或类数组对象
  294. * @method each
  295. * @param { Array } array 需要遍历的数组或者类数组
  296. * @param { Function } iterator 迭代器, 该方法接受两个参数, 第一个参数是当前所处理的value, 第二个参数是当前遍历对象的key
  297. * @example
  298. * ```javascript
  299. * var divs = document.getElmentByTagNames( "div" );
  300. *
  301. * //output: 0: DIV, 1: DIV ...
  302. * UE.utils.each( divs, funciton ( value, key ) {
  303. *
  304. * console.log( key + ":" + value.tagName );
  305. *
  306. * } );
  307. * ```
  308. */
  309. each: function (obj, iterator, context) {
  310. if (obj == null) return
  311. if (obj.length === +obj.length) {
  312. for (var i = 0, l = obj.length; i < l; i++) {
  313. if (iterator.call(context, obj[i], i, obj) === false) return false
  314. }
  315. } else {
  316. for (var key in obj) {
  317. if (obj.hasOwnProperty(key)) {
  318. if (iterator.call(context, obj[key], key, obj) === false)
  319. return false
  320. }
  321. }
  322. }
  323. },
  324. /**
  325. * 以给定对象作为原型创建一个新对象
  326. * @method makeInstance
  327. * @param { Object } protoObject 该对象将作为新创建对象的原型
  328. * @return { Object } 新的对象, 该对象的原型是给定的protoObject对象
  329. * @example
  330. * ```javascript
  331. *
  332. * var protoObject = { sayHello: function () { console.log('Hello UEditor!'); } };
  333. *
  334. * var newObject = UE.utils.makeInstance( protoObject );
  335. * //output: Hello UEditor!
  336. * newObject.sayHello();
  337. * ```
  338. */
  339. makeInstance: function (obj) {
  340. var noop = new Function()
  341. noop.prototype = obj
  342. obj = new noop()
  343. noop.prototype = null
  344. return obj
  345. },
  346. /**
  347. * 将source对象中的属性扩展到target对象上
  348. * @method extend
  349. * @remind 该方法将强制把source对象上的属性复制到target对象上
  350. * @see UE.utils.extend(Object,Object,Boolean)
  351. * @param { Object } target 目标对象, 新的属性将附加到该对象上
  352. * @param { Object } source 源对象, 该对象的属性会被附加到target对象上
  353. * @return { Object } 返回target对象
  354. * @example
  355. * ```javascript
  356. *
  357. * var target = { name: 'target', sex: 1 },
  358. * source = { name: 'source', age: 17 };
  359. *
  360. * UE.utils.extend( target, source );
  361. *
  362. * //output: { name: 'source', sex: 1, age: 17 }
  363. * console.log( target );
  364. *
  365. * ```
  366. */
  367. /**
  368. * 将source对象中的属性扩展到target对象上, 根据指定的isKeepTarget值决定是否保留目标对象中与
  369. * 源对象属性名相同的属性值。
  370. * @method extend
  371. * @param { Object } target 目标对象, 新的属性将附加到该对象上
  372. * @param { Object } source 源对象, 该对象的属性会被附加到target对象上
  373. * @param { Boolean } isKeepTarget 是否保留目标对象中与源对象中属性名相同的属性
  374. * @return { Object } 返回target对象
  375. * @example
  376. * ```javascript
  377. *
  378. * var target = { name: 'target', sex: 1 },
  379. * source = { name: 'source', age: 17 };
  380. *
  381. * UE.utils.extend( target, source, true );
  382. *
  383. * //output: { name: 'target', sex: 1, age: 17 }
  384. * console.log( target );
  385. *
  386. * ```
  387. */
  388. extend: function (t, s, b) {
  389. if (s) {
  390. for (var k in s) {
  391. if (!b || !t.hasOwnProperty(k)) {
  392. t[k] = s[k]
  393. }
  394. }
  395. }
  396. return t
  397. },
  398. /**
  399. * 将给定的多个对象的属性复制到目标对象target上
  400. * @method extend2
  401. * @remind 该方法将强制把源对象上的属性复制到target对象上
  402. * @remind 该方法支持两个及以上的参数, 从第二个参数开始, 其属性都会被复制到第一个参数上。 如果遇到同名的属性,
  403. * 将会覆盖掉之前的值。
  404. * @param { Object } target 目标对象, 新的属性将附加到该对象上
  405. * @param { Object... } source 源对象, 支持多个对象, 该对象的属性会被附加到target对象上
  406. * @return { Object } 返回target对象
  407. * @example
  408. * ```javascript
  409. *
  410. * var target = {},
  411. * source1 = { name: 'source', age: 17 },
  412. * source2 = { title: 'dev' };
  413. *
  414. * UE.utils.extend2( target, source1, source2 );
  415. *
  416. * //output: { name: 'source', age: 17, title: 'dev' }
  417. * console.log( target );
  418. *
  419. * ```
  420. */
  421. extend2: function (t) {
  422. var a = arguments
  423. for (var i = 1; i < a.length; i++) {
  424. var x = a[i]
  425. for (var k in x) {
  426. if (!t.hasOwnProperty(k)) {
  427. t[k] = x[k]
  428. }
  429. }
  430. }
  431. return t
  432. },
  433. /**
  434. * 模拟继承机制, 使得subClass继承自superClass
  435. * @method inherits
  436. * @param { Object } subClass 子类对象
  437. * @param { Object } superClass 超类对象
  438. * @warning 该方法只能让subClass继承超类的原型, subClass对象自身的属性和方法不会被继承
  439. * @return { Object } 继承superClass后的子类对象
  440. * @example
  441. * ```javascript
  442. * function SuperClass(){
  443. * this.name = "小李";
  444. * }
  445. *
  446. * SuperClass.prototype = {
  447. * hello:function(str){
  448. * console.log(this.name + str);
  449. * }
  450. * }
  451. *
  452. * function SubClass(){
  453. * this.name = "小张";
  454. * }
  455. *
  456. * UE.utils.inherits(SubClass,SuperClass);
  457. *
  458. * var sub = new SubClass();
  459. * //output: '小张早上好!
  460. * sub.hello("早上好!");
  461. * ```
  462. */
  463. inherits: function (subClass, superClass) {
  464. var oldP = subClass.prototype,
  465. newP = utils.makeInstance(superClass.prototype)
  466. utils.extend(newP, oldP, true)
  467. subClass.prototype = newP
  468. return (newP.constructor = subClass)
  469. },
  470. /**
  471. * 用指定的context对象作为函数fn的上下文
  472. * @method bind
  473. * @param { Function } fn 需要绑定上下文的函数对象
  474. * @param { Object } content 函数fn新的上下文对象
  475. * @return { Function } 一个新的函数, 该函数作为原始函数fn的代理, 将完成fn的上下文调换工作。
  476. * @example
  477. * ```javascript
  478. *
  479. * var name = 'window',
  480. * newTest = null;
  481. *
  482. * function test () {
  483. * console.log( this.name );
  484. * }
  485. *
  486. * newTest = UE.utils.bind( test, { name: 'object' } );
  487. *
  488. * //output: object
  489. * newTest();
  490. *
  491. * //output: window
  492. * test();
  493. *
  494. * ```
  495. */
  496. bind: function (fn, context) {
  497. return function () {
  498. return fn.apply(context, arguments)
  499. }
  500. },
  501. /**
  502. * 创建延迟指定时间后执行的函数fn
  503. * @method defer
  504. * @param { Function } fn 需要延迟执行的函数对象
  505. * @param { int } delay 延迟的时间, 单位是毫秒
  506. * @warning 该方法的时间控制是不精确的,仅仅只能保证函数的执行是在给定的时间之后,
  507. * 而不能保证刚好到达延迟时间时执行。
  508. * @return { Function } 目标函数fn的代理函数, 只有执行该函数才能起到延时效果
  509. * @example
  510. * ```javascript
  511. * var start = 0;
  512. *
  513. * function test(){
  514. * console.log( new Date() - start );
  515. * }
  516. *
  517. * var testDefer = UE.utils.defer( test, 1000 );
  518. * //
  519. * start = new Date();
  520. * //output: (大约在1000毫秒之后输出) 1000
  521. * testDefer();
  522. * ```
  523. */
  524. /**
  525. * 创建延迟指定时间后执行的函数fn, 如果在延迟时间内再次执行该方法, 将会根据指定的exclusion的值,
  526. * 决定是否取消前一次函数的执行, 如果exclusion的值为true, 则取消执行,反之,将继续执行前一个方法。
  527. * @method defer
  528. * @param { Function } fn 需要延迟执行的函数对象
  529. * @param { int } delay 延迟的时间, 单位是毫秒
  530. * @param { Boolean } exclusion 如果在延迟时间内再次执行该函数,该值将决定是否取消执行前一次函数的执行,
  531. * 值为true表示取消执行, 反之则将在执行前一次函数之后才执行本次函数调用。
  532. * @warning 该方法的时间控制是不精确的,仅仅只能保证函数的执行是在给定的时间之后,
  533. * 而不能保证刚好到达延迟时间时执行。
  534. * @return { Function } 目标函数fn的代理函数, 只有执行该函数才能起到延时效果
  535. * @example
  536. * ```javascript
  537. *
  538. * function test(){
  539. * console.log(1);
  540. * }
  541. *
  542. * var testDefer = UE.utils.defer( test, 1000, true );
  543. *
  544. * //output: (两次调用仅有一次输出) 1
  545. * testDefer();
  546. * testDefer();
  547. * ```
  548. */
  549. defer: function (fn, delay, exclusion) {
  550. var timerID
  551. return function () {
  552. if (exclusion) {
  553. clearTimeout(timerID)
  554. }
  555. timerID = setTimeout(fn, delay)
  556. }
  557. },
  558. /**
  559. * 获取元素item在数组array中首次出现的位置, 如果未找到item, 则返回-1
  560. * @method indexOf
  561. * @remind 该方法的匹配过程使用的是恒等“===”
  562. * @param { Array } array 需要查找的数组对象
  563. * @param { * } item 需要在目标数组中查找的值
  564. * @return { int } 返回item在目标数组array中首次出现的位置, 如果在数组中未找到item, 则返回-1
  565. * @example
  566. * ```javascript
  567. * var item = 1,
  568. * arr = [ 3, 4, 6, 8, 1, 1, 2 ];
  569. *
  570. * //output: 4
  571. * console.log( UE.utils.indexOf( arr, item ) );
  572. * ```
  573. */
  574. /**
  575. * 获取元素item数组array中首次出现的位置, 如果未找到item, 则返回-1。通过start的值可以指定搜索的起始位置。
  576. * @method indexOf
  577. * @remind 该方法的匹配过程使用的是恒等“===”
  578. * @param { Array } array 需要查找的数组对象
  579. * @param { * } item 需要在目标数组中查找的值
  580. * @param { int } start 搜索的起始位置
  581. * @return { int } 返回item在目标数组array中的start位置之后首次出现的位置, 如果在数组中未找到item, 则返回-1
  582. * @example
  583. * ```javascript
  584. * var item = 1,
  585. * arr = [ 3, 4, 6, 8, 1, 2, 8, 3, 2, 1, 1, 4 ];
  586. *
  587. * //output: 9
  588. * console.log( UE.utils.indexOf( arr, item, 5 ) );
  589. * ```
  590. */
  591. indexOf: function (array, item, start) {
  592. var index = -1
  593. start = this.isNumber(start) ? start : 0
  594. this.each(array, function (v, i) {
  595. if (i >= start && v === item) {
  596. index = i
  597. return false
  598. }
  599. })
  600. return index
  601. },
  602. /**
  603. * 移除数组array中所有的元素item
  604. * @method removeItem
  605. * @param { Array } array 要移除元素的目标数组
  606. * @param { * } item 将要被移除的元素
  607. * @remind 该方法的匹配过程使用的是恒等“===”
  608. * @example
  609. * ```javascript
  610. * var arr = [ 4, 5, 7, 1, 3, 4, 6 ];
  611. *
  612. * UE.utils.removeItem( arr, 4 );
  613. * //output: [ 5, 7, 1, 3, 6 ]
  614. * console.log( arr );
  615. *
  616. * ```
  617. */
  618. removeItem: function (array, item) {
  619. for (var i = 0, l = array.length; i < l; i++) {
  620. if (array[i] === item) {
  621. array.splice(i, 1)
  622. i--
  623. }
  624. }
  625. },
  626. /**
  627. * 删除字符串str的首尾空格
  628. * @method trim
  629. * @param { String } str 需要删除首尾空格的字符串
  630. * @return { String } 删除了首尾的空格后的字符串
  631. * @example
  632. * ```javascript
  633. *
  634. * var str = " UEdtior ";
  635. *
  636. * //output: 9
  637. * console.log( str.length );
  638. *
  639. * //output: 7
  640. * console.log( UE.utils.trim( " UEdtior " ).length );
  641. *
  642. * //output: 9
  643. * console.log( str.length );
  644. *
  645. * ```
  646. */
  647. trim: function (str) {
  648. return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, '')
  649. },
  650. /**
  651. * 将字符串str以','分隔成数组后,将该数组转换成哈希对象, 其生成的hash对象的key为数组中的元素, value为1
  652. * @method listToMap
  653. * @warning 该方法在生成的hash对象中,会为每一个key同时生成一个另一个全大写的key。
  654. * @param { String } str 该字符串将被以','分割为数组, 然后进行转化
  655. * @return { Object } 转化之后的hash对象
  656. * @example
  657. * ```javascript
  658. *
  659. * //output: Object {UEdtior: 1, UEDTIOR: 1, Hello: 1, HELLO: 1}
  660. * console.log( UE.utils.listToMap( 'UEdtior,Hello' ) );
  661. *
  662. * ```
  663. */
  664. /**
  665. * 将字符串数组转换成哈希对象, 其生成的hash对象的key为数组中的元素, value为1
  666. * @method listToMap
  667. * @warning 该方法在生成的hash对象中,会为每一个key同时生成一个另一个全大写的key。
  668. * @param { Array } arr 字符串数组
  669. * @return { Object } 转化之后的hash对象
  670. * @example
  671. * ```javascript
  672. *
  673. * //output: Object {UEdtior: 1, UEDTIOR: 1, Hello: 1, HELLO: 1}
  674. * console.log( UE.utils.listToMap( [ 'UEdtior', 'Hello' ] ) );
  675. *
  676. * ```
  677. */
  678. listToMap: function (list) {
  679. if (!list) return {}
  680. list = utils.isArray(list) ? list : list.split(',')
  681. for (var i = 0, ci, obj = {}; (ci = list[i++]); ) {
  682. obj[ci.toUpperCase()] = obj[ci] = 1
  683. }
  684. return obj
  685. },
  686. /**
  687. * 将str中的html符号转义,将转义“',&,<,",>”五个字符
  688. * @method unhtml
  689. * @param { String } str 需要转义的字符串
  690. * @return { String } 转义后的字符串
  691. * @example
  692. * ```javascript
  693. * var html = '<body>&</body>';
  694. *
  695. * //output: &lt;body&gt;&amp;&lt;/body&gt;
  696. * console.log( UE.utils.unhtml( html ) );
  697. *
  698. * ```
  699. */
  700. unhtml: function (str, reg) {
  701. return str
  702. ? str.replace(
  703. reg || /[&<">'](?:(amp|lt|quot|gt|#39|nbsp|#\d+);)?/g,
  704. function (a, b) {
  705. if (b) {
  706. return a
  707. } else {
  708. return {
  709. '<': '&lt;',
  710. '&': '&amp;',
  711. '"': '&quot;',
  712. '>': '&gt;',
  713. "'": '&#39;',
  714. }[a]
  715. }
  716. }
  717. )
  718. : ''
  719. },
  720. /**
  721. * 将url中的html字符转义, 仅转义 ', ", <, > 四个字符
  722. * @param { String } str 需要转义的字符串
  723. * @param { RegExp } reg 自定义的正则
  724. * @return { String } 转义后的字符串
  725. */
  726. unhtmlForUrl: function (str, reg) {
  727. return str
  728. ? str.replace(reg || /[<">']/g, function (a) {
  729. return {
  730. '<': '&lt;',
  731. '&': '&amp;',
  732. '"': '&quot;',
  733. '>': '&gt;',
  734. "'": '&#39;',
  735. }[a]
  736. })
  737. : ''
  738. },
  739. /**
  740. * 将str中的转义字符还原成html字符
  741. * @see UE.utils.unhtml(String);
  742. * @method html
  743. * @param { String } str 需要逆转义的字符串
  744. * @return { String } 逆转义后的字符串
  745. * @example
  746. * ```javascript
  747. *
  748. * var str = '&lt;body&gt;&amp;&lt;/body&gt;';
  749. *
  750. * //output: <body>&</body>
  751. * console.log( UE.utils.html( str ) );
  752. *
  753. * ```
  754. */
  755. html: function (str) {
  756. return str
  757. ? str.replace(/&((g|l|quo)t|amp|#39|nbsp);/g, function (m) {
  758. return {
  759. '&lt;': '<',
  760. '&amp;': '&',
  761. '&quot;': '"',
  762. '&gt;': '>',
  763. '&#39;': "'",
  764. '&nbsp;': ' ',
  765. }[m]
  766. })
  767. : ''
  768. },
  769. /**
  770. * 将css样式转换为驼峰的形式
  771. * @method cssStyleToDomStyle
  772. * @param { String } cssName 需要转换的css样式名
  773. * @return { String } 转换成驼峰形式后的css样式名
  774. * @example
  775. * ```javascript
  776. *
  777. * var str = 'border-top';
  778. *
  779. * //output: borderTop
  780. * console.log( UE.utils.cssStyleToDomStyle( str ) );
  781. *
  782. * ```
  783. */
  784. cssStyleToDomStyle: (function () {
  785. var test = document.createElement('div').style,
  786. cache = {
  787. float:
  788. test.cssFloat != undefined
  789. ? 'cssFloat'
  790. : test.styleFloat != undefined
  791. ? 'styleFloat'
  792. : 'float',
  793. }
  794. return function (cssName) {
  795. return (
  796. cache[cssName] ||
  797. (cache[cssName] = cssName
  798. .toLowerCase()
  799. .replace(/-./g, function (match) {
  800. return match.charAt(1).toUpperCase()
  801. }))
  802. )
  803. }
  804. })(),
  805. /**
  806. * 动态加载文件到doc中
  807. * @method loadFile
  808. * @param { DomDocument } document 需要加载资源文件的文档对象
  809. * @param { Object } options 加载资源文件的属性集合, 取值请参考代码示例
  810. * @example
  811. * ```javascript
  812. *
  813. * UE.utils.loadFile( document, {
  814. * src:"test.js",
  815. * tag:"script",
  816. * type:"text/javascript",
  817. * defer:"defer"
  818. * } );
  819. *
  820. * ```
  821. */
  822. /**
  823. * 动态加载文件到doc中,加载成功后执行的回调函数fn
  824. * @method loadFile
  825. * @param { DomDocument } document 需要加载资源文件的文档对象
  826. * @param { Object } options 加载资源文件的属性集合, 该集合支持的值是script标签和style标签支持的所有属性。
  827. * @param { Function } fn 资源文件加载成功之后执行的回调
  828. * @warning 对于在同一个文档中多次加载同一URL的文件, 该方法会在第一次加载之后缓存该请求,
  829. * 在此之后的所有同一URL的请求, 将会直接触发回调。
  830. * @example
  831. * ```javascript
  832. *
  833. * UE.utils.loadFile( document, {
  834. * src:"test.js",
  835. * tag:"script",
  836. * type:"text/javascript",
  837. * defer:"defer"
  838. * }, function () {
  839. * console.log('加载成功');
  840. * } );
  841. *
  842. * ```
  843. */
  844. loadFile: (function () {
  845. var tmpList = []
  846. function getItem(doc, obj) {
  847. try {
  848. for (var i = 0, ci; (ci = tmpList[i++]); ) {
  849. if (ci.doc === doc && ci.url == (obj.src || obj.href)) {
  850. return ci
  851. }
  852. }
  853. } catch (e) {
  854. return null
  855. }
  856. }
  857. return function (doc, obj, fn) {
  858. var item = getItem(doc, obj)
  859. if (item) {
  860. if (item.ready) {
  861. fn && fn()
  862. } else {
  863. item.funs.push(fn)
  864. }
  865. return
  866. }
  867. tmpList.push({
  868. doc: doc,
  869. url: obj.src || obj.href,
  870. funs: [fn],
  871. })
  872. if (!doc.body) {
  873. var html = []
  874. for (var p in obj) {
  875. if (p == 'tag') continue
  876. html.push(p + '="' + obj[p] + '"')
  877. }
  878. doc.write(
  879. '<' + obj.tag + ' ' + html.join(' ') + ' ></' + obj.tag + '>'
  880. )
  881. return
  882. }
  883. if (obj.id && doc.getElementById(obj.id)) {
  884. return
  885. }
  886. var element = doc.createElement(obj.tag)
  887. delete obj.tag
  888. for (var p in obj) {
  889. element.setAttribute(p, obj[p])
  890. }
  891. element.onload = element.onreadystatechange = function () {
  892. if (!this.readyState || /loaded|complete/.test(this.readyState)) {
  893. item = getItem(doc, obj)
  894. if (item.funs.length > 0) {
  895. item.ready = 1
  896. for (var fi; (fi = item.funs.pop()); ) {
  897. fi()
  898. }
  899. }
  900. element.onload = element.onreadystatechange = null
  901. }
  902. }
  903. element.onerror = function () {
  904. throw Error(
  905. 'The load ' +
  906. (obj.href || obj.src) +
  907. ' fails,check the url settings of file ueditor.config.js '
  908. )
  909. }
  910. doc.getElementsByTagName('head')[0].appendChild(element)
  911. }
  912. })(),
  913. /**
  914. * 判断obj对象是否为空
  915. * @method isEmptyObject
  916. * @param { * } obj 需要判断的对象
  917. * @remind 如果判断的对象是NULL, 将直接返回true, 如果是数组且为空, 返回true, 如果是字符串, 且字符串为空,
  918. * 返回true, 如果是普通对象, 且该对象没有任何实例属性, 返回true
  919. * @return { Boolean } 对象是否为空
  920. * @example
  921. * ```javascript
  922. *
  923. * //output: true
  924. * console.log( UE.utils.isEmptyObject( {} ) );
  925. *
  926. * //output: true
  927. * console.log( UE.utils.isEmptyObject( [] ) );
  928. *
  929. * //output: true
  930. * console.log( UE.utils.isEmptyObject( "" ) );
  931. *
  932. * //output: false
  933. * console.log( UE.utils.isEmptyObject( { key: 1 } ) );
  934. *
  935. * //output: false
  936. * console.log( UE.utils.isEmptyObject( [1] ) );
  937. *
  938. * //output: false
  939. * console.log( UE.utils.isEmptyObject( "1" ) );
  940. *
  941. * ```
  942. */
  943. isEmptyObject: function (obj) {
  944. if (obj == null) return true
  945. if (this.isArray(obj) || this.isString(obj)) return obj.length === 0
  946. for (var key in obj) if (obj.hasOwnProperty(key)) return false
  947. return true
  948. },
  949. /**
  950. * 把rgb格式的颜色值转换成16进制格式
  951. * @method fixColor
  952. * @param { String } rgb格式的颜色值
  953. * @param { String }
  954. * @example
  955. * rgb(255,255,255) => "#ffffff"
  956. */
  957. fixColor: function (name, value) {
  958. if (/color/i.test(name) && /rgba?/.test(value)) {
  959. var array = value.split(',')
  960. if (array.length > 3) return ''
  961. value = '#'
  962. for (var i = 0, color; (color = array[i++]); ) {
  963. color = parseInt(color.replace(/[^\d]/gi, ''), 10).toString(16)
  964. value += color.length == 1 ? '0' + color : color
  965. }
  966. value = value.toUpperCase()
  967. }
  968. return value
  969. },
  970. /**
  971. * 只针对border,padding,margin做了处理,因为性能问题
  972. * @public
  973. * @function
  974. * @param {String} val style字符串
  975. */
  976. optCss: function (val) {
  977. var padding, margin, border
  978. val = val.replace(
  979. /(padding|margin|border)\-([^:]+):([^;]+);?/gi,
  980. function (str, key, name, val) {
  981. if (val.split(' ').length == 1) {
  982. switch (key) {
  983. case 'padding':
  984. !padding && (padding = {})
  985. padding[name] = val
  986. return ''
  987. case 'margin':
  988. !margin && (margin = {})
  989. margin[name] = val
  990. return ''
  991. case 'border':
  992. return val == 'initial' ? '' : str
  993. }
  994. }
  995. return str
  996. }
  997. )
  998. function opt(obj, name) {
  999. if (!obj) {
  1000. return ''
  1001. }
  1002. var t = obj.top,
  1003. b = obj.bottom,
  1004. l = obj.left,
  1005. r = obj.right,
  1006. val = ''
  1007. if (!t || !l || !b || !r) {
  1008. for (var p in obj) {
  1009. val += ';' + name + '-' + p + ':' + obj[p] + ';'
  1010. }
  1011. } else {
  1012. val +=
  1013. ';' +
  1014. name +
  1015. ':' +
  1016. (t == b && b == l && l == r
  1017. ? t
  1018. : t == b && l == r
  1019. ? t + ' ' + l
  1020. : l == r
  1021. ? t + ' ' + l + ' ' + b
  1022. : t + ' ' + r + ' ' + b + ' ' + l) +
  1023. ';'
  1024. }
  1025. return val
  1026. }
  1027. val += opt(padding, 'padding') + opt(margin, 'margin')
  1028. return val
  1029. .replace(/^[ \n\r\t;]*|[ \n\r\t]*$/, '')
  1030. .replace(/;([ \n\r\t]+)|\1;/g, ';')
  1031. .replace(/(&((l|g)t|quot|#39))?;{2,}/g, function (a, b) {
  1032. return b ? b + ';;' : ';'
  1033. })
  1034. },
  1035. /**
  1036. * 克隆对象
  1037. * @method clone
  1038. * @param { Object } source 源对象
  1039. * @return { Object } source的一个副本
  1040. */
  1041. /**
  1042. * 深度克隆对象,将source的属性克隆到target对象, 会覆盖target重名的属性。
  1043. * @method clone
  1044. * @param { Object } source 源对象
  1045. * @param { Object } target 目标对象
  1046. * @return { Object } 附加了source对象所有属性的target对象
  1047. */
  1048. clone: function (source, target) {
  1049. var tmp
  1050. target = target || {}
  1051. for (var i in source) {
  1052. if (source.hasOwnProperty(i)) {
  1053. tmp = source[i]
  1054. if (typeof tmp == 'object') {
  1055. target[i] = utils.isArray(tmp) ? [] : {}
  1056. utils.clone(source[i], target[i])
  1057. } else {
  1058. target[i] = tmp
  1059. }
  1060. }
  1061. }
  1062. return target
  1063. },
  1064. /**
  1065. * 把cm/pt为单位的值转换为px为单位的值
  1066. * @method transUnitToPx
  1067. * @param { String } 待转换的带单位的字符串
  1068. * @return { String } 转换为px为计量单位的值的字符串
  1069. * @example
  1070. * ```javascript
  1071. *
  1072. * //output: 500px
  1073. * console.log( UE.utils.transUnitToPx( '20cm' ) );
  1074. *
  1075. * //output: 27px
  1076. * console.log( UE.utils.transUnitToPx( '20pt' ) );
  1077. *
  1078. * ```
  1079. */
  1080. transUnitToPx: function (val) {
  1081. if (!/(pt|cm)/.test(val)) {
  1082. return val
  1083. }
  1084. var unit
  1085. val.replace(/([\d.]+)(\w+)/, function (str, v, u) {
  1086. val = v
  1087. unit = u
  1088. })
  1089. switch (unit) {
  1090. case 'cm':
  1091. val = parseFloat(val) * 25
  1092. break
  1093. case 'pt':
  1094. val = Math.round((parseFloat(val) * 96) / 72)
  1095. }
  1096. return val + (val ? 'px' : '')
  1097. },
  1098. /**
  1099. * 在dom树ready之后执行给定的回调函数
  1100. * @method domReady
  1101. * @remind 如果在执行该方法的时候, dom树已经ready, 那么回调函数将立刻执行
  1102. * @param { Function } fn dom树ready之后的回调函数
  1103. * @example
  1104. * ```javascript
  1105. *
  1106. * UE.utils.domReady( function () {
  1107. *
  1108. * console.log('123');
  1109. *
  1110. * } );
  1111. *
  1112. * ```
  1113. */
  1114. domReady: (function () {
  1115. var fnArr = []
  1116. function doReady(doc) {
  1117. //确保onready只执行一次
  1118. doc.isReady = true
  1119. for (var ci; (ci = fnArr.pop()); ci()) {}
  1120. }
  1121. return function (onready, win) {
  1122. win = win || window
  1123. var doc = win.document
  1124. onready && fnArr.push(onready)
  1125. if (doc.readyState === 'complete') {
  1126. doReady(doc)
  1127. } else {
  1128. doc.isReady && doReady(doc)
  1129. if (browser.ie && browser.version != 11) {
  1130. ;(function () {
  1131. if (doc.isReady) return
  1132. try {
  1133. doc.documentElement.doScroll('left')
  1134. } catch (error) {
  1135. setTimeout(arguments.callee, 0)
  1136. return
  1137. }
  1138. doReady(doc)
  1139. })()
  1140. win.attachEvent('onload', function () {
  1141. doReady(doc)
  1142. })
  1143. } else {
  1144. doc.addEventListener(
  1145. 'DOMContentLoaded',
  1146. function () {
  1147. doc.removeEventListener(
  1148. 'DOMContentLoaded',
  1149. arguments.callee,
  1150. false
  1151. )
  1152. doReady(doc)
  1153. },
  1154. false
  1155. )
  1156. win.addEventListener(
  1157. 'load',
  1158. function () {
  1159. doReady(doc)
  1160. },
  1161. false
  1162. )
  1163. }
  1164. }
  1165. }
  1166. })(),
  1167. /**
  1168. * 动态添加css样式
  1169. * @method cssRule
  1170. * @param { String } 节点名称
  1171. * @grammar UE.utils.cssRule('添加的样式的节点名称',['样式','放到哪个document上'])
  1172. * @grammar UE.utils.cssRule('body','body{background:#ccc}') => null //给body添加背景颜色
  1173. * @grammar UE.utils.cssRule('body') =>样式的字符串 //取得key值为body的样式的内容,如果没有找到key值先关的样式将返回空,例如刚才那个背景颜色,将返回 body{background:#ccc}
  1174. * @grammar UE.utils.cssRule('body',document) => 返回指定key的样式,并且指定是哪个document
  1175. * @grammar UE.utils.cssRule('body','') =>null //清空给定的key值的背景颜色
  1176. */
  1177. cssRule:
  1178. browser.ie && browser.version != 11
  1179. ? function (key, style, doc) {
  1180. var indexList, index
  1181. if (
  1182. style === undefined ||
  1183. (style && style.nodeType && style.nodeType == 9)
  1184. ) {
  1185. //获取样式
  1186. doc =
  1187. style && style.nodeType && style.nodeType == 9
  1188. ? style
  1189. : doc || document
  1190. indexList = doc.indexList || (doc.indexList = {})
  1191. index = indexList[key]
  1192. if (index !== undefined) {
  1193. return doc.styleSheets[index].cssText
  1194. }
  1195. return undefined
  1196. }
  1197. doc = doc || document
  1198. indexList = doc.indexList || (doc.indexList = {})
  1199. index = indexList[key]
  1200. //清除样式
  1201. if (style === '') {
  1202. if (index !== undefined) {
  1203. doc.styleSheets[index].cssText = ''
  1204. delete indexList[key]
  1205. return true
  1206. }
  1207. return false
  1208. }
  1209. //添加样式
  1210. if (index !== undefined) {
  1211. sheetStyle = doc.styleSheets[index]
  1212. } else {
  1213. sheetStyle = doc.createStyleSheet(
  1214. '',
  1215. (index = doc.styleSheets.length)
  1216. )
  1217. indexList[key] = index
  1218. }
  1219. sheetStyle.cssText = style
  1220. }
  1221. : function (key, style, doc) {
  1222. var head, node
  1223. if (
  1224. style === undefined ||
  1225. (style && style.nodeType && style.nodeType == 9)
  1226. ) {
  1227. //获取样式
  1228. doc =
  1229. style && style.nodeType && style.nodeType == 9
  1230. ? style
  1231. : doc || document
  1232. node = doc.getElementById(key)
  1233. return node ? node.innerHTML : undefined
  1234. }
  1235. doc = doc || document
  1236. node = doc.getElementById(key)
  1237. //清除样式
  1238. if (style === '') {
  1239. if (node) {
  1240. node.parentNode.removeChild(node)
  1241. return true
  1242. }
  1243. return false
  1244. }
  1245. //添加样式
  1246. if (node) {
  1247. node.innerHTML = style
  1248. } else {
  1249. node = doc.createElement('style')
  1250. node.id = key
  1251. node.innerHTML = style
  1252. doc.getElementsByTagName('head')[0].appendChild(node)
  1253. }
  1254. },
  1255. sort: function (array, compareFn) {
  1256. compareFn =
  1257. compareFn ||
  1258. function (item1, item2) {
  1259. return item1.localeCompare(item2)
  1260. }
  1261. for (var i = 0, len = array.length; i < len; i++) {
  1262. for (var j = i, length = array.length; j < length; j++) {
  1263. if (compareFn(array[i], array[j]) > 0) {
  1264. var t = array[i]
  1265. array[i] = array[j]
  1266. array[j] = t
  1267. }
  1268. }
  1269. }
  1270. return array
  1271. },
  1272. serializeParam: function (json) {
  1273. var strArr = []
  1274. for (var i in json) {
  1275. //忽略默认的几个参数
  1276. if (i == 'method' || i == 'timeout' || i == 'async') continue
  1277. //传递过来的对象和函数不在提交之列
  1278. if (
  1279. !(
  1280. (typeof json[i]).toLowerCase() == 'function' ||
  1281. (typeof json[i]).toLowerCase() == 'object'
  1282. )
  1283. ) {
  1284. strArr.push(encodeURIComponent(i) + '=' + encodeURIComponent(json[i]))
  1285. } else if (utils.isArray(json[i])) {
  1286. //支持传数组内容
  1287. for (var j = 0; j < json[i].length; j++) {
  1288. strArr.push(
  1289. encodeURIComponent(i) + '[]=' + encodeURIComponent(json[i][j])
  1290. )
  1291. }
  1292. }
  1293. }
  1294. return strArr.join('&')
  1295. },
  1296. formatUrl: function (url) {
  1297. var u = url.replace(/&&/g, '&')
  1298. u = u.replace(/\?&/g, '?')
  1299. u = u.replace(/&$/g, '')
  1300. u = u.replace(/&#/g, '#')
  1301. u = u.replace(/&+/g, '&')
  1302. return u
  1303. },
  1304. isCrossDomainUrl: function (url) {
  1305. var a = document.createElement('a')
  1306. a.href = url
  1307. if (browser.ie) {
  1308. a.href = a.href
  1309. }
  1310. return !(
  1311. a.protocol == location.protocol &&
  1312. a.hostname == location.hostname &&
  1313. (a.port == location.port ||
  1314. (a.port == '80' && location.port == '') ||
  1315. (a.port == '' && location.port == '80'))
  1316. )
  1317. },
  1318. clearEmptyAttrs: function (obj) {
  1319. for (var p in obj) {
  1320. if (obj[p] === '') {
  1321. delete obj[p]
  1322. }
  1323. }
  1324. return obj
  1325. },
  1326. str2json: function (s) {
  1327. if (!utils.isString(s)) return null
  1328. if (window.JSON) {
  1329. return JSON.parse(s)
  1330. } else {
  1331. return new Function('return ' + utils.trim(s || ''))()
  1332. }
  1333. },
  1334. json2str: (function () {
  1335. if (window.JSON) {
  1336. return JSON.stringify
  1337. } else {
  1338. var escapeMap = {
  1339. '\b': '\\b',
  1340. '\t': '\\t',
  1341. '\n': '\\n',
  1342. '\f': '\\f',
  1343. '\r': '\\r',
  1344. '"': '\\"',
  1345. '\\': '\\\\',
  1346. }
  1347. function encodeString(source) {
  1348. if (/["\\\x00-\x1f]/.test(source)) {
  1349. source = source.replace(/["\\\x00-\x1f]/g, function (match) {
  1350. var c = escapeMap[match]
  1351. if (c) {
  1352. return c
  1353. }
  1354. c = match.charCodeAt()
  1355. return (
  1356. '\\u00' +
  1357. Math.floor(c / 16).toString(16) +
  1358. (c % 16).toString(16)
  1359. )
  1360. })
  1361. }
  1362. return '"' + source + '"'
  1363. }
  1364. function encodeArray(source) {
  1365. var result = ['['],
  1366. l = source.length,
  1367. preComma,
  1368. i,
  1369. item
  1370. for (i = 0; i < l; i++) {
  1371. item = source[i]
  1372. switch (typeof item) {
  1373. case 'undefined':
  1374. case 'function':
  1375. case 'unknown':
  1376. break
  1377. default:
  1378. if (preComma) {
  1379. result.push(',')
  1380. }
  1381. result.push(utils.json2str(item))
  1382. preComma = 1
  1383. }
  1384. }
  1385. result.push(']')
  1386. return result.join('')
  1387. }
  1388. function pad(source) {
  1389. return source < 10 ? '0' + source : source
  1390. }
  1391. function encodeDate(source) {
  1392. return (
  1393. '"' +
  1394. source.getFullYear() +
  1395. '-' +
  1396. pad(source.getMonth() + 1) +
  1397. '-' +
  1398. pad(source.getDate()) +
  1399. 'T' +
  1400. pad(source.getHours()) +
  1401. ':' +
  1402. pad(source.getMinutes()) +
  1403. ':' +
  1404. pad(source.getSeconds()) +
  1405. '"'
  1406. )
  1407. }
  1408. return function (value) {
  1409. switch (typeof value) {
  1410. case 'undefined':
  1411. return 'undefined'
  1412. case 'number':
  1413. return isFinite(value) ? String(value) : 'null'
  1414. case 'string':
  1415. return encodeString(value)
  1416. case 'boolean':
  1417. return String(value)
  1418. default:
  1419. if (value === null) {
  1420. return 'null'
  1421. } else if (utils.isArray(value)) {
  1422. return encodeArray(value)
  1423. } else if (utils.isDate(value)) {
  1424. return encodeDate(value)
  1425. } else {
  1426. var result = ['{'],
  1427. encode = utils.json2str,
  1428. preComma,
  1429. item
  1430. for (var key in value) {
  1431. if (Object.prototype.hasOwnProperty.call(value, key)) {
  1432. item = value[key]
  1433. switch (typeof item) {
  1434. case 'undefined':
  1435. case 'unknown':
  1436. case 'function':
  1437. break
  1438. default:
  1439. if (preComma) {
  1440. result.push(',')
  1441. }
  1442. preComma = 1
  1443. result.push(encode(key) + ':' + encode(item))
  1444. }
  1445. }
  1446. }
  1447. result.push('}')
  1448. return result.join('')
  1449. }
  1450. }
  1451. }
  1452. }
  1453. })(),
  1454. })
  1455. /**
  1456. * 判断给定的对象是否是字符串
  1457. * @method isString
  1458. * @param { * } object 需要判断的对象
  1459. * @return { Boolean } 给定的对象是否是字符串
  1460. */
  1461. /**
  1462. * 判断给定的对象是否是数组
  1463. * @method isArray
  1464. * @param { * } object 需要判断的对象
  1465. * @return { Boolean } 给定的对象是否是数组
  1466. */
  1467. /**
  1468. * 判断给定的对象是否是一个Function
  1469. * @method isFunction
  1470. * @param { * } object 需要判断的对象
  1471. * @return { Boolean } 给定的对象是否是Function
  1472. */
  1473. /**
  1474. * 判断给定的对象是否是Number
  1475. * @method isNumber
  1476. * @param { * } object 需要判断的对象
  1477. * @return { Boolean } 给定的对象是否是Number
  1478. */
  1479. /**
  1480. * 判断给定的对象是否是一个正则表达式
  1481. * @method isRegExp
  1482. * @param { * } object 需要判断的对象
  1483. * @return { Boolean } 给定的对象是否是正则表达式
  1484. */
  1485. /**
  1486. * 判断给定的对象是否是一个普通对象
  1487. * @method isObject
  1488. * @param { * } object 需要判断的对象
  1489. * @return { Boolean } 给定的对象是否是普通对象
  1490. */
  1491. utils.each(
  1492. ['String', 'Function', 'Array', 'Number', 'RegExp', 'Object', 'Date'],
  1493. function (v) {
  1494. UE.utils['is' + v] = function (obj) {
  1495. return Object.prototype.toString.apply(obj) == '[object ' + v + ']'
  1496. }
  1497. }
  1498. )
  1499. // core/EventBase.js
  1500. /**
  1501. * UE采用的事件基类
  1502. * @file
  1503. * @module UE
  1504. * @class EventBase
  1505. * @since 1.2.6.1
  1506. */
  1507. /**
  1508. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  1509. * @unfile
  1510. * @module UE
  1511. */
  1512. /**
  1513. * UE采用的事件基类,继承此类的对应类将获取addListener,removeListener,fireEvent方法。
  1514. * 在UE中,Editor以及所有ui实例都继承了该类,故可以在对应的ui对象以及editor对象上使用上述方法。
  1515. * @unfile
  1516. * @module UE
  1517. * @class EventBase
  1518. */
  1519. /**
  1520. * 通过此构造器,子类可以继承EventBase获取事件监听的方法
  1521. * @constructor
  1522. * @example
  1523. * ```javascript
  1524. * UE.EventBase.call(editor);
  1525. * ```
  1526. */
  1527. var EventBase = (UE.EventBase = function () {})
  1528. EventBase.prototype = {
  1529. /**
  1530. * 注册事件监听器
  1531. * @method addListener
  1532. * @param { String } types 监听的事件名称,同时监听多个事件使用空格分隔
  1533. * @param { Function } fn 监听的事件被触发时,会执行该回调函数
  1534. * @waining 事件被触发时,监听的函数假如返回的值恒等于true,回调函数的队列中后面的函数将不执行
  1535. * @example
  1536. * ```javascript
  1537. * editor.addListener('selectionchange',function(){
  1538. * console.log("选区已经变化!");
  1539. * })
  1540. * editor.addListener('beforegetcontent aftergetcontent',function(type){
  1541. * if(type == 'beforegetcontent'){
  1542. * //do something
  1543. * }else{
  1544. * //do something
  1545. * }
  1546. * console.log(this.getContent) // this是注册的事件的编辑器实例
  1547. * })
  1548. * ```
  1549. * @see UE.EventBase:fireEvent(String)
  1550. */
  1551. addListener: function (types, listener) {
  1552. types = utils.trim(types).split(/\s+/)
  1553. for (var i = 0, ti; (ti = types[i++]); ) {
  1554. getListener(this, ti, true).push(listener)
  1555. }
  1556. },
  1557. on: function (types, listener) {
  1558. return this.addListener(types, listener)
  1559. },
  1560. off: function (types, listener) {
  1561. return this.removeListener(types, listener)
  1562. },
  1563. trigger: function () {
  1564. return this.fireEvent.apply(this, arguments)
  1565. },
  1566. /**
  1567. * 移除事件监听器
  1568. * @method removeListener
  1569. * @param { String } types 移除的事件名称,同时移除多个事件使用空格分隔
  1570. * @param { Function } fn 移除监听事件的函数引用
  1571. * @example
  1572. * ```javascript
  1573. * //changeCallback为方法体
  1574. * editor.removeListener("selectionchange",changeCallback);
  1575. * ```
  1576. */
  1577. removeListener: function (types, listener) {
  1578. types = utils.trim(types).split(/\s+/)
  1579. for (var i = 0, ti; (ti = types[i++]); ) {
  1580. utils.removeItem(getListener(this, ti) || [], listener)
  1581. }
  1582. },
  1583. /**
  1584. * 触发事件
  1585. * @method fireEvent
  1586. * @param { String } types 触发的事件名称,同时触发多个事件使用空格分隔
  1587. * @remind 该方法会触发addListener
  1588. * @return { * } 返回触发事件的队列中,最后执行的回调函数的返回值
  1589. * @example
  1590. * ```javascript
  1591. * editor.fireEvent("selectionchange");
  1592. * ```
  1593. */
  1594. /**
  1595. * 触发事件
  1596. * @method fireEvent
  1597. * @param { String } types 触发的事件名称,同时触发多个事件使用空格分隔
  1598. * @param { *... } options 可选参数,可以传入一个或多个参数,会传给事件触发的回调函数
  1599. * @return { * } 返回触发事件的队列中,最后执行的回调函数的返回值
  1600. * @example
  1601. * ```javascript
  1602. *
  1603. * editor.addListener( "selectionchange", function ( type, arg1, arg2 ) {
  1604. *
  1605. * console.log( arg1 + " " + arg2 );
  1606. *
  1607. * } );
  1608. *
  1609. * //触发selectionchange事件, 会执行上面的事件监听器
  1610. * //output: Hello World
  1611. * editor.fireEvent("selectionchange", "Hello", "World");
  1612. * ```
  1613. */
  1614. fireEvent: function () {
  1615. var types = arguments[0]
  1616. types = utils.trim(types).split(' ')
  1617. for (var i = 0, ti; (ti = types[i++]); ) {
  1618. var listeners = getListener(this, ti),
  1619. r,
  1620. t,
  1621. k
  1622. if (listeners) {
  1623. k = listeners.length
  1624. while (k--) {
  1625. if (!listeners[k]) continue
  1626. t = listeners[k].apply(this, arguments)
  1627. if (t === true) {
  1628. return t
  1629. }
  1630. if (t !== undefined) {
  1631. r = t
  1632. }
  1633. }
  1634. }
  1635. if ((t = this['on' + ti.toLowerCase()])) {
  1636. r = t.apply(this, arguments)
  1637. }
  1638. }
  1639. return r
  1640. },
  1641. }
  1642. /**
  1643. * 获得对象所拥有监听类型的所有监听器
  1644. * @unfile
  1645. * @module UE
  1646. * @since 1.2.6.1
  1647. * @method getListener
  1648. * @public
  1649. * @param { Object } obj 查询监听器的对象
  1650. * @param { String } type 事件类型
  1651. * @param { Boolean } force 为true且当前所有type类型的侦听器不存在时,创建一个空监听器数组
  1652. * @return { Array } 监听器数组
  1653. */
  1654. function getListener(obj, type, force) {
  1655. var allListeners
  1656. type = type.toLowerCase()
  1657. return (
  1658. (allListeners =
  1659. obj.__allListeners || (force && (obj.__allListeners = {}))) &&
  1660. (allListeners[type] || (force && (allListeners[type] = [])))
  1661. )
  1662. }
  1663. // core/dtd.js
  1664. ///import editor.js
  1665. ///import core/dom/dom.js
  1666. ///import core/utils.js
  1667. /**
  1668. * dtd html语义化的体现类
  1669. * @constructor
  1670. * @namespace dtd
  1671. */
  1672. var dtd = (dom.dtd = (function () {
  1673. function _(s) {
  1674. for (var k in s) {
  1675. s[k.toUpperCase()] = s[k]
  1676. }
  1677. return s
  1678. }
  1679. var X = utils.extend2
  1680. var A = _({ isindex: 1, fieldset: 1 }),
  1681. B = _({ input: 1, button: 1, select: 1, textarea: 1, label: 1 }),
  1682. C = X(_({ a: 1 }), B),
  1683. D = X({ iframe: 1 }, C),
  1684. E = _({
  1685. hr: 1,
  1686. ul: 1,
  1687. menu: 1,
  1688. div: 1,
  1689. blockquote: 1,
  1690. noscript: 1,
  1691. table: 1,
  1692. center: 1,
  1693. address: 1,
  1694. dir: 1,
  1695. pre: 1,
  1696. h5: 1,
  1697. dl: 1,
  1698. h4: 1,
  1699. noframes: 1,
  1700. h6: 1,
  1701. ol: 1,
  1702. h1: 1,
  1703. h3: 1,
  1704. h2: 1,
  1705. }),
  1706. F = _({ ins: 1, del: 1, script: 1, style: 1 }),
  1707. G = X(
  1708. _({
  1709. b: 1,
  1710. acronym: 1,
  1711. bdo: 1,
  1712. var: 1,
  1713. '#': 1,
  1714. abbr: 1,
  1715. code: 1,
  1716. br: 1,
  1717. i: 1,
  1718. cite: 1,
  1719. kbd: 1,
  1720. u: 1,
  1721. strike: 1,
  1722. s: 1,
  1723. tt: 1,
  1724. strong: 1,
  1725. q: 1,
  1726. samp: 1,
  1727. em: 1,
  1728. dfn: 1,
  1729. span: 1,
  1730. }),
  1731. F
  1732. ),
  1733. H = X(
  1734. _({
  1735. sub: 1,
  1736. img: 1,
  1737. embed: 1,
  1738. object: 1,
  1739. sup: 1,
  1740. basefont: 1,
  1741. map: 1,
  1742. applet: 1,
  1743. font: 1,
  1744. big: 1,
  1745. small: 1,
  1746. }),
  1747. G
  1748. ),
  1749. I = X(_({ p: 1 }), H),
  1750. J = X(_({ iframe: 1 }), H, B),
  1751. K = _({
  1752. img: 1,
  1753. embed: 1,
  1754. noscript: 1,
  1755. br: 1,
  1756. kbd: 1,
  1757. center: 1,
  1758. button: 1,
  1759. basefont: 1,
  1760. h5: 1,
  1761. h4: 1,
  1762. samp: 1,
  1763. h6: 1,
  1764. ol: 1,
  1765. h1: 1,
  1766. h3: 1,
  1767. h2: 1,
  1768. form: 1,
  1769. font: 1,
  1770. '#': 1,
  1771. select: 1,
  1772. menu: 1,
  1773. ins: 1,
  1774. abbr: 1,
  1775. label: 1,
  1776. code: 1,
  1777. table: 1,
  1778. script: 1,
  1779. cite: 1,
  1780. input: 1,
  1781. iframe: 1,
  1782. strong: 1,
  1783. textarea: 1,
  1784. noframes: 1,
  1785. big: 1,
  1786. small: 1,
  1787. span: 1,
  1788. hr: 1,
  1789. sub: 1,
  1790. bdo: 1,
  1791. var: 1,
  1792. div: 1,
  1793. object: 1,
  1794. sup: 1,
  1795. strike: 1,
  1796. dir: 1,
  1797. map: 1,
  1798. dl: 1,
  1799. applet: 1,
  1800. del: 1,
  1801. isindex: 1,
  1802. fieldset: 1,
  1803. ul: 1,
  1804. b: 1,
  1805. acronym: 1,
  1806. a: 1,
  1807. blockquote: 1,
  1808. i: 1,
  1809. u: 1,
  1810. s: 1,
  1811. tt: 1,
  1812. address: 1,
  1813. q: 1,
  1814. pre: 1,
  1815. p: 1,
  1816. em: 1,
  1817. dfn: 1,
  1818. }),
  1819. L = X(_({ a: 0 }), J), //a不能被切开,所以把他
  1820. M = _({ tr: 1 }),
  1821. N = _({ '#': 1 }),
  1822. O = X(_({ param: 1 }), K),
  1823. P = X(_({ form: 1 }), A, D, E, I),
  1824. Q = _({ li: 1, ol: 1, ul: 1 }),
  1825. R = _({ style: 1, script: 1 }),
  1826. S = _({ base: 1, link: 1, meta: 1, title: 1 }),
  1827. T = X(S, R),
  1828. U = _({ head: 1, body: 1 }),
  1829. V = _({ html: 1 })
  1830. var block = _({
  1831. address: 1,
  1832. blockquote: 1,
  1833. center: 1,
  1834. dir: 1,
  1835. div: 1,
  1836. dl: 1,
  1837. fieldset: 1,
  1838. form: 1,
  1839. h1: 1,
  1840. h2: 1,
  1841. h3: 1,
  1842. h4: 1,
  1843. h5: 1,
  1844. h6: 1,
  1845. hr: 1,
  1846. isindex: 1,
  1847. menu: 1,
  1848. noframes: 1,
  1849. ol: 1,
  1850. p: 1,
  1851. pre: 1,
  1852. table: 1,
  1853. ul: 1,
  1854. }),
  1855. empty = _({
  1856. area: 1,
  1857. base: 1,
  1858. basefont: 1,
  1859. br: 1,
  1860. col: 1,
  1861. command: 1,
  1862. dialog: 1,
  1863. embed: 1,
  1864. hr: 1,
  1865. img: 1,
  1866. input: 1,
  1867. isindex: 1,
  1868. keygen: 1,
  1869. link: 1,
  1870. meta: 1,
  1871. param: 1,
  1872. source: 1,
  1873. track: 1,
  1874. wbr: 1,
  1875. })
  1876. return _({
  1877. // $ 表示自定的属性
  1878. // body外的元素列表.
  1879. $nonBodyContent: X(V, U, S),
  1880. //块结构元素列表
  1881. $block: block,
  1882. //内联元素列表
  1883. $inline: L,
  1884. $inlineWithA: X(_({ a: 1 }), L),
  1885. $body: X(_({ script: 1, style: 1 }), block),
  1886. $cdata: _({ script: 1, style: 1 }),
  1887. //自闭和元素
  1888. $empty: empty,
  1889. //不是自闭合,但不能让range选中里边
  1890. $nonChild: _({ iframe: 1, textarea: 1 }),
  1891. //列表元素列表
  1892. $listItem: _({ dd: 1, dt: 1, li: 1 }),
  1893. //列表根元素列表
  1894. $list: _({ ul: 1, ol: 1, dl: 1 }),
  1895. //不能认为是空的元素
  1896. $isNotEmpty: _({
  1897. table: 1,
  1898. ul: 1,
  1899. ol: 1,
  1900. dl: 1,
  1901. iframe: 1,
  1902. area: 1,
  1903. base: 1,
  1904. col: 1,
  1905. hr: 1,
  1906. img: 1,
  1907. embed: 1,
  1908. input: 1,
  1909. link: 1,
  1910. meta: 1,
  1911. param: 1,
  1912. h1: 1,
  1913. h2: 1,
  1914. h3: 1,
  1915. h4: 1,
  1916. h5: 1,
  1917. h6: 1,
  1918. }),
  1919. //如果没有子节点就可以删除的元素列表,像span,a
  1920. $removeEmpty: _({
  1921. a: 1,
  1922. abbr: 1,
  1923. acronym: 1,
  1924. address: 1,
  1925. b: 1,
  1926. bdo: 1,
  1927. big: 1,
  1928. cite: 1,
  1929. code: 1,
  1930. del: 1,
  1931. dfn: 1,
  1932. em: 1,
  1933. font: 1,
  1934. i: 1,
  1935. ins: 1,
  1936. label: 1,
  1937. kbd: 1,
  1938. q: 1,
  1939. s: 1,
  1940. samp: 1,
  1941. small: 1,
  1942. span: 1,
  1943. strike: 1,
  1944. strong: 1,
  1945. sub: 1,
  1946. sup: 1,
  1947. tt: 1,
  1948. u: 1,
  1949. var: 1,
  1950. }),
  1951. $removeEmptyBlock: _({ p: 1, div: 1 }),
  1952. //在table元素里的元素列表
  1953. $tableContent: _({
  1954. caption: 1,
  1955. col: 1,
  1956. colgroup: 1,
  1957. tbody: 1,
  1958. td: 1,
  1959. tfoot: 1,
  1960. th: 1,
  1961. thead: 1,
  1962. tr: 1,
  1963. table: 1,
  1964. }),
  1965. //不转换的标签
  1966. $notTransContent: _({ pre: 1, script: 1, style: 1, textarea: 1 }),
  1967. html: U,
  1968. head: T,
  1969. style: N,
  1970. script: N,
  1971. body: P,
  1972. base: {},
  1973. link: {},
  1974. meta: {},
  1975. title: N,
  1976. col: {},
  1977. tr: _({ td: 1, th: 1 }),
  1978. img: {},
  1979. embed: {},
  1980. colgroup: _({ thead: 1, col: 1, tbody: 1, tr: 1, tfoot: 1 }),
  1981. noscript: P,
  1982. td: P,
  1983. br: {},
  1984. th: P,
  1985. center: P,
  1986. kbd: L,
  1987. button: X(I, E),
  1988. basefont: {},
  1989. h5: L,
  1990. h4: L,
  1991. samp: L,
  1992. h6: L,
  1993. ol: Q,
  1994. h1: L,
  1995. h3: L,
  1996. option: N,
  1997. h2: L,
  1998. form: X(A, D, E, I),
  1999. select: _({ optgroup: 1, option: 1 }),
  2000. font: L,
  2001. ins: L,
  2002. menu: Q,
  2003. abbr: L,
  2004. label: L,
  2005. table: _({
  2006. thead: 1,
  2007. col: 1,
  2008. tbody: 1,
  2009. tr: 1,
  2010. colgroup: 1,
  2011. caption: 1,
  2012. tfoot: 1,
  2013. }),
  2014. code: L,
  2015. tfoot: M,
  2016. cite: L,
  2017. li: P,
  2018. input: {},
  2019. iframe: P,
  2020. strong: L,
  2021. textarea: N,
  2022. noframes: P,
  2023. big: L,
  2024. small: L,
  2025. //trace:
  2026. span: _({
  2027. '#': 1,
  2028. br: 1,
  2029. b: 1,
  2030. strong: 1,
  2031. u: 1,
  2032. i: 1,
  2033. em: 1,
  2034. sub: 1,
  2035. sup: 1,
  2036. strike: 1,
  2037. span: 1,
  2038. }),
  2039. hr: L,
  2040. dt: L,
  2041. sub: L,
  2042. optgroup: _({ option: 1 }),
  2043. param: {},
  2044. bdo: L,
  2045. var: L,
  2046. div: P,
  2047. object: O,
  2048. sup: L,
  2049. dd: P,
  2050. strike: L,
  2051. area: {},
  2052. dir: Q,
  2053. map: X(_({ area: 1, form: 1, p: 1 }), A, F, E),
  2054. applet: O,
  2055. dl: _({ dt: 1, dd: 1 }),
  2056. del: L,
  2057. isindex: {},
  2058. fieldset: X(_({ legend: 1 }), K),
  2059. thead: M,
  2060. ul: Q,
  2061. acronym: L,
  2062. b: L,
  2063. a: X(_({ a: 1 }), J),
  2064. blockquote: X(_({ td: 1, tr: 1, tbody: 1, li: 1 }), P),
  2065. caption: L,
  2066. i: L,
  2067. u: L,
  2068. tbody: M,
  2069. s: L,
  2070. address: X(D, I),
  2071. tt: L,
  2072. legend: L,
  2073. q: L,
  2074. pre: X(G, C),
  2075. p: X(_({ a: 1 }), L),
  2076. em: L,
  2077. dfn: L,
  2078. })
  2079. })())
  2080. // core/domUtils.js
  2081. /**
  2082. * Dom操作工具包
  2083. * @file
  2084. * @module UE.dom.domUtils
  2085. * @since 1.2.6.1
  2086. */
  2087. /**
  2088. * Dom操作工具包
  2089. * @unfile
  2090. * @module UE.dom.domUtils
  2091. */
  2092. function getDomNode(node, start, ltr, startFromChild, fn, guard) {
  2093. var tmpNode = startFromChild && node[start],
  2094. parent
  2095. !tmpNode && (tmpNode = node[ltr])
  2096. while (!tmpNode && (parent = (parent || node).parentNode)) {
  2097. if (parent.tagName == 'BODY' || (guard && !guard(parent))) {
  2098. return null
  2099. }
  2100. tmpNode = parent[ltr]
  2101. }
  2102. if (tmpNode && fn && !fn(tmpNode)) {
  2103. return getDomNode(tmpNode, start, ltr, false, fn)
  2104. }
  2105. return tmpNode
  2106. }
  2107. var attrFix =
  2108. ie && browser.version < 9
  2109. ? {
  2110. tabindex: 'tabIndex',
  2111. readonly: 'readOnly',
  2112. for: 'htmlFor',
  2113. class: 'className',
  2114. maxlength: 'maxLength',
  2115. cellspacing: 'cellSpacing',
  2116. cellpadding: 'cellPadding',
  2117. rowspan: 'rowSpan',
  2118. colspan: 'colSpan',
  2119. usemap: 'useMap',
  2120. frameborder: 'frameBorder',
  2121. }
  2122. : {
  2123. tabindex: 'tabIndex',
  2124. readonly: 'readOnly',
  2125. },
  2126. styleBlock = utils.listToMap([
  2127. '-webkit-box',
  2128. '-moz-box',
  2129. 'block',
  2130. 'list-item',
  2131. 'table',
  2132. 'table-row-group',
  2133. 'table-header-group',
  2134. 'table-footer-group',
  2135. 'table-row',
  2136. 'table-column-group',
  2137. 'table-column',
  2138. 'table-cell',
  2139. 'table-caption',
  2140. ])
  2141. var domUtils = (dom.domUtils = {
  2142. //节点常量
  2143. NODE_ELEMENT: 1,
  2144. NODE_DOCUMENT: 9,
  2145. NODE_TEXT: 3,
  2146. NODE_COMMENT: 8,
  2147. NODE_DOCUMENT_FRAGMENT: 11,
  2148. //位置关系
  2149. POSITION_IDENTICAL: 0,
  2150. POSITION_DISCONNECTED: 1,
  2151. POSITION_FOLLOWING: 2,
  2152. POSITION_PRECEDING: 4,
  2153. POSITION_IS_CONTAINED: 8,
  2154. POSITION_CONTAINS: 16,
  2155. //ie6使用其他的会有一段空白出现
  2156. fillChar: ie && browser.version == '6' ? '\ufeff' : '\u200B',
  2157. //-------------------------Node部分--------------------------------
  2158. keys: {
  2159. /*Backspace*/ 8: 1,
  2160. /*Delete*/ 46: 1,
  2161. /*Shift*/ 16: 1,
  2162. /*Ctrl*/ 17: 1,
  2163. /*Alt*/ 18: 1,
  2164. 37: 1,
  2165. 38: 1,
  2166. 39: 1,
  2167. 40: 1,
  2168. 13: 1 /*enter*/,
  2169. },
  2170. /**
  2171. * 获取节点A相对于节点B的位置关系
  2172. * @method getPosition
  2173. * @param { Node } nodeA 需要查询位置关系的节点A
  2174. * @param { Node } nodeB 需要查询位置关系的节点B
  2175. * @return { Number } 节点A与节点B的关系
  2176. * @example
  2177. * ```javascript
  2178. * //output: 20
  2179. * var position = UE.dom.domUtils.getPosition( document.documentElement, document.body );
  2180. *
  2181. * switch ( position ) {
  2182. *
  2183. * //0
  2184. * case UE.dom.domUtils.POSITION_IDENTICAL:
  2185. * console.log('元素相同');
  2186. * break;
  2187. * //1
  2188. * case UE.dom.domUtils.POSITION_DISCONNECTED:
  2189. * console.log('两个节点在不同的文档中');
  2190. * break;
  2191. * //2
  2192. * case UE.dom.domUtils.POSITION_FOLLOWING:
  2193. * console.log('节点A在节点B之后');
  2194. * break;
  2195. * //4
  2196. * case UE.dom.domUtils.POSITION_PRECEDING;
  2197. * console.log('节点A在节点B之前');
  2198. * break;
  2199. * //8
  2200. * case UE.dom.domUtils.POSITION_IS_CONTAINED:
  2201. * console.log('节点A被节点B包含');
  2202. * break;
  2203. * case 10:
  2204. * console.log('节点A被节点B包含且节点A在节点B之后');
  2205. * break;
  2206. * //16
  2207. * case UE.dom.domUtils.POSITION_CONTAINS:
  2208. * console.log('节点A包含节点B');
  2209. * break;
  2210. * case 20:
  2211. * console.log('节点A包含节点B且节点A在节点B之前');
  2212. * break;
  2213. *
  2214. * }
  2215. * ```
  2216. */
  2217. getPosition: function (nodeA, nodeB) {
  2218. // 如果两个节点是同一个节点
  2219. if (nodeA === nodeB) {
  2220. // domUtils.POSITION_IDENTICAL
  2221. return 0
  2222. }
  2223. var node,
  2224. parentsA = [nodeA],
  2225. parentsB = [nodeB]
  2226. node = nodeA
  2227. while ((node = node.parentNode)) {
  2228. // 如果nodeB是nodeA的祖先节点
  2229. if (node === nodeB) {
  2230. // domUtils.POSITION_IS_CONTAINED + domUtils.POSITION_FOLLOWING
  2231. return 10
  2232. }
  2233. parentsA.push(node)
  2234. }
  2235. node = nodeB
  2236. while ((node = node.parentNode)) {
  2237. // 如果nodeA是nodeB的祖先节点
  2238. if (node === nodeA) {
  2239. // domUtils.POSITION_CONTAINS + domUtils.POSITION_PRECEDING
  2240. return 20
  2241. }
  2242. parentsB.push(node)
  2243. }
  2244. parentsA.reverse()
  2245. parentsB.reverse()
  2246. if (parentsA[0] !== parentsB[0]) {
  2247. // domUtils.POSITION_DISCONNECTED
  2248. return 1
  2249. }
  2250. var i = -1
  2251. while ((i++, parentsA[i] === parentsB[i])) {}
  2252. nodeA = parentsA[i]
  2253. nodeB = parentsB[i]
  2254. while ((nodeA = nodeA.nextSibling)) {
  2255. if (nodeA === nodeB) {
  2256. // domUtils.POSITION_PRECEDING
  2257. return 4
  2258. }
  2259. }
  2260. // domUtils.POSITION_FOLLOWING
  2261. return 2
  2262. },
  2263. /**
  2264. * 检测节点node在父节点中的索引位置
  2265. * @method getNodeIndex
  2266. * @param { Node } node 需要检测的节点对象
  2267. * @return { Number } 该节点在父节点中的位置
  2268. * @see UE.dom.domUtils.getNodeIndex(Node,Boolean)
  2269. */
  2270. /**
  2271. * 检测节点node在父节点中的索引位置, 根据给定的mergeTextNode参数决定是否要合并多个连续的文本节点为一个节点
  2272. * @method getNodeIndex
  2273. * @param { Node } node 需要检测的节点对象
  2274. * @param { Boolean } mergeTextNode 是否合并多个连续的文本节点为一个节点
  2275. * @return { Number } 该节点在父节点中的位置
  2276. * @example
  2277. * ```javascript
  2278. *
  2279. * var node = document.createElement("div");
  2280. *
  2281. * node.appendChild( document.createTextNode( "hello" ) );
  2282. * node.appendChild( document.createTextNode( "world" ) );
  2283. * node.appendChild( node = document.createElement( "div" ) );
  2284. *
  2285. * //output: 2
  2286. * console.log( UE.dom.domUtils.getNodeIndex( node ) );
  2287. *
  2288. * //output: 1
  2289. * console.log( UE.dom.domUtils.getNodeIndex( node, true ) );
  2290. *
  2291. * ```
  2292. */
  2293. getNodeIndex: function (node, ignoreTextNode) {
  2294. var preNode = node,
  2295. i = 0
  2296. while ((preNode = preNode.previousSibling)) {
  2297. if (ignoreTextNode && preNode.nodeType == 3) {
  2298. if (preNode.nodeType != preNode.nextSibling.nodeType) {
  2299. i++
  2300. }
  2301. continue
  2302. }
  2303. i++
  2304. }
  2305. return i
  2306. },
  2307. /**
  2308. * 检测节点node是否在给定的document对象上
  2309. * @method inDoc
  2310. * @param { Node } node 需要检测的节点对象
  2311. * @param { DomDocument } doc 需要检测的document对象
  2312. * @return { Boolean } 该节点node是否在给定的document的dom树上
  2313. * @example
  2314. * ```javascript
  2315. *
  2316. * var node = document.createElement("div");
  2317. *
  2318. * //output: false
  2319. * console.log( UE.do.domUtils.inDoc( node, document ) );
  2320. *
  2321. * document.body.appendChild( node );
  2322. *
  2323. * //output: true
  2324. * console.log( UE.do.domUtils.inDoc( node, document ) );
  2325. *
  2326. * ```
  2327. */
  2328. inDoc: function (node, doc) {
  2329. return domUtils.getPosition(node, doc) == 10
  2330. },
  2331. /**
  2332. * 根据给定的过滤规则filterFn, 查找符合该过滤规则的node节点的第一个祖先节点,
  2333. * 查找的起点是给定node节点的父节点。
  2334. * @method findParent
  2335. * @param { Node } node 需要查找的节点
  2336. * @param { Function } filterFn 自定义的过滤方法。
  2337. * @warning 查找的终点是到body节点为止
  2338. * @remind 自定义的过滤方法filterFn接受一个Node对象作为参数, 该对象代表当前执行检测的祖先节点。 如果该
  2339. * 节点满足过滤条件, 则要求返回true, 这时将直接返回该节点作为findParent()的结果, 否则, 请返回false。
  2340. * @return { Node | Null } 如果找到符合过滤条件的节点, 就返回该节点, 否则返回NULL
  2341. * @example
  2342. * ```javascript
  2343. * var filterNode = UE.dom.domUtils.findParent( document.body.firstChild, function ( node ) {
  2344. *
  2345. * //由于查找的终点是body节点, 所以永远也不会匹配当前过滤器的条件, 即这里永远会返回false
  2346. * return node.tagName === "HTML";
  2347. *
  2348. * } );
  2349. *
  2350. * //output: true
  2351. * console.log( filterNode === null );
  2352. * ```
  2353. */
  2354. /**
  2355. * 根据给定的过滤规则filterFn, 查找符合该过滤规则的node节点的第一个祖先节点,
  2356. * 如果includeSelf的值为true,则查找的起点是给定的节点node, 否则, 起点是node的父节点
  2357. * @method findParent
  2358. * @param { Node } node 需要查找的节点
  2359. * @param { Function } filterFn 自定义的过滤方法。
  2360. * @param { Boolean } includeSelf 查找过程是否包含自身
  2361. * @warning 查找的终点是到body节点为止
  2362. * @remind 自定义的过滤方法filterFn接受一个Node对象作为参数, 该对象代表当前执行检测的祖先节点。 如果该
  2363. * 节点满足过滤条件, 则要求返回true, 这时将直接返回该节点作为findParent()的结果, 否则, 请返回false。
  2364. * @remind 如果includeSelf为true, 则过滤器第一次执行时的参数会是节点本身。
  2365. * 反之, 过滤器第一次执行时的参数将是该节点的父节点。
  2366. * @return { Node | Null } 如果找到符合过滤条件的节点, 就返回该节点, 否则返回NULL
  2367. * @example
  2368. * ```html
  2369. * <body>
  2370. *
  2371. * <div id="test">
  2372. * </div>
  2373. *
  2374. * <script type="text/javascript">
  2375. *
  2376. * //output: DIV, BODY
  2377. * var filterNode = UE.dom.domUtils.findParent( document.getElementById( "test" ), function ( node ) {
  2378. *
  2379. * console.log( node.tagName );
  2380. * return false;
  2381. *
  2382. * }, true );
  2383. *
  2384. * </script>
  2385. * </body>
  2386. * ```
  2387. */
  2388. findParent: function (node, filterFn, includeSelf) {
  2389. if (node && !domUtils.isBody(node)) {
  2390. node = includeSelf ? node : node.parentNode
  2391. while (node) {
  2392. if (!filterFn || filterFn(node) || domUtils.isBody(node)) {
  2393. return filterFn && !filterFn(node) && domUtils.isBody(node)
  2394. ? null
  2395. : node
  2396. }
  2397. node = node.parentNode
  2398. }
  2399. }
  2400. return null
  2401. },
  2402. /**
  2403. * 查找node的节点名为tagName的第一个祖先节点, 查找的起点是node节点的父节点。
  2404. * @method findParentByTagName
  2405. * @param { Node } node 需要查找的节点对象
  2406. * @param { Array } tagNames 需要查找的父节点的名称数组
  2407. * @warning 查找的终点是到body节点为止
  2408. * @return { Node | NULL } 如果找到符合条件的节点, 则返回该节点, 否则返回NULL
  2409. * @example
  2410. * ```javascript
  2411. * var node = UE.dom.domUtils.findParentByTagName( document.getElementsByTagName("div")[0], [ "BODY" ] );
  2412. * //output: BODY
  2413. * console.log( node.tagName );
  2414. * ```
  2415. */
  2416. /**
  2417. * 查找node的节点名为tagName的祖先节点, 如果includeSelf的值为true,则查找的起点是给定的节点node,
  2418. * 否则, 起点是node的父节点。
  2419. * @method findParentByTagName
  2420. * @param { Node } node 需要查找的节点对象
  2421. * @param { Array } tagNames 需要查找的父节点的名称数组
  2422. * @param { Boolean } includeSelf 查找过程是否包含node节点自身
  2423. * @warning 查找的终点是到body节点为止
  2424. * @return { Node | NULL } 如果找到符合条件的节点, 则返回该节点, 否则返回NULL
  2425. * @example
  2426. * ```javascript
  2427. * var queryTarget = document.getElementsByTagName("div")[0];
  2428. * var node = UE.dom.domUtils.findParentByTagName( queryTarget, [ "DIV" ], true );
  2429. * //output: true
  2430. * console.log( queryTarget === node );
  2431. * ```
  2432. */
  2433. findParentByTagName: function (node, tagNames, includeSelf, excludeFn) {
  2434. tagNames = utils.listToMap(
  2435. utils.isArray(tagNames) ? tagNames : [tagNames]
  2436. )
  2437. return domUtils.findParent(
  2438. node,
  2439. function (node) {
  2440. return tagNames[node.tagName] && !(excludeFn && excludeFn(node))
  2441. },
  2442. includeSelf
  2443. )
  2444. },
  2445. /**
  2446. * 查找节点node的祖先节点集合, 查找的起点是给定节点的父节点,结果集中不包含给定的节点。
  2447. * @method findParents
  2448. * @param { Node } node 需要查找的节点对象
  2449. * @return { Array } 给定节点的祖先节点数组
  2450. * @grammar UE.dom.domUtils.findParents(node) => Array //返回一个祖先节点数组集合,不包含自身
  2451. * @grammar UE.dom.domUtils.findParents(node,includeSelf) => Array //返回一个祖先节点数组集合,includeSelf指定是否包含自身
  2452. * @grammar UE.dom.domUtils.findParents(node,includeSelf,filterFn) => Array //返回一个祖先节点数组集合,filterFn指定过滤条件,返回true的node将被选取
  2453. * @grammar UE.dom.domUtils.findParents(node,includeSelf,filterFn,closerFirst) => Array //返回一个祖先节点数组集合,closerFirst为true的话,node的直接父亲节点是数组的第0个
  2454. */
  2455. /**
  2456. * 查找节点node的祖先节点集合, 如果includeSelf的值为true,
  2457. * 则返回的结果集中允许出现当前给定的节点, 否则, 该节点不会出现在其结果集中。
  2458. * @method findParents
  2459. * @param { Node } node 需要查找的节点对象
  2460. * @param { Boolean } includeSelf 查找的结果中是否允许包含当前查找的节点对象
  2461. * @return { Array } 给定节点的祖先节点数组
  2462. */
  2463. findParents: function (node, includeSelf, filterFn, closerFirst) {
  2464. var parents =
  2465. includeSelf && ((filterFn && filterFn(node)) || !filterFn) ? [node] : []
  2466. while ((node = domUtils.findParent(node, filterFn))) {
  2467. parents.push(node)
  2468. }
  2469. return closerFirst ? parents : parents.reverse()
  2470. },
  2471. /**
  2472. * 在节点node后面插入新节点newNode
  2473. * @method insertAfter
  2474. * @param { Node } node 目标节点
  2475. * @param { Node } newNode 新插入的节点, 该节点将置于目标节点之后
  2476. * @return { Node } 新插入的节点
  2477. */
  2478. insertAfter: function (node, newNode) {
  2479. return node.nextSibling
  2480. ? node.parentNode.insertBefore(newNode, node.nextSibling)
  2481. : node.parentNode.appendChild(newNode)
  2482. },
  2483. /**
  2484. * 删除节点node及其下属的所有节点
  2485. * @method remove
  2486. * @param { Node } node 需要删除的节点对象
  2487. * @return { Node } 返回刚删除的节点对象
  2488. * @example
  2489. * ```html
  2490. * <div id="test">
  2491. * <div id="child">你好</div>
  2492. * </div>
  2493. * <script>
  2494. * UE.dom.domUtils.remove( document.body, false );
  2495. * //output: false
  2496. * console.log( document.getElementById( "child" ) !== null );
  2497. * </script>
  2498. * ```
  2499. */
  2500. /**
  2501. * 删除节点node,并根据keepChildren的值决定是否保留子节点
  2502. * @method remove
  2503. * @param { Node } node 需要删除的节点对象
  2504. * @param { Boolean } keepChildren 是否需要保留子节点
  2505. * @return { Node } 返回刚删除的节点对象
  2506. * @example
  2507. * ```html
  2508. * <div id="test">
  2509. * <div id="child">你好</div>
  2510. * </div>
  2511. * <script>
  2512. * UE.dom.domUtils.remove( document.body, true );
  2513. * //output: true
  2514. * console.log( document.getElementById( "child" ) !== null );
  2515. * </script>
  2516. * ```
  2517. */
  2518. remove: function (node, keepChildren) {
  2519. var parent = node.parentNode,
  2520. child
  2521. if (parent) {
  2522. if (keepChildren && node.hasChildNodes()) {
  2523. while ((child = node.firstChild)) {
  2524. parent.insertBefore(child, node)
  2525. }
  2526. }
  2527. parent.removeChild(node)
  2528. }
  2529. return node
  2530. },
  2531. /**
  2532. * 取得node节点的下一个兄弟节点, 如果该节点其后没有兄弟节点, 则递归查找其父节点之后的第一个兄弟节点,
  2533. * 直到找到满足条件的节点或者递归到BODY节点之后才会结束。
  2534. * @method getNextDomNode
  2535. * @param { Node } node 需要获取其后的兄弟节点的节点对象
  2536. * @return { Node | NULL } 如果找满足条件的节点, 则返回该节点, 否则返回NULL
  2537. * @example
  2538. * ```html
  2539. * <body>
  2540. * <div id="test">
  2541. * <span></span>
  2542. * </div>
  2543. * <i>xxx</i>
  2544. * </body>
  2545. * <script>
  2546. *
  2547. * //output: i节点
  2548. * console.log( UE.dom.domUtils.getNextDomNode( document.getElementById( "test" ) ) );
  2549. *
  2550. * </script>
  2551. * ```
  2552. * @example
  2553. * ```html
  2554. * <body>
  2555. * <div>
  2556. * <span></span>
  2557. * <i id="test">xxx</i>
  2558. * </div>
  2559. * <b>xxx</b>
  2560. * </body>
  2561. * <script>
  2562. *
  2563. * //由于id为test的i节点之后没有兄弟节点, 则查找其父节点(div)后面的兄弟节点
  2564. * //output: b节点
  2565. * console.log( UE.dom.domUtils.getNextDomNode( document.getElementById( "test" ) ) );
  2566. *
  2567. * </script>
  2568. * ```
  2569. */
  2570. /**
  2571. * 取得node节点的下一个兄弟节点, 如果startFromChild的值为ture,则先获取其子节点,
  2572. * 如果有子节点则直接返回第一个子节点;如果没有子节点或者startFromChild的值为false,
  2573. * 则执行<a href="#UE.dom.domUtils.getNextDomNode(Node)">getNextDomNode(Node node)</a>的查找过程。
  2574. * @method getNextDomNode
  2575. * @param { Node } node 需要获取其后的兄弟节点的节点对象
  2576. * @param { Boolean } startFromChild 查找过程是否从其子节点开始
  2577. * @return { Node | NULL } 如果找满足条件的节点, 则返回该节点, 否则返回NULL
  2578. * @see UE.dom.domUtils.getNextDomNode(Node)
  2579. */
  2580. getNextDomNode: function (node, startFromChild, filterFn, guard) {
  2581. return getDomNode(
  2582. node,
  2583. 'firstChild',
  2584. 'nextSibling',
  2585. startFromChild,
  2586. filterFn,
  2587. guard
  2588. )
  2589. },
  2590. getPreDomNode: function (node, startFromChild, filterFn, guard) {
  2591. return getDomNode(
  2592. node,
  2593. 'lastChild',
  2594. 'previousSibling',
  2595. startFromChild,
  2596. filterFn,
  2597. guard
  2598. )
  2599. },
  2600. /**
  2601. * 检测节点node是否属是UEditor定义的bookmark节点
  2602. * @method isBookmarkNode
  2603. * @private
  2604. * @param { Node } node 需要检测的节点对象
  2605. * @return { Boolean } 是否是bookmark节点
  2606. * @example
  2607. * ```html
  2608. * <span id="_baidu_bookmark_1"></span>
  2609. * <script>
  2610. * var bookmarkNode = document.getElementById("_baidu_bookmark_1");
  2611. * //output: true
  2612. * console.log( UE.dom.domUtils.isBookmarkNode( bookmarkNode ) );
  2613. * </script>
  2614. * ```
  2615. */
  2616. isBookmarkNode: function (node) {
  2617. return node.nodeType == 1 && node.id && /^_baidu_bookmark_/i.test(node.id)
  2618. },
  2619. /**
  2620. * 获取节点node所属的window对象
  2621. * @method getWindow
  2622. * @param { Node } node 节点对象
  2623. * @return { Window } 当前节点所属的window对象
  2624. * @example
  2625. * ```javascript
  2626. * //output: true
  2627. * console.log( UE.dom.domUtils.getWindow( document.body ) === window );
  2628. * ```
  2629. */
  2630. getWindow: function (node) {
  2631. var doc = node.ownerDocument || node
  2632. return doc.defaultView || doc.parentWindow
  2633. },
  2634. /**
  2635. * 获取离nodeA与nodeB最近的公共的祖先节点
  2636. * @method getCommonAncestor
  2637. * @param { Node } nodeA 第一个节点
  2638. * @param { Node } nodeB 第二个节点
  2639. * @remind 如果给定的两个节点是同一个节点, 将直接返回该节点。
  2640. * @return { Node | NULL } 如果未找到公共节点, 返回NULL, 否则返回最近的公共祖先节点。
  2641. * @example
  2642. * ```javascript
  2643. * var commonAncestor = UE.dom.domUtils.getCommonAncestor( document.body, document.body.firstChild );
  2644. * //output: true
  2645. * console.log( commonAncestor.tagName.toLowerCase() === 'body' );
  2646. * ```
  2647. */
  2648. getCommonAncestor: function (nodeA, nodeB) {
  2649. if (nodeA === nodeB) return nodeA
  2650. var parentsA = [nodeA],
  2651. parentsB = [nodeB],
  2652. parent = nodeA,
  2653. i = -1
  2654. while ((parent = parent.parentNode)) {
  2655. if (parent === nodeB) {
  2656. return parent
  2657. }
  2658. parentsA.push(parent)
  2659. }
  2660. parent = nodeB
  2661. while ((parent = parent.parentNode)) {
  2662. if (parent === nodeA) return parent
  2663. parentsB.push(parent)
  2664. }
  2665. parentsA.reverse()
  2666. parentsB.reverse()
  2667. while ((i++, parentsA[i] === parentsB[i])) {}
  2668. return i == 0 ? null : parentsA[i - 1]
  2669. },
  2670. /**
  2671. * 清除node节点左右连续为空的兄弟inline节点
  2672. * @method clearEmptySibling
  2673. * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
  2674. * 则这些兄弟节点将被删除
  2675. * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext) //ignoreNext指定是否忽略右边空节点
  2676. * @grammar UE.dom.domUtils.clearEmptySibling(node,ignoreNext,ignorePre) //ignorePre指定是否忽略左边空节点
  2677. * @example
  2678. * ```html
  2679. * <body>
  2680. * <div></div>
  2681. * <span id="test"></span>
  2682. * <i></i>
  2683. * <b></b>
  2684. * <em>xxx</em>
  2685. * <span></span>
  2686. * </body>
  2687. * <script>
  2688. *
  2689. * UE.dom.domUtils.clearEmptySibling( document.getElementById( "test" ) );
  2690. *
  2691. * //output: <div></div><span id="test"></span><em>xxx</em><span></span>
  2692. * console.log( document.body.innerHTML );
  2693. *
  2694. * </script>
  2695. * ```
  2696. */
  2697. /**
  2698. * 清除node节点左右连续为空的兄弟inline节点, 如果ignoreNext的值为true,
  2699. * 则忽略对右边兄弟节点的操作。
  2700. * @method clearEmptySibling
  2701. * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
  2702. * @param { Boolean } ignoreNext 是否忽略忽略对右边的兄弟节点的操作
  2703. * 则这些兄弟节点将被删除
  2704. * @see UE.dom.domUtils.clearEmptySibling(Node)
  2705. */
  2706. /**
  2707. * 清除node节点左右连续为空的兄弟inline节点, 如果ignoreNext的值为true,
  2708. * 则忽略对右边兄弟节点的操作, 如果ignorePre的值为true,则忽略对左边兄弟节点的操作。
  2709. * @method clearEmptySibling
  2710. * @param { Node } node 执行的节点对象, 如果该节点的左右连续的兄弟节点是空的inline节点,
  2711. * @param { Boolean } ignoreNext 是否忽略忽略对右边的兄弟节点的操作
  2712. * @param { Boolean } ignorePre 是否忽略忽略对左边的兄弟节点的操作
  2713. * 则这些兄弟节点将被删除
  2714. * @see UE.dom.domUtils.clearEmptySibling(Node)
  2715. */
  2716. clearEmptySibling: function (node, ignoreNext, ignorePre) {
  2717. function clear(next, dir) {
  2718. var tmpNode
  2719. while (
  2720. next &&
  2721. !domUtils.isBookmarkNode(next) &&
  2722. (domUtils.isEmptyInlineElement(next) ||
  2723. //这里不能把空格算进来会吧空格干掉,出现文字间的空格丢掉了
  2724. !new RegExp('[^\t\n\r' + domUtils.fillChar + ']').test(
  2725. next.nodeValue
  2726. ))
  2727. ) {
  2728. tmpNode = next[dir]
  2729. domUtils.remove(next)
  2730. next = tmpNode
  2731. }
  2732. }
  2733. !ignoreNext && clear(node.nextSibling, 'nextSibling')
  2734. !ignorePre && clear(node.previousSibling, 'previousSibling')
  2735. },
  2736. /**
  2737. * 将一个文本节点textNode拆分成两个文本节点,offset指定拆分位置
  2738. * @method split
  2739. * @param { Node } textNode 需要拆分的文本节点对象
  2740. * @param { int } offset 需要拆分的位置, 位置计算从0开始
  2741. * @return { Node } 拆分后形成的新节点
  2742. * @example
  2743. * ```html
  2744. * <div id="test">abcdef</div>
  2745. * <script>
  2746. * var newNode = UE.dom.domUtils.split( document.getElementById( "test" ).firstChild, 3 );
  2747. * //output: def
  2748. * console.log( newNode.nodeValue );
  2749. * </script>
  2750. * ```
  2751. */
  2752. split: function (node, offset) {
  2753. var doc = node.ownerDocument
  2754. if (browser.ie && offset == node.nodeValue.length) {
  2755. var next = doc.createTextNode('')
  2756. return domUtils.insertAfter(node, next)
  2757. }
  2758. var retval = node.splitText(offset)
  2759. //ie8下splitText不会跟新childNodes,我们手动触发他的更新
  2760. if (browser.ie8) {
  2761. var tmpNode = doc.createTextNode('')
  2762. domUtils.insertAfter(retval, tmpNode)
  2763. domUtils.remove(tmpNode)
  2764. }
  2765. return retval
  2766. },
  2767. /**
  2768. * 检测文本节点textNode是否为空节点(包括空格、换行、占位符等字符)
  2769. * @method isWhitespace
  2770. * @param { Node } node 需要检测的节点对象
  2771. * @return { Boolean } 检测的节点是否为空
  2772. * @example
  2773. * ```html
  2774. * <div id="test">
  2775. *
  2776. * </div>
  2777. * <script>
  2778. * //output: true
  2779. * console.log( UE.dom.domUtils.isWhitespace( document.getElementById("test").firstChild ) );
  2780. * </script>
  2781. * ```
  2782. */
  2783. isWhitespace: function (node) {
  2784. return !new RegExp('[^ \t\n\r' + domUtils.fillChar + ']').test(
  2785. node.nodeValue
  2786. )
  2787. },
  2788. /**
  2789. * 获取元素element相对于viewport的位置坐标
  2790. * @method getXY
  2791. * @param { Node } element 需要计算位置的节点对象
  2792. * @return { Object } 返回形如{x:left,y:top}的一个key-value映射对象, 其中键x代表水平偏移距离,
  2793. * y代表垂直偏移距离。
  2794. *
  2795. * @example
  2796. * ```javascript
  2797. * var location = UE.dom.domUtils.getXY( document.getElementById("test") );
  2798. * //output: test的坐标为: 12, 24
  2799. * console.log( 'test的坐标为: ', location.x, ',', location.y );
  2800. * ```
  2801. */
  2802. getXY: function (element) {
  2803. var x = 0,
  2804. y = 0
  2805. while (element.offsetParent) {
  2806. y += element.offsetTop
  2807. x += element.offsetLeft
  2808. element = element.offsetParent
  2809. }
  2810. return { x: x, y: y }
  2811. },
  2812. /**
  2813. * 为元素element绑定原生DOM事件,type为事件类型,handler为处理函数
  2814. * @method on
  2815. * @param { Node } element 需要绑定事件的节点对象
  2816. * @param { String } type 绑定的事件类型
  2817. * @param { Function } handler 事件处理器
  2818. * @example
  2819. * ```javascript
  2820. * UE.dom.domUtils.on(document.body,"click",function(e){
  2821. * //e为事件对象,this为被点击元素对戏那个
  2822. * });
  2823. * ```
  2824. */
  2825. /**
  2826. * 为元素element绑定原生DOM事件,type为事件类型,handler为处理函数
  2827. * @method on
  2828. * @param { Node } element 需要绑定事件的节点对象
  2829. * @param { Array } type 绑定的事件类型数组
  2830. * @param { Function } handler 事件处理器
  2831. * @example
  2832. * ```javascript
  2833. * UE.dom.domUtils.on(document.body,["click","mousedown"],function(evt){
  2834. * //evt为事件对象,this为被点击元素对象
  2835. * });
  2836. * ```
  2837. */
  2838. on: function (element, type, handler) {
  2839. var types = utils.isArray(type) ? type : utils.trim(type).split(/\s+/),
  2840. k = types.length
  2841. if (k)
  2842. while (k--) {
  2843. type = types[k]
  2844. if (element.addEventListener) {
  2845. element.addEventListener(type, handler, false)
  2846. } else {
  2847. if (!handler._d) {
  2848. handler._d = {
  2849. els: [],
  2850. }
  2851. }
  2852. var key = type + handler.toString(),
  2853. index = utils.indexOf(handler._d.els, element)
  2854. if (!handler._d[key] || index == -1) {
  2855. if (index == -1) {
  2856. handler._d.els.push(element)
  2857. }
  2858. if (!handler._d[key]) {
  2859. handler._d[key] = function (evt) {
  2860. return handler.call(evt.srcElement, evt || window.event)
  2861. }
  2862. }
  2863. element.attachEvent('on' + type, handler._d[key])
  2864. }
  2865. }
  2866. }
  2867. element = null
  2868. },
  2869. /**
  2870. * 解除DOM事件绑定
  2871. * @method un
  2872. * @param { Node } element 需要解除事件绑定的节点对象
  2873. * @param { String } type 需要接触绑定的事件类型
  2874. * @param { Function } handler 对应的事件处理器
  2875. * @example
  2876. * ```javascript
  2877. * UE.dom.domUtils.un(document.body,"click",function(evt){
  2878. * //evt为事件对象,this为被点击元素对象
  2879. * });
  2880. * ```
  2881. */
  2882. /**
  2883. * 解除DOM事件绑定
  2884. * @method un
  2885. * @param { Node } element 需要解除事件绑定的节点对象
  2886. * @param { Array } type 需要接触绑定的事件类型数组
  2887. * @param { Function } handler 对应的事件处理器
  2888. * @example
  2889. * ```javascript
  2890. * UE.dom.domUtils.un(document.body, ["click","mousedown"],function(evt){
  2891. * //evt为事件对象,this为被点击元素对象
  2892. * });
  2893. * ```
  2894. */
  2895. un: function (element, type, handler) {
  2896. var types = utils.isArray(type) ? type : utils.trim(type).split(/\s+/),
  2897. k = types.length
  2898. if (k)
  2899. while (k--) {
  2900. type = types[k]
  2901. if (element.removeEventListener) {
  2902. element.removeEventListener(type, handler, false)
  2903. } else {
  2904. var key = type + handler.toString()
  2905. try {
  2906. element.detachEvent(
  2907. 'on' + type,
  2908. handler._d ? handler._d[key] : handler
  2909. )
  2910. } catch (e) {}
  2911. if (handler._d && handler._d[key]) {
  2912. var index = utils.indexOf(handler._d.els, element)
  2913. if (index != -1) {
  2914. handler._d.els.splice(index, 1)
  2915. }
  2916. handler._d.els.length == 0 && delete handler._d[key]
  2917. }
  2918. }
  2919. }
  2920. },
  2921. /**
  2922. * 比较节点nodeA与节点nodeB是否具有相同的标签名、属性名以及属性值
  2923. * @method isSameElement
  2924. * @param { Node } nodeA 需要比较的节点
  2925. * @param { Node } nodeB 需要比较的节点
  2926. * @return { Boolean } 两个节点是否具有相同的标签名、属性名以及属性值
  2927. * @example
  2928. * ```html
  2929. * <span style="font-size:12px">ssss</span>
  2930. * <span style="font-size:12px">bbbbb</span>
  2931. * <span style="font-size:13px">ssss</span>
  2932. * <span style="font-size:14px">bbbbb</span>
  2933. *
  2934. * <script>
  2935. *
  2936. * var nodes = document.getElementsByTagName( "span" );
  2937. *
  2938. * //output: true
  2939. * console.log( UE.dom.domUtils.isSameElement( nodes[0], nodes[1] ) );
  2940. *
  2941. * //output: false
  2942. * console.log( UE.dom.domUtils.isSameElement( nodes[2], nodes[3] ) );
  2943. *
  2944. * </script>
  2945. * ```
  2946. */
  2947. isSameElement: function (nodeA, nodeB) {
  2948. if (nodeA.tagName != nodeB.tagName) {
  2949. return false
  2950. }
  2951. var thisAttrs = nodeA.attributes,
  2952. otherAttrs = nodeB.attributes
  2953. if (!ie && thisAttrs.length != otherAttrs.length) {
  2954. return false
  2955. }
  2956. var attrA,
  2957. attrB,
  2958. al = 0,
  2959. bl = 0
  2960. for (var i = 0; (attrA = thisAttrs[i++]); ) {
  2961. if (attrA.nodeName == 'style') {
  2962. if (attrA.specified) {
  2963. al++
  2964. }
  2965. if (domUtils.isSameStyle(nodeA, nodeB)) {
  2966. continue
  2967. } else {
  2968. return false
  2969. }
  2970. }
  2971. if (ie) {
  2972. if (attrA.specified) {
  2973. al++
  2974. attrB = otherAttrs.getNamedItem(attrA.nodeName)
  2975. } else {
  2976. continue
  2977. }
  2978. } else {
  2979. attrB = nodeB.attributes[attrA.nodeName]
  2980. }
  2981. if (!attrB.specified || attrA.nodeValue != attrB.nodeValue) {
  2982. return false
  2983. }
  2984. }
  2985. // 有可能attrB的属性包含了attrA的属性之外还有自己的属性
  2986. if (ie) {
  2987. for (i = 0; (attrB = otherAttrs[i++]); ) {
  2988. if (attrB.specified) {
  2989. bl++
  2990. }
  2991. }
  2992. if (al != bl) {
  2993. return false
  2994. }
  2995. }
  2996. return true
  2997. },
  2998. /**
  2999. * 判断节点nodeA与节点nodeB的元素的style属性是否一致
  3000. * @method isSameStyle
  3001. * @param { Node } nodeA 需要比较的节点
  3002. * @param { Node } nodeB 需要比较的节点
  3003. * @return { Boolean } 两个节点是否具有相同的style属性值
  3004. * @example
  3005. * ```html
  3006. * <span style="font-size:12px">ssss</span>
  3007. * <span style="font-size:12px">bbbbb</span>
  3008. * <span style="font-size:13px">ssss</span>
  3009. * <span style="font-size:14px">bbbbb</span>
  3010. *
  3011. * <script>
  3012. *
  3013. * var nodes = document.getElementsByTagName( "span" );
  3014. *
  3015. * //output: true
  3016. * console.log( UE.dom.domUtils.isSameStyle( nodes[0], nodes[1] ) );
  3017. *
  3018. * //output: false
  3019. * console.log( UE.dom.domUtils.isSameStyle( nodes[2], nodes[3] ) );
  3020. *
  3021. * </script>
  3022. * ```
  3023. */
  3024. isSameStyle: function (nodeA, nodeB) {
  3025. var styleA = nodeA.style.cssText
  3026. .replace(/( ?; ?)/g, ';')
  3027. .replace(/( ?: ?)/g, ':'),
  3028. styleB = nodeB.style.cssText
  3029. .replace(/( ?; ?)/g, ';')
  3030. .replace(/( ?: ?)/g, ':')
  3031. if (browser.opera) {
  3032. styleA = nodeA.style
  3033. styleB = nodeB.style
  3034. if (styleA.length != styleB.length) return false
  3035. for (var p in styleA) {
  3036. if (/^(\d+|csstext)$/i.test(p)) {
  3037. continue
  3038. }
  3039. if (styleA[p] != styleB[p]) {
  3040. return false
  3041. }
  3042. }
  3043. return true
  3044. }
  3045. if (!styleA || !styleB) {
  3046. return styleA == styleB
  3047. }
  3048. styleA = styleA.split(';')
  3049. styleB = styleB.split(';')
  3050. if (styleA.length != styleB.length) {
  3051. return false
  3052. }
  3053. for (var i = 0, ci; (ci = styleA[i++]); ) {
  3054. if (utils.indexOf(styleB, ci) == -1) {
  3055. return false
  3056. }
  3057. }
  3058. return true
  3059. },
  3060. /**
  3061. * 检查节点node是否为block元素
  3062. * @method isBlockElm
  3063. * @param { Node } node 需要检测的节点对象
  3064. * @return { Boolean } 是否是block元素节点
  3065. * @warning 该方法的判断规则如下: 如果该元素原本是block元素, 则不论该元素当前的css样式是什么都会返回true;
  3066. * 否则,检测该元素的css样式, 如果该元素当前是block元素, 则返回true。 其余情况下都返回false。
  3067. * @example
  3068. * ```html
  3069. * <span id="test1" style="display: block"></span>
  3070. * <span id="test2"></span>
  3071. * <div id="test3" style="display: inline"></div>
  3072. *
  3073. * <script>
  3074. *
  3075. * //output: true
  3076. * console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test1") ) );
  3077. *
  3078. * //output: false
  3079. * console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test2") ) );
  3080. *
  3081. * //output: true
  3082. * console.log( UE.dom.domUtils.isBlockElm( document.getElementById("test3") ) );
  3083. *
  3084. * </script>
  3085. * ```
  3086. */
  3087. isBlockElm: function (node) {
  3088. return (
  3089. node.nodeType == 1 &&
  3090. (dtd.$block[node.tagName] ||
  3091. styleBlock[domUtils.getComputedStyle(node, 'display')]) &&
  3092. !dtd.$nonChild[node.tagName]
  3093. )
  3094. },
  3095. /**
  3096. * 检测node节点是否为body节点
  3097. * @method isBody
  3098. * @param { Element } node 需要检测的dom元素
  3099. * @return { Boolean } 给定的元素是否是body元素
  3100. * @example
  3101. * ```javascript
  3102. * //output: true
  3103. * console.log( UE.dom.domUtils.isBody( document.body ) );
  3104. * ```
  3105. */
  3106. isBody: function (node) {
  3107. return node && node.nodeType == 1 && node.tagName.toLowerCase() == 'body'
  3108. },
  3109. /**
  3110. * 以node节点为分界,将该节点的指定祖先节点parent拆分成两个独立的节点,
  3111. * 拆分形成的两个节点之间是node节点
  3112. * @method breakParent
  3113. * @param { Node } node 作为分界的节点对象
  3114. * @param { Node } parent 该节点必须是node节点的祖先节点, 且是block节点。
  3115. * @return { Node } 给定的node分界节点
  3116. * @example
  3117. * ```javascript
  3118. *
  3119. * var node = document.createElement("span"),
  3120. * wrapNode = document.createElement( "div" ),
  3121. * parent = document.createElement("p");
  3122. *
  3123. * parent.appendChild( node );
  3124. * wrapNode.appendChild( parent );
  3125. *
  3126. * //拆分前
  3127. * //output: <p><span></span></p>
  3128. * console.log( wrapNode.innerHTML );
  3129. *
  3130. *
  3131. * UE.dom.domUtils.breakParent( node, parent );
  3132. * //拆分后
  3133. * //output: <p></p><span></span><p></p>
  3134. * console.log( wrapNode.innerHTML );
  3135. *
  3136. * ```
  3137. */
  3138. breakParent: function (node, parent) {
  3139. var tmpNode,
  3140. parentClone = node,
  3141. clone = node,
  3142. leftNodes,
  3143. rightNodes
  3144. do {
  3145. parentClone = parentClone.parentNode
  3146. if (leftNodes) {
  3147. tmpNode = parentClone.cloneNode(false)
  3148. tmpNode.appendChild(leftNodes)
  3149. leftNodes = tmpNode
  3150. tmpNode = parentClone.cloneNode(false)
  3151. tmpNode.appendChild(rightNodes)
  3152. rightNodes = tmpNode
  3153. } else {
  3154. leftNodes = parentClone.cloneNode(false)
  3155. rightNodes = leftNodes.cloneNode(false)
  3156. }
  3157. while ((tmpNode = clone.previousSibling)) {
  3158. leftNodes.insertBefore(tmpNode, leftNodes.firstChild)
  3159. }
  3160. while ((tmpNode = clone.nextSibling)) {
  3161. rightNodes.appendChild(tmpNode)
  3162. }
  3163. clone = parentClone
  3164. } while (parent !== parentClone)
  3165. tmpNode = parent.parentNode
  3166. tmpNode.insertBefore(leftNodes, parent)
  3167. tmpNode.insertBefore(rightNodes, parent)
  3168. tmpNode.insertBefore(node, rightNodes)
  3169. domUtils.remove(parent)
  3170. return node
  3171. },
  3172. /**
  3173. * 检查节点node是否是空inline节点
  3174. * @method isEmptyInlineElement
  3175. * @param { Node } node 需要检测的节点对象
  3176. * @return { Number } 如果给定的节点是空的inline节点, 则返回1, 否则返回0。
  3177. * @example
  3178. * ```html
  3179. * <b><i></i></b> => 1
  3180. * <b><i></i><u></u></b> => 1
  3181. * <b></b> => 1
  3182. * <b>xx<i></i></b> => 0
  3183. * ```
  3184. */
  3185. isEmptyInlineElement: function (node) {
  3186. if (node.nodeType != 1 || !dtd.$removeEmpty[node.tagName]) {
  3187. return 0
  3188. }
  3189. node = node.firstChild
  3190. while (node) {
  3191. //如果是创建的bookmark就跳过
  3192. if (domUtils.isBookmarkNode(node)) {
  3193. return 0
  3194. }
  3195. if (
  3196. (node.nodeType == 1 && !domUtils.isEmptyInlineElement(node)) ||
  3197. (node.nodeType == 3 && !domUtils.isWhitespace(node))
  3198. ) {
  3199. return 0
  3200. }
  3201. node = node.nextSibling
  3202. }
  3203. return 1
  3204. },
  3205. /**
  3206. * 删除node节点下首尾两端的空白文本子节点
  3207. * @method trimWhiteTextNode
  3208. * @param { Element } node 需要执行删除操作的元素对象
  3209. * @example
  3210. * ```javascript
  3211. * var node = document.createElement("div");
  3212. *
  3213. * node.appendChild( document.createTextNode( "" ) );
  3214. *
  3215. * node.appendChild( document.createElement("div") );
  3216. *
  3217. * node.appendChild( document.createTextNode( "" ) );
  3218. *
  3219. * //3
  3220. * console.log( node.childNodes.length );
  3221. *
  3222. * UE.dom.domUtils.trimWhiteTextNode( node );
  3223. *
  3224. * //1
  3225. * console.log( node.childNodes.length );
  3226. * ```
  3227. */
  3228. trimWhiteTextNode: function (node) {
  3229. function remove(dir) {
  3230. var child
  3231. while (
  3232. (child = node[dir]) &&
  3233. child.nodeType == 3 &&
  3234. domUtils.isWhitespace(child)
  3235. ) {
  3236. node.removeChild(child)
  3237. }
  3238. }
  3239. remove('firstChild')
  3240. remove('lastChild')
  3241. },
  3242. /**
  3243. * 合并node节点下相同的子节点
  3244. * @name mergeChild
  3245. * @desc
  3246. * UE.dom.domUtils.mergeChild(node,tagName) //tagName要合并的子节点的标签
  3247. * @example
  3248. * <p><span style="font-size:12px;">xx<span style="font-size:12px;">aa</span>xx</span></p>
  3249. * ==> UE.dom.domUtils.mergeChild(node,'span')
  3250. * <p><span style="font-size:12px;">xxaaxx</span></p>
  3251. */
  3252. mergeChild: function (node, tagName, attrs) {
  3253. var list = domUtils.getElementsByTagName(node, node.tagName.toLowerCase())
  3254. for (var i = 0, ci; (ci = list[i++]); ) {
  3255. if (!ci.parentNode || domUtils.isBookmarkNode(ci)) {
  3256. continue
  3257. }
  3258. //span单独处理
  3259. if (ci.tagName.toLowerCase() == 'span') {
  3260. if (node === ci.parentNode) {
  3261. domUtils.trimWhiteTextNode(node)
  3262. if (node.childNodes.length == 1) {
  3263. node.style.cssText = ci.style.cssText + ';' + node.style.cssText
  3264. domUtils.remove(ci, true)
  3265. continue
  3266. }
  3267. }
  3268. ci.style.cssText = node.style.cssText + ';' + ci.style.cssText
  3269. if (attrs) {
  3270. var style = attrs.style
  3271. if (style) {
  3272. style = style.split(';')
  3273. for (var j = 0, s; (s = style[j++]); ) {
  3274. ci.style[utils.cssStyleToDomStyle(s.split(':')[0])] =
  3275. s.split(':')[1]
  3276. }
  3277. }
  3278. }
  3279. if (domUtils.isSameStyle(ci, node)) {
  3280. domUtils.remove(ci, true)
  3281. }
  3282. continue
  3283. }
  3284. if (domUtils.isSameElement(node, ci)) {
  3285. domUtils.remove(ci, true)
  3286. }
  3287. }
  3288. },
  3289. /**
  3290. * 原生方法getElementsByTagName的封装
  3291. * @method getElementsByTagName
  3292. * @param { Node } node 目标节点对象
  3293. * @param { String } tagName 需要查找的节点的tagName, 多个tagName以空格分割
  3294. * @return { Array } 符合条件的节点集合
  3295. */
  3296. getElementsByTagName: function (node, name, filter) {
  3297. if (filter && utils.isString(filter)) {
  3298. var className = filter
  3299. filter = function (node) {
  3300. return domUtils.hasClass(node, className)
  3301. }
  3302. }
  3303. name = utils
  3304. .trim(name)
  3305. .replace(/[ ]{2,}/g, ' ')
  3306. .split(' ')
  3307. var arr = []
  3308. for (var n = 0, ni; (ni = name[n++]); ) {
  3309. var list = node.getElementsByTagName(ni)
  3310. for (var i = 0, ci; (ci = list[i++]); ) {
  3311. if (!filter || filter(ci)) arr.push(ci)
  3312. }
  3313. }
  3314. return arr
  3315. },
  3316. /**
  3317. * 将节点node提取到父节点上
  3318. * @method mergeToParent
  3319. * @param { Element } node 需要提取的元素对象
  3320. * @example
  3321. * ```html
  3322. * <div id="parent">
  3323. * <div id="sub">
  3324. * <span id="child"></span>
  3325. * </div>
  3326. * </div>
  3327. *
  3328. * <script>
  3329. *
  3330. * var child = document.getElementById( "child" );
  3331. *
  3332. * //output: sub
  3333. * console.log( child.parentNode.id );
  3334. *
  3335. * UE.dom.domUtils.mergeToParent( child );
  3336. *
  3337. * //output: parent
  3338. * console.log( child.parentNode.id );
  3339. *
  3340. * </script>
  3341. * ```
  3342. */
  3343. mergeToParent: function (node) {
  3344. var parent = node.parentNode
  3345. while (parent && dtd.$removeEmpty[parent.tagName]) {
  3346. if (parent.tagName == node.tagName || parent.tagName == 'A') {
  3347. //针对a标签单独处理
  3348. domUtils.trimWhiteTextNode(parent)
  3349. //span需要特殊处理 不处理这样的情况 <span stlye="color:#fff">xxx<span style="color:#ccc">xxx</span>xxx</span>
  3350. if (
  3351. (parent.tagName == 'SPAN' && !domUtils.isSameStyle(parent, node)) ||
  3352. (parent.tagName == 'A' && node.tagName == 'SPAN')
  3353. ) {
  3354. if (parent.childNodes.length > 1 || parent !== node.parentNode) {
  3355. node.style.cssText =
  3356. parent.style.cssText + ';' + node.style.cssText
  3357. parent = parent.parentNode
  3358. continue
  3359. } else {
  3360. parent.style.cssText += ';' + node.style.cssText
  3361. //trace:952 a标签要保持下划线
  3362. if (parent.tagName == 'A') {
  3363. parent.style.textDecoration = 'underline'
  3364. }
  3365. }
  3366. }
  3367. if (parent.tagName != 'A') {
  3368. parent === node.parentNode && domUtils.remove(node, true)
  3369. break
  3370. }
  3371. }
  3372. parent = parent.parentNode
  3373. }
  3374. },
  3375. /**
  3376. * 合并节点node的左右兄弟节点
  3377. * @method mergeSibling
  3378. * @param { Element } node 需要合并的目标节点
  3379. * @example
  3380. * ```html
  3381. * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
  3382. *
  3383. * <script>
  3384. * var demoNode = document.getElementById("test");
  3385. * UE.dom.domUtils.mergeSibling( demoNode );
  3386. * //output: xxxxoooxxxx
  3387. * console.log( demoNode.innerHTML );
  3388. * </script>
  3389. * ```
  3390. */
  3391. /**
  3392. * 合并节点node的左右兄弟节点, 可以根据给定的条件选择是否忽略合并左节点。
  3393. * @method mergeSibling
  3394. * @param { Element } node 需要合并的目标节点
  3395. * @param { Boolean } ignorePre 是否忽略合并左节点
  3396. * @example
  3397. * ```html
  3398. * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
  3399. *
  3400. * <script>
  3401. * var demoNode = document.getElementById("test");
  3402. * UE.dom.domUtils.mergeSibling( demoNode, true );
  3403. * //output: oooxxxx
  3404. * console.log( demoNode.innerHTML );
  3405. * </script>
  3406. * ```
  3407. */
  3408. /**
  3409. * 合并节点node的左右兄弟节点,可以根据给定的条件选择是否忽略合并左右节点。
  3410. * @method mergeSibling
  3411. * @param { Element } node 需要合并的目标节点
  3412. * @param { Boolean } ignorePre 是否忽略合并左节点
  3413. * @param { Boolean } ignoreNext 是否忽略合并右节点
  3414. * @remind 如果同时忽略左右节点, 则该操作什么也不会做
  3415. * @example
  3416. * ```html
  3417. * <b>xxxx</b><b id="test">ooo</b><b>xxxx</b>
  3418. *
  3419. * <script>
  3420. * var demoNode = document.getElementById("test");
  3421. * UE.dom.domUtils.mergeSibling( demoNode, false, true );
  3422. * //output: xxxxooo
  3423. * console.log( demoNode.innerHTML );
  3424. * </script>
  3425. * ```
  3426. */
  3427. mergeSibling: function (node, ignorePre, ignoreNext) {
  3428. function merge(rtl, start, node) {
  3429. var next
  3430. if (
  3431. (next = node[rtl]) &&
  3432. !domUtils.isBookmarkNode(next) &&
  3433. next.nodeType == 1 &&
  3434. domUtils.isSameElement(node, next)
  3435. ) {
  3436. while (next.firstChild) {
  3437. if (start == 'firstChild') {
  3438. node.insertBefore(next.lastChild, node.firstChild)
  3439. } else {
  3440. node.appendChild(next.firstChild)
  3441. }
  3442. }
  3443. domUtils.remove(next)
  3444. }
  3445. }
  3446. !ignorePre && merge('previousSibling', 'firstChild', node)
  3447. !ignoreNext && merge('nextSibling', 'lastChild', node)
  3448. },
  3449. /**
  3450. * 设置节点node及其子节点不会被选中
  3451. * @method unSelectable
  3452. * @param { Element } node 需要执行操作的dom元素
  3453. * @remind 执行该操作后的节点, 将不能被鼠标选中
  3454. * @example
  3455. * ```javascript
  3456. * UE.dom.domUtils.unSelectable( document.body );
  3457. * ```
  3458. */
  3459. unSelectable:
  3460. (ie && browser.ie9below) || browser.opera
  3461. ? function (node) {
  3462. //for ie9
  3463. node.onselectstart = function () {
  3464. return false
  3465. }
  3466. node.onclick =
  3467. node.onkeyup =
  3468. node.onkeydown =
  3469. function () {
  3470. return false
  3471. }
  3472. node.unselectable = 'on'
  3473. node.setAttribute('unselectable', 'on')
  3474. for (var i = 0, ci; (ci = node.all[i++]); ) {
  3475. switch (ci.tagName.toLowerCase()) {
  3476. case 'iframe':
  3477. case 'textarea':
  3478. case 'input':
  3479. case 'select':
  3480. break
  3481. default:
  3482. ci.unselectable = 'on'
  3483. node.setAttribute('unselectable', 'on')
  3484. }
  3485. }
  3486. }
  3487. : function (node) {
  3488. node.style.MozUserSelect =
  3489. node.style.webkitUserSelect =
  3490. node.style.msUserSelect =
  3491. node.style.KhtmlUserSelect =
  3492. 'none'
  3493. },
  3494. /**
  3495. * 删除节点node上的指定属性名称的属性
  3496. * @method removeAttributes
  3497. * @param { Node } node 需要删除属性的节点对象
  3498. * @param { String } attrNames 可以是空格隔开的多个属性名称,该操作将会依次删除相应的属性
  3499. * @example
  3500. * ```html
  3501. * <div id="wrap">
  3502. * <span style="font-size:14px;" id="test" name="followMe">xxxxx</span>
  3503. * </div>
  3504. *
  3505. * <script>
  3506. *
  3507. * UE.dom.domUtils.removeAttributes( document.getElementById( "test" ), "id name" );
  3508. *
  3509. * //output: <span style="font-size:14px;">xxxxx</span>
  3510. * console.log( document.getElementById("wrap").innerHTML );
  3511. *
  3512. * </script>
  3513. * ```
  3514. */
  3515. /**
  3516. * 删除节点node上的指定属性名称的属性
  3517. * @method removeAttributes
  3518. * @param { Node } node 需要删除属性的节点对象
  3519. * @param { Array } attrNames 需要删除的属性名数组
  3520. * @example
  3521. * ```html
  3522. * <div id="wrap">
  3523. * <span style="font-size:14px;" id="test" name="followMe">xxxxx</span>
  3524. * </div>
  3525. *
  3526. * <script>
  3527. *
  3528. * UE.dom.domUtils.removeAttributes( document.getElementById( "test" ), ["id", "name"] );
  3529. *
  3530. * //output: <span style="font-size:14px;">xxxxx</span>
  3531. * console.log( document.getElementById("wrap").innerHTML );
  3532. *
  3533. * </script>
  3534. * ```
  3535. */
  3536. removeAttributes: function (node, attrNames) {
  3537. attrNames = utils.isArray(attrNames)
  3538. ? attrNames
  3539. : utils
  3540. .trim(attrNames)
  3541. .replace(/[ ]{2,}/g, ' ')
  3542. .split(' ')
  3543. for (var i = 0, ci; (ci = attrNames[i++]); ) {
  3544. ci = attrFix[ci] || ci
  3545. switch (ci) {
  3546. case 'className':
  3547. node[ci] = ''
  3548. break
  3549. case 'style':
  3550. node.style.cssText = ''
  3551. var val = node.getAttributeNode('style')
  3552. !browser.ie && val && node.removeAttributeNode(val)
  3553. }
  3554. node.removeAttribute(ci)
  3555. }
  3556. },
  3557. /**
  3558. * 在doc下创建一个标签名为tag,属性为attrs的元素
  3559. * @method createElement
  3560. * @param { DomDocument } doc 新创建的元素属于该document节点创建
  3561. * @param { String } tagName 需要创建的元素的标签名
  3562. * @param { Object } attrs 新创建的元素的属性key-value集合
  3563. * @return { Element } 新创建的元素对象
  3564. * @example
  3565. * ```javascript
  3566. * var ele = UE.dom.domUtils.createElement( document, 'div', {
  3567. * id: 'test'
  3568. * } );
  3569. *
  3570. * //output: DIV
  3571. * console.log( ele.tagName );
  3572. *
  3573. * //output: test
  3574. * console.log( ele.id );
  3575. *
  3576. * ```
  3577. */
  3578. createElement: function (doc, tag, attrs) {
  3579. return domUtils.setAttributes(doc.createElement(tag), attrs)
  3580. },
  3581. /**
  3582. * 为节点node添加属性attrs,attrs为属性键值对
  3583. * @method setAttributes
  3584. * @param { Element } node 需要设置属性的元素对象
  3585. * @param { Object } attrs 需要设置的属性名-值对
  3586. * @return { Element } 设置属性的元素对象
  3587. * @example
  3588. * ```html
  3589. * <span id="test"></span>
  3590. *
  3591. * <script>
  3592. *
  3593. * var testNode = UE.dom.domUtils.setAttributes( document.getElementById( "test" ), {
  3594. * id: 'demo'
  3595. * } );
  3596. *
  3597. * //output: demo
  3598. * console.log( testNode.id );
  3599. *
  3600. * </script>
  3601. *
  3602. */
  3603. setAttributes: function (node, attrs) {
  3604. for (var attr in attrs) {
  3605. if (attrs.hasOwnProperty(attr)) {
  3606. var value = attrs[attr]
  3607. switch (attr) {
  3608. case 'class':
  3609. //ie下要这样赋值,setAttribute不起作用
  3610. node.className = value
  3611. break
  3612. case 'style':
  3613. node.style.cssText = node.style.cssText + ';' + value
  3614. break
  3615. case 'innerHTML':
  3616. node[attr] = value
  3617. break
  3618. case 'value':
  3619. node.value = value
  3620. break
  3621. default:
  3622. node.setAttribute(attrFix[attr] || attr, value)
  3623. }
  3624. }
  3625. }
  3626. return node
  3627. },
  3628. /**
  3629. * 获取元素element经过计算后的样式值
  3630. * @method getComputedStyle
  3631. * @param { Element } element 需要获取样式的元素对象
  3632. * @param { String } styleName 需要获取的样式名
  3633. * @return { String } 获取到的样式值
  3634. * @example
  3635. * ```html
  3636. * <style type="text/css">
  3637. * #test {
  3638. * font-size: 15px;
  3639. * }
  3640. * </style>
  3641. *
  3642. * <span id="test"></span>
  3643. *
  3644. * <script>
  3645. * //output: 15px
  3646. * console.log( UE.dom.domUtils.getComputedStyle( document.getElementById( "test" ), 'font-size' ) );
  3647. * </script>
  3648. * ```
  3649. */
  3650. getComputedStyle: function (element, styleName) {
  3651. //一下的属性单独处理
  3652. var pros = 'width height top left'
  3653. if (pros.indexOf(styleName) > -1) {
  3654. return (
  3655. element[
  3656. 'offset' +
  3657. styleName.replace(/^\w/, function (s) {
  3658. return s.toUpperCase()
  3659. })
  3660. ] + 'px'
  3661. )
  3662. }
  3663. //忽略文本节点
  3664. if (element.nodeType == 3) {
  3665. element = element.parentNode
  3666. }
  3667. //ie下font-size若body下定义了font-size,则从currentStyle里会取到这个font-size. 取不到实际值,故此修改.
  3668. if (
  3669. browser.ie &&
  3670. browser.version < 9 &&
  3671. styleName == 'font-size' &&
  3672. !element.style.fontSize &&
  3673. !dtd.$empty[element.tagName] &&
  3674. !dtd.$nonChild[element.tagName]
  3675. ) {
  3676. var span = element.ownerDocument.createElement('span')
  3677. span.style.cssText = 'padding:0;border:0;font-family:simsun;'
  3678. span.innerHTML = '.'
  3679. element.appendChild(span)
  3680. var result = span.offsetHeight
  3681. element.removeChild(span)
  3682. span = null
  3683. return result + 'px'
  3684. }
  3685. try {
  3686. var value =
  3687. domUtils.getStyle(element, styleName) ||
  3688. (window.getComputedStyle
  3689. ? domUtils
  3690. .getWindow(element)
  3691. .getComputedStyle(element, '')
  3692. .getPropertyValue(styleName)
  3693. : (element.currentStyle || element.style)[
  3694. utils.cssStyleToDomStyle(styleName)
  3695. ])
  3696. } catch (e) {
  3697. return ''
  3698. }
  3699. return utils.transUnitToPx(utils.fixColor(styleName, value))
  3700. },
  3701. /**
  3702. * 删除元素element指定的className
  3703. * @method removeClasses
  3704. * @param { Element } ele 需要删除class的元素节点
  3705. * @param { String } classNames 需要删除的className, 多个className之间以空格分开
  3706. * @example
  3707. * ```html
  3708. * <span id="test" class="test1 test2 test3">xxx</span>
  3709. *
  3710. * <script>
  3711. *
  3712. * var testNode = document.getElementById( "test" );
  3713. * UE.dom.domUtils.removeClasses( testNode, "test1 test2" );
  3714. *
  3715. * //output: test3
  3716. * console.log( testNode.className );
  3717. *
  3718. * </script>
  3719. * ```
  3720. */
  3721. /**
  3722. * 删除元素element指定的className
  3723. * @method removeClasses
  3724. * @param { Element } ele 需要删除class的元素节点
  3725. * @param { Array } classNames 需要删除的className数组
  3726. * @example
  3727. * ```html
  3728. * <span id="test" class="test1 test2 test3">xxx</span>
  3729. *
  3730. * <script>
  3731. *
  3732. * var testNode = document.getElementById( "test" );
  3733. * UE.dom.domUtils.removeClasses( testNode, ["test1", "test2"] );
  3734. *
  3735. * //output: test3
  3736. * console.log( testNode.className );
  3737. *
  3738. * </script>
  3739. * ```
  3740. */
  3741. removeClasses: function (elm, classNames) {
  3742. classNames = utils.isArray(classNames)
  3743. ? classNames
  3744. : utils
  3745. .trim(classNames)
  3746. .replace(/[ ]{2,}/g, ' ')
  3747. .split(' ')
  3748. for (var i = 0, ci, cls = elm.className; (ci = classNames[i++]); ) {
  3749. cls = cls.replace(new RegExp('\\b' + ci + '\\b'), '')
  3750. }
  3751. cls = utils.trim(cls).replace(/[ ]{2,}/g, ' ')
  3752. if (cls) {
  3753. elm.className = cls
  3754. } else {
  3755. domUtils.removeAttributes(elm, ['class'])
  3756. }
  3757. },
  3758. /**
  3759. * 给元素element添加className
  3760. * @method addClass
  3761. * @param { Node } ele 需要增加className的元素
  3762. * @param { String } classNames 需要添加的className, 多个className之间以空格分割
  3763. * @remind 相同的类名不会被重复添加
  3764. * @example
  3765. * ```html
  3766. * <span id="test" class="cls1 cls2"></span>
  3767. *
  3768. * <script>
  3769. * var testNode = document.getElementById("test");
  3770. *
  3771. * UE.dom.domUtils.addClass( testNode, "cls2 cls3 cls4" );
  3772. *
  3773. * //output: cl1 cls2 cls3 cls4
  3774. * console.log( testNode.className );
  3775. *
  3776. * <script>
  3777. * ```
  3778. */
  3779. /**
  3780. * 给元素element添加className
  3781. * @method addClass
  3782. * @param { Node } ele 需要增加className的元素
  3783. * @param { Array } classNames 需要添加的className的数组
  3784. * @remind 相同的类名不会被重复添加
  3785. * @example
  3786. * ```html
  3787. * <span id="test" class="cls1 cls2"></span>
  3788. *
  3789. * <script>
  3790. * var testNode = document.getElementById("test");
  3791. *
  3792. * UE.dom.domUtils.addClass( testNode, ["cls2", "cls3", "cls4"] );
  3793. *
  3794. * //output: cl1 cls2 cls3 cls4
  3795. * console.log( testNode.className );
  3796. *
  3797. * <script>
  3798. * ```
  3799. */
  3800. addClass: function (elm, classNames) {
  3801. if (!elm) return
  3802. classNames = utils
  3803. .trim(classNames)
  3804. .replace(/[ ]{2,}/g, ' ')
  3805. .split(' ')
  3806. for (var i = 0, ci, cls = elm.className; (ci = classNames[i++]); ) {
  3807. if (!new RegExp('\\b' + ci + '\\b').test(cls)) {
  3808. cls += ' ' + ci
  3809. }
  3810. }
  3811. elm.className = utils.trim(cls)
  3812. },
  3813. /**
  3814. * 判断元素element是否包含给定的样式类名className
  3815. * @method hasClass
  3816. * @param { Node } ele 需要检测的元素
  3817. * @param { String } classNames 需要检测的className, 多个className之间用空格分割
  3818. * @return { Boolean } 元素是否包含所有给定的className
  3819. * @example
  3820. * ```html
  3821. * <span id="test1" class="cls1 cls2"></span>
  3822. *
  3823. * <script>
  3824. * var test1 = document.getElementById("test1");
  3825. *
  3826. * //output: false
  3827. * console.log( UE.dom.domUtils.hasClass( test1, "cls2 cls1 cls3" ) );
  3828. *
  3829. * //output: true
  3830. * console.log( UE.dom.domUtils.hasClass( test1, "cls2 cls1" ) );
  3831. * </script>
  3832. * ```
  3833. */
  3834. /**
  3835. * 判断元素element是否包含给定的样式类名className
  3836. * @method hasClass
  3837. * @param { Node } ele 需要检测的元素
  3838. * @param { Array } classNames 需要检测的className数组
  3839. * @return { Boolean } 元素是否包含所有给定的className
  3840. * @example
  3841. * ```html
  3842. * <span id="test1" class="cls1 cls2"></span>
  3843. *
  3844. * <script>
  3845. * var test1 = document.getElementById("test1");
  3846. *
  3847. * //output: false
  3848. * console.log( UE.dom.domUtils.hasClass( test1, [ "cls2", "cls1", "cls3" ] ) );
  3849. *
  3850. * //output: true
  3851. * console.log( UE.dom.domUtils.hasClass( test1, [ "cls2", "cls1" ]) );
  3852. * </script>
  3853. * ```
  3854. */
  3855. hasClass: function (element, className) {
  3856. if (utils.isRegExp(className)) {
  3857. return className.test(element.className)
  3858. }
  3859. className = utils
  3860. .trim(className)
  3861. .replace(/[ ]{2,}/g, ' ')
  3862. .split(' ')
  3863. for (var i = 0, ci, cls = element.className; (ci = className[i++]); ) {
  3864. if (!new RegExp('\\b' + ci + '\\b', 'i').test(cls)) {
  3865. return false
  3866. }
  3867. }
  3868. return i - 1 == className.length
  3869. },
  3870. /**
  3871. * 阻止事件默认行为
  3872. * @method preventDefault
  3873. * @param { Event } evt 需要阻止默认行为的事件对象
  3874. * @example
  3875. * ```javascript
  3876. * UE.dom.domUtils.preventDefault( evt );
  3877. * ```
  3878. */
  3879. preventDefault: function (evt) {
  3880. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false)
  3881. },
  3882. /**
  3883. * 删除元素element指定的样式
  3884. * @method removeStyle
  3885. * @param { Element } element 需要删除样式的元素
  3886. * @param { String } styleName 需要删除的样式名
  3887. * @example
  3888. * ```html
  3889. * <span id="test" style="color: red; background: blue;"></span>
  3890. *
  3891. * <script>
  3892. *
  3893. * var testNode = document.getElementById("test");
  3894. *
  3895. * UE.dom.domUtils.removeStyle( testNode, 'color' );
  3896. *
  3897. * //output: background: blue;
  3898. * console.log( testNode.style.cssText );
  3899. *
  3900. * </script>
  3901. * ```
  3902. */
  3903. removeStyle: function (element, name) {
  3904. if (browser.ie) {
  3905. //针对color先单独处理一下
  3906. if (name == 'color') {
  3907. name = '(^|;)' + name
  3908. }
  3909. element.style.cssText = element.style.cssText.replace(
  3910. new RegExp(name + '[^:]*:[^;]+;?', 'ig'),
  3911. ''
  3912. )
  3913. } else {
  3914. if (element.style.removeProperty) {
  3915. element.style.removeProperty(name)
  3916. } else {
  3917. element.style.removeAttribute(utils.cssStyleToDomStyle(name))
  3918. }
  3919. }
  3920. if (!element.style.cssText) {
  3921. domUtils.removeAttributes(element, ['style'])
  3922. }
  3923. },
  3924. /**
  3925. * 获取元素element的style属性的指定值
  3926. * @method getStyle
  3927. * @param { Element } element 需要获取属性值的元素
  3928. * @param { String } styleName 需要获取的style的名称
  3929. * @warning 该方法仅获取元素style属性中所标明的值
  3930. * @return { String } 该元素包含指定的style属性值
  3931. * @example
  3932. * ```html
  3933. * <div id="test" style="color: red;"></div>
  3934. *
  3935. * <script>
  3936. *
  3937. * var testNode = document.getElementById( "test" );
  3938. *
  3939. * //output: red
  3940. * console.log( UE.dom.domUtils.getStyle( testNode, "color" ) );
  3941. *
  3942. * //output: ""
  3943. * console.log( UE.dom.domUtils.getStyle( testNode, "background" ) );
  3944. *
  3945. * </script>
  3946. * ```
  3947. */
  3948. getStyle: function (element, name) {
  3949. var value = element.style[utils.cssStyleToDomStyle(name)]
  3950. return utils.fixColor(name, value)
  3951. },
  3952. /**
  3953. * 为元素element设置样式属性值
  3954. * @method setStyle
  3955. * @param { Element } element 需要设置样式的元素
  3956. * @param { String } styleName 样式名
  3957. * @param { String } styleValue 样式值
  3958. * @example
  3959. * ```html
  3960. * <div id="test"></div>
  3961. *
  3962. * <script>
  3963. *
  3964. * var testNode = document.getElementById( "test" );
  3965. *
  3966. * //output: ""
  3967. * console.log( testNode.style.color );
  3968. *
  3969. * UE.dom.domUtils.setStyle( testNode, 'color', 'red' );
  3970. * //output: "red"
  3971. * console.log( testNode.style.color );
  3972. *
  3973. * </script>
  3974. * ```
  3975. */
  3976. setStyle: function (element, name, value) {
  3977. element.style[utils.cssStyleToDomStyle(name)] = value
  3978. if (!utils.trim(element.style.cssText)) {
  3979. this.removeAttributes(element, 'style')
  3980. }
  3981. },
  3982. /**
  3983. * 为元素element设置多个样式属性值
  3984. * @method setStyles
  3985. * @param { Element } element 需要设置样式的元素
  3986. * @param { Object } styles 样式名值对
  3987. * @example
  3988. * ```html
  3989. * <div id="test"></div>
  3990. *
  3991. * <script>
  3992. *
  3993. * var testNode = document.getElementById( "test" );
  3994. *
  3995. * //output: ""
  3996. * console.log( testNode.style.color );
  3997. *
  3998. * UE.dom.domUtils.setStyles( testNode, {
  3999. * 'color': 'red'
  4000. * } );
  4001. * //output: "red"
  4002. * console.log( testNode.style.color );
  4003. *
  4004. * </script>
  4005. * ```
  4006. */
  4007. setStyles: function (element, styles) {
  4008. for (var name in styles) {
  4009. if (styles.hasOwnProperty(name)) {
  4010. domUtils.setStyle(element, name, styles[name])
  4011. }
  4012. }
  4013. },
  4014. /**
  4015. * 删除_moz_dirty属性
  4016. * @private
  4017. * @method removeDirtyAttr
  4018. */
  4019. removeDirtyAttr: function (node) {
  4020. for (
  4021. var i = 0, ci, nodes = node.getElementsByTagName('*');
  4022. (ci = nodes[i++]);
  4023. ) {
  4024. ci.removeAttribute('_moz_dirty')
  4025. }
  4026. node.removeAttribute('_moz_dirty')
  4027. },
  4028. /**
  4029. * 获取子节点的数量
  4030. * @method getChildCount
  4031. * @param { Element } node 需要检测的元素
  4032. * @return { Number } 给定的node元素的子节点数量
  4033. * @example
  4034. * ```html
  4035. * <div id="test">
  4036. * <span></span>
  4037. * </div>
  4038. *
  4039. * <script>
  4040. *
  4041. * //output: 3
  4042. * console.log( UE.dom.domUtils.getChildCount( document.getElementById("test") ) );
  4043. *
  4044. * </script>
  4045. * ```
  4046. */
  4047. /**
  4048. * 根据给定的过滤规则, 获取符合条件的子节点的数量
  4049. * @method getChildCount
  4050. * @param { Element } node 需要检测的元素
  4051. * @param { Function } fn 过滤器, 要求对符合条件的子节点返回true, 反之则要求返回false
  4052. * @return { Number } 符合过滤条件的node元素的子节点数量
  4053. * @example
  4054. * ```html
  4055. * <div id="test">
  4056. * <span></span>
  4057. * </div>
  4058. *
  4059. * <script>
  4060. *
  4061. * //output: 1
  4062. * console.log( UE.dom.domUtils.getChildCount( document.getElementById("test"), function ( node ) {
  4063. *
  4064. * return node.nodeType === 1;
  4065. *
  4066. * } ) );
  4067. *
  4068. * </script>
  4069. * ```
  4070. */
  4071. getChildCount: function (node, fn) {
  4072. var count = 0,
  4073. first = node.firstChild
  4074. fn =
  4075. fn ||
  4076. function () {
  4077. return 1
  4078. }
  4079. while (first) {
  4080. if (fn(first)) {
  4081. count++
  4082. }
  4083. first = first.nextSibling
  4084. }
  4085. return count
  4086. },
  4087. /**
  4088. * 判断给定节点是否为空节点
  4089. * @method isEmptyNode
  4090. * @param { Node } node 需要检测的节点对象
  4091. * @return { Boolean } 节点是否为空
  4092. * @example
  4093. * ```javascript
  4094. * UE.dom.domUtils.isEmptyNode( document.body );
  4095. * ```
  4096. */
  4097. isEmptyNode: function (node) {
  4098. return (
  4099. !node.firstChild ||
  4100. domUtils.getChildCount(node, function (node) {
  4101. return (
  4102. !domUtils.isBr(node) &&
  4103. !domUtils.isBookmarkNode(node) &&
  4104. !domUtils.isWhitespace(node)
  4105. )
  4106. }) == 0
  4107. )
  4108. },
  4109. clearSelectedArr: function (nodes) {
  4110. var node
  4111. while ((node = nodes.pop())) {
  4112. domUtils.removeAttributes(node, ['class'])
  4113. }
  4114. },
  4115. /**
  4116. * 将显示区域滚动到指定节点的位置
  4117. * @method scrollToView
  4118. * @param {Node} node 节点
  4119. * @param {window} win window对象
  4120. * @param {Number} offsetTop 距离上方的偏移量
  4121. */
  4122. scrollToView: function (node, win, offsetTop) {
  4123. var getViewPaneSize = function () {
  4124. var doc = win.document,
  4125. mode = doc.compatMode == 'CSS1Compat'
  4126. return {
  4127. width:
  4128. (mode ? doc.documentElement.clientWidth : doc.body.clientWidth) ||
  4129. 0,
  4130. height:
  4131. (mode
  4132. ? doc.documentElement.clientHeight
  4133. : doc.body.clientHeight) || 0,
  4134. }
  4135. },
  4136. getScrollPosition = function (win) {
  4137. if ('pageXOffset' in win) {
  4138. return {
  4139. x: win.pageXOffset || 0,
  4140. y: win.pageYOffset || 0,
  4141. }
  4142. } else {
  4143. var doc = win.document
  4144. return {
  4145. x: doc.documentElement.scrollLeft || doc.body.scrollLeft || 0,
  4146. y: doc.documentElement.scrollTop || doc.body.scrollTop || 0,
  4147. }
  4148. }
  4149. }
  4150. var winHeight = getViewPaneSize().height,
  4151. offset = winHeight * -1 + offsetTop
  4152. offset += node.offsetHeight || 0
  4153. var elementPosition = domUtils.getXY(node)
  4154. offset += elementPosition.y
  4155. var currentScroll = getScrollPosition(win).y
  4156. // offset += 50;
  4157. if (offset > currentScroll || offset < currentScroll - winHeight) {
  4158. win.scrollTo(0, offset + (offset < 0 ? -20 : 20))
  4159. }
  4160. },
  4161. /**
  4162. * 判断给定节点是否为br
  4163. * @method isBr
  4164. * @param { Node } node 需要判断的节点对象
  4165. * @return { Boolean } 给定的节点是否是br节点
  4166. */
  4167. isBr: function (node) {
  4168. return node.nodeType == 1 && node.tagName == 'BR'
  4169. },
  4170. /**
  4171. * 判断给定的节点是否是一个“填充”节点
  4172. * @private
  4173. * @method isFillChar
  4174. * @param { Node } node 需要判断的节点
  4175. * @param { Boolean } isInStart 是否从节点内容的开始位置匹配
  4176. * @returns { Boolean } 节点是否是填充节点
  4177. */
  4178. isFillChar: function (node, isInStart) {
  4179. if (node.nodeType != 3) return false
  4180. var text = node.nodeValue
  4181. if (isInStart) {
  4182. return new RegExp('^' + domUtils.fillChar).test(text)
  4183. }
  4184. return !text.replace(new RegExp(domUtils.fillChar, 'g'), '').length
  4185. },
  4186. isStartInblock: function (range) {
  4187. var tmpRange = range.cloneRange(),
  4188. flag = 0,
  4189. start = tmpRange.startContainer,
  4190. tmp
  4191. if (start.nodeType == 1 && start.childNodes[tmpRange.startOffset]) {
  4192. start = start.childNodes[tmpRange.startOffset]
  4193. var pre = start.previousSibling
  4194. while (pre && domUtils.isFillChar(pre)) {
  4195. start = pre
  4196. pre = pre.previousSibling
  4197. }
  4198. }
  4199. if (this.isFillChar(start, true) && tmpRange.startOffset == 1) {
  4200. tmpRange.setStartBefore(start)
  4201. start = tmpRange.startContainer
  4202. }
  4203. while (start && domUtils.isFillChar(start)) {
  4204. tmp = start
  4205. start = start.previousSibling
  4206. }
  4207. if (tmp) {
  4208. tmpRange.setStartBefore(tmp)
  4209. start = tmpRange.startContainer
  4210. }
  4211. if (
  4212. start.nodeType == 1 &&
  4213. domUtils.isEmptyNode(start) &&
  4214. tmpRange.startOffset == 1
  4215. ) {
  4216. tmpRange.setStart(start, 0).collapse(true)
  4217. }
  4218. while (!tmpRange.startOffset) {
  4219. start = tmpRange.startContainer
  4220. if (domUtils.isBlockElm(start) || domUtils.isBody(start)) {
  4221. flag = 1
  4222. break
  4223. }
  4224. var pre = tmpRange.startContainer.previousSibling,
  4225. tmpNode
  4226. if (!pre) {
  4227. tmpRange.setStartBefore(tmpRange.startContainer)
  4228. } else {
  4229. while (pre && domUtils.isFillChar(pre)) {
  4230. tmpNode = pre
  4231. pre = pre.previousSibling
  4232. }
  4233. if (tmpNode) {
  4234. tmpRange.setStartBefore(tmpNode)
  4235. } else {
  4236. tmpRange.setStartBefore(tmpRange.startContainer)
  4237. }
  4238. }
  4239. }
  4240. return flag && !domUtils.isBody(tmpRange.startContainer) ? 1 : 0
  4241. },
  4242. /**
  4243. * 判断给定的元素是否是一个空元素
  4244. * @method isEmptyBlock
  4245. * @param { Element } node 需要判断的元素
  4246. * @return { Boolean } 是否是空元素
  4247. * @example
  4248. * ```html
  4249. * <div id="test"></div>
  4250. *
  4251. * <script>
  4252. * //output: true
  4253. * console.log( UE.dom.domUtils.isEmptyBlock( document.getElementById("test") ) );
  4254. * </script>
  4255. * ```
  4256. */
  4257. /**
  4258. * 根据指定的判断规则判断给定的元素是否是一个空元素
  4259. * @method isEmptyBlock
  4260. * @param { Element } node 需要判断的元素
  4261. * @param { RegExp } reg 对内容执行判断的正则表达式对象
  4262. * @return { Boolean } 是否是空元素
  4263. */
  4264. isEmptyBlock: function (node, reg) {
  4265. // HaoChuan9421
  4266. if (!node) {
  4267. return
  4268. }
  4269. if (node.nodeType != 1) return 0
  4270. reg = reg || new RegExp('[ \xa0\t\r\n' + domUtils.fillChar + ']', 'g')
  4271. if (
  4272. node[browser.ie ? 'innerText' : 'textContent'].replace(reg, '').length >
  4273. 0
  4274. ) {
  4275. return 0
  4276. }
  4277. for (var n in dtd.$isNotEmpty) {
  4278. if (node.getElementsByTagName(n).length) {
  4279. return 0
  4280. }
  4281. }
  4282. return 1
  4283. },
  4284. /**
  4285. * 移动元素使得该元素的位置移动指定的偏移量的距离
  4286. * @method setViewportOffset
  4287. * @param { Element } element 需要设置偏移量的元素
  4288. * @param { Object } offset 偏移量, 形如{ left: 100, top: 50 }的一个键值对, 表示该元素将在
  4289. * 现有的位置上向水平方向偏移offset.left的距离, 在竖直方向上偏移
  4290. * offset.top的距离
  4291. * @example
  4292. * ```html
  4293. * <div id="test" style="top: 100px; left: 50px; position: absolute;"></div>
  4294. *
  4295. * <script>
  4296. *
  4297. * var testNode = document.getElementById("test");
  4298. *
  4299. * UE.dom.domUtils.setViewportOffset( testNode, {
  4300. * left: 200,
  4301. * top: 50
  4302. * } );
  4303. *
  4304. * //output: top: 300px; left: 100px; position: absolute;
  4305. * console.log( testNode.style.cssText );
  4306. *
  4307. * </script>
  4308. * ```
  4309. */
  4310. setViewportOffset: function (element, offset) {
  4311. var left = parseInt(element.style.left) | 0
  4312. var top = parseInt(element.style.top) | 0
  4313. var rect = element.getBoundingClientRect()
  4314. var offsetLeft = offset.left - rect.left
  4315. var offsetTop = offset.top - rect.top
  4316. if (offsetLeft) {
  4317. element.style.left = left + offsetLeft + 'px'
  4318. }
  4319. if (offsetTop) {
  4320. element.style.top = top + offsetTop + 'px'
  4321. }
  4322. },
  4323. /**
  4324. * 用“填充字符”填充节点
  4325. * @method fillNode
  4326. * @private
  4327. * @param { DomDocument } doc 填充的节点所在的docment对象
  4328. * @param { Node } node 需要填充的节点对象
  4329. * @example
  4330. * ```html
  4331. * <div id="test"></div>
  4332. *
  4333. * <script>
  4334. * var testNode = document.getElementById("test");
  4335. *
  4336. * //output: 0
  4337. * console.log( testNode.childNodes.length );
  4338. *
  4339. * UE.dom.domUtils.fillNode( document, testNode );
  4340. *
  4341. * //output: 1
  4342. * console.log( testNode.childNodes.length );
  4343. *
  4344. * </script>
  4345. * ```
  4346. */
  4347. fillNode: function (doc, node) {
  4348. var tmpNode = browser.ie
  4349. ? doc.createTextNode(domUtils.fillChar)
  4350. : doc.createElement('br')
  4351. node.innerHTML = ''
  4352. node.appendChild(tmpNode)
  4353. },
  4354. /**
  4355. * 把节点src的所有子节点追加到另一个节点tag上去
  4356. * @method moveChild
  4357. * @param { Node } src 源节点, 该节点下的所有子节点将被移除
  4358. * @param { Node } tag 目标节点, 从源节点移除的子节点将被追加到该节点下
  4359. * @example
  4360. * ```html
  4361. * <div id="test1">
  4362. * <span></span>
  4363. * </div>
  4364. * <div id="test2">
  4365. * <div></div>
  4366. * </div>
  4367. *
  4368. * <script>
  4369. *
  4370. * var test1 = document.getElementById("test1"),
  4371. * test2 = document.getElementById("test2");
  4372. *
  4373. * UE.dom.domUtils.moveChild( test1, test2 );
  4374. *
  4375. * //output: ""(空字符串)
  4376. * console.log( test1.innerHTML );
  4377. *
  4378. * //output: "<div></div><span></span>"
  4379. * console.log( test2.innerHTML );
  4380. *
  4381. * </script>
  4382. * ```
  4383. */
  4384. /**
  4385. * 把节点src的所有子节点移动到另一个节点tag上去, 可以通过dir参数控制附加的行为是“追加”还是“插入顶部”
  4386. * @method moveChild
  4387. * @param { Node } src 源节点, 该节点下的所有子节点将被移除
  4388. * @param { Node } tag 目标节点, 从源节点移除的子节点将被附加到该节点下
  4389. * @param { Boolean } dir 附加方式, 如果为true, 则附加进去的节点将被放到目标节点的顶部, 反之,则放到末尾
  4390. * @example
  4391. * ```html
  4392. * <div id="test1">
  4393. * <span></span>
  4394. * </div>
  4395. * <div id="test2">
  4396. * <div></div>
  4397. * </div>
  4398. *
  4399. * <script>
  4400. *
  4401. * var test1 = document.getElementById("test1"),
  4402. * test2 = document.getElementById("test2");
  4403. *
  4404. * UE.dom.domUtils.moveChild( test1, test2, true );
  4405. *
  4406. * //output: ""(空字符串)
  4407. * console.log( test1.innerHTML );
  4408. *
  4409. * //output: "<span></span><div></div>"
  4410. * console.log( test2.innerHTML );
  4411. *
  4412. * </script>
  4413. * ```
  4414. */
  4415. moveChild: function (src, tag, dir) {
  4416. while (src.firstChild) {
  4417. if (dir && tag.firstChild) {
  4418. tag.insertBefore(src.lastChild, tag.firstChild)
  4419. } else {
  4420. tag.appendChild(src.firstChild)
  4421. }
  4422. }
  4423. },
  4424. /**
  4425. * 判断节点的标签上是否不存在任何属性
  4426. * @method hasNoAttributes
  4427. * @private
  4428. * @param { Node } node 需要检测的节点对象
  4429. * @return { Boolean } 节点是否不包含任何属性
  4430. * @example
  4431. * ```html
  4432. * <div id="test"><span>xxxx</span></div>
  4433. *
  4434. * <script>
  4435. *
  4436. * //output: false
  4437. * console.log( UE.dom.domUtils.hasNoAttributes( document.getElementById("test") ) );
  4438. *
  4439. * //output: true
  4440. * console.log( UE.dom.domUtils.hasNoAttributes( document.getElementById("test").firstChild ) );
  4441. *
  4442. * </script>
  4443. * ```
  4444. */
  4445. hasNoAttributes: function (node) {
  4446. return browser.ie
  4447. ? /^<\w+\s*?>/.test(node.outerHTML)
  4448. : node.attributes.length == 0
  4449. },
  4450. /**
  4451. * 检测节点是否是UEditor所使用的辅助节点
  4452. * @method isCustomeNode
  4453. * @private
  4454. * @param { Node } node 需要检测的节点
  4455. * @remind 辅助节点是指编辑器要完成工作临时添加的节点, 在输出的时候将会从编辑器内移除, 不会影响最终的结果。
  4456. * @return { Boolean } 给定的节点是否是一个辅助节点
  4457. */
  4458. isCustomeNode: function (node) {
  4459. return node.nodeType == 1 && node.getAttribute('_ue_custom_node_')
  4460. },
  4461. /**
  4462. * 检测节点的标签是否是给定的标签
  4463. * @method isTagNode
  4464. * @param { Node } node 需要检测的节点对象
  4465. * @param { String } tagName 标签
  4466. * @return { Boolean } 节点的标签是否是给定的标签
  4467. * @example
  4468. * ```html
  4469. * <div id="test"></div>
  4470. *
  4471. * <script>
  4472. *
  4473. * //output: true
  4474. * console.log( UE.dom.domUtils.isTagNode( document.getElementById("test"), "div" ) );
  4475. *
  4476. * </script>
  4477. * ```
  4478. */
  4479. isTagNode: function (node, tagNames) {
  4480. return (
  4481. node.nodeType == 1 &&
  4482. new RegExp('\\b' + node.tagName + '\\b', 'i').test(tagNames)
  4483. )
  4484. },
  4485. /**
  4486. * 给定一个节点数组,在通过指定的过滤器过滤后, 获取其中满足过滤条件的第一个节点
  4487. * @method filterNodeList
  4488. * @param { Array } nodeList 需要过滤的节点数组
  4489. * @param { Function } fn 过滤器, 对符合条件的节点, 执行结果返回true, 反之则返回false
  4490. * @return { Node | NULL } 如果找到符合过滤条件的节点, 则返回该节点, 否则返回NULL
  4491. * @example
  4492. * ```javascript
  4493. * var divNodes = document.getElementsByTagName("div");
  4494. * divNodes = [].slice.call( divNodes, 0 );
  4495. *
  4496. * //output: null
  4497. * console.log( UE.dom.domUtils.filterNodeList( divNodes, function ( node ) {
  4498. * return node.tagName.toLowerCase() !== 'div';
  4499. * } ) );
  4500. * ```
  4501. */
  4502. /**
  4503. * 给定一个节点数组nodeList和一组标签名tagNames, 获取其中能够匹配标签名的节点集合中的第一个节点
  4504. * @method filterNodeList
  4505. * @param { Array } nodeList 需要过滤的节点数组
  4506. * @param { String } tagNames 需要匹配的标签名, 多个标签名之间用空格分割
  4507. * @return { Node | NULL } 如果找到标签名匹配的节点, 则返回该节点, 否则返回NULL
  4508. * @example
  4509. * ```javascript
  4510. * var divNodes = document.getElementsByTagName("div");
  4511. * divNodes = [].slice.call( divNodes, 0 );
  4512. *
  4513. * //output: null
  4514. * console.log( UE.dom.domUtils.filterNodeList( divNodes, 'a span' ) );
  4515. * ```
  4516. */
  4517. /**
  4518. * 给定一个节点数组,在通过指定的过滤器过滤后, 如果参数forAll为true, 则会返回所有满足过滤
  4519. * 条件的节点集合, 否则, 返回满足条件的节点集合中的第一个节点
  4520. * @method filterNodeList
  4521. * @param { Array } nodeList 需要过滤的节点数组
  4522. * @param { Function } fn 过滤器, 对符合条件的节点, 执行结果返回true, 反之则返回false
  4523. * @param { Boolean } forAll 是否返回整个节点数组, 如果该参数为false, 则返回节点集合中的第一个节点
  4524. * @return { Array | Node | NULL } 如果找到符合过滤条件的节点, 则根据参数forAll的值决定返回满足
  4525. * 过滤条件的节点数组或第一个节点, 否则返回NULL
  4526. * @example
  4527. * ```javascript
  4528. * var divNodes = document.getElementsByTagName("div");
  4529. * divNodes = [].slice.call( divNodes, 0 );
  4530. *
  4531. * //output: 3(假定有3个div)
  4532. * console.log( divNodes.length );
  4533. *
  4534. * var nodes = UE.dom.domUtils.filterNodeList( divNodes, function ( node ) {
  4535. * return node.tagName.toLowerCase() === 'div';
  4536. * }, true );
  4537. *
  4538. * //output: 3
  4539. * console.log( nodes.length );
  4540. *
  4541. * var node = UE.dom.domUtils.filterNodeList( divNodes, function ( node ) {
  4542. * return node.tagName.toLowerCase() === 'div';
  4543. * }, false );
  4544. *
  4545. * //output: div
  4546. * console.log( node.nodeName );
  4547. * ```
  4548. */
  4549. filterNodeList: function (nodelist, filter, forAll) {
  4550. var results = []
  4551. if (!utils.isFunction(filter)) {
  4552. var str = filter
  4553. filter = function (n) {
  4554. return (
  4555. utils.indexOf(
  4556. utils.isArray(str) ? str : str.split(' '),
  4557. n.tagName.toLowerCase()
  4558. ) != -1
  4559. )
  4560. }
  4561. }
  4562. utils.each(nodelist, function (n) {
  4563. filter(n) && results.push(n)
  4564. })
  4565. return results.length == 0
  4566. ? null
  4567. : results.length == 1 || !forAll
  4568. ? results[0]
  4569. : results
  4570. },
  4571. /**
  4572. * 查询给定的range选区是否在给定的node节点内,且在该节点的最末尾
  4573. * @method isInNodeEndBoundary
  4574. * @param { UE.dom.Range } rng 需要判断的range对象, 该对象的startContainer不能为NULL
  4575. * @param node 需要检测的节点对象
  4576. * @return { Number } 如果给定的选取range对象是在node内部的最末端, 则返回1, 否则返回0
  4577. */
  4578. isInNodeEndBoundary: function (rng, node) {
  4579. var start = rng.startContainer
  4580. if (start.nodeType == 3 && rng.startOffset != start.nodeValue.length) {
  4581. return 0
  4582. }
  4583. if (start.nodeType == 1 && rng.startOffset != start.childNodes.length) {
  4584. return 0
  4585. }
  4586. while (start !== node) {
  4587. if (start.nextSibling) {
  4588. return 0
  4589. }
  4590. start = start.parentNode
  4591. }
  4592. return 1
  4593. },
  4594. isBoundaryNode: function (node, dir) {
  4595. var tmp
  4596. while (!domUtils.isBody(node)) {
  4597. tmp = node
  4598. node = node.parentNode
  4599. if (tmp !== node[dir]) {
  4600. return false
  4601. }
  4602. }
  4603. return true
  4604. },
  4605. fillHtml: browser.ie11below ? '&nbsp;' : '<br/>',
  4606. })
  4607. var fillCharReg = new RegExp(domUtils.fillChar, 'g')
  4608. // core/Range.js
  4609. /**
  4610. * Range封装
  4611. * @file
  4612. * @module UE.dom
  4613. * @class Range
  4614. * @since 1.2.6.1
  4615. */
  4616. /**
  4617. * dom操作封装
  4618. * @unfile
  4619. * @module UE.dom
  4620. */
  4621. /**
  4622. * Range实现类,本类是UEditor底层核心类,封装不同浏览器之间的Range操作。
  4623. * @unfile
  4624. * @module UE.dom
  4625. * @class Range
  4626. */
  4627. ;(function () {
  4628. var guid = 0,
  4629. fillChar = domUtils.fillChar,
  4630. fillData
  4631. /**
  4632. * 更新range的collapse状态
  4633. * @param {Range} range range对象
  4634. */
  4635. function updateCollapse(range) {
  4636. range.collapsed =
  4637. range.startContainer &&
  4638. range.endContainer &&
  4639. range.startContainer === range.endContainer &&
  4640. range.startOffset == range.endOffset
  4641. }
  4642. function selectOneNode(rng) {
  4643. return (
  4644. !rng.collapsed &&
  4645. rng.startContainer.nodeType == 1 &&
  4646. rng.startContainer === rng.endContainer &&
  4647. rng.endOffset - rng.startOffset == 1
  4648. )
  4649. }
  4650. function setEndPoint(toStart, node, offset, range) {
  4651. //如果node是自闭合标签要处理
  4652. if (
  4653. node.nodeType == 1 &&
  4654. (dtd.$empty[node.tagName] || dtd.$nonChild[node.tagName])
  4655. ) {
  4656. offset = domUtils.getNodeIndex(node) + (toStart ? 0 : 1)
  4657. node = node.parentNode
  4658. }
  4659. if (toStart) {
  4660. range.startContainer = node
  4661. range.startOffset = offset
  4662. if (!range.endContainer) {
  4663. range.collapse(true)
  4664. }
  4665. } else {
  4666. range.endContainer = node
  4667. range.endOffset = offset
  4668. if (!range.startContainer) {
  4669. range.collapse(false)
  4670. }
  4671. }
  4672. updateCollapse(range)
  4673. return range
  4674. }
  4675. function execContentsAction(range, action) {
  4676. //调整边界
  4677. //range.includeBookmark();
  4678. var start = range.startContainer,
  4679. end = range.endContainer,
  4680. startOffset = range.startOffset,
  4681. endOffset = range.endOffset,
  4682. doc = range.document,
  4683. frag = doc.createDocumentFragment(),
  4684. tmpStart,
  4685. tmpEnd
  4686. if (start.nodeType == 1) {
  4687. start =
  4688. start.childNodes[startOffset] ||
  4689. (tmpStart = start.appendChild(doc.createTextNode('')))
  4690. }
  4691. if (end.nodeType == 1) {
  4692. end =
  4693. end.childNodes[endOffset] ||
  4694. (tmpEnd = end.appendChild(doc.createTextNode('')))
  4695. }
  4696. if (start === end && start.nodeType == 3) {
  4697. frag.appendChild(
  4698. doc.createTextNode(
  4699. start.substringData(startOffset, endOffset - startOffset)
  4700. )
  4701. )
  4702. //is not clone
  4703. if (action) {
  4704. start.deleteData(startOffset, endOffset - startOffset)
  4705. range.collapse(true)
  4706. }
  4707. return frag
  4708. }
  4709. var current,
  4710. currentLevel,
  4711. clone = frag,
  4712. startParents = domUtils.findParents(start, true),
  4713. endParents = domUtils.findParents(end, true)
  4714. for (var i = 0; startParents[i] == endParents[i]; ) {
  4715. i++
  4716. }
  4717. for (var j = i, si; (si = startParents[j]); j++) {
  4718. current = si.nextSibling
  4719. if (si == start) {
  4720. if (!tmpStart) {
  4721. if (range.startContainer.nodeType == 3) {
  4722. clone.appendChild(
  4723. doc.createTextNode(start.nodeValue.slice(startOffset))
  4724. )
  4725. //is not clone
  4726. if (action) {
  4727. start.deleteData(
  4728. startOffset,
  4729. start.nodeValue.length - startOffset
  4730. )
  4731. }
  4732. } else {
  4733. clone.appendChild(!action ? start.cloneNode(true) : start)
  4734. }
  4735. }
  4736. } else {
  4737. currentLevel = si.cloneNode(false)
  4738. clone.appendChild(currentLevel)
  4739. }
  4740. while (current) {
  4741. if (current === end || current === endParents[j]) {
  4742. break
  4743. }
  4744. si = current.nextSibling
  4745. clone.appendChild(!action ? current.cloneNode(true) : current)
  4746. current = si
  4747. }
  4748. clone = currentLevel
  4749. }
  4750. clone = frag
  4751. if (!startParents[i]) {
  4752. clone.appendChild(startParents[i - 1].cloneNode(false))
  4753. clone = clone.firstChild
  4754. }
  4755. for (var j = i, ei; (ei = endParents[j]); j++) {
  4756. current = ei.previousSibling
  4757. if (ei == end) {
  4758. if (!tmpEnd && range.endContainer.nodeType == 3) {
  4759. clone.appendChild(
  4760. doc.createTextNode(end.substringData(0, endOffset))
  4761. )
  4762. //is not clone
  4763. if (action) {
  4764. end.deleteData(0, endOffset)
  4765. }
  4766. }
  4767. } else {
  4768. currentLevel = ei.cloneNode(false)
  4769. clone.appendChild(currentLevel)
  4770. }
  4771. //如果两端同级,右边第一次已经被开始做了
  4772. if (j != i || !startParents[i]) {
  4773. while (current) {
  4774. if (current === start) {
  4775. break
  4776. }
  4777. ei = current.previousSibling
  4778. clone.insertBefore(
  4779. !action ? current.cloneNode(true) : current,
  4780. clone.firstChild
  4781. )
  4782. current = ei
  4783. }
  4784. }
  4785. clone = currentLevel
  4786. }
  4787. if (action) {
  4788. range
  4789. .setStartBefore(
  4790. !endParents[i]
  4791. ? endParents[i - 1]
  4792. : !startParents[i]
  4793. ? startParents[i - 1]
  4794. : endParents[i]
  4795. )
  4796. .collapse(true)
  4797. }
  4798. tmpStart && domUtils.remove(tmpStart)
  4799. tmpEnd && domUtils.remove(tmpEnd)
  4800. return frag
  4801. }
  4802. /**
  4803. * 创建一个跟document绑定的空的Range实例
  4804. * @constructor
  4805. * @param { Document } document 新建的选区所属的文档对象
  4806. */
  4807. /**
  4808. * @property { Node } startContainer 当前Range的开始边界的容器节点, 可以是一个元素节点或者是文本节点
  4809. */
  4810. /**
  4811. * @property { Node } startOffset 当前Range的开始边界容器节点的偏移量, 如果是元素节点,
  4812. * 该值就是childNodes中的第几个节点, 如果是文本节点就是文本内容的第几个字符
  4813. */
  4814. /**
  4815. * @property { Node } endContainer 当前Range的结束边界的容器节点, 可以是一个元素节点或者是文本节点
  4816. */
  4817. /**
  4818. * @property { Node } endOffset 当前Range的结束边界容器节点的偏移量, 如果是元素节点,
  4819. * 该值就是childNodes中的第几个节点, 如果是文本节点就是文本内容的第几个字符
  4820. */
  4821. /**
  4822. * @property { Boolean } collapsed 当前Range是否闭合
  4823. * @default true
  4824. * @remind Range是闭合的时候, startContainer === endContainer && startOffset === endOffset
  4825. */
  4826. /**
  4827. * @property { Document } document 当前Range所属的Document对象
  4828. * @remind 不同range的的document属性可以是不同的
  4829. */
  4830. var Range = (dom.Range = function (document) {
  4831. var me = this
  4832. me.startContainer = me.startOffset = me.endContainer = me.endOffset = null
  4833. me.document = document
  4834. me.collapsed = true
  4835. })
  4836. /**
  4837. * 删除fillData
  4838. * @param doc
  4839. * @param excludeNode
  4840. */
  4841. function removeFillData(doc, excludeNode) {
  4842. try {
  4843. if (fillData && domUtils.inDoc(fillData, doc)) {
  4844. if (!fillData.nodeValue.replace(fillCharReg, '').length) {
  4845. var tmpNode = fillData.parentNode
  4846. domUtils.remove(fillData)
  4847. while (
  4848. tmpNode &&
  4849. domUtils.isEmptyInlineElement(tmpNode) &&
  4850. //safari的contains有bug
  4851. (browser.safari
  4852. ? !(
  4853. domUtils.getPosition(tmpNode, excludeNode) &
  4854. domUtils.POSITION_CONTAINS
  4855. )
  4856. : !tmpNode.contains(excludeNode))
  4857. ) {
  4858. fillData = tmpNode.parentNode
  4859. domUtils.remove(tmpNode)
  4860. tmpNode = fillData
  4861. }
  4862. } else {
  4863. fillData.nodeValue = fillData.nodeValue.replace(fillCharReg, '')
  4864. }
  4865. }
  4866. } catch (e) {}
  4867. }
  4868. /**
  4869. * @param node
  4870. * @param dir
  4871. */
  4872. function mergeSibling(node, dir) {
  4873. var tmpNode
  4874. node = node[dir]
  4875. while (node && domUtils.isFillChar(node)) {
  4876. tmpNode = node[dir]
  4877. domUtils.remove(node)
  4878. node = tmpNode
  4879. }
  4880. }
  4881. Range.prototype = {
  4882. /**
  4883. * 克隆选区的内容到一个DocumentFragment里
  4884. * @method cloneContents
  4885. * @return { DocumentFragment | NULL } 如果选区是闭合的将返回null, 否则, 返回包含所clone内容的DocumentFragment元素
  4886. * @example
  4887. * ```html
  4888. * <body>
  4889. * <!-- 中括号表示选区 -->
  4890. * <b>x<i>x[x</i>xx]x</b>
  4891. *
  4892. * <script>
  4893. * //range是已选中的选区
  4894. * var fragment = range.cloneContents(),
  4895. * node = document.createElement("div");
  4896. *
  4897. * node.appendChild( fragment );
  4898. *
  4899. * //output: <i>x</i>xx
  4900. * console.log( node.innerHTML );
  4901. *
  4902. * </script>
  4903. * </body>
  4904. * ```
  4905. */
  4906. cloneContents: function () {
  4907. return this.collapsed ? null : execContentsAction(this, 0)
  4908. },
  4909. /**
  4910. * 删除当前选区范围中的所有内容
  4911. * @method deleteContents
  4912. * @remind 执行完该操作后, 当前Range对象变成了闭合状态
  4913. * @return { UE.dom.Range } 当前操作的Range对象
  4914. * @example
  4915. * ```html
  4916. * <body>
  4917. * <!-- 中括号表示选区 -->
  4918. * <b>x<i>x[x</i>xx]x</b>
  4919. *
  4920. * <script>
  4921. * //range是已选中的选区
  4922. * range.deleteContents();
  4923. *
  4924. * //竖线表示闭合后的选区位置
  4925. * //output: <b>x<i>x</i>|x</b>
  4926. * console.log( document.body.innerHTML );
  4927. *
  4928. * //此时, range的各项属性为
  4929. * //output: B
  4930. * console.log( range.startContainer.tagName );
  4931. * //output: 2
  4932. * console.log( range.startOffset );
  4933. * //output: B
  4934. * console.log( range.endContainer.tagName );
  4935. * //output: 2
  4936. * console.log( range.endOffset );
  4937. * //output: true
  4938. * console.log( range.collapsed );
  4939. *
  4940. * </script>
  4941. * </body>
  4942. * ```
  4943. */
  4944. deleteContents: function () {
  4945. var txt
  4946. if (!this.collapsed) {
  4947. execContentsAction(this, 1)
  4948. }
  4949. if (browser.webkit) {
  4950. txt = this.startContainer
  4951. if (txt.nodeType == 3 && !txt.nodeValue.length) {
  4952. this.setStartBefore(txt).collapse(true)
  4953. domUtils.remove(txt)
  4954. }
  4955. }
  4956. return this
  4957. },
  4958. /**
  4959. * 将当前选区的内容提取到一个DocumentFragment里
  4960. * @method extractContents
  4961. * @remind 执行该操作后, 选区将变成闭合状态
  4962. * @warning 执行该操作后, 原来选区所选中的内容将从dom树上剥离出来
  4963. * @return { DocumentFragment } 返回包含所提取内容的DocumentFragment对象
  4964. * @example
  4965. * ```html
  4966. * <body>
  4967. * <!-- 中括号表示选区 -->
  4968. * <b>x<i>x[x</i>xx]x</b>
  4969. *
  4970. * <script>
  4971. * //range是已选中的选区
  4972. * var fragment = range.extractContents(),
  4973. * node = document.createElement( "div" );
  4974. *
  4975. * node.appendChild( fragment );
  4976. *
  4977. * //竖线表示闭合后的选区位置
  4978. *
  4979. * //output: <b>x<i>x</i>|x</b>
  4980. * console.log( document.body.innerHTML );
  4981. * //output: <i>x</i>xx
  4982. * console.log( node.innerHTML );
  4983. *
  4984. * //此时, range的各项属性为
  4985. * //output: B
  4986. * console.log( range.startContainer.tagName );
  4987. * //output: 2
  4988. * console.log( range.startOffset );
  4989. * //output: B
  4990. * console.log( range.endContainer.tagName );
  4991. * //output: 2
  4992. * console.log( range.endOffset );
  4993. * //output: true
  4994. * console.log( range.collapsed );
  4995. *
  4996. * </script>
  4997. * </body>
  4998. */
  4999. extractContents: function () {
  5000. return this.collapsed ? null : execContentsAction(this, 2)
  5001. },
  5002. /**
  5003. * 设置Range的开始容器节点和偏移量
  5004. * @method setStart
  5005. * @remind 如果给定的节点是元素节点,那么offset指的是其子元素中索引为offset的元素,
  5006. * 如果是文本节点,那么offset指的是其文本内容的第offset个字符
  5007. * @remind 如果提供的容器节点是一个不能包含子元素的节点, 则该选区的开始容器将被设置
  5008. * 为该节点的父节点, 此时, 其距离开始容器的偏移量也变成了该节点在其父节点
  5009. * 中的索引
  5010. * @param { Node } node 将被设为当前选区开始边界容器的节点对象
  5011. * @param { int } offset 选区的开始位置偏移量
  5012. * @return { UE.dom.Range } 当前range对象
  5013. * @example
  5014. * ```html
  5015. * <!-- 选区 -->
  5016. * <b>xxx<i>x<span>xx</span>xx<em>xx</em>xxx</i>[xxx]</b>
  5017. *
  5018. * <script>
  5019. *
  5020. * //执行操作
  5021. * range.setStart( document.getElementsByTagName("i")[0], 1 );
  5022. *
  5023. * //此时, 选区变成了
  5024. * //<b>xxx<i>x[<span>xx</span>xx<em>xx</em>xxx</i>xxx]</b>
  5025. *
  5026. * </script>
  5027. * ```
  5028. * @example
  5029. * ```html
  5030. * <!-- 选区 -->
  5031. * <b>xxx<img>[xx]x</b>
  5032. *
  5033. * <script>
  5034. *
  5035. * //执行操作
  5036. * range.setStart( document.getElementsByTagName("img")[0], 3 );
  5037. *
  5038. * //此时, 选区变成了
  5039. * //<b>xxx[<img>xx]x</b>
  5040. *
  5041. * </script>
  5042. * ```
  5043. */
  5044. setStart: function (node, offset) {
  5045. return setEndPoint(true, node, offset, this)
  5046. },
  5047. /**
  5048. * 设置Range的结束容器和偏移量
  5049. * @method setEnd
  5050. * @param { Node } node 作为当前选区结束边界容器的节点对象
  5051. * @param { int } offset 结束边界的偏移量
  5052. * @see UE.dom.Range:setStart(Node,int)
  5053. * @return { UE.dom.Range } 当前range对象
  5054. */
  5055. setEnd: function (node, offset) {
  5056. return setEndPoint(false, node, offset, this)
  5057. },
  5058. /**
  5059. * 将Range开始位置设置到node节点之后
  5060. * @method setStartAfter
  5061. * @remind 该操作将会把给定节点的父节点作为range的开始容器, 且偏移量是该节点在其父节点中的位置索引+1
  5062. * @param { Node } node 选区的开始边界将紧接着该节点之后
  5063. * @return { UE.dom.Range } 当前range对象
  5064. * @example
  5065. * ```html
  5066. * <!-- 选区示例 -->
  5067. * <b>xx<i>xxx</i><span>xx[x</span>xxx]</b>
  5068. *
  5069. * <script>
  5070. *
  5071. * //执行操作
  5072. * range.setStartAfter( document.getElementsByTagName("i")[0] );
  5073. *
  5074. * //结果选区
  5075. * //<b>xx<i>xxx</i>[<span>xxx</span>xxx]</b>
  5076. *
  5077. * </script>
  5078. * ```
  5079. */
  5080. setStartAfter: function (node) {
  5081. return this.setStart(node.parentNode, domUtils.getNodeIndex(node) + 1)
  5082. },
  5083. /**
  5084. * 将Range开始位置设置到node节点之前
  5085. * @method setStartBefore
  5086. * @remind 该操作将会把给定节点的父节点作为range的开始容器, 且偏移量是该节点在其父节点中的位置索引
  5087. * @param { Node } node 新的选区开始位置在该节点之前
  5088. * @see UE.dom.Range:setStartAfter(Node)
  5089. * @return { UE.dom.Range } 当前range对象
  5090. */
  5091. setStartBefore: function (node) {
  5092. return this.setStart(node.parentNode, domUtils.getNodeIndex(node))
  5093. },
  5094. /**
  5095. * 将Range结束位置设置到node节点之后
  5096. * @method setEndAfter
  5097. * @remind 该操作将会把给定节点的父节点作为range的结束容器, 且偏移量是该节点在其父节点中的位置索引+1
  5098. * @param { Node } node 目标节点
  5099. * @see UE.dom.Range:setStartAfter(Node)
  5100. * @return { UE.dom.Range } 当前range对象
  5101. * @example
  5102. * ```html
  5103. * <!-- 选区示例 -->
  5104. * <b>[xx<i>xxx</i><span>xx]x</span>xxx</b>
  5105. *
  5106. * <script>
  5107. *
  5108. * //执行操作
  5109. * range.setStartAfter( document.getElementsByTagName("span")[0] );
  5110. *
  5111. * //结果选区
  5112. * //<b>[xx<i>xxx</i><span>xxx</span>]xxx</b>
  5113. *
  5114. * </script>
  5115. * ```
  5116. */
  5117. setEndAfter: function (node) {
  5118. return this.setEnd(node.parentNode, domUtils.getNodeIndex(node) + 1)
  5119. },
  5120. /**
  5121. * 将Range结束位置设置到node节点之前
  5122. * @method setEndBefore
  5123. * @remind 该操作将会把给定节点的父节点作为range的结束容器, 且偏移量是该节点在其父节点中的位置索引
  5124. * @param { Node } node 目标节点
  5125. * @see UE.dom.Range:setEndAfter(Node)
  5126. * @return { UE.dom.Range } 当前range对象
  5127. */
  5128. setEndBefore: function (node) {
  5129. return this.setEnd(node.parentNode, domUtils.getNodeIndex(node))
  5130. },
  5131. /**
  5132. * 设置Range的开始位置到node节点内的第一个子节点之前
  5133. * @method setStartAtFirst
  5134. * @remind 选区的开始容器将变成给定的节点, 且偏移量为0
  5135. * @remind 如果给定的节点是元素节点, 则该节点必须是允许包含子节点的元素。
  5136. * @param { Node } node 目标节点
  5137. * @see UE.dom.Range:setStartBefore(Node)
  5138. * @return { UE.dom.Range } 当前range对象
  5139. * @example
  5140. * ```html
  5141. * <!-- 选区示例 -->
  5142. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5143. *
  5144. * <script>
  5145. *
  5146. * //执行操作
  5147. * range.setStartAtFirst( document.getElementsByTagName("i")[0] );
  5148. *
  5149. * //结果选区
  5150. * //<b>xx<i>[xxx</i><span>xx]x</span>xxx</b>
  5151. *
  5152. * </script>
  5153. * ```
  5154. */
  5155. setStartAtFirst: function (node) {
  5156. return this.setStart(node, 0)
  5157. },
  5158. /**
  5159. * 设置Range的开始位置到node节点内的最后一个节点之后
  5160. * @method setStartAtLast
  5161. * @remind 选区的开始容器将变成给定的节点, 且偏移量为该节点的子节点数
  5162. * @remind 如果给定的节点是元素节点, 则该节点必须是允许包含子节点的元素。
  5163. * @param { Node } node 目标节点
  5164. * @see UE.dom.Range:setStartAtFirst(Node)
  5165. * @return { UE.dom.Range } 当前range对象
  5166. */
  5167. setStartAtLast: function (node) {
  5168. return this.setStart(
  5169. node,
  5170. node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length
  5171. )
  5172. },
  5173. /**
  5174. * 设置Range的结束位置到node节点内的第一个节点之前
  5175. * @method setEndAtFirst
  5176. * @param { Node } node 目标节点
  5177. * @remind 选区的结束容器将变成给定的节点, 且偏移量为0
  5178. * @remind node必须是一个元素节点, 且必须是允许包含子节点的元素。
  5179. * @see UE.dom.Range:setStartAtFirst(Node)
  5180. * @return { UE.dom.Range } 当前range对象
  5181. */
  5182. setEndAtFirst: function (node) {
  5183. return this.setEnd(node, 0)
  5184. },
  5185. /**
  5186. * 设置Range的结束位置到node节点内的最后一个节点之后
  5187. * @method setEndAtLast
  5188. * @param { Node } node 目标节点
  5189. * @remind 选区的结束容器将变成给定的节点, 且偏移量为该节点的子节点数量
  5190. * @remind node必须是一个元素节点, 且必须是允许包含子节点的元素。
  5191. * @see UE.dom.Range:setStartAtFirst(Node)
  5192. * @return { UE.dom.Range } 当前range对象
  5193. */
  5194. setEndAtLast: function (node) {
  5195. return this.setEnd(
  5196. node,
  5197. node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length
  5198. )
  5199. },
  5200. /**
  5201. * 选中给定节点
  5202. * @method selectNode
  5203. * @remind 此时, 选区的开始容器和结束容器都是该节点的父节点, 其startOffset是该节点在父节点中的位置索引,
  5204. * 而endOffset为startOffset+1
  5205. * @param { Node } node 需要选中的节点
  5206. * @return { UE.dom.Range } 当前range对象,此时的range仅包含当前给定的节点对象
  5207. * @example
  5208. * ```html
  5209. * <!-- 选区示例 -->
  5210. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5211. *
  5212. * <script>
  5213. *
  5214. * //执行操作
  5215. * range.selectNode( document.getElementsByTagName("i")[0] );
  5216. *
  5217. * //结果选区
  5218. * //<b>xx[<i>xxx</i>]<span>xxx</span>xxx</b>
  5219. *
  5220. * </script>
  5221. * ```
  5222. */
  5223. selectNode: function (node) {
  5224. return this.setStartBefore(node).setEndAfter(node)
  5225. },
  5226. /**
  5227. * 选中给定节点内部的所有节点
  5228. * @method selectNodeContents
  5229. * @remind 此时, 选区的开始容器和结束容器都是该节点, 其startOffset为0,
  5230. * 而endOffset是该节点的子节点数。
  5231. * @param { Node } node 目标节点, 当前range将包含该节点内的所有节点
  5232. * @return { UE.dom.Range } 当前range对象, 此时range仅包含给定节点的所有子节点
  5233. * @example
  5234. * ```html
  5235. * <!-- 选区示例 -->
  5236. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5237. *
  5238. * <script>
  5239. *
  5240. * //执行操作
  5241. * range.selectNode( document.getElementsByTagName("b")[0] );
  5242. *
  5243. * //结果选区
  5244. * //<b>[xx<i>xxx</i><span>xxx</span>xxx]</b>
  5245. *
  5246. * </script>
  5247. * ```
  5248. */
  5249. selectNodeContents: function (node) {
  5250. return this.setStart(node, 0).setEndAtLast(node)
  5251. },
  5252. /**
  5253. * clone当前Range对象
  5254. * @method cloneRange
  5255. * @remind 返回的range是一个全新的range对象, 其内部所有属性与当前被clone的range相同。
  5256. * @return { UE.dom.Range } 当前range对象的一个副本
  5257. */
  5258. cloneRange: function () {
  5259. var me = this
  5260. return new Range(me.document)
  5261. .setStart(me.startContainer, me.startOffset)
  5262. .setEnd(me.endContainer, me.endOffset)
  5263. },
  5264. /**
  5265. * 向当前选区的结束处闭合选区
  5266. * @method collapse
  5267. * @return { UE.dom.Range } 当前range对象
  5268. * @example
  5269. * ```html
  5270. * <!-- 选区示例 -->
  5271. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5272. *
  5273. * <script>
  5274. *
  5275. * //执行操作
  5276. * range.collapse();
  5277. *
  5278. * //结果选区
  5279. * //“|”表示选区已闭合
  5280. * //<b>xx<i>xxx</i><span>xx|x</span>xxx</b>
  5281. *
  5282. * </script>
  5283. * ```
  5284. */
  5285. /**
  5286. * 闭合当前选区,根据给定的toStart参数项决定是向当前选区开始处闭合还是向结束处闭合,
  5287. * 如果toStart的值为true,则向开始位置闭合, 反之,向结束位置闭合。
  5288. * @method collapse
  5289. * @param { Boolean } toStart 是否向选区开始处闭合
  5290. * @return { UE.dom.Range } 当前range对象,此时range对象处于闭合状态
  5291. * @see UE.dom.Range:collapse()
  5292. * @example
  5293. * ```html
  5294. * <!-- 选区示例 -->
  5295. * <b>xx<i>xxx</i><span>[xx]x</span>xxx</b>
  5296. *
  5297. * <script>
  5298. *
  5299. * //执行操作
  5300. * range.collapse( true );
  5301. *
  5302. * //结果选区
  5303. * //“|”表示选区已闭合
  5304. * //<b>xx<i>xxx</i><span>|xxx</span>xxx</b>
  5305. *
  5306. * </script>
  5307. * ```
  5308. */
  5309. collapse: function (toStart) {
  5310. var me = this
  5311. if (toStart) {
  5312. me.endContainer = me.startContainer
  5313. me.endOffset = me.startOffset
  5314. } else {
  5315. me.startContainer = me.endContainer
  5316. me.startOffset = me.endOffset
  5317. }
  5318. me.collapsed = true
  5319. return me
  5320. },
  5321. /**
  5322. * 调整range的开始位置和结束位置,使其"收缩"到最小的位置
  5323. * @method shrinkBoundary
  5324. * @return { UE.dom.Range } 当前range对象
  5325. * @example
  5326. * ```html
  5327. * <span>xx<b>xx[</b>xxxxx]</span> => <span>xx<b>xx</b>[xxxxx]</span>
  5328. * ```
  5329. *
  5330. * @example
  5331. * ```html
  5332. * <!-- 选区示例 -->
  5333. * <b>x[xx</b><i>]xxx</i>
  5334. *
  5335. * <script>
  5336. *
  5337. * //执行收缩
  5338. * range.shrinkBoundary();
  5339. *
  5340. * //结果选区
  5341. * //<b>x[xx]</b><i>xxx</i>
  5342. * </script>
  5343. * ```
  5344. *
  5345. * @example
  5346. * ```html
  5347. * [<b><i>xxxx</i>xxxxxxx</b>] => <b><i>[xxxx</i>xxxxxxx]</b>
  5348. * ```
  5349. */
  5350. /**
  5351. * 调整range的开始位置和结束位置,使其"收缩"到最小的位置,
  5352. * 如果ignoreEnd的值为true,则忽略对结束位置的调整
  5353. * @method shrinkBoundary
  5354. * @param { Boolean } ignoreEnd 是否忽略对结束位置的调整
  5355. * @return { UE.dom.Range } 当前range对象
  5356. * @see UE.dom.domUtils.Range:shrinkBoundary()
  5357. */
  5358. shrinkBoundary: function (ignoreEnd) {
  5359. var me = this,
  5360. child,
  5361. collapsed = me.collapsed
  5362. function check(node) {
  5363. return (
  5364. node.nodeType == 1 &&
  5365. !domUtils.isBookmarkNode(node) &&
  5366. !dtd.$empty[node.tagName] &&
  5367. !dtd.$nonChild[node.tagName]
  5368. )
  5369. }
  5370. while (
  5371. me.startContainer.nodeType == 1 && //是element
  5372. (child = me.startContainer.childNodes[me.startOffset]) && //子节点也是element
  5373. check(child)
  5374. ) {
  5375. me.setStart(child, 0)
  5376. }
  5377. if (collapsed) {
  5378. return me.collapse(true)
  5379. }
  5380. if (!ignoreEnd) {
  5381. while (
  5382. me.endContainer.nodeType == 1 && //是element
  5383. me.endOffset > 0 && //如果是空元素就退出 endOffset=0那么endOffst-1为负值,childNodes[endOffset]报错
  5384. (child = me.endContainer.childNodes[me.endOffset - 1]) && //子节点也是element
  5385. check(child)
  5386. ) {
  5387. me.setEnd(child, child.childNodes.length)
  5388. }
  5389. }
  5390. return me
  5391. },
  5392. /**
  5393. * 获取离当前选区内包含的所有节点最近的公共祖先节点,
  5394. * @method getCommonAncestor
  5395. * @remind 返回的公共祖先节点一定不是range自身的容器节点, 但有可能是一个文本节点
  5396. * @return { Node } 当前range对象内所有节点的公共祖先节点
  5397. * @example
  5398. * ```html
  5399. * //选区示例
  5400. * <span>xxx<b>x[x<em>xx]x</em>xxx</b>xx</span>
  5401. * <script>
  5402. *
  5403. * var node = range.getCommonAncestor();
  5404. *
  5405. * //公共祖先节点是: b节点
  5406. * //输出: B
  5407. * console.log(node.tagName);
  5408. *
  5409. * </script>
  5410. * ```
  5411. */
  5412. /**
  5413. * 获取当前选区所包含的所有节点的公共祖先节点, 可以根据给定的参数 includeSelf 决定获取到
  5414. * 的公共祖先节点是否可以是当前选区的startContainer或endContainer节点, 如果 includeSelf
  5415. * 的取值为true, 则返回的节点可以是自身的容器节点, 否则, 则不能是容器节点
  5416. * @method getCommonAncestor
  5417. * @param { Boolean } includeSelf 是否允许获取到的公共祖先节点是当前range对象的容器节点
  5418. * @return { Node } 当前range对象内所有节点的公共祖先节点
  5419. * @see UE.dom.Range:getCommonAncestor()
  5420. * @example
  5421. * ```html
  5422. * <body>
  5423. *
  5424. * <!-- 选区示例 -->
  5425. * <b>xxx<i>xxxx<span>xx[x</span>xx]x</i>xxxxxxx</b>
  5426. *
  5427. * <script>
  5428. *
  5429. * var node = range.getCommonAncestor( false );
  5430. *
  5431. * //这里的公共祖先节点是B而不是I, 是因为参数限制了获取到的节点不能是容器节点
  5432. * //output: B
  5433. * console.log( node.tagName );
  5434. *
  5435. * </script>
  5436. *
  5437. * </body>
  5438. * ```
  5439. */
  5440. /**
  5441. * 获取当前选区所包含的所有节点的公共祖先节点, 可以根据给定的参数 includeSelf 决定获取到
  5442. * 的公共祖先节点是否可以是当前选区的startContainer或endContainer节点, 如果 includeSelf
  5443. * 的取值为true, 则返回的节点可以是自身的容器节点, 否则, 则不能是容器节点; 同时可以根据
  5444. * ignoreTextNode 参数的取值决定是否忽略类型为文本节点的祖先节点。
  5445. * @method getCommonAncestor
  5446. * @param { Boolean } includeSelf 是否允许获取到的公共祖先节点是当前range对象的容器节点
  5447. * @param { Boolean } ignoreTextNode 获取祖先节点的过程中是否忽略类型为文本节点的祖先节点
  5448. * @return { Node } 当前range对象内所有节点的公共祖先节点
  5449. * @see UE.dom.Range:getCommonAncestor()
  5450. * @see UE.dom.Range:getCommonAncestor(Boolean)
  5451. * @example
  5452. * ```html
  5453. * <body>
  5454. *
  5455. * <!-- 选区示例 -->
  5456. * <b>xxx<i>xxxx<span>x[x]x</span>xxx</i>xxxxxxx</b>
  5457. *
  5458. * <script>
  5459. *
  5460. * var node = range.getCommonAncestor( true, false );
  5461. *
  5462. * //output: SPAN
  5463. * console.log( node.tagName );
  5464. *
  5465. * </script>
  5466. *
  5467. * </body>
  5468. * ```
  5469. */
  5470. getCommonAncestor: function (includeSelf, ignoreTextNode) {
  5471. var me = this,
  5472. start = me.startContainer,
  5473. end = me.endContainer
  5474. if (start === end) {
  5475. if (includeSelf && selectOneNode(this)) {
  5476. start = start.childNodes[me.startOffset]
  5477. if (start.nodeType == 1) return start
  5478. }
  5479. //只有在上来就相等的情况下才会出现是文本的情况
  5480. return ignoreTextNode && start.nodeType == 3
  5481. ? start.parentNode
  5482. : start
  5483. }
  5484. return domUtils.getCommonAncestor(start, end)
  5485. },
  5486. /**
  5487. * 调整当前Range的开始和结束边界容器,如果是容器节点是文本节点,就调整到包含该文本节点的父节点上
  5488. * @method trimBoundary
  5489. * @remind 该操作有可能会引起文本节点被切开
  5490. * @return { UE.dom.Range } 当前range对象
  5491. * @example
  5492. * ```html
  5493. *
  5494. * //选区示例
  5495. * <b>xxx<i>[xxxxx]</i>xxx</b>
  5496. *
  5497. * <script>
  5498. * //未调整前, 选区的开始容器和结束都是文本节点
  5499. * //执行调整
  5500. * range.trimBoundary();
  5501. *
  5502. * //调整之后, 容器节点变成了i节点
  5503. * //<b>xxx[<i>xxxxx</i>]xxx</b>
  5504. * </script>
  5505. * ```
  5506. */
  5507. /**
  5508. * 调整当前Range的开始和结束边界容器,如果是容器节点是文本节点,就调整到包含该文本节点的父节点上,
  5509. * 可以根据 ignoreEnd 参数的值决定是否调整对结束边界的调整
  5510. * @method trimBoundary
  5511. * @param { Boolean } ignoreEnd 是否忽略对结束边界的调整
  5512. * @return { UE.dom.Range } 当前range对象
  5513. * @example
  5514. * ```html
  5515. *
  5516. * //选区示例
  5517. * <b>xxx<i>[xxxxx]</i>xxx</b>
  5518. *
  5519. * <script>
  5520. * //未调整前, 选区的开始容器和结束都是文本节点
  5521. * //执行调整
  5522. * range.trimBoundary( true );
  5523. *
  5524. * //调整之后, 开始容器节点变成了i节点
  5525. * //但是, 结束容器没有发生变化
  5526. * //<b>xxx[<i>xxxxx]</i>xxx</b>
  5527. * </script>
  5528. * ```
  5529. */
  5530. trimBoundary: function (ignoreEnd) {
  5531. this.txtToElmBoundary()
  5532. var start = this.startContainer,
  5533. offset = this.startOffset,
  5534. collapsed = this.collapsed,
  5535. end = this.endContainer
  5536. if (start.nodeType == 3) {
  5537. if (offset == 0) {
  5538. this.setStartBefore(start)
  5539. } else {
  5540. if (offset >= start.nodeValue.length) {
  5541. this.setStartAfter(start)
  5542. } else {
  5543. var textNode = domUtils.split(start, offset)
  5544. //跟新结束边界
  5545. if (start === end) {
  5546. this.setEnd(textNode, this.endOffset - offset)
  5547. } else if (start.parentNode === end) {
  5548. this.endOffset += 1
  5549. }
  5550. this.setStartBefore(textNode)
  5551. }
  5552. }
  5553. if (collapsed) {
  5554. return this.collapse(true)
  5555. }
  5556. }
  5557. if (!ignoreEnd) {
  5558. offset = this.endOffset
  5559. end = this.endContainer
  5560. if (end.nodeType == 3) {
  5561. if (offset == 0) {
  5562. this.setEndBefore(end)
  5563. } else {
  5564. offset < end.nodeValue.length && domUtils.split(end, offset)
  5565. this.setEndAfter(end)
  5566. }
  5567. }
  5568. }
  5569. return this
  5570. },
  5571. /**
  5572. * 如果选区在文本的边界上,就扩展选区到文本的父节点上, 如果当前选区是闭合的, 则什么也不做
  5573. * @method txtToElmBoundary
  5574. * @remind 该操作不会修改dom节点
  5575. * @return { UE.dom.Range } 当前range对象
  5576. */
  5577. /**
  5578. * 如果选区在文本的边界上,就扩展选区到文本的父节点上, 如果当前选区是闭合的, 则根据参数项
  5579. * ignoreCollapsed 的值决定是否执行该调整
  5580. * @method txtToElmBoundary
  5581. * @param { Boolean } ignoreCollapsed 是否忽略选区的闭合状态, 如果该参数取值为true, 则
  5582. * 不论选区是否闭合, 都会执行该操作, 反之, 则不会对闭合的选区执行该操作
  5583. * @return { UE.dom.Range } 当前range对象
  5584. */
  5585. txtToElmBoundary: function (ignoreCollapsed) {
  5586. function adjust(r, c) {
  5587. var container = r[c + 'Container'],
  5588. offset = r[c + 'Offset']
  5589. if (container.nodeType == 3) {
  5590. if (!offset) {
  5591. r[
  5592. 'set' +
  5593. c.replace(/(\w)/, function (a) {
  5594. return a.toUpperCase()
  5595. }) +
  5596. 'Before'
  5597. ](container)
  5598. } else if (offset >= container.nodeValue.length) {
  5599. r[
  5600. 'set' +
  5601. c.replace(/(\w)/, function (a) {
  5602. return a.toUpperCase()
  5603. }) +
  5604. 'After'
  5605. ](container)
  5606. }
  5607. }
  5608. }
  5609. if (ignoreCollapsed || !this.collapsed) {
  5610. adjust(this, 'start')
  5611. adjust(this, 'end')
  5612. }
  5613. return this
  5614. },
  5615. /**
  5616. * 在当前选区的开始位置前插入节点,新插入的节点会被该range包含
  5617. * @method insertNode
  5618. * @param { Node } node 需要插入的节点
  5619. * @remind 插入的节点可以是一个DocumentFragment依次插入多个节点
  5620. * @return { UE.dom.Range } 当前range对象
  5621. */
  5622. insertNode: function (node) {
  5623. var first = node,
  5624. length = 1
  5625. if (node.nodeType == 11) {
  5626. first = node.firstChild
  5627. length = node.childNodes.length
  5628. }
  5629. this.trimBoundary(true)
  5630. var start = this.startContainer,
  5631. offset = this.startOffset
  5632. var nextNode = start.childNodes[offset]
  5633. if (nextNode) {
  5634. start.insertBefore(node, nextNode)
  5635. } else {
  5636. start.appendChild(node)
  5637. }
  5638. if (first.parentNode === this.endContainer) {
  5639. this.endOffset = this.endOffset + length
  5640. }
  5641. return this.setStartBefore(first)
  5642. },
  5643. /**
  5644. * 闭合选区到当前选区的开始位置, 并且定位光标到闭合后的位置
  5645. * @method setCursor
  5646. * @return { UE.dom.Range } 当前range对象
  5647. * @see UE.dom.Range:collapse()
  5648. */
  5649. /**
  5650. * 闭合选区,可以根据参数toEnd的值控制选区是向前闭合还是向后闭合, 并且定位光标到闭合后的位置。
  5651. * @method setCursor
  5652. * @param { Boolean } toEnd 是否向后闭合, 如果为true, 则闭合选区时, 将向结束容器方向闭合,
  5653. * 反之,则向开始容器方向闭合
  5654. * @return { UE.dom.Range } 当前range对象
  5655. * @see UE.dom.Range:collapse(Boolean)
  5656. */
  5657. setCursor: function (toEnd, noFillData) {
  5658. return this.collapse(!toEnd).select(noFillData)
  5659. },
  5660. /**
  5661. * 创建当前range的一个书签,记录下当前range的位置,方便当dom树改变时,还能找回原来的选区位置
  5662. * @method createBookmark
  5663. * @param { Boolean } serialize 控制返回的标记位置是对当前位置的引用还是ID,如果该值为true,则
  5664. * 返回标记位置的ID, 反之则返回标记位置节点的引用
  5665. * @return { Object } 返回一个书签记录键值对, 其包含的key有: start => 开始标记的ID或者引用,
  5666. * end => 结束标记的ID或引用, id => 当前标记的类型, 如果为true,则表示
  5667. * 返回的记录的类型为ID, 反之则为引用
  5668. */
  5669. createBookmark: function (serialize, same) {
  5670. var endNode,
  5671. startNode = this.document.createElement('span')
  5672. startNode.style.cssText = 'display:none;line-height:0px;'
  5673. startNode.appendChild(this.document.createTextNode('\u200D'))
  5674. startNode.id = '_baidu_bookmark_start_' + (same ? '' : guid++)
  5675. if (!this.collapsed) {
  5676. endNode = startNode.cloneNode(true)
  5677. endNode.id = '_baidu_bookmark_end_' + (same ? '' : guid++)
  5678. }
  5679. this.insertNode(startNode)
  5680. if (endNode) {
  5681. this.collapse().insertNode(endNode).setEndBefore(endNode)
  5682. }
  5683. this.setStartAfter(startNode)
  5684. return {
  5685. start: serialize ? startNode.id : startNode,
  5686. end: endNode ? (serialize ? endNode.id : endNode) : null,
  5687. id: serialize,
  5688. }
  5689. },
  5690. /**
  5691. * 调整当前range的边界到书签位置,并删除该书签对象所标记的位置内的节点
  5692. * @method moveToBookmark
  5693. * @param { BookMark } bookmark createBookmark所创建的标签对象
  5694. * @return { UE.dom.Range } 当前range对象
  5695. * @see UE.dom.Range:createBookmark(Boolean)
  5696. */
  5697. moveToBookmark: function (bookmark) {
  5698. var start = bookmark.id
  5699. ? this.document.getElementById(bookmark.start)
  5700. : bookmark.start,
  5701. end =
  5702. bookmark.end && bookmark.id
  5703. ? this.document.getElementById(bookmark.end)
  5704. : bookmark.end
  5705. this.setStartBefore(start)
  5706. domUtils.remove(start)
  5707. if (end) {
  5708. this.setEndBefore(end)
  5709. domUtils.remove(end)
  5710. } else {
  5711. this.collapse(true)
  5712. }
  5713. return this
  5714. },
  5715. /**
  5716. * 调整range的边界,使其"放大"到最近的父节点
  5717. * @method enlarge
  5718. * @remind 会引起选区的变化
  5719. * @return { UE.dom.Range } 当前range对象
  5720. */
  5721. /**
  5722. * 调整range的边界,使其"放大"到最近的父节点,根据参数 toBlock 的取值, 可以
  5723. * 要求扩大之后的父节点是block节点
  5724. * @method enlarge
  5725. * @param { Boolean } toBlock 是否要求扩大之后的父节点必须是block节点
  5726. * @return { UE.dom.Range } 当前range对象
  5727. */
  5728. enlarge: function (toBlock, stopFn) {
  5729. var isBody = domUtils.isBody,
  5730. pre,
  5731. node,
  5732. tmp = this.document.createTextNode('')
  5733. if (toBlock) {
  5734. node = this.startContainer
  5735. if (node.nodeType == 1) {
  5736. if (node.childNodes[this.startOffset]) {
  5737. pre = node = node.childNodes[this.startOffset]
  5738. } else {
  5739. node.appendChild(tmp)
  5740. pre = node = tmp
  5741. }
  5742. } else {
  5743. pre = node
  5744. }
  5745. while (1) {
  5746. if (domUtils.isBlockElm(node)) {
  5747. node = pre
  5748. while (
  5749. (pre = node.previousSibling) &&
  5750. !domUtils.isBlockElm(pre)
  5751. ) {
  5752. node = pre
  5753. }
  5754. this.setStartBefore(node)
  5755. break
  5756. }
  5757. pre = node
  5758. node = node.parentNode
  5759. }
  5760. node = this.endContainer
  5761. if (node.nodeType == 1) {
  5762. if ((pre = node.childNodes[this.endOffset])) {
  5763. node.insertBefore(tmp, pre)
  5764. } else {
  5765. node.appendChild(tmp)
  5766. }
  5767. pre = node = tmp
  5768. } else {
  5769. pre = node
  5770. }
  5771. while (1) {
  5772. if (domUtils.isBlockElm(node)) {
  5773. node = pre
  5774. while ((pre = node.nextSibling) && !domUtils.isBlockElm(pre)) {
  5775. node = pre
  5776. }
  5777. this.setEndAfter(node)
  5778. break
  5779. }
  5780. pre = node
  5781. node = node.parentNode
  5782. }
  5783. if (tmp.parentNode === this.endContainer) {
  5784. this.endOffset--
  5785. }
  5786. domUtils.remove(tmp)
  5787. }
  5788. // 扩展边界到最大
  5789. if (!this.collapsed) {
  5790. while (this.startOffset == 0) {
  5791. if (stopFn && stopFn(this.startContainer)) {
  5792. break
  5793. }
  5794. if (isBody(this.startContainer)) {
  5795. break
  5796. }
  5797. this.setStartBefore(this.startContainer)
  5798. }
  5799. while (
  5800. this.endOffset ==
  5801. (this.endContainer.nodeType == 1
  5802. ? this.endContainer.childNodes.length
  5803. : this.endContainer.nodeValue.length)
  5804. ) {
  5805. if (stopFn && stopFn(this.endContainer)) {
  5806. break
  5807. }
  5808. if (isBody(this.endContainer)) {
  5809. break
  5810. }
  5811. this.setEndAfter(this.endContainer)
  5812. }
  5813. }
  5814. return this
  5815. },
  5816. enlargeToBlockElm: function (ignoreEnd) {
  5817. while (!domUtils.isBlockElm(this.startContainer)) {
  5818. this.setStartBefore(this.startContainer)
  5819. }
  5820. if (!ignoreEnd) {
  5821. while (!domUtils.isBlockElm(this.endContainer)) {
  5822. this.setEndAfter(this.endContainer)
  5823. }
  5824. }
  5825. return this
  5826. },
  5827. /**
  5828. * 调整Range的边界,使其"缩小"到最合适的位置
  5829. * @method adjustmentBoundary
  5830. * @return { UE.dom.Range } 当前range对象
  5831. * @see UE.dom.Range:shrinkBoundary()
  5832. */
  5833. adjustmentBoundary: function () {
  5834. if (!this.collapsed) {
  5835. while (
  5836. !domUtils.isBody(this.startContainer) &&
  5837. this.startOffset ==
  5838. this.startContainer[
  5839. this.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'
  5840. ].length &&
  5841. this.startContainer[
  5842. this.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'
  5843. ].length
  5844. ) {
  5845. this.setStartAfter(this.startContainer)
  5846. }
  5847. while (
  5848. !domUtils.isBody(this.endContainer) &&
  5849. !this.endOffset &&
  5850. this.endContainer[
  5851. this.endContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'
  5852. ].length
  5853. ) {
  5854. this.setEndBefore(this.endContainer)
  5855. }
  5856. }
  5857. return this
  5858. },
  5859. /**
  5860. * 给range选区中的内容添加给定的inline标签
  5861. * @method applyInlineStyle
  5862. * @param { String } tagName 需要添加的标签名
  5863. * @example
  5864. * ```html
  5865. * <p>xxxx[xxxx]x</p> ==> range.applyInlineStyle("strong") ==> <p>xxxx[<strong>xxxx</strong>]x</p>
  5866. * ```
  5867. */
  5868. /**
  5869. * 给range选区中的内容添加给定的inline标签, 并且为标签附加上一些初始化属性。
  5870. * @method applyInlineStyle
  5871. * @param { String } tagName 需要添加的标签名
  5872. * @param { Object } attrs 跟随新添加的标签的属性
  5873. * @return { UE.dom.Range } 当前选区
  5874. * @example
  5875. * ```html
  5876. * <p>xxxx[xxxx]x</p>
  5877. *
  5878. * ==>
  5879. *
  5880. * <!-- 执行操作 -->
  5881. * range.applyInlineStyle("strong",{"style":"font-size:12px"})
  5882. *
  5883. * ==>
  5884. *
  5885. * <p>xxxx[<strong style="font-size:12px">xxxx</strong>]x</p>
  5886. * ```
  5887. */
  5888. applyInlineStyle: function (tagName, attrs, list) {
  5889. if (this.collapsed) return this
  5890. this.trimBoundary()
  5891. .enlarge(false, function (node) {
  5892. return node.nodeType == 1 && domUtils.isBlockElm(node)
  5893. })
  5894. .adjustmentBoundary()
  5895. var bookmark = this.createBookmark(),
  5896. end = bookmark.end,
  5897. filterFn = function (node) {
  5898. return node.nodeType == 1
  5899. ? node.tagName.toLowerCase() != 'br'
  5900. : !domUtils.isWhitespace(node)
  5901. },
  5902. current = domUtils.getNextDomNode(bookmark.start, false, filterFn),
  5903. node,
  5904. pre,
  5905. range = this.cloneRange()
  5906. while (
  5907. current &&
  5908. domUtils.getPosition(current, end) & domUtils.POSITION_PRECEDING
  5909. ) {
  5910. if (current.nodeType == 3 || dtd[tagName][current.tagName]) {
  5911. range.setStartBefore(current)
  5912. node = current
  5913. while (
  5914. node &&
  5915. (node.nodeType == 3 || dtd[tagName][node.tagName]) &&
  5916. node !== end
  5917. ) {
  5918. pre = node
  5919. node = domUtils.getNextDomNode(
  5920. node,
  5921. node.nodeType == 1,
  5922. null,
  5923. function (parent) {
  5924. return dtd[tagName][parent.tagName]
  5925. }
  5926. )
  5927. }
  5928. var frag = range.setEndAfter(pre).extractContents(),
  5929. elm
  5930. if (list && list.length > 0) {
  5931. var level, top
  5932. top = level = list[0].cloneNode(false)
  5933. for (var i = 1, ci; (ci = list[i++]); ) {
  5934. level.appendChild(ci.cloneNode(false))
  5935. level = level.firstChild
  5936. }
  5937. elm = level
  5938. } else {
  5939. elm = range.document.createElement(tagName)
  5940. }
  5941. if (attrs) {
  5942. domUtils.setAttributes(elm, attrs)
  5943. }
  5944. elm.appendChild(frag)
  5945. range.insertNode(list ? top : elm)
  5946. //处理下滑线在a上的情况
  5947. var aNode
  5948. if (
  5949. tagName == 'span' &&
  5950. attrs.style &&
  5951. /text\-decoration/.test(attrs.style) &&
  5952. (aNode = domUtils.findParentByTagName(elm, 'a', true))
  5953. ) {
  5954. domUtils.setAttributes(aNode, attrs)
  5955. domUtils.remove(elm, true)
  5956. elm = aNode
  5957. } else {
  5958. domUtils.mergeSibling(elm)
  5959. domUtils.clearEmptySibling(elm)
  5960. }
  5961. //去除子节点相同的
  5962. domUtils.mergeChild(elm, attrs)
  5963. current = domUtils.getNextDomNode(elm, false, filterFn)
  5964. domUtils.mergeToParent(elm)
  5965. if (node === end) {
  5966. break
  5967. }
  5968. } else {
  5969. current = domUtils.getNextDomNode(current, true, filterFn)
  5970. }
  5971. }
  5972. return this.moveToBookmark(bookmark)
  5973. },
  5974. /**
  5975. * 移除当前选区内指定的inline标签,但保留其中的内容
  5976. * @method removeInlineStyle
  5977. * @param { String } tagName 需要移除的标签名
  5978. * @return { UE.dom.Range } 当前的range对象
  5979. * @example
  5980. * ```html
  5981. * xx[x<span>xxx<em>yyy</em>zz]z</span> => range.removeInlineStyle(["em"]) => xx[x<span>xxxyyyzz]z</span>
  5982. * ```
  5983. */
  5984. /**
  5985. * 移除当前选区内指定的一组inline标签,但保留其中的内容
  5986. * @method removeInlineStyle
  5987. * @param { Array } tagNameArr 需要移除的标签名的数组
  5988. * @return { UE.dom.Range } 当前的range对象
  5989. * @see UE.dom.Range:removeInlineStyle(String)
  5990. */
  5991. removeInlineStyle: function (tagNames) {
  5992. if (this.collapsed) return this
  5993. tagNames = utils.isArray(tagNames) ? tagNames : [tagNames]
  5994. this.shrinkBoundary().adjustmentBoundary()
  5995. var start = this.startContainer,
  5996. end = this.endContainer
  5997. while (1) {
  5998. if (start.nodeType == 1) {
  5999. if (utils.indexOf(tagNames, start.tagName.toLowerCase()) > -1) {
  6000. break
  6001. }
  6002. if (start.tagName.toLowerCase() == 'body') {
  6003. start = null
  6004. break
  6005. }
  6006. }
  6007. start = start.parentNode
  6008. }
  6009. while (1) {
  6010. if (end.nodeType == 1) {
  6011. if (utils.indexOf(tagNames, end.tagName.toLowerCase()) > -1) {
  6012. break
  6013. }
  6014. if (end.tagName.toLowerCase() == 'body') {
  6015. end = null
  6016. break
  6017. }
  6018. }
  6019. end = end.parentNode
  6020. }
  6021. var bookmark = this.createBookmark(),
  6022. frag,
  6023. tmpRange
  6024. if (start) {
  6025. tmpRange = this.cloneRange()
  6026. .setEndBefore(bookmark.start)
  6027. .setStartBefore(start)
  6028. frag = tmpRange.extractContents()
  6029. tmpRange.insertNode(frag)
  6030. domUtils.clearEmptySibling(start, true)
  6031. start.parentNode.insertBefore(bookmark.start, start)
  6032. }
  6033. if (end) {
  6034. tmpRange = this.cloneRange()
  6035. .setStartAfter(bookmark.end)
  6036. .setEndAfter(end)
  6037. frag = tmpRange.extractContents()
  6038. tmpRange.insertNode(frag)
  6039. domUtils.clearEmptySibling(end, false, true)
  6040. end.parentNode.insertBefore(bookmark.end, end.nextSibling)
  6041. }
  6042. var current = domUtils.getNextDomNode(
  6043. bookmark.start,
  6044. false,
  6045. function (node) {
  6046. return node.nodeType == 1
  6047. }
  6048. ),
  6049. next
  6050. while (current && current !== bookmark.end) {
  6051. next = domUtils.getNextDomNode(current, true, function (node) {
  6052. return node.nodeType == 1
  6053. })
  6054. if (utils.indexOf(tagNames, current.tagName.toLowerCase()) > -1) {
  6055. domUtils.remove(current, true)
  6056. }
  6057. current = next
  6058. }
  6059. return this.moveToBookmark(bookmark)
  6060. },
  6061. /**
  6062. * 获取当前选中的自闭合的节点
  6063. * @method getClosedNode
  6064. * @return { Node | NULL } 如果当前选中的是自闭合节点, 则返回该节点, 否则返回NULL
  6065. */
  6066. getClosedNode: function () {
  6067. var node
  6068. if (!this.collapsed) {
  6069. var range = this.cloneRange().adjustmentBoundary().shrinkBoundary()
  6070. if (selectOneNode(range)) {
  6071. var child = range.startContainer.childNodes[range.startOffset]
  6072. if (
  6073. child &&
  6074. child.nodeType == 1 &&
  6075. (dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName])
  6076. ) {
  6077. node = child
  6078. }
  6079. }
  6080. }
  6081. return node
  6082. },
  6083. /**
  6084. * 在页面上高亮range所表示的选区
  6085. * @method select
  6086. * @return { UE.dom.Range } 返回当前Range对象
  6087. */
  6088. //这里不区分ie9以上,trace:3824
  6089. select: browser.ie
  6090. ? function (noFillData, textRange) {
  6091. var nativeRange
  6092. if (!this.collapsed) this.shrinkBoundary()
  6093. var node = this.getClosedNode()
  6094. if (node && !textRange) {
  6095. try {
  6096. nativeRange = this.document.body.createControlRange()
  6097. nativeRange.addElement(node)
  6098. nativeRange.select()
  6099. } catch (e) {}
  6100. return this
  6101. }
  6102. var bookmark = this.createBookmark(),
  6103. start = bookmark.start,
  6104. end
  6105. nativeRange = this.document.body.createTextRange()
  6106. nativeRange.moveToElementText(start)
  6107. nativeRange.moveStart('character', 1)
  6108. if (!this.collapsed) {
  6109. var nativeRangeEnd = this.document.body.createTextRange()
  6110. end = bookmark.end
  6111. nativeRangeEnd.moveToElementText(end)
  6112. nativeRange.setEndPoint('EndToEnd', nativeRangeEnd)
  6113. } else {
  6114. if (!noFillData && this.startContainer.nodeType != 3) {
  6115. //使用<span>|x<span>固定住光标
  6116. var tmpText = this.document.createTextNode(fillChar),
  6117. tmp = this.document.createElement('span')
  6118. tmp.appendChild(this.document.createTextNode(fillChar))
  6119. start.parentNode.insertBefore(tmp, start)
  6120. start.parentNode.insertBefore(tmpText, start)
  6121. //当点b,i,u时,不能清除i上边的b
  6122. removeFillData(this.document, tmpText)
  6123. fillData = tmpText
  6124. mergeSibling(tmp, 'previousSibling')
  6125. mergeSibling(start, 'nextSibling')
  6126. nativeRange.moveStart('character', -1)
  6127. nativeRange.collapse(true)
  6128. }
  6129. }
  6130. this.moveToBookmark(bookmark)
  6131. tmp && domUtils.remove(tmp)
  6132. //IE在隐藏状态下不支持range操作,catch一下
  6133. try {
  6134. nativeRange.select()
  6135. } catch (e) {}
  6136. return this
  6137. }
  6138. : function (notInsertFillData) {
  6139. function checkOffset(rng) {
  6140. function check(node, offset, dir) {
  6141. if (node.nodeType == 3 && node.nodeValue.length < offset) {
  6142. rng[dir + 'Offset'] = node.nodeValue.length
  6143. }
  6144. }
  6145. check(rng.startContainer, rng.startOffset, 'start')
  6146. check(rng.endContainer, rng.endOffset, 'end')
  6147. }
  6148. var win = domUtils.getWindow(this.document),
  6149. sel = win.getSelection(),
  6150. txtNode
  6151. //FF下关闭自动长高时滚动条在关闭dialog时会跳
  6152. //ff下如果不body.focus将不能定位闭合光标到编辑器内
  6153. browser.gecko ? this.document.body.focus() : win.focus()
  6154. if (sel) {
  6155. sel.removeAllRanges()
  6156. // trace:870 chrome/safari后边是br对于闭合得range不能定位 所以去掉了判断
  6157. // this.startContainer.nodeType != 3 &&! ((child = this.startContainer.childNodes[this.startOffset]) && child.nodeType == 1 && child.tagName == 'BR'
  6158. if (this.collapsed && !notInsertFillData) {
  6159. // //opear如果没有节点接着,原生的不能够定位,不能在body的第一级插入空白节点
  6160. // if (notInsertFillData && browser.opera && !domUtils.isBody(this.startContainer) && this.startContainer.nodeType == 1) {
  6161. // var tmp = this.document.createTextNode('');
  6162. // this.insertNode(tmp).setStart(tmp, 0).collapse(true);
  6163. // }
  6164. //
  6165. //处理光标落在文本节点的情况
  6166. //处理以下的情况
  6167. //<b>|xxxx</b>
  6168. //<b>xxxx</b>|xxxx
  6169. //xxxx<b>|</b>
  6170. var start = this.startContainer,
  6171. child = start
  6172. if (start.nodeType == 1) {
  6173. child = start.childNodes[this.startOffset]
  6174. }
  6175. if (
  6176. !(start.nodeType == 3 && this.startOffset) &&
  6177. (child
  6178. ? !child.previousSibling ||
  6179. child.previousSibling.nodeType != 3
  6180. : !start.lastChild || start.lastChild.nodeType != 3)
  6181. ) {
  6182. txtNode = this.document.createTextNode(fillChar)
  6183. //跟着前边走
  6184. this.insertNode(txtNode)
  6185. removeFillData(this.document, txtNode)
  6186. mergeSibling(txtNode, 'previousSibling')
  6187. mergeSibling(txtNode, 'nextSibling')
  6188. fillData = txtNode
  6189. this.setStart(txtNode, browser.webkit ? 1 : 0).collapse(true)
  6190. }
  6191. }
  6192. var nativeRange = this.document.createRange()
  6193. if (
  6194. this.collapsed &&
  6195. browser.opera &&
  6196. this.startContainer.nodeType == 1
  6197. ) {
  6198. var child = this.startContainer.childNodes[this.startOffset]
  6199. if (!child) {
  6200. //往前靠拢
  6201. child = this.startContainer.lastChild
  6202. if (child && domUtils.isBr(child)) {
  6203. this.setStartBefore(child).collapse(true)
  6204. }
  6205. } else {
  6206. //向后靠拢
  6207. while (child && domUtils.isBlockElm(child)) {
  6208. if (child.nodeType == 1 && child.childNodes[0]) {
  6209. child = child.childNodes[0]
  6210. } else {
  6211. break
  6212. }
  6213. }
  6214. child && this.setStartBefore(child).collapse(true)
  6215. }
  6216. }
  6217. //是createAddress最后一位算的不准,现在这里进行微调
  6218. checkOffset(this)
  6219. nativeRange.setStart(this.startContainer, this.startOffset)
  6220. nativeRange.setEnd(this.endContainer, this.endOffset)
  6221. sel.addRange(nativeRange)
  6222. }
  6223. return this
  6224. },
  6225. /**
  6226. * 滚动到当前range开始的位置
  6227. * @method scrollToView
  6228. * @param { Window } win 当前range对象所属的window对象
  6229. * @return { UE.dom.Range } 当前Range对象
  6230. */
  6231. /**
  6232. * 滚动到距离当前range开始位置 offset 的位置处
  6233. * @method scrollToView
  6234. * @param { Window } win 当前range对象所属的window对象
  6235. * @param { Number } offset 距离range开始位置处的偏移量, 如果为正数, 则向下偏移, 反之, 则向上偏移
  6236. * @return { UE.dom.Range } 当前Range对象
  6237. */
  6238. scrollToView: function (win, offset) {
  6239. win = win ? window : domUtils.getWindow(this.document)
  6240. var me = this,
  6241. span = me.document.createElement('span')
  6242. //trace:717
  6243. span.innerHTML = '&nbsp;'
  6244. me.cloneRange().insertNode(span)
  6245. domUtils.scrollToView(span, win, offset)
  6246. domUtils.remove(span)
  6247. return me
  6248. },
  6249. /**
  6250. * 判断当前选区内容是否占位符
  6251. * @private
  6252. * @method inFillChar
  6253. * @return { Boolean } 如果是占位符返回true,否则返回false
  6254. */
  6255. inFillChar: function () {
  6256. var start = this.startContainer
  6257. if (
  6258. this.collapsed &&
  6259. start.nodeType == 3 &&
  6260. start.nodeValue.replace(new RegExp('^' + domUtils.fillChar), '')
  6261. .length +
  6262. 1 ==
  6263. start.nodeValue.length
  6264. ) {
  6265. return true
  6266. }
  6267. return false
  6268. },
  6269. /**
  6270. * 保存
  6271. * @method createAddress
  6272. * @private
  6273. * @return { Boolean } 返回开始和结束的位置
  6274. * @example
  6275. * ```html
  6276. * <body>
  6277. * <p>
  6278. * aaaa
  6279. * <em>
  6280. * <!-- 选区开始 -->
  6281. * bbbb
  6282. * <!-- 选区结束 -->
  6283. * </em>
  6284. * </p>
  6285. *
  6286. * <script>
  6287. * //output: {startAddress:[0,1,0,0],endAddress:[0,1,0,4]}
  6288. * console.log( range.createAddress() );
  6289. * </script>
  6290. * </body>
  6291. * ```
  6292. */
  6293. createAddress: function (ignoreEnd, ignoreTxt) {
  6294. var addr = {},
  6295. me = this
  6296. function getAddress(isStart) {
  6297. var node = isStart ? me.startContainer : me.endContainer
  6298. var parents = domUtils.findParents(node, true, function (node) {
  6299. return !domUtils.isBody(node)
  6300. }),
  6301. addrs = []
  6302. for (var i = 0, ci; (ci = parents[i++]); ) {
  6303. addrs.push(domUtils.getNodeIndex(ci, ignoreTxt))
  6304. }
  6305. var firstIndex = 0
  6306. if (ignoreTxt) {
  6307. if (node.nodeType == 3) {
  6308. var tmpNode = node.previousSibling
  6309. while (tmpNode && tmpNode.nodeType == 3) {
  6310. firstIndex += tmpNode.nodeValue.replace(fillCharReg, '').length
  6311. tmpNode = tmpNode.previousSibling
  6312. }
  6313. firstIndex += isStart ? me.startOffset : me.endOffset // - (fillCharReg.test(node.nodeValue) ? 1 : 0 )
  6314. } else {
  6315. node = node.childNodes[isStart ? me.startOffset : me.endOffset]
  6316. if (node) {
  6317. firstIndex = domUtils.getNodeIndex(node, ignoreTxt)
  6318. } else {
  6319. node = isStart ? me.startContainer : me.endContainer
  6320. var first = node.firstChild
  6321. while (first) {
  6322. if (domUtils.isFillChar(first)) {
  6323. first = first.nextSibling
  6324. continue
  6325. }
  6326. firstIndex++
  6327. if (first.nodeType == 3) {
  6328. while (first && first.nodeType == 3) {
  6329. first = first.nextSibling
  6330. }
  6331. } else {
  6332. first = first.nextSibling
  6333. }
  6334. }
  6335. }
  6336. }
  6337. } else {
  6338. firstIndex = isStart
  6339. ? domUtils.isFillChar(node)
  6340. ? 0
  6341. : me.startOffset
  6342. : me.endOffset
  6343. }
  6344. if (firstIndex < 0) {
  6345. firstIndex = 0
  6346. }
  6347. addrs.push(firstIndex)
  6348. return addrs
  6349. }
  6350. addr.startAddress = getAddress(true)
  6351. if (!ignoreEnd) {
  6352. addr.endAddress = me.collapsed
  6353. ? [].concat(addr.startAddress)
  6354. : getAddress()
  6355. }
  6356. return addr
  6357. },
  6358. /**
  6359. * 保存
  6360. * @method createAddress
  6361. * @private
  6362. * @return { Boolean } 返回开始和结束的位置
  6363. * @example
  6364. * ```html
  6365. * <body>
  6366. * <p>
  6367. * aaaa
  6368. * <em>
  6369. * <!-- 选区开始 -->
  6370. * bbbb
  6371. * <!-- 选区结束 -->
  6372. * </em>
  6373. * </p>
  6374. *
  6375. * <script>
  6376. * var range = editor.selection.getRange();
  6377. * range.moveToAddress({startAddress:[0,1,0,0],endAddress:[0,1,0,4]});
  6378. * range.select();
  6379. * //output: 'bbbb'
  6380. * console.log(editor.selection.getText());
  6381. * </script>
  6382. * </body>
  6383. * ```
  6384. */
  6385. moveToAddress: function (addr, ignoreEnd) {
  6386. var me = this
  6387. function getNode(address, isStart) {
  6388. var tmpNode = me.document.body,
  6389. parentNode,
  6390. offset
  6391. for (var i = 0, ci, l = address.length; i < l; i++) {
  6392. ci = address[i]
  6393. parentNode = tmpNode
  6394. tmpNode = tmpNode.childNodes[ci]
  6395. if (!tmpNode) {
  6396. offset = ci
  6397. break
  6398. }
  6399. }
  6400. if (isStart) {
  6401. if (tmpNode) {
  6402. me.setStartBefore(tmpNode)
  6403. } else {
  6404. me.setStart(parentNode, offset)
  6405. }
  6406. } else {
  6407. if (tmpNode) {
  6408. me.setEndBefore(tmpNode)
  6409. } else {
  6410. me.setEnd(parentNode, offset)
  6411. }
  6412. }
  6413. }
  6414. getNode(addr.startAddress, true)
  6415. !ignoreEnd && addr.endAddress && getNode(addr.endAddress)
  6416. return me
  6417. },
  6418. /**
  6419. * 判断给定的Range对象是否和当前Range对象表示的是同一个选区
  6420. * @method equals
  6421. * @param { UE.dom.Range } 需要判断的Range对象
  6422. * @return { Boolean } 如果给定的Range对象与当前Range对象表示的是同一个选区, 则返回true, 否则返回false
  6423. */
  6424. equals: function (rng) {
  6425. for (var p in this) {
  6426. if (this.hasOwnProperty(p)) {
  6427. if (this[p] !== rng[p]) return false
  6428. }
  6429. }
  6430. return true
  6431. },
  6432. /**
  6433. * 遍历range内的节点。每当遍历一个节点时, 都会执行参数项 doFn 指定的函数, 该函数的接受当前遍历的节点
  6434. * 作为其参数。
  6435. * @method traversal
  6436. * @param { Function } doFn 对每个遍历的节点要执行的方法, 该方法接受当前遍历的节点作为其参数
  6437. * @return { UE.dom.Range } 当前range对象
  6438. * @example
  6439. * ```html
  6440. *
  6441. * <body>
  6442. *
  6443. * <!-- 选区开始 -->
  6444. * <span></span>
  6445. * <a></a>
  6446. * <!-- 选区结束 -->
  6447. * </body>
  6448. *
  6449. * <script>
  6450. *
  6451. * //output: <span></span><a></a>
  6452. * console.log( range.cloneContents() );
  6453. *
  6454. * range.traversal( function ( node ) {
  6455. *
  6456. * if ( node.nodeType === 1 ) {
  6457. * node.className = "test";
  6458. * }
  6459. *
  6460. * } );
  6461. *
  6462. * //output: <span class="test"></span><a class="test"></a>
  6463. * console.log( range.cloneContents() );
  6464. *
  6465. * </script>
  6466. * ```
  6467. */
  6468. /**
  6469. * 遍历range内的节点。
  6470. * 每当遍历一个节点时, 都会执行参数项 doFn 指定的函数, 该函数的接受当前遍历的节点
  6471. * 作为其参数。
  6472. * 可以通过参数项 filterFn 来指定一个过滤器, 只有符合该过滤器过滤规则的节点才会触
  6473. * 发doFn函数的执行
  6474. * @method traversal
  6475. * @param { Function } doFn 对每个遍历的节点要执行的方法, 该方法接受当前遍历的节点作为其参数
  6476. * @param { Function } filterFn 过滤器, 该函数接受当前遍历的节点作为参数, 如果该节点满足过滤
  6477. * 规则, 请返回true, 该节点会触发doFn, 否则, 请返回false, 则该节点不
  6478. * 会触发doFn。
  6479. * @return { UE.dom.Range } 当前range对象
  6480. * @see UE.dom.Range:traversal(Function)
  6481. * @example
  6482. * ```html
  6483. *
  6484. * <body>
  6485. *
  6486. * <!-- 选区开始 -->
  6487. * <span></span>
  6488. * <a></a>
  6489. * <!-- 选区结束 -->
  6490. * </body>
  6491. *
  6492. * <script>
  6493. *
  6494. * //output: <span></span><a></a>
  6495. * console.log( range.cloneContents() );
  6496. *
  6497. * range.traversal( function ( node ) {
  6498. *
  6499. * node.className = "test";
  6500. *
  6501. * }, function ( node ) {
  6502. * return node.nodeType === 1;
  6503. * } );
  6504. *
  6505. * //output: <span class="test"></span><a class="test"></a>
  6506. * console.log( range.cloneContents() );
  6507. *
  6508. * </script>
  6509. * ```
  6510. */
  6511. traversal: function (doFn, filterFn) {
  6512. if (this.collapsed) return this
  6513. var bookmark = this.createBookmark(),
  6514. end = bookmark.end,
  6515. current = domUtils.getNextDomNode(bookmark.start, false, filterFn)
  6516. while (
  6517. current &&
  6518. current !== end &&
  6519. domUtils.getPosition(current, end) & domUtils.POSITION_PRECEDING
  6520. ) {
  6521. var tmpNode = domUtils.getNextDomNode(current, false, filterFn)
  6522. doFn(current)
  6523. current = tmpNode
  6524. }
  6525. return this.moveToBookmark(bookmark)
  6526. },
  6527. }
  6528. })()
  6529. // core/Selection.js
  6530. /**
  6531. * 选集
  6532. * @file
  6533. * @module UE.dom
  6534. * @class Selection
  6535. * @since 1.2.6.1
  6536. */
  6537. /**
  6538. * 选区集合
  6539. * @unfile
  6540. * @module UE.dom
  6541. * @class Selection
  6542. */
  6543. ;(function () {
  6544. function getBoundaryInformation(range, start) {
  6545. var getIndex = domUtils.getNodeIndex
  6546. range = range.duplicate()
  6547. range.collapse(start)
  6548. var parent = range.parentElement()
  6549. //如果节点里没有子节点,直接退出
  6550. if (!parent.hasChildNodes()) {
  6551. return { container: parent, offset: 0 }
  6552. }
  6553. var siblings = parent.children,
  6554. child,
  6555. testRange = range.duplicate(),
  6556. startIndex = 0,
  6557. endIndex = siblings.length - 1,
  6558. index = -1,
  6559. distance
  6560. while (startIndex <= endIndex) {
  6561. index = Math.floor((startIndex + endIndex) / 2)
  6562. child = siblings[index]
  6563. testRange.moveToElementText(child)
  6564. var position = testRange.compareEndPoints('StartToStart', range)
  6565. if (position > 0) {
  6566. endIndex = index - 1
  6567. } else if (position < 0) {
  6568. startIndex = index + 1
  6569. } else {
  6570. //trace:1043
  6571. return { container: parent, offset: getIndex(child) }
  6572. }
  6573. }
  6574. if (index == -1) {
  6575. testRange.moveToElementText(parent)
  6576. testRange.setEndPoint('StartToStart', range)
  6577. distance = testRange.text.replace(/(\r\n|\r)/g, '\n').length
  6578. siblings = parent.childNodes
  6579. if (!distance) {
  6580. child = siblings[siblings.length - 1]
  6581. return { container: child, offset: child.nodeValue.length }
  6582. }
  6583. var i = siblings.length
  6584. while (distance > 0) {
  6585. distance -= siblings[--i].nodeValue.length
  6586. }
  6587. return { container: siblings[i], offset: -distance }
  6588. }
  6589. testRange.collapse(position > 0)
  6590. testRange.setEndPoint(position > 0 ? 'StartToStart' : 'EndToStart', range)
  6591. distance = testRange.text.replace(/(\r\n|\r)/g, '\n').length
  6592. if (!distance) {
  6593. return dtd.$empty[child.tagName] || dtd.$nonChild[child.tagName]
  6594. ? {
  6595. container: parent,
  6596. offset: getIndex(child) + (position > 0 ? 0 : 1),
  6597. }
  6598. : {
  6599. container: child,
  6600. offset: position > 0 ? 0 : child.childNodes.length,
  6601. }
  6602. }
  6603. while (distance > 0) {
  6604. try {
  6605. var pre = child
  6606. child = child[position > 0 ? 'previousSibling' : 'nextSibling']
  6607. distance -= child.nodeValue.length
  6608. } catch (e) {
  6609. return { container: parent, offset: getIndex(pre) }
  6610. }
  6611. }
  6612. return {
  6613. container: child,
  6614. offset: position > 0 ? -distance : child.nodeValue.length + distance,
  6615. }
  6616. }
  6617. /**
  6618. * 将ieRange转换为Range对象
  6619. * @param {Range} ieRange ieRange对象
  6620. * @param {Range} range Range对象
  6621. * @return {Range} range 返回转换后的Range对象
  6622. */
  6623. function transformIERangeToRange(ieRange, range) {
  6624. if (ieRange.item) {
  6625. range.selectNode(ieRange.item(0))
  6626. } else {
  6627. var bi = getBoundaryInformation(ieRange, true)
  6628. range.setStart(bi.container, bi.offset)
  6629. if (ieRange.compareEndPoints('StartToEnd', ieRange) != 0) {
  6630. bi = getBoundaryInformation(ieRange, false)
  6631. range.setEnd(bi.container, bi.offset)
  6632. }
  6633. }
  6634. return range
  6635. }
  6636. /**
  6637. * 获得ieRange
  6638. * @param {Selection} sel Selection对象
  6639. * @return {ieRange} 得到ieRange
  6640. */
  6641. function _getIERange(sel) {
  6642. var ieRange
  6643. //ie下有可能报错
  6644. try {
  6645. ieRange = sel.getNative().createRange()
  6646. } catch (e) {
  6647. return null
  6648. }
  6649. var el = ieRange.item ? ieRange.item(0) : ieRange.parentElement()
  6650. if ((el.ownerDocument || el) === sel.document) {
  6651. return ieRange
  6652. }
  6653. return null
  6654. }
  6655. var Selection = (dom.Selection = function (doc) {
  6656. var me = this,
  6657. iframe
  6658. me.document = doc
  6659. if (browser.ie9below) {
  6660. iframe = domUtils.getWindow(doc).frameElement
  6661. domUtils.on(iframe, 'beforedeactivate', function () {
  6662. me._bakIERange = me.getIERange()
  6663. })
  6664. domUtils.on(iframe, 'activate', function () {
  6665. try {
  6666. if (!_getIERange(me) && me._bakIERange) {
  6667. me._bakIERange.select()
  6668. }
  6669. } catch (ex) {}
  6670. me._bakIERange = null
  6671. })
  6672. }
  6673. iframe = doc = null
  6674. })
  6675. Selection.prototype = {
  6676. rangeInBody: function (rng, txtRange) {
  6677. var node =
  6678. browser.ie9below || txtRange
  6679. ? rng.item
  6680. ? rng.item()
  6681. : rng.parentElement()
  6682. : rng.startContainer
  6683. return (
  6684. node === this.document.body || domUtils.inDoc(node, this.document)
  6685. )
  6686. },
  6687. /**
  6688. * 获取原生seleciton对象
  6689. * @method getNative
  6690. * @return { Object } 获得selection对象
  6691. * @example
  6692. * ```javascript
  6693. * editor.selection.getNative();
  6694. * ```
  6695. */
  6696. getNative: function () {
  6697. var doc = this.document
  6698. try {
  6699. return !doc
  6700. ? null
  6701. : browser.ie9below
  6702. ? doc.selection
  6703. : domUtils.getWindow(doc).getSelection()
  6704. } catch (e) {
  6705. return null
  6706. }
  6707. },
  6708. /**
  6709. * 获得ieRange
  6710. * @method getIERange
  6711. * @return { Object } 返回ie原生的Range
  6712. * @example
  6713. * ```javascript
  6714. * editor.selection.getIERange();
  6715. * ```
  6716. */
  6717. getIERange: function () {
  6718. var ieRange = _getIERange(this)
  6719. if (!ieRange) {
  6720. if (this._bakIERange) {
  6721. return this._bakIERange
  6722. }
  6723. }
  6724. return ieRange
  6725. },
  6726. /**
  6727. * 缓存当前选区的range和选区的开始节点
  6728. * @method cache
  6729. */
  6730. cache: function () {
  6731. this.clear()
  6732. this._cachedRange = this.getRange()
  6733. this._cachedStartElement = this.getStart()
  6734. this._cachedStartElementPath = this.getStartElementPath()
  6735. },
  6736. /**
  6737. * 获取选区开始位置的父节点到body
  6738. * @method getStartElementPath
  6739. * @return { Array } 返回父节点集合
  6740. * @example
  6741. * ```javascript
  6742. * editor.selection.getStartElementPath();
  6743. * ```
  6744. */
  6745. getStartElementPath: function () {
  6746. if (this._cachedStartElementPath) {
  6747. return this._cachedStartElementPath
  6748. }
  6749. var start = this.getStart()
  6750. if (start) {
  6751. return domUtils.findParents(start, true, null, true)
  6752. }
  6753. return []
  6754. },
  6755. /**
  6756. * 清空缓存
  6757. * @method clear
  6758. */
  6759. clear: function () {
  6760. this._cachedStartElementPath =
  6761. this._cachedRange =
  6762. this._cachedStartElement =
  6763. null
  6764. },
  6765. /**
  6766. * 编辑器是否得到了选区
  6767. * @method isFocus
  6768. */
  6769. isFocus: function () {
  6770. try {
  6771. if (browser.ie9below) {
  6772. var nativeRange = _getIERange(this)
  6773. return !!(nativeRange && this.rangeInBody(nativeRange))
  6774. } else {
  6775. return !!this.getNative().rangeCount
  6776. }
  6777. } catch (e) {
  6778. return false
  6779. }
  6780. },
  6781. /**
  6782. * 获取选区对应的Range
  6783. * @method getRange
  6784. * @return { Object } 得到Range对象
  6785. * @example
  6786. * ```javascript
  6787. * editor.selection.getRange();
  6788. * ```
  6789. */
  6790. getRange: function () {
  6791. var me = this
  6792. function optimze(range) {
  6793. var child = me.document.body.firstChild,
  6794. collapsed = range.collapsed
  6795. while (child && child.firstChild) {
  6796. range.setStart(child, 0)
  6797. child = child.firstChild
  6798. }
  6799. if (!range.startContainer) {
  6800. range.setStart(me.document.body, 0)
  6801. }
  6802. if (collapsed) {
  6803. range.collapse(true)
  6804. }
  6805. }
  6806. if (me._cachedRange != null) {
  6807. return this._cachedRange
  6808. }
  6809. var range = new baidu.editor.dom.Range(me.document)
  6810. if (browser.ie9below) {
  6811. var nativeRange = me.getIERange()
  6812. if (nativeRange) {
  6813. //备份的_bakIERange可能已经实效了,dom树发生了变化比如从源码模式切回来,所以try一下,实效就放到body开始位置
  6814. try {
  6815. transformIERangeToRange(nativeRange, range)
  6816. } catch (e) {
  6817. optimze(range)
  6818. }
  6819. } else {
  6820. optimze(range)
  6821. }
  6822. } else {
  6823. var sel = me.getNative()
  6824. if (sel && sel.rangeCount) {
  6825. var firstRange = sel.getRangeAt(0)
  6826. var lastRange = sel.getRangeAt(sel.rangeCount - 1)
  6827. range
  6828. .setStart(firstRange.startContainer, firstRange.startOffset)
  6829. .setEnd(lastRange.endContainer, lastRange.endOffset)
  6830. if (
  6831. range.collapsed &&
  6832. domUtils.isBody(range.startContainer) &&
  6833. !range.startOffset
  6834. ) {
  6835. optimze(range)
  6836. }
  6837. } else {
  6838. //trace:1734 有可能已经不在dom树上了,标识的节点
  6839. if (
  6840. this._bakRange &&
  6841. domUtils.inDoc(this._bakRange.startContainer, this.document)
  6842. ) {
  6843. return this._bakRange
  6844. }
  6845. optimze(range)
  6846. }
  6847. }
  6848. return (this._bakRange = range)
  6849. },
  6850. /**
  6851. * 获取开始元素,用于状态反射
  6852. * @method getStart
  6853. * @return { Element } 获得开始元素
  6854. * @example
  6855. * ```javascript
  6856. * editor.selection.getStart();
  6857. * ```
  6858. */
  6859. getStart: function () {
  6860. if (this._cachedStartElement) {
  6861. return this._cachedStartElement
  6862. }
  6863. var range = browser.ie9below ? this.getIERange() : this.getRange(),
  6864. tmpRange,
  6865. start,
  6866. tmp,
  6867. parent
  6868. if (browser.ie9below) {
  6869. if (!range) {
  6870. //todo 给第一个值可能会有问题
  6871. return this.document.body.firstChild
  6872. }
  6873. //control元素
  6874. if (range.item) {
  6875. return range.item(0)
  6876. }
  6877. tmpRange = range.duplicate()
  6878. //修正ie下<b>x</b>[xx] 闭合后 <b>x|</b>xx
  6879. tmpRange.text.length > 0 && tmpRange.moveStart('character', 1)
  6880. tmpRange.collapse(1)
  6881. start = tmpRange.parentElement()
  6882. parent = tmp = range.parentElement()
  6883. while ((tmp = tmp.parentNode)) {
  6884. if (tmp == start) {
  6885. start = parent
  6886. break
  6887. }
  6888. }
  6889. } else {
  6890. range.shrinkBoundary()
  6891. start = range.startContainer
  6892. if (start.nodeType == 1 && start.hasChildNodes()) {
  6893. start =
  6894. start.childNodes[
  6895. Math.min(start.childNodes.length - 1, range.startOffset)
  6896. ]
  6897. }
  6898. if (start.nodeType == 3) {
  6899. return start.parentNode
  6900. }
  6901. }
  6902. return start
  6903. },
  6904. /**
  6905. * 得到选区中的文本
  6906. * @method getText
  6907. * @return { String } 选区中包含的文本
  6908. * @example
  6909. * ```javascript
  6910. * editor.selection.getText();
  6911. * ```
  6912. */
  6913. getText: function () {
  6914. var nativeSel, nativeRange
  6915. if (this.isFocus() && (nativeSel = this.getNative())) {
  6916. nativeRange = browser.ie9below
  6917. ? nativeSel.createRange()
  6918. : nativeSel.getRangeAt(0)
  6919. return browser.ie9below ? nativeRange.text : nativeRange.toString()
  6920. }
  6921. return ''
  6922. },
  6923. /**
  6924. * 清除选区
  6925. * @method clearRange
  6926. * @example
  6927. * ```javascript
  6928. * editor.selection.clearRange();
  6929. * ```
  6930. */
  6931. clearRange: function () {
  6932. this.getNative()[browser.ie9below ? 'empty' : 'removeAllRanges']()
  6933. },
  6934. }
  6935. })()
  6936. // core/Editor.js
  6937. /**
  6938. * 编辑器主类,包含编辑器提供的大部分公用接口
  6939. * @file
  6940. * @module UE
  6941. * @class Editor
  6942. * @since 1.2.6.1
  6943. */
  6944. /**
  6945. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  6946. * @unfile
  6947. * @module UE
  6948. */
  6949. /**
  6950. * UEditor的核心类,为用户提供与编辑器交互的接口。
  6951. * @unfile
  6952. * @module UE
  6953. * @class Editor
  6954. */
  6955. ;(function () {
  6956. var uid = 0,
  6957. _selectionChangeTimer
  6958. /**
  6959. * 获取编辑器的html内容,赋值到编辑器所在表单的textarea文本域里面
  6960. * @private
  6961. * @method setValue
  6962. * @param { UE.Editor } editor 编辑器事例
  6963. */
  6964. function setValue(form, editor) {
  6965. var textarea
  6966. if (editor.textarea) {
  6967. if (utils.isString(editor.textarea)) {
  6968. for (
  6969. var i = 0,
  6970. ti,
  6971. tis = domUtils.getElementsByTagName(form, 'textarea');
  6972. (ti = tis[i++]);
  6973. ) {
  6974. if (ti.id == 'ueditor_textarea_' + editor.options.textarea) {
  6975. textarea = ti
  6976. break
  6977. }
  6978. }
  6979. } else {
  6980. textarea = editor.textarea
  6981. }
  6982. }
  6983. if (!textarea) {
  6984. form.appendChild(
  6985. (textarea = domUtils.createElement(document, 'textarea', {
  6986. name: editor.options.textarea,
  6987. id: 'ueditor_textarea_' + editor.options.textarea,
  6988. style: 'display:none',
  6989. }))
  6990. )
  6991. //不要产生多个textarea
  6992. editor.textarea = textarea
  6993. }
  6994. !textarea.getAttribute('name') &&
  6995. textarea.setAttribute('name', editor.options.textarea)
  6996. textarea.value = editor.hasContents()
  6997. ? editor.options.allHtmlEnabled
  6998. ? editor.getAllHtml()
  6999. : editor.getContent(null, null, true)
  7000. : ''
  7001. }
  7002. function loadPlugins(me) {
  7003. //初始化插件
  7004. for (var pi in UE.plugins) {
  7005. UE.plugins[pi].call(me)
  7006. }
  7007. }
  7008. function checkCurLang(I18N) {
  7009. for (var lang in I18N) {
  7010. return lang
  7011. }
  7012. }
  7013. function langReadied(me) {
  7014. me.langIsReady = true
  7015. me.fireEvent('langReady')
  7016. }
  7017. /**
  7018. * 编辑器准备就绪后会触发该事件
  7019. * @module UE
  7020. * @class Editor
  7021. * @event ready
  7022. * @remind render方法执行完成之后,会触发该事件
  7023. * @remind
  7024. * @example
  7025. * ```javascript
  7026. * editor.addListener( 'ready', function( editor ) {
  7027. * editor.execCommand( 'focus' ); //编辑器家在完成后,让编辑器拿到焦点
  7028. * } );
  7029. * ```
  7030. */
  7031. /**
  7032. * 执行destroy方法,会触发该事件
  7033. * @module UE
  7034. * @class Editor
  7035. * @event destroy
  7036. * @see UE.Editor:destroy()
  7037. */
  7038. /**
  7039. * 执行reset方法,会触发该事件
  7040. * @module UE
  7041. * @class Editor
  7042. * @event reset
  7043. * @see UE.Editor:reset()
  7044. */
  7045. /**
  7046. * 执行focus方法,会触发该事件
  7047. * @module UE
  7048. * @class Editor
  7049. * @event focus
  7050. * @see UE.Editor:focus(Boolean)
  7051. */
  7052. /**
  7053. * 语言加载完成会触发该事件
  7054. * @module UE
  7055. * @class Editor
  7056. * @event langReady
  7057. */
  7058. /**
  7059. * 运行命令之后会触发该命令
  7060. * @module UE
  7061. * @class Editor
  7062. * @event beforeExecCommand
  7063. */
  7064. /**
  7065. * 运行命令之后会触发该命令
  7066. * @module UE
  7067. * @class Editor
  7068. * @event afterExecCommand
  7069. */
  7070. /**
  7071. * 运行命令之前会触发该命令
  7072. * @module UE
  7073. * @class Editor
  7074. * @event firstBeforeExecCommand
  7075. */
  7076. /**
  7077. * 在getContent方法执行之前会触发该事件
  7078. * @module UE
  7079. * @class Editor
  7080. * @event beforeGetContent
  7081. * @see UE.Editor:getContent()
  7082. */
  7083. /**
  7084. * 在getContent方法执行之后会触发该事件
  7085. * @module UE
  7086. * @class Editor
  7087. * @event afterGetContent
  7088. * @see UE.Editor:getContent()
  7089. */
  7090. /**
  7091. * 在getAllHtml方法执行时会触发该事件
  7092. * @module UE
  7093. * @class Editor
  7094. * @event getAllHtml
  7095. * @see UE.Editor:getAllHtml()
  7096. */
  7097. /**
  7098. * 在setContent方法执行之前会触发该事件
  7099. * @module UE
  7100. * @class Editor
  7101. * @event beforeSetContent
  7102. * @see UE.Editor:setContent(String)
  7103. */
  7104. /**
  7105. * 在setContent方法执行之后会触发该事件
  7106. * @module UE
  7107. * @class Editor
  7108. * @event afterSetContent
  7109. * @see UE.Editor:setContent(String)
  7110. */
  7111. /**
  7112. * 每当编辑器内部选区发生改变时,将触发该事件
  7113. * @event selectionchange
  7114. * @warning 该事件的触发非常频繁,不建议在该事件的处理过程中做重量级的处理
  7115. * @example
  7116. * ```javascript
  7117. * editor.addListener( 'selectionchange', function( editor ) {
  7118. * console.log('选区发生改变');
  7119. * }
  7120. */
  7121. /**
  7122. * 在所有selectionchange的监听函数执行之前,会触发该事件
  7123. * @module UE
  7124. * @class Editor
  7125. * @event beforeSelectionChange
  7126. * @see UE.Editor:selectionchange
  7127. */
  7128. /**
  7129. * 在所有selectionchange的监听函数执行完之后,会触发该事件
  7130. * @module UE
  7131. * @class Editor
  7132. * @event afterSelectionChange
  7133. * @see UE.Editor:selectionchange
  7134. */
  7135. /**
  7136. * 编辑器内容发生改变时会触发该事件
  7137. * @module UE
  7138. * @class Editor
  7139. * @event contentChange
  7140. */
  7141. /**
  7142. * 以默认参数构建一个编辑器实例
  7143. * @constructor
  7144. * @remind 通过 改构造方法实例化的编辑器,不带ui层.需要render到一个容器,编辑器实例才能正常渲染到页面
  7145. * @example
  7146. * ```javascript
  7147. * var editor = new UE.Editor();
  7148. * editor.execCommand('blod');
  7149. * ```
  7150. * @see UE.Config
  7151. */
  7152. /**
  7153. * 以给定的参数集合创建一个编辑器实例,对于未指定的参数,将应用默认参数。
  7154. * @constructor
  7155. * @remind 通过 改构造方法实例化的编辑器,不带ui层.需要render到一个容器,编辑器实例才能正常渲染到页面
  7156. * @param { Object } setting 创建编辑器的参数
  7157. * @example
  7158. * ```javascript
  7159. * var editor = new UE.Editor();
  7160. * editor.execCommand('blod');
  7161. * ```
  7162. * @see UE.Config
  7163. */
  7164. var Editor = (UE.Editor = function (options) {
  7165. var me = this
  7166. me.uid = uid++
  7167. EventBase.call(me)
  7168. me.commands = {}
  7169. me.options = utils.extend(
  7170. utils.clone(options || {}),
  7171. UEDITOR_CONFIG,
  7172. true
  7173. )
  7174. me.shortcutkeys = {}
  7175. me.inputRules = []
  7176. me.outputRules = []
  7177. //设置默认的常用属性
  7178. me.setOpt(Editor.defaultOptions(me))
  7179. /* 尝试异步加载后台配置 */
  7180. me.loadServerConfig()
  7181. if (!utils.isEmptyObject(UE.I18N)) {
  7182. //修改默认的语言类型
  7183. me.options.lang = checkCurLang(UE.I18N)
  7184. UE.plugin.load(me)
  7185. langReadied(me)
  7186. } else {
  7187. utils.loadFile(
  7188. document,
  7189. {
  7190. src:
  7191. me.options.langPath +
  7192. me.options.lang +
  7193. '/' +
  7194. me.options.lang +
  7195. '.js',
  7196. tag: 'script',
  7197. type: 'text/javascript',
  7198. defer: 'defer',
  7199. },
  7200. function () {
  7201. UE.plugin.load(me)
  7202. langReadied(me)
  7203. }
  7204. )
  7205. }
  7206. UE.instants['ueditorInstant' + me.uid] = me
  7207. })
  7208. Editor.prototype = {
  7209. registerCommand: function (name, obj) {
  7210. this.commands[name] = obj
  7211. },
  7212. /**
  7213. * 编辑器对外提供的监听ready事件的接口, 通过调用该方法,达到的效果与监听ready事件是一致的
  7214. * @method ready
  7215. * @param { Function } fn 编辑器ready之后所执行的回调, 如果在注册事件之前编辑器已经ready,将会
  7216. * 立即触发该回调。
  7217. * @remind 需要等待编辑器加载完成后才能执行的代码,可以使用该方法传入
  7218. * @example
  7219. * ```javascript
  7220. * editor.ready( function( editor ) {
  7221. * editor.setContent('初始化完毕');
  7222. * } );
  7223. * ```
  7224. * @see UE.Editor.event:ready
  7225. */
  7226. ready: function (fn) {
  7227. var me = this
  7228. if (fn) {
  7229. me.isReady ? fn.apply(me) : me.addListener('ready', fn)
  7230. }
  7231. },
  7232. /**
  7233. * 该方法是提供给插件里面使用,设置配置项默认值
  7234. * @method setOpt
  7235. * @warning 三处设置配置项的优先级: 实例化时传入参数 > setOpt()设置 > config文件里设置
  7236. * @warning 该方法仅供编辑器插件内部和编辑器初始化时调用,其他地方不能调用。
  7237. * @param { String } key 编辑器的可接受的选项名称
  7238. * @param { * } val 该选项可接受的值
  7239. * @example
  7240. * ```javascript
  7241. * editor.setOpt( 'initContent', '欢迎使用编辑器' );
  7242. * ```
  7243. */
  7244. /**
  7245. * 该方法是提供给插件里面使用,以{key:value}集合的方式设置插件内用到的配置项默认值
  7246. * @method setOpt
  7247. * @warning 三处设置配置项的优先级: 实例化时传入参数 > setOpt()设置 > config文件里设置
  7248. * @warning 该方法仅供编辑器插件内部和编辑器初始化时调用,其他地方不能调用。
  7249. * @param { Object } options 将要设置的选项的键值对对象
  7250. * @example
  7251. * ```javascript
  7252. * editor.setOpt( {
  7253. * 'initContent': '欢迎使用编辑器'
  7254. * } );
  7255. * ```
  7256. */
  7257. setOpt: function (key, val) {
  7258. var obj = {}
  7259. if (utils.isString(key)) {
  7260. obj[key] = val
  7261. } else {
  7262. obj = key
  7263. }
  7264. utils.extend(this.options, obj, true)
  7265. },
  7266. getOpt: function (key) {
  7267. return this.options[key]
  7268. },
  7269. /**
  7270. * 销毁编辑器实例,使用textarea代替
  7271. * @method destroy
  7272. * @example
  7273. * ```javascript
  7274. * editor.destroy();
  7275. * ```
  7276. */
  7277. destroy: function () {
  7278. var me = this
  7279. me.fireEvent('destroy')
  7280. var container = me.container.parentNode
  7281. var textarea = me.textarea
  7282. if (!textarea) {
  7283. textarea = document.createElement('textarea')
  7284. container.parentNode.insertBefore(textarea, container)
  7285. } else {
  7286. textarea.style.display = ''
  7287. }
  7288. textarea.style.width = me.iframe.offsetWidth + 'px'
  7289. textarea.style.height = me.iframe.offsetHeight + 'px'
  7290. textarea.value = me.getContent()
  7291. textarea.id = me.key
  7292. container.innerHTML = ''
  7293. domUtils.remove(container)
  7294. var key = me.key
  7295. //trace:2004
  7296. for (var p in me) {
  7297. if (me.hasOwnProperty(p)) {
  7298. delete this[p]
  7299. }
  7300. }
  7301. UE.delEditor(key)
  7302. },
  7303. /**
  7304. * 渲染编辑器的DOM到指定容器
  7305. * @method render
  7306. * @param { String } containerId 指定一个容器ID
  7307. * @remind 执行该方法,会触发ready事件
  7308. * @warning 必须且只能调用一次
  7309. */
  7310. /**
  7311. * 渲染编辑器的DOM到指定容器
  7312. * @method render
  7313. * @param { Element } containerDom 直接指定容器对象
  7314. * @remind 执行该方法,会触发ready事件
  7315. * @warning 必须且只能调用一次
  7316. */
  7317. render: function (container) {
  7318. var me = this,
  7319. options = me.options,
  7320. getStyleValue = function (attr) {
  7321. return parseInt(domUtils.getComputedStyle(container, attr))
  7322. }
  7323. if (utils.isString(container)) {
  7324. container = document.getElementById(container)
  7325. }
  7326. if (container) {
  7327. if (options.initialFrameWidth) {
  7328. options.minFrameWidth = options.initialFrameWidth
  7329. } else {
  7330. options.minFrameWidth = options.initialFrameWidth =
  7331. container.offsetWidth
  7332. }
  7333. if (options.initialFrameHeight) {
  7334. options.minFrameHeight = options.initialFrameHeight
  7335. } else {
  7336. options.initialFrameHeight = options.minFrameHeight =
  7337. container.offsetHeight
  7338. }
  7339. container.style.width = /%$/.test(options.initialFrameWidth)
  7340. ? '100%'
  7341. : options.initialFrameWidth -
  7342. getStyleValue('padding-left') -
  7343. getStyleValue('padding-right') +
  7344. 'px'
  7345. container.style.height = /%$/.test(options.initialFrameHeight)
  7346. ? '100%'
  7347. : options.initialFrameHeight -
  7348. getStyleValue('padding-top') -
  7349. getStyleValue('padding-bottom') +
  7350. 'px'
  7351. container.style.zIndex = options.zIndex
  7352. var html =
  7353. (ie && browser.version < 9 ? '' : '<!DOCTYPE html>') +
  7354. "<html xmlns='http://www.w3.org/1999/xhtml' class='view' ><head>" +
  7355. "<style type='text/css'>" +
  7356. //设置四周的留边
  7357. '.view{padding:0;word-wrap:break-word;cursor:text;height:90%;}\n' +
  7358. //设置默认字体和字号
  7359. //font-family不能呢随便改,在safari下fillchar会有解析问题
  7360. 'body{margin:8px;font-family:sans-serif;font-size:16px;}' +
  7361. //设置段落间距
  7362. 'p{margin:5px 0;}</style>' +
  7363. (options.iframeCssUrl
  7364. ? "<link rel='stylesheet' type='text/css' href='" +
  7365. utils.unhtml(options.iframeCssUrl) +
  7366. "'/>"
  7367. : '') +
  7368. (options.initialStyle
  7369. ? '<style>' + options.initialStyle + '</style>'
  7370. : '') +
  7371. "</head><body class='view' ></body>" +
  7372. "<script type='text/javascript' " +
  7373. (ie ? "defer='defer'" : '') +
  7374. " id='_initialScript'>" +
  7375. "setTimeout(function(){editor = window.parent.UE.instants['ueditorInstant" +
  7376. me.uid +
  7377. "'];editor._setup(document);},0);" +
  7378. "var _tmpScript = document.getElementById('_initialScript');_tmpScript.parentNode.removeChild(_tmpScript);</script></html>"
  7379. container.appendChild(
  7380. domUtils.createElement(document, 'iframe', {
  7381. id: 'ueditor_' + me.uid,
  7382. width: '100%',
  7383. height: '100%',
  7384. frameborder: '0',
  7385. //先注释掉了,加的原因忘记了,但开启会直接导致全屏模式下内容多时不会出现滚动条
  7386. // scrolling :'no',
  7387. src:
  7388. 'javascript:void(function(){document.open();' +
  7389. (options.customDomain && document.domain != location.hostname
  7390. ? 'document.domain="' + document.domain + '";'
  7391. : '') +
  7392. 'document.write("' +
  7393. html +
  7394. '");document.close();}())',
  7395. })
  7396. )
  7397. container.style.overflow = 'hidden'
  7398. //解决如果是给定的百分比,会导致高度算不对的问题
  7399. setTimeout(function () {
  7400. if (/%$/.test(options.initialFrameWidth)) {
  7401. options.minFrameWidth = options.initialFrameWidth =
  7402. container.offsetWidth
  7403. //如果这里给定宽度,会导致ie在拖动窗口大小时,编辑区域不随着变化
  7404. // container.style.width = options.initialFrameWidth + 'px';
  7405. }
  7406. if (/%$/.test(options.initialFrameHeight)) {
  7407. options.minFrameHeight = options.initialFrameHeight =
  7408. container.offsetHeight
  7409. container.style.height = options.initialFrameHeight + 'px'
  7410. }
  7411. })
  7412. }
  7413. },
  7414. /**
  7415. * 编辑器初始化
  7416. * @method _setup
  7417. * @private
  7418. * @param { Element } doc 编辑器Iframe中的文档对象
  7419. */
  7420. _setup: function (doc) {
  7421. var me = this,
  7422. options = me.options
  7423. if (ie) {
  7424. doc.body.disabled = true
  7425. doc.body.contentEditable = true
  7426. doc.body.disabled = false
  7427. } else {
  7428. doc.body.contentEditable = true
  7429. }
  7430. doc.body.spellcheck = false
  7431. me.document = doc
  7432. me.window = doc.defaultView || doc.parentWindow
  7433. me.iframe = me.window.frameElement
  7434. me.body = doc.body
  7435. me.selection = new dom.Selection(doc)
  7436. //gecko初始化就能得到range,无法判断isFocus了
  7437. var geckoSel
  7438. if (browser.gecko && (geckoSel = this.selection.getNative())) {
  7439. geckoSel.removeAllRanges()
  7440. }
  7441. this._initEvents()
  7442. //为form提交提供一个隐藏的textarea
  7443. for (
  7444. var form = this.iframe.parentNode;
  7445. !domUtils.isBody(form);
  7446. form = form.parentNode
  7447. ) {
  7448. if (form.tagName == 'FORM') {
  7449. me.form = form
  7450. if (me.options.autoSyncData) {
  7451. domUtils.on(me.window, 'blur', function () {
  7452. setValue(form, me)
  7453. })
  7454. } else {
  7455. domUtils.on(form, 'submit', function () {
  7456. setValue(this, me)
  7457. })
  7458. }
  7459. break
  7460. }
  7461. }
  7462. if (options.initialContent) {
  7463. if (options.autoClearinitialContent) {
  7464. var oldExecCommand = me.execCommand
  7465. me.execCommand = function () {
  7466. me.fireEvent('firstBeforeExecCommand')
  7467. return oldExecCommand.apply(me, arguments)
  7468. }
  7469. this._setDefaultContent(options.initialContent)
  7470. } else this.setContent(options.initialContent, false, true)
  7471. }
  7472. //编辑器不能为空内容
  7473. if (domUtils.isEmptyNode(me.body)) {
  7474. me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>'
  7475. }
  7476. //如果要求focus, 就把光标定位到内容开始
  7477. if (options.focus) {
  7478. setTimeout(function () {
  7479. me.focus(me.options.focusInEnd)
  7480. //如果自动清除开着,就不需要做selectionchange;
  7481. !me.options.autoClearinitialContent && me._selectionChange()
  7482. }, 0)
  7483. }
  7484. if (!me.container) {
  7485. me.container = this.iframe.parentNode
  7486. }
  7487. if (options.fullscreen && me.ui) {
  7488. me.ui.setFullScreen(true)
  7489. }
  7490. try {
  7491. me.document.execCommand('2D-position', false, false)
  7492. } catch (e) {}
  7493. try {
  7494. me.document.execCommand('enableInlineTableEditing', false, false)
  7495. } catch (e) {}
  7496. try {
  7497. me.document.execCommand('enableObjectResizing', false, false)
  7498. } catch (e) {}
  7499. //挂接快捷键
  7500. me._bindshortcutKeys()
  7501. me.isReady = 1
  7502. me.fireEvent('ready')
  7503. options.onready && options.onready.call(me)
  7504. if (!browser.ie9below) {
  7505. domUtils.on(me.window, ['blur', 'focus'], function (e) {
  7506. //chrome下会出现alt+tab切换时,导致选区位置不对
  7507. if (e.type == 'blur') {
  7508. me._bakRange = me.selection.getRange()
  7509. try {
  7510. me._bakNativeRange = me.selection.getNative().getRangeAt(0)
  7511. me.selection.getNative().removeAllRanges()
  7512. } catch (e) {
  7513. me._bakNativeRange = null
  7514. }
  7515. } else {
  7516. try {
  7517. me._bakRange && me._bakRange.select()
  7518. } catch (e) {}
  7519. }
  7520. })
  7521. }
  7522. //trace:1518 ff3.6body不够寛,会导致点击空白处无法获得焦点
  7523. if (browser.gecko && browser.version <= 10902) {
  7524. //修复ff3.6初始化进来,不能点击获得焦点
  7525. me.body.contentEditable = false
  7526. setTimeout(function () {
  7527. me.body.contentEditable = true
  7528. }, 100)
  7529. setInterval(function () {
  7530. me.body.style.height = me.iframe.offsetHeight - 20 + 'px'
  7531. }, 100)
  7532. }
  7533. !options.isShow && me.setHide()
  7534. options.readonly && me.setDisabled()
  7535. },
  7536. /**
  7537. * 同步数据到编辑器所在的form
  7538. * 从编辑器的容器节点向上查找form元素,若找到,就同步编辑内容到找到的form里,为提交数据做准备,主要用于是手动提交的情况
  7539. * 后台取得数据的键值,使用你容器上的name属性,如果没有就使用参数里的textarea项
  7540. * @method sync
  7541. * @example
  7542. * ```javascript
  7543. * editor.sync();
  7544. * form.sumbit(); //form变量已经指向了form元素
  7545. * ```
  7546. */
  7547. /**
  7548. * 根据传入的formId,在页面上查找要同步数据的表单,若找到,就同步编辑内容到找到的form里,为提交数据做准备
  7549. * 后台取得数据的键值,该键值默认使用给定的编辑器容器的name属性,如果没有name属性则使用参数项里给定的“textarea”项
  7550. * @method sync
  7551. * @param { String } formID 指定一个要同步数据的form的id,编辑器的数据会同步到你指定form下
  7552. */
  7553. sync: function (formId) {
  7554. var me = this,
  7555. form = formId
  7556. ? document.getElementById(formId)
  7557. : domUtils.findParent(
  7558. me.iframe.parentNode,
  7559. function (node) {
  7560. return node.tagName == 'FORM'
  7561. },
  7562. true
  7563. )
  7564. form && setValue(form, me)
  7565. },
  7566. /**
  7567. * 设置编辑器高度
  7568. * @method setHeight
  7569. * @remind 当配置项autoHeightEnabled为真时,该方法无效
  7570. * @param { Number } number 设置的高度值,纯数值,不带单位
  7571. * @example
  7572. * ```javascript
  7573. * editor.setHeight(number);
  7574. * ```
  7575. */
  7576. setHeight: function (height, notSetHeight) {
  7577. if (height !== parseInt(this.iframe.parentNode.style.height)) {
  7578. this.iframe.parentNode.style.height = height + 'px'
  7579. }
  7580. !notSetHeight &&
  7581. (this.options.minFrameHeight = this.options.initialFrameHeight =
  7582. height)
  7583. this.body.style.height = height + 'px'
  7584. !notSetHeight && this.trigger('setHeight')
  7585. },
  7586. /**
  7587. * 为编辑器的编辑命令提供快捷键
  7588. * 这个接口是为插件扩展提供的接口,主要是为新添加的插件,如果需要添加快捷键,所提供的接口
  7589. * @method addshortcutkey
  7590. * @param { Object } keyset 命令名和快捷键键值对对象,多个按钮的快捷键用“+”分隔
  7591. * @example
  7592. * ```javascript
  7593. * editor.addshortcutkey({
  7594. * "Bold" : "ctrl+66",//^B
  7595. * "Italic" : "ctrl+73", //^I
  7596. * });
  7597. * ```
  7598. */
  7599. /**
  7600. * 这个接口是为插件扩展提供的接口,主要是为新添加的插件,如果需要添加快捷键,所提供的接口
  7601. * @method addshortcutkey
  7602. * @param { String } cmd 触发快捷键时,响应的命令
  7603. * @param { String } keys 快捷键的字符串,多个按钮用“+”分隔
  7604. * @example
  7605. * ```javascript
  7606. * editor.addshortcutkey("Underline", "ctrl+85"); //^U
  7607. * ```
  7608. */
  7609. addshortcutkey: function (cmd, keys) {
  7610. var obj = {}
  7611. if (keys) {
  7612. obj[cmd] = keys
  7613. } else {
  7614. obj = cmd
  7615. }
  7616. utils.extend(this.shortcutkeys, obj)
  7617. },
  7618. /**
  7619. * 对编辑器设置keydown事件监听,绑定快捷键和命令,当快捷键组合触发成功,会响应对应的命令
  7620. * @method _bindshortcutKeys
  7621. * @private
  7622. */
  7623. _bindshortcutKeys: function () {
  7624. var me = this,
  7625. shortcutkeys = this.shortcutkeys
  7626. me.addListener('keydown', function (type, e) {
  7627. var keyCode = e.keyCode || e.which
  7628. for (var i in shortcutkeys) {
  7629. var tmp = shortcutkeys[i].split(',')
  7630. for (var t = 0, ti; (ti = tmp[t++]); ) {
  7631. ti = ti.split(':')
  7632. var key = ti[0],
  7633. param = ti[1]
  7634. if (
  7635. /^(ctrl)(\+shift)?\+(\d+)$/.test(key.toLowerCase()) ||
  7636. /^(\d+)$/.test(key)
  7637. ) {
  7638. if (
  7639. ((RegExp.$1 == 'ctrl' ? e.ctrlKey || e.metaKey : 0) &&
  7640. (RegExp.$2 != '' ? e[RegExp.$2.slice(1) + 'Key'] : 1) &&
  7641. keyCode == RegExp.$3) ||
  7642. keyCode == RegExp.$1
  7643. ) {
  7644. if (me.queryCommandState(i, param) != -1)
  7645. me.execCommand(i, param)
  7646. domUtils.preventDefault(e)
  7647. }
  7648. }
  7649. }
  7650. }
  7651. })
  7652. },
  7653. /**
  7654. * 获取编辑器的内容
  7655. * @method getContent
  7656. * @warning 该方法获取到的是经过编辑器内置的过滤规则进行过滤后得到的内容
  7657. * @return { String } 编辑器的内容字符串, 如果编辑器的内容为空,或者是空的标签内容(如:”&lt;p&gt;&lt;br/&gt;&lt;/p&gt;“), 则返回空字符串
  7658. * @example
  7659. * ```javascript
  7660. * //编辑器html内容:<p>1<strong>2<em>34</em>5</strong>6</p>
  7661. * var content = editor.getContent(); //返回值:<p>1<strong>2<em>34</em>5</strong>6</p>
  7662. * ```
  7663. */
  7664. /**
  7665. * 获取编辑器的内容。 可以通过参数定义编辑器内置的判空规则
  7666. * @method getContent
  7667. * @param { Function } fn 自定的判空规则, 要求该方法返回一个boolean类型的值,
  7668. * 代表当前编辑器的内容是否空,
  7669. * 如果返回true, 则该方法将直接返回空字符串;如果返回false,则编辑器将返回
  7670. * 经过内置过滤规则处理后的内容。
  7671. * @remind 该方法在处理包含有初始化内容的时候能起到很好的作用。
  7672. * @warning 该方法获取到的是经过编辑器内置的过滤规则进行过滤后得到的内容
  7673. * @return { String } 编辑器的内容字符串
  7674. * @example
  7675. * ```javascript
  7676. * // editor 是一个编辑器的实例
  7677. * var content = editor.getContent( function ( editor ) {
  7678. * return editor.body.innerHTML === '欢迎使用UEditor'; //返回空字符串
  7679. * } );
  7680. * ```
  7681. */
  7682. getContent: function (cmd, fn, notSetCursor, ignoreBlank, formatter) {
  7683. var me = this
  7684. if (cmd && utils.isFunction(cmd)) {
  7685. fn = cmd
  7686. cmd = ''
  7687. }
  7688. if (fn ? !fn() : !this.hasContents()) {
  7689. return ''
  7690. }
  7691. me.fireEvent('beforegetcontent')
  7692. var root = UE.htmlparser(me.body.innerHTML, ignoreBlank)
  7693. me.filterOutputRule(root)
  7694. me.fireEvent('aftergetcontent', cmd, root)
  7695. return root.toHtml(formatter)
  7696. },
  7697. /**
  7698. * 取得完整的html代码,可以直接显示成完整的html文档
  7699. * @method getAllHtml
  7700. * @return { String } 编辑器的内容html文档字符串
  7701. * @eaxmple
  7702. * ```javascript
  7703. * editor.getAllHtml(); //返回格式大致是: <html><head>...</head><body>...</body></html>
  7704. * ```
  7705. */
  7706. getAllHtml: function () {
  7707. var me = this,
  7708. headHtml = [],
  7709. html = ''
  7710. me.fireEvent('getAllHtml', headHtml)
  7711. if (browser.ie && browser.version > 8) {
  7712. var headHtmlForIE9 = ''
  7713. utils.each(me.document.styleSheets, function (si) {
  7714. headHtmlForIE9 += si.href
  7715. ? '<link rel="stylesheet" type="text/css" href="' +
  7716. si.href +
  7717. '" />'
  7718. : '<style>' + si.cssText + '</style>'
  7719. })
  7720. utils.each(me.document.getElementsByTagName('script'), function (si) {
  7721. headHtmlForIE9 += si.outerHTML
  7722. })
  7723. }
  7724. return (
  7725. '<html><head>' +
  7726. (me.options.charset
  7727. ? '<meta http-equiv="Content-Type" content="text/html; charset=' +
  7728. me.options.charset +
  7729. '"/>'
  7730. : '') +
  7731. (headHtmlForIE9 ||
  7732. me.document.getElementsByTagName('head')[0].innerHTML) +
  7733. headHtml.join('\n') +
  7734. '</head>' +
  7735. '<body ' +
  7736. (ie && browser.version < 9 ? 'class="view"' : '') +
  7737. '>' +
  7738. me.getContent(null, null, true) +
  7739. '</body></html>'
  7740. )
  7741. },
  7742. /**
  7743. * 得到编辑器的纯文本内容,但会保留段落格式
  7744. * @method getPlainTxt
  7745. * @return { String } 编辑器带段落格式的纯文本内容字符串
  7746. * @example
  7747. * ```javascript
  7748. * //编辑器html内容:<p><strong>1</strong></p><p><strong>2</strong></p>
  7749. * console.log(editor.getPlainTxt()); //输出:"1\n2\n
  7750. * ```
  7751. */
  7752. getPlainTxt: function () {
  7753. var reg = new RegExp(domUtils.fillChar, 'g'),
  7754. html = this.body.innerHTML.replace(/[\n\r]/g, '') //ie要先去了\n在处理
  7755. html = html
  7756. .replace(/<(p|div)[^>]*>(<br\/?>|&nbsp;)<\/\1>/gi, '\n')
  7757. .replace(/<br\/?>/gi, '\n')
  7758. .replace(/<[^>/]+>/g, '')
  7759. .replace(/(\n)?<\/([^>]+)>/g, function (a, b, c) {
  7760. return dtd.$block[c] ? '\n' : b ? b : ''
  7761. })
  7762. //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
  7763. return html
  7764. .replace(reg, '')
  7765. .replace(/\u00a0/g, ' ')
  7766. .replace(/&nbsp;/g, ' ')
  7767. },
  7768. /**
  7769. * 获取编辑器中的纯文本内容,没有段落格式
  7770. * @method getContentTxt
  7771. * @return { String } 编辑器不带段落格式的纯文本内容字符串
  7772. * @example
  7773. * ```javascript
  7774. * //编辑器html内容:<p><strong>1</strong></p><p><strong>2</strong></p>
  7775. * console.log(editor.getPlainTxt()); //输出:"12
  7776. * ```
  7777. */
  7778. getContentTxt: function () {
  7779. var reg = new RegExp(domUtils.fillChar, 'g')
  7780. //取出来的空格会有c2a0会变成乱码,处理这种情况\u00a0
  7781. return this.body[browser.ie ? 'innerText' : 'textContent']
  7782. .replace(reg, '')
  7783. .replace(/\u00a0/g, ' ')
  7784. },
  7785. /**
  7786. * 设置编辑器的内容,可修改编辑器当前的html内容
  7787. * @method setContent
  7788. * @warning 通过该方法插入的内容,是经过编辑器内置的过滤规则进行过滤后得到的内容
  7789. * @warning 该方法会触发selectionchange事件
  7790. * @param { String } html 要插入的html内容
  7791. * @example
  7792. * ```javascript
  7793. * editor.getContent('<p>test</p>');
  7794. * ```
  7795. */
  7796. /**
  7797. * 设置编辑器的内容,可修改编辑器当前的html内容
  7798. * @method setContent
  7799. * @warning 通过该方法插入的内容,是经过编辑器内置的过滤规则进行过滤后得到的内容
  7800. * @warning 该方法会触发selectionchange事件
  7801. * @param { String } html 要插入的html内容
  7802. * @param { Boolean } isAppendTo 若传入true,不清空原来的内容,在最后插入内容,否则,清空内容再插入
  7803. * @example
  7804. * ```javascript
  7805. * //假设设置前的编辑器内容是 <p>old text</p>
  7806. * editor.setContent('<p>new text</p>', true); //插入的结果是<p>old text</p><p>new text</p>
  7807. * ```
  7808. */
  7809. setContent: function (html, isAppendTo, notFireSelectionchange) {
  7810. var me = this
  7811. me.fireEvent('beforesetcontent', html)
  7812. var root = UE.htmlparser(html)
  7813. me.filterInputRule(root)
  7814. html = root.toHtml()
  7815. me.body.innerHTML = (isAppendTo ? me.body.innerHTML : '') + html
  7816. function isCdataDiv(node) {
  7817. return node.tagName == 'DIV' && node.getAttribute('cdata_tag')
  7818. }
  7819. //给文本或者inline节点套p标签
  7820. if (me.options.enterTag == 'p') {
  7821. var child = this.body.firstChild,
  7822. tmpNode
  7823. if (
  7824. !child ||
  7825. (child.nodeType == 1 &&
  7826. (dtd.$cdata[child.tagName] ||
  7827. isCdataDiv(child) ||
  7828. domUtils.isCustomeNode(child)) &&
  7829. child === this.body.lastChild)
  7830. ) {
  7831. this.body.innerHTML =
  7832. '<p>' +
  7833. (browser.ie ? '&nbsp;' : '<br/>') +
  7834. '</p>' +
  7835. this.body.innerHTML
  7836. } else {
  7837. var p = me.document.createElement('p')
  7838. while (child) {
  7839. while (
  7840. child &&
  7841. (child.nodeType == 3 ||
  7842. (child.nodeType == 1 &&
  7843. dtd.p[child.tagName] &&
  7844. !dtd.$cdata[child.tagName]))
  7845. ) {
  7846. tmpNode = child.nextSibling
  7847. p.appendChild(child)
  7848. child = tmpNode
  7849. }
  7850. if (p.firstChild) {
  7851. if (!child) {
  7852. me.body.appendChild(p)
  7853. break
  7854. } else {
  7855. child.parentNode.insertBefore(p, child)
  7856. p = me.document.createElement('p')
  7857. }
  7858. }
  7859. child = child.nextSibling
  7860. }
  7861. }
  7862. }
  7863. me.fireEvent('aftersetcontent')
  7864. me.fireEvent('contentchange')
  7865. !notFireSelectionchange && me._selectionChange()
  7866. //清除保存的选区
  7867. me._bakRange = me._bakIERange = me._bakNativeRange = null
  7868. //trace:1742 setContent后gecko能得到焦点问题
  7869. var geckoSel
  7870. if (browser.gecko && (geckoSel = this.selection.getNative())) {
  7871. geckoSel.removeAllRanges()
  7872. }
  7873. if (me.options.autoSyncData) {
  7874. me.form && setValue(me.form, me)
  7875. }
  7876. },
  7877. /**
  7878. * 让编辑器获得焦点,默认focus到编辑器头部
  7879. * @method focus
  7880. * @example
  7881. * ```javascript
  7882. * editor.focus()
  7883. * ```
  7884. */
  7885. /**
  7886. * 让编辑器获得焦点,toEnd确定focus位置
  7887. * @method focus
  7888. * @param { Boolean } toEnd 默认focus到编辑器头部,toEnd为true时focus到内容尾部
  7889. * @example
  7890. * ```javascript
  7891. * editor.focus(true)
  7892. * ```
  7893. */
  7894. focus: function (toEnd) {
  7895. try {
  7896. var me = this,
  7897. rng = me.selection.getRange()
  7898. if (toEnd) {
  7899. var node = me.body.lastChild
  7900. if (node && node.nodeType == 1 && !dtd.$empty[node.tagName]) {
  7901. if (domUtils.isEmptyBlock(node)) {
  7902. rng.setStartAtFirst(node)
  7903. } else {
  7904. rng.setStartAtLast(node)
  7905. }
  7906. rng.collapse(true)
  7907. }
  7908. rng.setCursor(true)
  7909. } else {
  7910. if (
  7911. !rng.collapsed &&
  7912. domUtils.isBody(rng.startContainer) &&
  7913. rng.startOffset == 0
  7914. ) {
  7915. var node = me.body.firstChild
  7916. if (node && node.nodeType == 1 && !dtd.$empty[node.tagName]) {
  7917. rng.setStartAtFirst(node).collapse(true)
  7918. }
  7919. }
  7920. rng.select(true)
  7921. }
  7922. this.fireEvent('focus selectionchange')
  7923. } catch (e) {}
  7924. },
  7925. isFocus: function () {
  7926. return this.selection.isFocus()
  7927. },
  7928. blur: function () {
  7929. var sel = this.selection.getNative()
  7930. if (sel.empty && browser.ie) {
  7931. var nativeRng = document.body.createTextRange()
  7932. nativeRng.moveToElementText(document.body)
  7933. nativeRng.collapse(true)
  7934. nativeRng.select()
  7935. sel.empty()
  7936. } else {
  7937. sel.removeAllRanges()
  7938. }
  7939. //this.fireEvent('blur selectionchange');
  7940. },
  7941. /**
  7942. * 初始化UE事件及部分事件代理
  7943. * @method _initEvents
  7944. * @private
  7945. */
  7946. _initEvents: function () {
  7947. var me = this,
  7948. doc = me.document,
  7949. win = me.window
  7950. me._proxyDomEvent = utils.bind(me._proxyDomEvent, me)
  7951. domUtils.on(
  7952. doc,
  7953. [
  7954. 'click',
  7955. 'contextmenu',
  7956. 'mousedown',
  7957. 'keydown',
  7958. 'keyup',
  7959. 'keypress',
  7960. 'mouseup',
  7961. 'mouseover',
  7962. 'mouseout',
  7963. 'selectstart',
  7964. ],
  7965. me._proxyDomEvent
  7966. )
  7967. domUtils.on(win, ['focus', 'blur'], me._proxyDomEvent)
  7968. domUtils.on(me.body, 'drop', function (e) {
  7969. //阻止ff下默认的弹出新页面打开图片
  7970. if (browser.gecko && e.stopPropagation) {
  7971. e.stopPropagation()
  7972. }
  7973. me.fireEvent('contentchange')
  7974. })
  7975. domUtils.on(doc, ['mouseup', 'keydown'], function (evt) {
  7976. //特殊键不触发selectionchange
  7977. if (
  7978. evt.type == 'keydown' &&
  7979. (evt.ctrlKey || evt.metaKey || evt.shiftKey || evt.altKey)
  7980. ) {
  7981. return
  7982. }
  7983. if (evt.button == 2) return
  7984. me._selectionChange(250, evt)
  7985. })
  7986. },
  7987. /**
  7988. * 触发事件代理
  7989. * @method _proxyDomEvent
  7990. * @private
  7991. * @return { * } fireEvent的返回值
  7992. * @see UE.EventBase:fireEvent(String)
  7993. */
  7994. _proxyDomEvent: function (evt) {
  7995. if (
  7996. this.fireEvent(
  7997. 'before' + evt.type.replace(/^on/, '').toLowerCase()
  7998. ) === false
  7999. ) {
  8000. return false
  8001. }
  8002. if (this.fireEvent(evt.type.replace(/^on/, ''), evt) === false) {
  8003. return false
  8004. }
  8005. return this.fireEvent(
  8006. 'after' + evt.type.replace(/^on/, '').toLowerCase()
  8007. )
  8008. },
  8009. /**
  8010. * 变化选区
  8011. * @method _selectionChange
  8012. * @private
  8013. */
  8014. _selectionChange: function (delay, evt) {
  8015. var me = this
  8016. //有光标才做selectionchange 为了解决未focus时点击source不能触发更改工具栏状态的问题(source命令notNeedUndo=1)
  8017. // if ( !me.selection.isFocus() ){
  8018. // return;
  8019. // }
  8020. var hackForMouseUp = false
  8021. var mouseX, mouseY
  8022. if (browser.ie && browser.version < 9 && evt && evt.type == 'mouseup') {
  8023. var range = this.selection.getRange()
  8024. if (!range.collapsed) {
  8025. hackForMouseUp = true
  8026. mouseX = evt.clientX
  8027. mouseY = evt.clientY
  8028. }
  8029. }
  8030. clearTimeout(_selectionChangeTimer)
  8031. _selectionChangeTimer = setTimeout(function () {
  8032. if (!me.selection || !me.selection.getNative()) {
  8033. return
  8034. }
  8035. //修复一个IE下的bug: 鼠标点击一段已选择的文本中间时,可能在mouseup后的一段时间内取到的range是在selection的type为None下的错误值.
  8036. //IE下如果用户是拖拽一段已选择文本,则不会触发mouseup事件,所以这里的特殊处理不会对其有影响
  8037. var ieRange
  8038. if (hackForMouseUp && me.selection.getNative().type == 'None') {
  8039. ieRange = me.document.body.createTextRange()
  8040. try {
  8041. ieRange.moveToPoint(mouseX, mouseY)
  8042. } catch (ex) {
  8043. ieRange = null
  8044. }
  8045. }
  8046. var bakGetIERange
  8047. if (ieRange) {
  8048. bakGetIERange = me.selection.getIERange
  8049. me.selection.getIERange = function () {
  8050. return ieRange
  8051. }
  8052. }
  8053. me.selection.cache()
  8054. if (bakGetIERange) {
  8055. me.selection.getIERange = bakGetIERange
  8056. }
  8057. if (me.selection._cachedRange && me.selection._cachedStartElement) {
  8058. me.fireEvent('beforeselectionchange')
  8059. // 第二个参数causeByUi为true代表由用户交互造成的selectionchange.
  8060. me.fireEvent('selectionchange', !!evt)
  8061. me.fireEvent('afterselectionchange')
  8062. me.selection.clear()
  8063. }
  8064. }, delay || 50)
  8065. },
  8066. /**
  8067. * 执行编辑命令
  8068. * @method _callCmdFn
  8069. * @private
  8070. * @param { String } fnName 函数名称
  8071. * @param { * } args 传给命令函数的参数
  8072. * @return { * } 返回命令函数运行的返回值
  8073. */
  8074. _callCmdFn: function (fnName, args) {
  8075. var cmdName = args[0].toLowerCase(),
  8076. cmd,
  8077. cmdFn
  8078. cmd = this.commands[cmdName] || UE.commands[cmdName]
  8079. cmdFn = cmd && cmd[fnName]
  8080. //没有querycommandstate或者没有command的都默认返回0
  8081. if ((!cmd || !cmdFn) && fnName == 'queryCommandState') {
  8082. return 0
  8083. } else if (cmdFn) {
  8084. return cmdFn.apply(this, args)
  8085. }
  8086. },
  8087. /**
  8088. * 执行编辑命令cmdName,完成富文本编辑效果
  8089. * @method execCommand
  8090. * @param { String } cmdName 需要执行的命令
  8091. * @remind 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
  8092. * @return { * } 返回命令函数运行的返回值
  8093. * @example
  8094. * ```javascript
  8095. * editor.execCommand(cmdName);
  8096. * ```
  8097. */
  8098. execCommand: function (cmdName) {
  8099. cmdName = cmdName.toLowerCase()
  8100. var me = this,
  8101. result,
  8102. cmd = me.commands[cmdName] || UE.commands[cmdName]
  8103. if (!cmd || !cmd.execCommand) {
  8104. return null
  8105. }
  8106. if (!cmd.notNeedUndo && !me.__hasEnterExecCommand) {
  8107. me.__hasEnterExecCommand = true
  8108. if (me.queryCommandState.apply(me, arguments) != -1) {
  8109. me.fireEvent('saveScene')
  8110. me.fireEvent.apply(
  8111. me,
  8112. ['beforeexeccommand', cmdName].concat(arguments)
  8113. )
  8114. result = this._callCmdFn('execCommand', arguments)
  8115. //保存场景时,做了内容对比,再看是否进行contentchange触发,这里多触发了一次,去掉
  8116. // (!cmd.ignoreContentChange && !me._ignoreContentChange) && me.fireEvent('contentchange');
  8117. me.fireEvent.apply(
  8118. me,
  8119. ['afterexeccommand', cmdName].concat(arguments)
  8120. )
  8121. me.fireEvent('saveScene')
  8122. }
  8123. me.__hasEnterExecCommand = false
  8124. } else {
  8125. result = this._callCmdFn('execCommand', arguments)
  8126. !me.__hasEnterExecCommand &&
  8127. !cmd.ignoreContentChange &&
  8128. !me._ignoreContentChange &&
  8129. me.fireEvent('contentchange')
  8130. }
  8131. !me.__hasEnterExecCommand &&
  8132. !cmd.ignoreContentChange &&
  8133. !me._ignoreContentChange &&
  8134. me._selectionChange()
  8135. return result
  8136. },
  8137. /**
  8138. * 根据传入的command命令,查选编辑器当前的选区,返回命令的状态
  8139. * @method queryCommandState
  8140. * @param { String } cmdName 需要查询的命令名称
  8141. * @remind 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
  8142. * @return { Number } number 返回放前命令的状态,返回值三种情况:(-1|0|1)
  8143. * @example
  8144. * ```javascript
  8145. * editor.queryCommandState(cmdName) => (-1|0|1)
  8146. * ```
  8147. * @see COMMAND.LIST
  8148. */
  8149. queryCommandState: function (cmdName) {
  8150. return this._callCmdFn('queryCommandState', arguments)
  8151. },
  8152. /**
  8153. * 根据传入的command命令,查选编辑器当前的选区,根据命令返回相关的值
  8154. * @method queryCommandValue
  8155. * @param { String } cmdName 需要查询的命令名称
  8156. * @remind 具体命令的使用请参考<a href="#COMMAND.LIST">命令列表</a>
  8157. * @remind 只有部分插件有此方法
  8158. * @return { * } 返回每个命令特定的当前状态值
  8159. * @grammar editor.queryCommandValue(cmdName) => {*}
  8160. * @see COMMAND.LIST
  8161. */
  8162. queryCommandValue: function (cmdName) {
  8163. return this._callCmdFn('queryCommandValue', arguments)
  8164. },
  8165. /**
  8166. * 检查编辑区域中是否有内容
  8167. * @method hasContents
  8168. * @remind 默认有文本内容,或者有以下节点都不认为是空
  8169. * table,ul,ol,dl,iframe,area,base,col,hr,img,embed,input,link,meta,param
  8170. * @return { Boolean } 检查有内容返回true,否则返回false
  8171. * @example
  8172. * ```javascript
  8173. * editor.hasContents()
  8174. * ```
  8175. */
  8176. /**
  8177. * 检查编辑区域中是否有内容,若包含参数tags中的节点类型,直接返回true
  8178. * @method hasContents
  8179. * @param { Array } tags 传入数组判断时用到的节点类型
  8180. * @return { Boolean } 若文档中包含tags数组里对应的tag,返回true,否则返回false
  8181. * @example
  8182. * ```javascript
  8183. * editor.hasContents(['span']);
  8184. * ```
  8185. */
  8186. hasContents: function (tags) {
  8187. if (tags) {
  8188. for (var i = 0, ci; (ci = tags[i++]); ) {
  8189. if (this.document.getElementsByTagName(ci).length > 0) {
  8190. return true
  8191. }
  8192. }
  8193. }
  8194. if (!domUtils.isEmptyBlock(this.body)) {
  8195. return true
  8196. }
  8197. //随时添加,定义的特殊标签如果存在,不能认为是空
  8198. tags = ['div']
  8199. for (i = 0; (ci = tags[i++]); ) {
  8200. var nodes = domUtils.getElementsByTagName(this.document, ci)
  8201. for (var n = 0, cn; (cn = nodes[n++]); ) {
  8202. if (domUtils.isCustomeNode(cn)) {
  8203. return true
  8204. }
  8205. }
  8206. }
  8207. return false
  8208. },
  8209. /**
  8210. * 重置编辑器,可用来做多个tab使用同一个编辑器实例
  8211. * @method reset
  8212. * @remind 此方法会清空编辑器内容,清空回退列表,会触发reset事件
  8213. * @example
  8214. * ```javascript
  8215. * editor.reset()
  8216. * ```
  8217. */
  8218. reset: function () {
  8219. this.fireEvent('reset')
  8220. },
  8221. /**
  8222. * 设置当前编辑区域可以编辑
  8223. * @method setEnabled
  8224. * @example
  8225. * ```javascript
  8226. * editor.setEnabled()
  8227. * ```
  8228. */
  8229. setEnabled: function () {
  8230. var me = this,
  8231. range
  8232. if (me.body.contentEditable == 'false') {
  8233. me.body.contentEditable = true
  8234. range = me.selection.getRange()
  8235. //有可能内容丢失了
  8236. try {
  8237. range.moveToBookmark(me.lastBk)
  8238. delete me.lastBk
  8239. } catch (e) {
  8240. range.setStartAtFirst(me.body).collapse(true)
  8241. }
  8242. range.select(true)
  8243. if (me.bkqueryCommandState) {
  8244. me.queryCommandState = me.bkqueryCommandState
  8245. delete me.bkqueryCommandState
  8246. }
  8247. if (me.bkqueryCommandValue) {
  8248. me.queryCommandValue = me.bkqueryCommandValue
  8249. delete me.bkqueryCommandValue
  8250. }
  8251. me.fireEvent('selectionchange')
  8252. }
  8253. },
  8254. enable: function () {
  8255. return this.setEnabled()
  8256. },
  8257. /** 设置当前编辑区域不可编辑
  8258. * @method setDisabled
  8259. */
  8260. /** 设置当前编辑区域不可编辑,except中的命令除外
  8261. * @method setDisabled
  8262. * @param { String } except 例外命令的字符串
  8263. * @remind 即使设置了disable,此处配置的例外命令仍然可以执行
  8264. * @example
  8265. * ```javascript
  8266. * editor.setDisabled('bold'); //禁用工具栏中除加粗之外的所有功能
  8267. * ```
  8268. */
  8269. /** 设置当前编辑区域不可编辑,except中的命令除外
  8270. * @method setDisabled
  8271. * @param { Array } except 例外命令的字符串数组,数组中的命令仍然可以执行
  8272. * @remind 即使设置了disable,此处配置的例外命令仍然可以执行
  8273. * @example
  8274. * ```javascript
  8275. * editor.setDisabled(['bold','insertimage']); //禁用工具栏中除加粗和插入图片之外的所有功能
  8276. * ```
  8277. */
  8278. setDisabled: function (except) {
  8279. var me = this
  8280. except = except ? (utils.isArray(except) ? except : [except]) : []
  8281. if (me.body.contentEditable == 'true') {
  8282. if (!me.lastBk) {
  8283. me.lastBk = me.selection.getRange().createBookmark(true)
  8284. }
  8285. me.body.contentEditable = false
  8286. me.bkqueryCommandState = me.queryCommandState
  8287. me.bkqueryCommandValue = me.queryCommandValue
  8288. me.queryCommandState = function (type) {
  8289. if (utils.indexOf(except, type) != -1) {
  8290. return me.bkqueryCommandState.apply(me, arguments)
  8291. }
  8292. return -1
  8293. }
  8294. me.queryCommandValue = function (type) {
  8295. if (utils.indexOf(except, type) != -1) {
  8296. return me.bkqueryCommandValue.apply(me, arguments)
  8297. }
  8298. return null
  8299. }
  8300. me.fireEvent('selectionchange')
  8301. }
  8302. },
  8303. disable: function (except) {
  8304. return this.setDisabled(except)
  8305. },
  8306. /**
  8307. * 设置默认内容
  8308. * @method _setDefaultContent
  8309. * @private
  8310. * @param { String } cont 要存入的内容
  8311. */
  8312. _setDefaultContent: (function () {
  8313. function clear() {
  8314. var me = this
  8315. if (me.document.getElementById('initContent')) {
  8316. me.body.innerHTML = '<p>' + (ie ? '' : '<br/>') + '</p>'
  8317. me.removeListener('firstBeforeExecCommand focus', clear)
  8318. setTimeout(function () {
  8319. me.focus()
  8320. me._selectionChange()
  8321. }, 0)
  8322. }
  8323. }
  8324. return function (cont) {
  8325. var me = this
  8326. me.body.innerHTML = '<p id="initContent">' + cont + '</p>'
  8327. me.addListener('firstBeforeExecCommand focus', clear)
  8328. }
  8329. })(),
  8330. /**
  8331. * 显示编辑器
  8332. * @method setShow
  8333. * @example
  8334. * ```javascript
  8335. * editor.setShow()
  8336. * ```
  8337. */
  8338. setShow: function () {
  8339. var me = this,
  8340. range = me.selection.getRange()
  8341. if (me.container.style.display == 'none') {
  8342. //有可能内容丢失了
  8343. try {
  8344. range.moveToBookmark(me.lastBk)
  8345. delete me.lastBk
  8346. } catch (e) {
  8347. range.setStartAtFirst(me.body).collapse(true)
  8348. }
  8349. //ie下focus实效,所以做了个延迟
  8350. setTimeout(function () {
  8351. range.select(true)
  8352. }, 100)
  8353. me.container.style.display = ''
  8354. }
  8355. },
  8356. show: function () {
  8357. return this.setShow()
  8358. },
  8359. /**
  8360. * 隐藏编辑器
  8361. * @method setHide
  8362. * @example
  8363. * ```javascript
  8364. * editor.setHide()
  8365. * ```
  8366. */
  8367. setHide: function () {
  8368. var me = this
  8369. if (!me.lastBk) {
  8370. me.lastBk = me.selection.getRange().createBookmark(true)
  8371. }
  8372. me.container.style.display = 'none'
  8373. },
  8374. hide: function () {
  8375. return this.setHide()
  8376. },
  8377. /**
  8378. * 根据指定的路径,获取对应的语言资源
  8379. * @method getLang
  8380. * @param { String } path 路径根据的是lang目录下的语言文件的路径结构
  8381. * @return { Object | String } 根据路径返回语言资源的Json格式对象或者语言字符串
  8382. * @example
  8383. * ```javascript
  8384. * editor.getLang('contextMenu.delete'); //如果当前是中文,那返回是的是'删除'
  8385. * ```
  8386. */
  8387. getLang: function (path) {
  8388. // HaoChuan9421
  8389. if (!this.options) {
  8390. return ''
  8391. }
  8392. var lang = UE.I18N[this.options.lang]
  8393. if (!lang) {
  8394. throw Error('not import language file')
  8395. }
  8396. path = (path || '').split('.')
  8397. for (var i = 0, ci; (ci = path[i++]); ) {
  8398. lang = lang[ci]
  8399. if (!lang) break
  8400. }
  8401. return lang
  8402. },
  8403. /**
  8404. * 计算编辑器html内容字符串的长度
  8405. * @method getContentLength
  8406. * @return { Number } 返回计算的长度
  8407. * @example
  8408. * ```javascript
  8409. * //编辑器html内容<p><strong>132</strong></p>
  8410. * editor.getContentLength() //返回27
  8411. * ```
  8412. */
  8413. /**
  8414. * 计算编辑器当前纯文本内容的长度
  8415. * @method getContentLength
  8416. * @param { Boolean } ingoneHtml 传入true时,只按照纯文本来计算
  8417. * @return { Number } 返回计算的长度,内容中有hr/img/iframe标签,长度加1
  8418. * @example
  8419. * ```javascript
  8420. * //编辑器html内容<p><strong>132</strong></p>
  8421. * editor.getContentLength() //返回3
  8422. * ```
  8423. */
  8424. getContentLength: function (ingoneHtml, tagNames) {
  8425. var count = this.getContent(false, false, true).length
  8426. if (ingoneHtml) {
  8427. tagNames = (tagNames || []).concat(['hr', 'img', 'iframe'])
  8428. count = this.getContentTxt().replace(/[\t\r\n]+/g, '').length
  8429. for (var i = 0, ci; (ci = tagNames[i++]); ) {
  8430. count += this.document.getElementsByTagName(ci).length
  8431. }
  8432. }
  8433. return count
  8434. },
  8435. /**
  8436. * 注册输入过滤规则
  8437. * @method addInputRule
  8438. * @param { Function } rule 要添加的过滤规则
  8439. * @example
  8440. * ```javascript
  8441. * editor.addInputRule(function(root){
  8442. * $.each(root.getNodesByTagName('div'),function(i,node){
  8443. * node.tagName="p";
  8444. * });
  8445. * });
  8446. * ```
  8447. */
  8448. addInputRule: function (rule) {
  8449. this.inputRules.push(rule)
  8450. },
  8451. /**
  8452. * 执行注册的过滤规则
  8453. * @method filterInputRule
  8454. * @param { UE.uNode } root 要过滤的uNode节点
  8455. * @remind 执行editor.setContent方法和执行'inserthtml'命令后,会运行该过滤函数
  8456. * @example
  8457. * ```javascript
  8458. * editor.filterInputRule(editor.body);
  8459. * ```
  8460. * @see UE.Editor:addInputRule
  8461. */
  8462. filterInputRule: function (root) {
  8463. for (var i = 0, ci; (ci = this.inputRules[i++]); ) {
  8464. ci.call(this, root)
  8465. }
  8466. },
  8467. /**
  8468. * 注册输出过滤规则
  8469. * @method addOutputRule
  8470. * @param { Function } rule 要添加的过滤规则
  8471. * @example
  8472. * ```javascript
  8473. * editor.addOutputRule(function(root){
  8474. * $.each(root.getNodesByTagName('p'),function(i,node){
  8475. * node.tagName="div";
  8476. * });
  8477. * });
  8478. * ```
  8479. */
  8480. addOutputRule: function (rule) {
  8481. this.outputRules.push(rule)
  8482. },
  8483. /**
  8484. * 根据输出过滤规则,过滤编辑器内容
  8485. * @method filterOutputRule
  8486. * @remind 执行editor.getContent方法的时候,会先运行该过滤函数
  8487. * @param { UE.uNode } root 要过滤的uNode节点
  8488. * @example
  8489. * ```javascript
  8490. * editor.filterOutputRule(editor.body);
  8491. * ```
  8492. * @see UE.Editor:addOutputRule
  8493. */
  8494. filterOutputRule: function (root) {
  8495. for (var i = 0, ci; (ci = this.outputRules[i++]); ) {
  8496. ci.call(this, root)
  8497. }
  8498. },
  8499. /**
  8500. * 根据action名称获取请求的路径
  8501. * @method getActionUrl
  8502. * @remind 假如没有设置serverUrl,会根据imageUrl设置默认的controller路径
  8503. * @param { String } action action名称
  8504. * @example
  8505. * ```javascript
  8506. * editor.getActionUrl('config'); //返回 "/ueditor/php/controller.php?action=config"
  8507. * editor.getActionUrl('image'); //返回 "/ueditor/php/controller.php?action=uplaodimage"
  8508. * editor.getActionUrl('scrawl'); //返回 "/ueditor/php/controller.php?action=uplaodscrawl"
  8509. * editor.getActionUrl('imageManager'); //返回 "/ueditor/php/controller.php?action=listimage"
  8510. * ```
  8511. */
  8512. getActionUrl: function (action) {
  8513. console.log(action, 'action')
  8514. var actionName = this.getOpt(action) || action,
  8515. imageUrl = this.getOpt('imageUrl'),
  8516. serverUrl = this.getOpt('serverUrl')
  8517. if (!serverUrl && imageUrl) {
  8518. console.log(action, 'action1')
  8519. serverUrl = imageUrl.replace(/^(.*[\/]).+([\.].+)$/, '$1controller$2')
  8520. }
  8521. console.log(serverUrl, 'serverUrl')
  8522. // serverUrl =
  8523. // 'http://mentor.site.ximengnaikang.com/ueditor/controller.php'
  8524. // if (action == 'uploadimage') serverUrl = '/daili/base/common/upload'
  8525. if (serverUrl) {
  8526. console.log(action, 'action2')
  8527. serverUrl =
  8528. serverUrl +
  8529. (serverUrl.indexOf('?') == -1 ? '?' : '&') +
  8530. 'action=' +
  8531. (actionName || '')
  8532. console.log(utils.formatUrl(serverUrl), 'action3')
  8533. return utils.formatUrl(serverUrl)
  8534. } else {
  8535. return ''
  8536. }
  8537. },
  8538. }
  8539. utils.inherits(Editor, EventBase)
  8540. })()
  8541. // core/Editor.defaultoptions.js
  8542. //维护编辑器一下默认的不在插件中的配置项
  8543. UE.Editor.defaultOptions = function (editor) {
  8544. var _url = editor.options.UEDITOR_HOME_URL
  8545. return {
  8546. isShow: true,
  8547. initialContent: '',
  8548. initialStyle: '',
  8549. autoClearinitialContent: false,
  8550. iframeCssUrl: _url + 'themes/iframe.css',
  8551. textarea: 'editorValue',
  8552. focus: false,
  8553. focusInEnd: true,
  8554. autoClearEmptyNode: true,
  8555. fullscreen: false,
  8556. readonly: false,
  8557. zIndex: 999,
  8558. imagePopup: true,
  8559. enterTag: 'p',
  8560. customDomain: false,
  8561. lang: 'zh-cn',
  8562. langPath: _url + 'lang/',
  8563. theme: 'default',
  8564. themePath: _url + 'themes/',
  8565. allHtmlEnabled: false,
  8566. scaleEnabled: false,
  8567. tableNativeEditInFF: false,
  8568. autoSyncData: true,
  8569. fileNameFormat: '{time}{rand:6}',
  8570. }
  8571. }
  8572. // core/loadconfig.js
  8573. ;(function () {
  8574. console.log('此处请求')
  8575. UE.Editor.prototype.loadServerConfig = function () {
  8576. var me = this
  8577. let aa = ''
  8578. setTimeout(function () {
  8579. try {
  8580. console.log('ppppp')
  8581. me.options.imageUrl &&
  8582. me.setOpt(
  8583. 'serverUrl',
  8584. me.options.imageUrl.replace(
  8585. /^(.*[\/]).+([\.].+)$/,
  8586. '$1controller$2'
  8587. )
  8588. )
  8589. var configUrl = me.getActionUrl('config'),
  8590. isJsonp = utils.isCrossDomainUrl(configUrl)
  8591. console.log(me.getActionUrl('config'), 'console.log')
  8592. /* 发出ajax请求 */
  8593. me._serverConfigLoaded = false
  8594. console.log(' 发出ajax请求 ')
  8595. aa =
  8596. configUrl &&
  8597. UE.ajax.request(configUrl, {
  8598. method: 'GET',
  8599. dataType: isJsonp ? 'jsonp' : '',
  8600. onComplete: function (x) {
  8601. //提交成功回调
  8602. console.log(x, 'ppppppppppppppppppppppppppppppppppppppp')
  8603. },
  8604. onsuccess: function (r) {
  8605. console.log(r, 'ooooooooooooooooooooo')
  8606. try {
  8607. var config = isJsonp ? r : eval('(' + r.responseText + ')')
  8608. //var config = ieval('(' + r.responseText + ')')
  8609. utils.extend(me.options, config)
  8610. me.fireEvent('serverConfigLoaded')
  8611. me._serverConfigLoaded = true
  8612. } catch (e) {
  8613. console.log(e, '返回错误')
  8614. showErrorMsg(me.getLang('loadconfigFormatError'))
  8615. }
  8616. },
  8617. onerror: function () {
  8618. showErrorMsg(me.getLang('loadconfigHttpError'))
  8619. },
  8620. })
  8621. } catch (e) {
  8622. console.log(aa, 'aa')
  8623. showErrorMsg(me.getLang('loadconfigError'))
  8624. }
  8625. })
  8626. function showErrorMsg(msg) {
  8627. console.log('aa')
  8628. console && console.error(msg)
  8629. //me.fireEvent('showMessage', {
  8630. // 'title': msg,
  8631. // 'type': 'error'
  8632. //});
  8633. }
  8634. }
  8635. UE.Editor.prototype.isServerConfigLoaded = function () {
  8636. var me = this
  8637. return me._serverConfigLoaded || false
  8638. }
  8639. UE.Editor.prototype.afterConfigReady = function (handler) {
  8640. if (!handler || !utils.isFunction(handler)) return
  8641. var me = this
  8642. var readyHandler = function () {
  8643. handler.apply(me, arguments)
  8644. me.removeListener('serverConfigLoaded', readyHandler)
  8645. }
  8646. if (me.isServerConfigLoaded()) {
  8647. handler.call(me, 'serverConfigLoaded')
  8648. } else {
  8649. me.addListener('serverConfigLoaded', readyHandler)
  8650. }
  8651. }
  8652. })()
  8653. // core/ajax.js
  8654. /**
  8655. * @file
  8656. * @module UE.ajax
  8657. * @since 1.2.6.1
  8658. */
  8659. /**
  8660. * 提供对ajax请求的支持
  8661. * @module UE.ajax
  8662. */
  8663. UE.ajax = (function () {
  8664. //创建一个ajaxRequest对象
  8665. var fnStr = 'XMLHttpRequest()'
  8666. try {
  8667. new ActiveXObject('Msxml2.XMLHTTP')
  8668. fnStr = "ActiveXObject('Msxml2.XMLHTTP')"
  8669. } catch (e) {
  8670. try {
  8671. new ActiveXObject('Microsoft.XMLHTTP')
  8672. fnStr = "ActiveXObject('Microsoft.XMLHTTP')"
  8673. } catch (e) {}
  8674. }
  8675. var creatAjaxRequest = new Function('return new ' + fnStr)
  8676. /**
  8677. * 将json参数转化成适合ajax提交的参数列表
  8678. * @param json
  8679. */
  8680. function json2str(json) {
  8681. var strArr = []
  8682. for (var i in json) {
  8683. //忽略默认的几个参数
  8684. if (
  8685. i == 'method' ||
  8686. i == 'timeout' ||
  8687. i == 'async' ||
  8688. i == 'dataType' ||
  8689. i == 'callback'
  8690. )
  8691. continue
  8692. //忽略控制
  8693. if (json[i] == undefined || json[i] == null) continue
  8694. //传递过来的对象和函数不在提交之列
  8695. if (
  8696. !(
  8697. (typeof json[i]).toLowerCase() == 'function' ||
  8698. (typeof json[i]).toLowerCase() == 'object'
  8699. )
  8700. ) {
  8701. strArr.push(encodeURIComponent(i) + '=' + encodeURIComponent(json[i]))
  8702. } else if (utils.isArray(json[i])) {
  8703. //支持传数组内容
  8704. for (var j = 0; j < json[i].length; j++) {
  8705. strArr.push(
  8706. encodeURIComponent(i) + '[]=' + encodeURIComponent(json[i][j])
  8707. )
  8708. }
  8709. }
  8710. }
  8711. return strArr.join('&')
  8712. }
  8713. function doAjax(url, ajaxOptions) {
  8714. var xhr = creatAjaxRequest(),
  8715. //是否超时
  8716. timeIsOut = false,
  8717. //默认参数
  8718. defaultAjaxOptions = {
  8719. method: 'POST',
  8720. timeout: 5000,
  8721. async: true,
  8722. data: {}, //需要传递对象的话只能覆盖
  8723. onsuccess: function () {},
  8724. onerror: function () {},
  8725. }
  8726. if (typeof url === 'object') {
  8727. ajaxOptions = url
  8728. url = ajaxOptions.url
  8729. }
  8730. if (!xhr || !url) return
  8731. var ajaxOpts = ajaxOptions
  8732. ? utils.extend(defaultAjaxOptions, ajaxOptions)
  8733. : defaultAjaxOptions
  8734. var submitStr = json2str(ajaxOpts) // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing"
  8735. //如果用户直接通过data参数传递json对象过来,则也要将此json对象转化为字符串
  8736. if (!utils.isEmptyObject(ajaxOpts.data)) {
  8737. submitStr += (submitStr ? '&' : '') + json2str(ajaxOpts.data)
  8738. }
  8739. //超时检测
  8740. var timerID = setTimeout(function () {
  8741. if (xhr.readyState != 4) {
  8742. timeIsOut = true
  8743. xhr.abort()
  8744. clearTimeout(timerID)
  8745. }
  8746. }, ajaxOpts.timeout)
  8747. var method = ajaxOpts.method.toUpperCase()
  8748. var str =
  8749. url +
  8750. (url.indexOf('?') == -1 ? '?' : '&') +
  8751. (method == 'POST' ? '' : submitStr + '&noCache=' + +new Date())
  8752. xhr.open(method, str, ajaxOpts.async)
  8753. xhr.onreadystatechange = function () {
  8754. if (xhr.readyState == 4) {
  8755. if (!timeIsOut && xhr.status == 200) {
  8756. ajaxOpts.onsuccess(xhr)
  8757. } else {
  8758. ajaxOpts.onerror(xhr)
  8759. }
  8760. }
  8761. }
  8762. if (method == 'POST') {
  8763. xhr.setRequestHeader(
  8764. 'Content-Type',
  8765. 'application/x-www-form-urlencoded'
  8766. )
  8767. xhr.send(submitStr)
  8768. } else {
  8769. xhr.send(null)
  8770. }
  8771. }
  8772. function doJsonp(url, opts) {
  8773. var successhandler = opts.onsuccess || function () {},
  8774. scr = document.createElement('SCRIPT'),
  8775. options = opts || {},
  8776. charset = options['charset'],
  8777. callbackField = options['jsonp'] || 'callback',
  8778. callbackFnName,
  8779. timeOut = options['timeOut'] || 0,
  8780. timer,
  8781. reg = new RegExp('(\\?|&)' + callbackField + '=([^&]*)'),
  8782. matches
  8783. if (utils.isFunction(successhandler)) {
  8784. callbackFnName =
  8785. 'bd__editor__' + Math.floor(Math.random() * 2147483648).toString(36)
  8786. window[callbackFnName] = getCallBack(0)
  8787. } else if (utils.isString(successhandler)) {
  8788. callbackFnName = successhandler
  8789. } else {
  8790. if ((matches = reg.exec(url))) {
  8791. callbackFnName = matches[2]
  8792. }
  8793. }
  8794. url = url.replace(reg, '\x241' + callbackField + '=' + callbackFnName)
  8795. if (url.search(reg) < 0) {
  8796. url +=
  8797. (url.indexOf('?') < 0 ? '?' : '&') +
  8798. callbackField +
  8799. '=' +
  8800. callbackFnName
  8801. }
  8802. var queryStr = json2str(opts) // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing"
  8803. //如果用户直接通过data参数传递json对象过来,则也要将此json对象转化为字符串
  8804. if (!utils.isEmptyObject(opts.data)) {
  8805. queryStr += (queryStr ? '&' : '') + json2str(opts.data)
  8806. }
  8807. if (queryStr) {
  8808. url = url.replace(/\?/, '?' + queryStr + '&')
  8809. }
  8810. scr.onerror = getCallBack(1)
  8811. if (timeOut) {
  8812. timer = setTimeout(getCallBack(1), timeOut)
  8813. }
  8814. createScriptTag(scr, url, charset)
  8815. function createScriptTag(scr, url, charset) {
  8816. scr.setAttribute('type', 'text/javascript')
  8817. scr.setAttribute('defer', 'defer')
  8818. charset && scr.setAttribute('charset', charset)
  8819. scr.setAttribute('src', url)
  8820. document.getElementsByTagName('head')[0].appendChild(scr)
  8821. }
  8822. function getCallBack(onTimeOut) {
  8823. return function () {
  8824. try {
  8825. if (onTimeOut) {
  8826. options.onerror && options.onerror()
  8827. } else {
  8828. try {
  8829. clearTimeout(timer)
  8830. successhandler.apply(window, arguments)
  8831. } catch (e) {}
  8832. }
  8833. } catch (exception) {
  8834. options.onerror && options.onerror.call(window, exception)
  8835. } finally {
  8836. options.oncomplete && options.oncomplete.apply(window, arguments)
  8837. scr.parentNode && scr.parentNode.removeChild(scr)
  8838. window[callbackFnName] = null
  8839. try {
  8840. delete window[callbackFnName]
  8841. } catch (e) {}
  8842. }
  8843. }
  8844. }
  8845. }
  8846. return {
  8847. /**
  8848. * 根据给定的参数项,向指定的url发起一个ajax请求。 ajax请求完成后,会根据请求结果调用相应回调: 如果请求
  8849. * 成功, 则调用onsuccess回调, 失败则调用 onerror 回调
  8850. * @method request
  8851. * @param { URLString } url ajax请求的url地址
  8852. * @param { Object } ajaxOptions ajax请求选项的键值对,支持的选项如下:
  8853. * @example
  8854. * ```javascript
  8855. * //向sayhello.php发起一个异步的Ajax GET请求, 请求超时时间为10s, 请求完成后执行相应的回调。
  8856. * UE.ajax.requeset( 'sayhello.php', {
  8857. *
  8858. * //请求方法。可选值: 'GET', 'POST',默认值是'POST'
  8859. * method: 'GET',
  8860. *
  8861. * //超时时间。 默认为5000, 单位是ms
  8862. * timeout: 10000,
  8863. *
  8864. * //是否是异步请求。 true为异步请求, false为同步请求
  8865. * async: true,
  8866. *
  8867. * //请求携带的数据。如果请求为GET请求, data会经过stringify后附加到请求url之后。
  8868. * data: {
  8869. * name: 'ueditor'
  8870. * },
  8871. *
  8872. * //请求成功后的回调, 该回调接受当前的XMLHttpRequest对象作为参数。
  8873. * onsuccess: function ( xhr ) {
  8874. * console.log( xhr.responseText );
  8875. * },
  8876. *
  8877. * //请求失败或者超时后的回调。
  8878. * onerror: function ( xhr ) {
  8879. * alert( 'Ajax请求失败' );
  8880. * }
  8881. *
  8882. * } );
  8883. * ```
  8884. */
  8885. /**
  8886. * 根据给定的参数项发起一个ajax请求, 参数项里必须包含一个url地址。 ajax请求完成后,会根据请求结果调用相应回调: 如果请求
  8887. * 成功, 则调用onsuccess回调, 失败则调用 onerror 回调。
  8888. * @method request
  8889. * @warning 如果在参数项里未提供一个key为“url”的地址值,则该请求将直接退出。
  8890. * @param { Object } ajaxOptions ajax请求选项的键值对,支持的选项如下:
  8891. * @example
  8892. * ```javascript
  8893. *
  8894. * //向sayhello.php发起一个异步的Ajax POST请求, 请求超时时间为5s, 请求完成后不执行任何回调。
  8895. * UE.ajax.requeset( 'sayhello.php', {
  8896. *
  8897. * //请求的地址, 该项是必须的。
  8898. * url: 'sayhello.php'
  8899. *
  8900. * } );
  8901. * ```
  8902. */
  8903. request: function (url, opts) {
  8904. if (opts && opts.dataType == 'jsonp') {
  8905. doJsonp(url, opts)
  8906. } else {
  8907. doAjax(url, opts)
  8908. }
  8909. },
  8910. getJSONP: function (url, data, fn) {
  8911. var opts = {
  8912. data: data,
  8913. oncomplete: fn,
  8914. }
  8915. doJsonp(url, opts)
  8916. },
  8917. }
  8918. })()
  8919. // core/filterword.js
  8920. /**
  8921. * UE过滤word的静态方法
  8922. * @file
  8923. */
  8924. /**
  8925. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  8926. * @module UE
  8927. */
  8928. /**
  8929. * 根据传入html字符串过滤word
  8930. * @module UE
  8931. * @since 1.2.6.1
  8932. * @method filterWord
  8933. * @param { String } html html字符串
  8934. * @return { String } 已过滤后的结果字符串
  8935. * @example
  8936. * ```javascript
  8937. * UE.filterWord(html);
  8938. * ```
  8939. */
  8940. var filterWord = (UE.filterWord = (function () {
  8941. //是否是word过来的内容
  8942. function isWordDocument(str) {
  8943. return /(class="?Mso|style="[^"]*\bmso\-|w:WordDocument|<(v|o):|lang=)/gi.test(
  8944. str
  8945. )
  8946. }
  8947. //去掉小数
  8948. function transUnit(v) {
  8949. v = v.replace(/[\d.]+\w+/g, function (m) {
  8950. return utils.transUnitToPx(m)
  8951. })
  8952. return v
  8953. }
  8954. function filterPasteWord(str) {
  8955. return (
  8956. str
  8957. .replace(/[\t\r\n]+/g, ' ')
  8958. .replace(/<!--[\s\S]*?-->/gi, '')
  8959. //转换图片
  8960. .replace(/<v:shape [^>]*>[\s\S]*?.<\/v:shape>/gi, function (str) {
  8961. //opera能自己解析出image所这里直接返回空
  8962. if (browser.opera) {
  8963. return ''
  8964. }
  8965. try {
  8966. //有可能是bitmap占为图,无用,直接过滤掉,主要体现在粘贴excel表格中
  8967. if (/Bitmap/i.test(str)) {
  8968. return ''
  8969. }
  8970. var width = str.match(/width:([ \d.]*p[tx])/i)[1],
  8971. height = str.match(/height:([ \d.]*p[tx])/i)[1],
  8972. src = str.match(/src=\s*"([^"]*)"/i)[1]
  8973. return (
  8974. '<img width="' +
  8975. transUnit(width) +
  8976. '" height="' +
  8977. transUnit(height) +
  8978. '" src="' +
  8979. src +
  8980. '" />'
  8981. )
  8982. } catch (e) {
  8983. return ''
  8984. }
  8985. })
  8986. //针对wps添加的多余标签处理
  8987. .replace(/<\/?div[^>]*>/g, '')
  8988. //去掉多余的属性
  8989. .replace(/v:\w+=(["']?)[^'"]+\1/g, '')
  8990. .replace(
  8991. /<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|xml|meta|link|style|\w+:\w+)(?=[\s\/>]))[^>]*>/gi,
  8992. ''
  8993. )
  8994. .replace(
  8995. /<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi,
  8996. '<p><strong>$1</strong></p>'
  8997. )
  8998. //去掉多余的属性
  8999. .replace(
  9000. /\s+(class|lang|align)\s*=\s*(['"]?)([\w-]+)\2/gi,
  9001. function (str, name, marks, val) {
  9002. //保留list的标示
  9003. return name == 'class' && val == 'MsoListParagraph' ? str : ''
  9004. }
  9005. )
  9006. //清除多余的font/span不能匹配&nbsp;有可能是空格
  9007. .replace(/<(font|span)[^>]*>(\s*)<\/\1>/gi, function (a, b, c) {
  9008. return c.replace(/[\t\r\n ]+/g, ' ')
  9009. })
  9010. //处理style的问题
  9011. .replace(
  9012. /(<[a-z][^>]*)\sstyle=(["'])([^\2]*?)\2/gi,
  9013. function (str, tag, tmp, style) {
  9014. var n = [],
  9015. s = style
  9016. .replace(/^\s+|\s+$/, '')
  9017. .replace(/&#39;/g, "'")
  9018. .replace(/&quot;/gi, "'")
  9019. .replace(/[\d.]+(cm|pt)/g, function (str) {
  9020. return utils.transUnitToPx(str)
  9021. })
  9022. .split(/;\s*/g)
  9023. for (var i = 0, v; (v = s[i]); i++) {
  9024. var name,
  9025. value,
  9026. parts = v.split(':')
  9027. if (parts.length == 2) {
  9028. name = parts[0].toLowerCase()
  9029. value = parts[1].toLowerCase()
  9030. if (
  9031. (/^(background)\w*/.test(name) &&
  9032. value.replace(/(initial|\s)/g, '').length == 0) ||
  9033. (/^(margin)\w*/.test(name) && /^0\w+$/.test(value))
  9034. ) {
  9035. continue
  9036. }
  9037. switch (name) {
  9038. case 'mso-padding-alt':
  9039. case 'mso-padding-top-alt':
  9040. case 'mso-padding-right-alt':
  9041. case 'mso-padding-bottom-alt':
  9042. case 'mso-padding-left-alt':
  9043. case 'mso-margin-alt':
  9044. case 'mso-margin-top-alt':
  9045. case 'mso-margin-right-alt':
  9046. case 'mso-margin-bottom-alt':
  9047. case 'mso-margin-left-alt':
  9048. //ie下会出现挤到一起的情况
  9049. //case "mso-table-layout-alt":
  9050. case 'mso-height':
  9051. case 'mso-width':
  9052. case 'mso-vertical-align-alt':
  9053. //trace:1819 ff下会解析出padding在table上
  9054. if (!/<table/.test(tag))
  9055. n[i] =
  9056. name.replace(/^mso-|-alt$/g, '') +
  9057. ':' +
  9058. transUnit(value)
  9059. continue
  9060. case 'horiz-align':
  9061. n[i] = 'text-align:' + value
  9062. continue
  9063. case 'vert-align':
  9064. n[i] = 'vertical-align:' + value
  9065. continue
  9066. case 'font-color':
  9067. case 'mso-foreground':
  9068. n[i] = 'color:' + value
  9069. continue
  9070. case 'mso-background':
  9071. case 'mso-highlight':
  9072. n[i] = 'background:' + value
  9073. continue
  9074. case 'mso-default-height':
  9075. n[i] = 'min-height:' + transUnit(value)
  9076. continue
  9077. case 'mso-default-width':
  9078. n[i] = 'min-width:' + transUnit(value)
  9079. continue
  9080. case 'mso-padding-between-alt':
  9081. n[i] =
  9082. 'border-collapse:separate;border-spacing:' +
  9083. transUnit(value)
  9084. continue
  9085. case 'text-line-through':
  9086. if (value == 'single' || value == 'double') {
  9087. n[i] = 'text-decoration:line-through'
  9088. }
  9089. continue
  9090. case 'mso-zero-height':
  9091. if (value == 'yes') {
  9092. n[i] = 'display:none'
  9093. }
  9094. continue
  9095. // case 'background':
  9096. // break;
  9097. case 'margin':
  9098. if (!/[1-9]/.test(value)) {
  9099. continue
  9100. }
  9101. }
  9102. if (
  9103. /^(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(
  9104. name
  9105. ) ||
  9106. (/text\-indent|padding|margin/.test(name) &&
  9107. /\-[\d.]+/.test(value))
  9108. ) {
  9109. continue
  9110. }
  9111. n[i] = name + ':' + parts[1]
  9112. }
  9113. }
  9114. return (
  9115. tag +
  9116. (n.length
  9117. ? ' style="' + n.join(';').replace(/;{2,}/g, ';') + '"'
  9118. : '')
  9119. )
  9120. }
  9121. )
  9122. )
  9123. }
  9124. return function (html) {
  9125. return isWordDocument(html) ? filterPasteWord(html) : html
  9126. }
  9127. })())
  9128. // core/node.js
  9129. /**
  9130. * 编辑器模拟的节点类
  9131. * @file
  9132. * @module UE
  9133. * @class uNode
  9134. * @since 1.2.6.1
  9135. */
  9136. /**
  9137. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  9138. * @unfile
  9139. * @module UE
  9140. */
  9141. ;(function () {
  9142. /**
  9143. * 编辑器模拟的节点类
  9144. * @unfile
  9145. * @module UE
  9146. * @class uNode
  9147. */
  9148. /**
  9149. * 通过一个键值对,创建一个uNode对象
  9150. * @constructor
  9151. * @param { Object } attr 传入要创建的uNode的初始属性
  9152. * @example
  9153. * ```javascript
  9154. * var node = new uNode({
  9155. * type:'element',
  9156. * tagName:'span',
  9157. * attrs:{style:'font-size:14px;'}
  9158. * }
  9159. * ```
  9160. */
  9161. var uNode = (UE.uNode = function (obj) {
  9162. this.type = obj.type
  9163. this.data = obj.data
  9164. this.tagName = obj.tagName
  9165. this.parentNode = obj.parentNode
  9166. this.attrs = obj.attrs || {}
  9167. this.children = obj.children
  9168. })
  9169. var notTransAttrs = {
  9170. href: 1,
  9171. src: 1,
  9172. _src: 1,
  9173. _href: 1,
  9174. cdata_data: 1,
  9175. }
  9176. var notTransTagName = {
  9177. style: 1,
  9178. script: 1,
  9179. }
  9180. var indentChar = ' ',
  9181. breakChar = '\n'
  9182. function insertLine(arr, current, begin) {
  9183. arr.push(breakChar)
  9184. return current + (begin ? 1 : -1)
  9185. }
  9186. function insertIndent(arr, current) {
  9187. //插入缩进
  9188. for (var i = 0; i < current; i++) {
  9189. arr.push(indentChar)
  9190. }
  9191. }
  9192. //创建uNode的静态方法
  9193. //支持标签和html
  9194. uNode.createElement = function (html) {
  9195. if (/[<>]/.test(html)) {
  9196. return UE.htmlparser(html).children[0]
  9197. } else {
  9198. return new uNode({
  9199. type: 'element',
  9200. children: [],
  9201. tagName: html,
  9202. })
  9203. }
  9204. }
  9205. uNode.createText = function (data, noTrans) {
  9206. return new UE.uNode({
  9207. type: 'text',
  9208. data: noTrans ? data : utils.unhtml(data || ''),
  9209. })
  9210. }
  9211. function nodeToHtml(node, arr, formatter, current) {
  9212. switch (node.type) {
  9213. case 'root':
  9214. for (var i = 0, ci; (ci = node.children[i++]); ) {
  9215. //插入新行
  9216. if (
  9217. formatter &&
  9218. ci.type == 'element' &&
  9219. !dtd.$inlineWithA[ci.tagName] &&
  9220. i > 1
  9221. ) {
  9222. insertLine(arr, current, true)
  9223. insertIndent(arr, current)
  9224. }
  9225. nodeToHtml(ci, arr, formatter, current)
  9226. }
  9227. break
  9228. case 'text':
  9229. isText(node, arr)
  9230. break
  9231. case 'element':
  9232. isElement(node, arr, formatter, current)
  9233. break
  9234. case 'comment':
  9235. isComment(node, arr, formatter)
  9236. }
  9237. return arr
  9238. }
  9239. function isText(node, arr) {
  9240. if (node.parentNode.tagName == 'pre') {
  9241. //源码模式下输入html标签,不能做转换处理,直接输出
  9242. arr.push(node.data)
  9243. } else {
  9244. arr.push(
  9245. notTransTagName[node.parentNode.tagName]
  9246. ? utils.html(node.data)
  9247. : node.data.replace(/[ ]{2}/g, ' &nbsp;')
  9248. )
  9249. }
  9250. }
  9251. function isElement(node, arr, formatter, current) {
  9252. var attrhtml = ''
  9253. if (node.attrs) {
  9254. attrhtml = []
  9255. var attrs = node.attrs
  9256. for (var a in attrs) {
  9257. //这里就针对
  9258. //<p>'<img src='http://nsclick.baidu.com/u.gif?&asdf=\"sdf&asdfasdfs;asdf'></p>
  9259. //这里边的\"做转换,要不用innerHTML直接被截断了,属性src
  9260. //有可能做的不够
  9261. attrhtml.push(
  9262. a +
  9263. (attrs[a] !== undefined
  9264. ? '="' +
  9265. (notTransAttrs[a]
  9266. ? utils.html(attrs[a]).replace(/["]/g, function (a) {
  9267. return '&quot;'
  9268. })
  9269. : utils.unhtml(attrs[a])) +
  9270. '"'
  9271. : '')
  9272. )
  9273. }
  9274. attrhtml = attrhtml.join(' ')
  9275. }
  9276. arr.push(
  9277. '<' +
  9278. node.tagName +
  9279. (attrhtml ? ' ' + attrhtml : '') +
  9280. (dtd.$empty[node.tagName] ? '/' : '') +
  9281. '>'
  9282. )
  9283. //插入新行
  9284. if (
  9285. formatter &&
  9286. !dtd.$inlineWithA[node.tagName] &&
  9287. node.tagName != 'pre'
  9288. ) {
  9289. if (node.children && node.children.length) {
  9290. current = insertLine(arr, current, true)
  9291. insertIndent(arr, current)
  9292. }
  9293. }
  9294. if (node.children && node.children.length) {
  9295. for (var i = 0, ci; (ci = node.children[i++]); ) {
  9296. if (
  9297. formatter &&
  9298. ci.type == 'element' &&
  9299. !dtd.$inlineWithA[ci.tagName] &&
  9300. i > 1
  9301. ) {
  9302. insertLine(arr, current)
  9303. insertIndent(arr, current)
  9304. }
  9305. nodeToHtml(ci, arr, formatter, current)
  9306. }
  9307. }
  9308. if (!dtd.$empty[node.tagName]) {
  9309. if (
  9310. formatter &&
  9311. !dtd.$inlineWithA[node.tagName] &&
  9312. node.tagName != 'pre'
  9313. ) {
  9314. if (node.children && node.children.length) {
  9315. current = insertLine(arr, current)
  9316. insertIndent(arr, current)
  9317. }
  9318. }
  9319. arr.push('</' + node.tagName + '>')
  9320. }
  9321. }
  9322. function isComment(node, arr) {
  9323. arr.push('<!--' + node.data + '-->')
  9324. }
  9325. function getNodeById(root, id) {
  9326. var node
  9327. if (root.type == 'element' && root.getAttr('id') == id) {
  9328. return root
  9329. }
  9330. if (root.children && root.children.length) {
  9331. for (var i = 0, ci; (ci = root.children[i++]); ) {
  9332. if ((node = getNodeById(ci, id))) {
  9333. return node
  9334. }
  9335. }
  9336. }
  9337. }
  9338. function getNodesByTagName(node, tagName, arr) {
  9339. if (node.type == 'element' && node.tagName == tagName) {
  9340. arr.push(node)
  9341. }
  9342. if (node.children && node.children.length) {
  9343. for (var i = 0, ci; (ci = node.children[i++]); ) {
  9344. getNodesByTagName(ci, tagName, arr)
  9345. }
  9346. }
  9347. }
  9348. function nodeTraversal(root, fn) {
  9349. if (root.children && root.children.length) {
  9350. for (var i = 0, ci; (ci = root.children[i]); ) {
  9351. nodeTraversal(ci, fn)
  9352. //ci被替换的情况,这里就不再走 fn了
  9353. if (ci.parentNode) {
  9354. if (ci.children && ci.children.length) {
  9355. fn(ci)
  9356. }
  9357. if (ci.parentNode) i++
  9358. }
  9359. }
  9360. } else {
  9361. fn(root)
  9362. }
  9363. }
  9364. uNode.prototype = {
  9365. /**
  9366. * 当前节点对象,转换成html文本
  9367. * @method toHtml
  9368. * @return { String } 返回转换后的html字符串
  9369. * @example
  9370. * ```javascript
  9371. * node.toHtml();
  9372. * ```
  9373. */
  9374. /**
  9375. * 当前节点对象,转换成html文本
  9376. * @method toHtml
  9377. * @param { Boolean } formatter 是否格式化返回值
  9378. * @return { String } 返回转换后的html字符串
  9379. * @example
  9380. * ```javascript
  9381. * node.toHtml( true );
  9382. * ```
  9383. */
  9384. toHtml: function (formatter) {
  9385. var arr = []
  9386. nodeToHtml(this, arr, formatter, 0)
  9387. return arr.join('')
  9388. },
  9389. /**
  9390. * 获取节点的html内容
  9391. * @method innerHTML
  9392. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  9393. * @return { String } 返回节点的html内容
  9394. * @example
  9395. * ```javascript
  9396. * var htmlstr = node.innerHTML();
  9397. * ```
  9398. */
  9399. /**
  9400. * 设置节点的html内容
  9401. * @method innerHTML
  9402. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  9403. * @param { String } htmlstr 传入要设置的html内容
  9404. * @return { UE.uNode } 返回节点本身
  9405. * @example
  9406. * ```javascript
  9407. * node.innerHTML('<span>text</span>');
  9408. * ```
  9409. */
  9410. innerHTML: function (htmlstr) {
  9411. if (this.type != 'element' || dtd.$empty[this.tagName]) {
  9412. return this
  9413. }
  9414. if (utils.isString(htmlstr)) {
  9415. if (this.children) {
  9416. for (var i = 0, ci; (ci = this.children[i++]); ) {
  9417. ci.parentNode = null
  9418. }
  9419. }
  9420. this.children = []
  9421. var tmpRoot = UE.htmlparser(htmlstr)
  9422. for (var i = 0, ci; (ci = tmpRoot.children[i++]); ) {
  9423. this.children.push(ci)
  9424. ci.parentNode = this
  9425. }
  9426. return this
  9427. } else {
  9428. var tmpRoot = new UE.uNode({
  9429. type: 'root',
  9430. children: this.children,
  9431. })
  9432. return tmpRoot.toHtml()
  9433. }
  9434. },
  9435. /**
  9436. * 获取节点的纯文本内容
  9437. * @method innerText
  9438. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  9439. * @return { String } 返回节点的存文本内容
  9440. * @example
  9441. * ```javascript
  9442. * var textStr = node.innerText();
  9443. * ```
  9444. */
  9445. /**
  9446. * 设置节点的纯文本内容
  9447. * @method innerText
  9448. * @warning 假如节点的type不是'element',或节点的标签名称不在dtd列表里,直接返回当前节点
  9449. * @param { String } textStr 传入要设置的文本内容
  9450. * @return { UE.uNode } 返回节点本身
  9451. * @example
  9452. * ```javascript
  9453. * node.innerText('<span>text</span>');
  9454. * ```
  9455. */
  9456. innerText: function (textStr, noTrans) {
  9457. if (this.type != 'element' || dtd.$empty[this.tagName]) {
  9458. return this
  9459. }
  9460. if (textStr) {
  9461. if (this.children) {
  9462. for (var i = 0, ci; (ci = this.children[i++]); ) {
  9463. ci.parentNode = null
  9464. }
  9465. }
  9466. this.children = []
  9467. this.appendChild(uNode.createText(textStr, noTrans))
  9468. return this
  9469. } else {
  9470. return this.toHtml().replace(/<[^>]+>/g, '')
  9471. }
  9472. },
  9473. /**
  9474. * 获取当前对象的data属性
  9475. * @method getData
  9476. * @return { Object } 若节点的type值是elemenet,返回空字符串,否则返回节点的data属性
  9477. * @example
  9478. * ```javascript
  9479. * node.getData();
  9480. * ```
  9481. */
  9482. getData: function () {
  9483. if (this.type == 'element') return ''
  9484. return this.data
  9485. },
  9486. /**
  9487. * 获取当前节点下的第一个子节点
  9488. * @method firstChild
  9489. * @return { UE.uNode } 返回第一个子节点
  9490. * @example
  9491. * ```javascript
  9492. * node.firstChild(); //返回第一个子节点
  9493. * ```
  9494. */
  9495. firstChild: function () {
  9496. // if (this.type != 'element' || dtd.$empty[this.tagName]) {
  9497. // return this;
  9498. // }
  9499. return this.children ? this.children[0] : null
  9500. },
  9501. /**
  9502. * 获取当前节点下的最后一个子节点
  9503. * @method lastChild
  9504. * @return { UE.uNode } 返回最后一个子节点
  9505. * @example
  9506. * ```javascript
  9507. * node.lastChild(); //返回最后一个子节点
  9508. * ```
  9509. */
  9510. lastChild: function () {
  9511. // if (this.type != 'element' || dtd.$empty[this.tagName] ) {
  9512. // return this;
  9513. // }
  9514. return this.children ? this.children[this.children.length - 1] : null
  9515. },
  9516. /**
  9517. * 获取和当前节点有相同父亲节点的前一个节点
  9518. * @method previousSibling
  9519. * @return { UE.uNode } 返回前一个节点
  9520. * @example
  9521. * ```javascript
  9522. * node.children[2].previousSibling(); //返回子节点node.children[1]
  9523. * ```
  9524. */
  9525. previousSibling: function () {
  9526. var parent = this.parentNode
  9527. for (var i = 0, ci; (ci = parent.children[i]); i++) {
  9528. if (ci === this) {
  9529. return i == 0 ? null : parent.children[i - 1]
  9530. }
  9531. }
  9532. },
  9533. /**
  9534. * 获取和当前节点有相同父亲节点的后一个节点
  9535. * @method nextSibling
  9536. * @return { UE.uNode } 返回后一个节点,找不到返回null
  9537. * @example
  9538. * ```javascript
  9539. * node.children[2].nextSibling(); //如果有,返回子节点node.children[3]
  9540. * ```
  9541. */
  9542. nextSibling: function () {
  9543. var parent = this.parentNode
  9544. for (var i = 0, ci; (ci = parent.children[i++]); ) {
  9545. if (ci === this) {
  9546. return parent.children[i]
  9547. }
  9548. }
  9549. },
  9550. /**
  9551. * 用新的节点替换当前节点
  9552. * @method replaceChild
  9553. * @param { UE.uNode } target 要替换成该节点参数
  9554. * @param { UE.uNode } source 要被替换掉的节点
  9555. * @return { UE.uNode } 返回替换之后的节点对象
  9556. * @example
  9557. * ```javascript
  9558. * node.replaceChild(newNode, childNode); //用newNode替换childNode,childNode是node的子节点
  9559. * ```
  9560. */
  9561. replaceChild: function (target, source) {
  9562. if (this.children) {
  9563. if (target.parentNode) {
  9564. target.parentNode.removeChild(target)
  9565. }
  9566. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9567. if (ci === source) {
  9568. this.children.splice(i, 1, target)
  9569. source.parentNode = null
  9570. target.parentNode = this
  9571. return target
  9572. }
  9573. }
  9574. }
  9575. },
  9576. /**
  9577. * 在节点的子节点列表最后位置插入一个节点
  9578. * @method appendChild
  9579. * @param { UE.uNode } node 要插入的节点
  9580. * @return { UE.uNode } 返回刚插入的子节点
  9581. * @example
  9582. * ```javascript
  9583. * node.appendChild( newNode ); //在node内插入子节点newNode
  9584. * ```
  9585. */
  9586. appendChild: function (node) {
  9587. if (
  9588. this.type == 'root' ||
  9589. (this.type == 'element' && !dtd.$empty[this.tagName])
  9590. ) {
  9591. if (!this.children) {
  9592. this.children = []
  9593. }
  9594. if (node.parentNode) {
  9595. node.parentNode.removeChild(node)
  9596. }
  9597. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9598. if (ci === node) {
  9599. this.children.splice(i, 1)
  9600. break
  9601. }
  9602. }
  9603. this.children.push(node)
  9604. node.parentNode = this
  9605. return node
  9606. }
  9607. },
  9608. /**
  9609. * 在传入节点的前面插入一个节点
  9610. * @method insertBefore
  9611. * @param { UE.uNode } target 要插入的节点
  9612. * @param { UE.uNode } source 在该参数节点前面插入
  9613. * @return { UE.uNode } 返回刚插入的子节点
  9614. * @example
  9615. * ```javascript
  9616. * node.parentNode.insertBefore(newNode, node); //在node节点后面插入newNode
  9617. * ```
  9618. */
  9619. insertBefore: function (target, source) {
  9620. if (this.children) {
  9621. if (target.parentNode) {
  9622. target.parentNode.removeChild(target)
  9623. }
  9624. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9625. if (ci === source) {
  9626. this.children.splice(i, 0, target)
  9627. target.parentNode = this
  9628. return target
  9629. }
  9630. }
  9631. }
  9632. },
  9633. /**
  9634. * 在传入节点的后面插入一个节点
  9635. * @method insertAfter
  9636. * @param { UE.uNode } target 要插入的节点
  9637. * @param { UE.uNode } source 在该参数节点后面插入
  9638. * @return { UE.uNode } 返回刚插入的子节点
  9639. * @example
  9640. * ```javascript
  9641. * node.parentNode.insertAfter(newNode, node); //在node节点后面插入newNode
  9642. * ```
  9643. */
  9644. insertAfter: function (target, source) {
  9645. if (this.children) {
  9646. if (target.parentNode) {
  9647. target.parentNode.removeChild(target)
  9648. }
  9649. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9650. if (ci === source) {
  9651. this.children.splice(i + 1, 0, target)
  9652. target.parentNode = this
  9653. return target
  9654. }
  9655. }
  9656. }
  9657. },
  9658. /**
  9659. * 从当前节点的子节点列表中,移除节点
  9660. * @method removeChild
  9661. * @param { UE.uNode } node 要移除的节点引用
  9662. * @param { Boolean } keepChildren 是否保留移除节点的子节点,若传入true,自动把移除节点的子节点插入到移除的位置
  9663. * @return { * } 返回刚移除的子节点
  9664. * @example
  9665. * ```javascript
  9666. * node.removeChild(childNode,true); //在node的子节点列表中移除child节点,并且吧child的子节点插入到移除的位置
  9667. * ```
  9668. */
  9669. removeChild: function (node, keepChildren) {
  9670. if (this.children) {
  9671. for (var i = 0, ci; (ci = this.children[i]); i++) {
  9672. if (ci === node) {
  9673. this.children.splice(i, 1)
  9674. ci.parentNode = null
  9675. if (keepChildren && ci.children && ci.children.length) {
  9676. for (var j = 0, cj; (cj = ci.children[j]); j++) {
  9677. this.children.splice(i + j, 0, cj)
  9678. cj.parentNode = this
  9679. }
  9680. }
  9681. return ci
  9682. }
  9683. }
  9684. }
  9685. },
  9686. /**
  9687. * 获取当前节点所代表的元素属性,即获取attrs对象下的属性值
  9688. * @method getAttr
  9689. * @param { String } attrName 要获取的属性名称
  9690. * @return { * } 返回attrs对象下的属性值
  9691. * @example
  9692. * ```javascript
  9693. * node.getAttr('title');
  9694. * ```
  9695. */
  9696. getAttr: function (attrName) {
  9697. return this.attrs && this.attrs[attrName.toLowerCase()]
  9698. },
  9699. /**
  9700. * 设置当前节点所代表的元素属性,即设置attrs对象下的属性值
  9701. * @method setAttr
  9702. * @param { String } attrName 要设置的属性名称
  9703. * @param { * } attrVal 要设置的属性值,类型视设置的属性而定
  9704. * @return { * } 返回attrs对象下的属性值
  9705. * @example
  9706. * ```javascript
  9707. * node.setAttr('title','标题');
  9708. * ```
  9709. */
  9710. setAttr: function (attrName, attrVal) {
  9711. if (!attrName) {
  9712. delete this.attrs
  9713. return
  9714. }
  9715. if (!this.attrs) {
  9716. this.attrs = {}
  9717. }
  9718. if (utils.isObject(attrName)) {
  9719. for (var a in attrName) {
  9720. if (!attrName[a]) {
  9721. delete this.attrs[a]
  9722. } else {
  9723. this.attrs[a.toLowerCase()] = attrName[a]
  9724. }
  9725. }
  9726. } else {
  9727. if (!attrVal) {
  9728. delete this.attrs[attrName]
  9729. } else {
  9730. this.attrs[attrName.toLowerCase()] = attrVal
  9731. }
  9732. }
  9733. },
  9734. /**
  9735. * 获取当前节点在父节点下的位置索引
  9736. * @method getIndex
  9737. * @return { Number } 返回索引数值,如果没有父节点,返回-1
  9738. * @example
  9739. * ```javascript
  9740. * node.getIndex();
  9741. * ```
  9742. */
  9743. getIndex: function () {
  9744. var parent = this.parentNode
  9745. for (var i = 0, ci; (ci = parent.children[i]); i++) {
  9746. if (ci === this) {
  9747. return i
  9748. }
  9749. }
  9750. return -1
  9751. },
  9752. /**
  9753. * 在当前节点下,根据id查找节点
  9754. * @method getNodeById
  9755. * @param { String } id 要查找的id
  9756. * @return { UE.uNode } 返回找到的节点
  9757. * @example
  9758. * ```javascript
  9759. * node.getNodeById('textId');
  9760. * ```
  9761. */
  9762. getNodeById: function (id) {
  9763. var node
  9764. if (this.children && this.children.length) {
  9765. for (var i = 0, ci; (ci = this.children[i++]); ) {
  9766. if ((node = getNodeById(ci, id))) {
  9767. return node
  9768. }
  9769. }
  9770. }
  9771. },
  9772. /**
  9773. * 在当前节点下,根据元素名称查找节点列表
  9774. * @method getNodesByTagName
  9775. * @param { String } tagNames 要查找的元素名称
  9776. * @return { Array } 返回找到的节点列表
  9777. * @example
  9778. * ```javascript
  9779. * node.getNodesByTagName('span');
  9780. * ```
  9781. */
  9782. getNodesByTagName: function (tagNames) {
  9783. tagNames = utils
  9784. .trim(tagNames)
  9785. .replace(/[ ]{2,}/g, ' ')
  9786. .split(' ')
  9787. var arr = [],
  9788. me = this
  9789. utils.each(tagNames, function (tagName) {
  9790. if (me.children && me.children.length) {
  9791. for (var i = 0, ci; (ci = me.children[i++]); ) {
  9792. getNodesByTagName(ci, tagName, arr)
  9793. }
  9794. }
  9795. })
  9796. return arr
  9797. },
  9798. /**
  9799. * 根据样式名称,获取节点的样式值
  9800. * @method getStyle
  9801. * @param { String } name 要获取的样式名称
  9802. * @return { String } 返回样式值
  9803. * @example
  9804. * ```javascript
  9805. * node.getStyle('font-size');
  9806. * ```
  9807. */
  9808. getStyle: function (name) {
  9809. var cssStyle = this.getAttr('style')
  9810. if (!cssStyle) {
  9811. return ''
  9812. }
  9813. var reg = new RegExp('(^|;)\\s*' + name + ':([^;]+)', 'i')
  9814. var match = cssStyle.match(reg)
  9815. if (match && match[0]) {
  9816. return match[2]
  9817. }
  9818. return ''
  9819. },
  9820. /**
  9821. * 给节点设置样式
  9822. * @method setStyle
  9823. * @param { String } name 要设置的的样式名称
  9824. * @param { String } val 要设置的的样值
  9825. * @example
  9826. * ```javascript
  9827. * node.setStyle('font-size', '12px');
  9828. * ```
  9829. */
  9830. setStyle: function (name, val) {
  9831. function exec(name, val) {
  9832. var reg = new RegExp('(^|;)\\s*' + name + ':([^;]+;?)', 'gi')
  9833. cssStyle = cssStyle.replace(reg, '$1')
  9834. if (val) {
  9835. cssStyle = name + ':' + utils.unhtml(val) + ';' + cssStyle
  9836. }
  9837. }
  9838. var cssStyle = this.getAttr('style')
  9839. if (!cssStyle) {
  9840. cssStyle = ''
  9841. }
  9842. if (utils.isObject(name)) {
  9843. for (var a in name) {
  9844. exec(a, name[a])
  9845. }
  9846. } else {
  9847. exec(name, val)
  9848. }
  9849. this.setAttr('style', utils.trim(cssStyle))
  9850. },
  9851. /**
  9852. * 传入一个函数,递归遍历当前节点下的所有节点
  9853. * @method traversal
  9854. * @param { Function } fn 遍历到节点的时,传入节点作为参数,运行此函数
  9855. * @example
  9856. * ```javascript
  9857. * traversal(node, function(){
  9858. * console.log(node.type);
  9859. * });
  9860. * ```
  9861. */
  9862. traversal: function (fn) {
  9863. if (this.children && this.children.length) {
  9864. nodeTraversal(this, fn)
  9865. }
  9866. return this
  9867. },
  9868. }
  9869. })()
  9870. // core/htmlparser.js
  9871. /**
  9872. * html字符串转换成uNode节点
  9873. * @file
  9874. * @module UE
  9875. * @since 1.2.6.1
  9876. */
  9877. /**
  9878. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  9879. * @unfile
  9880. * @module UE
  9881. */
  9882. /**
  9883. * html字符串转换成uNode节点的静态方法
  9884. * @method htmlparser
  9885. * @param { String } htmlstr 要转换的html代码
  9886. * @param { Boolean } ignoreBlank 若设置为true,转换的时候忽略\n\r\t等空白字符
  9887. * @return { uNode } 给定的html片段转换形成的uNode对象
  9888. * @example
  9889. * ```javascript
  9890. * var root = UE.htmlparser('<p><b>htmlparser</b></p>', true);
  9891. * ```
  9892. */
  9893. var htmlparser = (UE.htmlparser = function (htmlstr, ignoreBlank) {
  9894. //todo 原来的方式 [^"'<>\/] 有\/就不能配对上 <TD vAlign=top background=../AAA.JPG> 这样的标签了
  9895. //先去掉了,加上的原因忘了,这里先记录
  9896. var re_tag =
  9897. /<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\s\/<>]+)\s*((?:(?:"[^"]*")|(?:'[^']*')|[^"'<>])*)\/?>))/g,
  9898. re_attr =
  9899. /([\w\-:.]+)(?:(?:\s*=\s*(?:(?:"([^"]*)")|(?:'([^']*)')|([^\s>]+)))|(?=\s|$))/g
  9900. //ie下取得的html可能会有\n存在,要去掉,在处理replace(/[\t\r\n]*/g,'');代码高量的\n不能去除
  9901. var allowEmptyTags = {
  9902. b: 1,
  9903. code: 1,
  9904. i: 1,
  9905. u: 1,
  9906. strike: 1,
  9907. s: 1,
  9908. tt: 1,
  9909. strong: 1,
  9910. q: 1,
  9911. samp: 1,
  9912. em: 1,
  9913. span: 1,
  9914. sub: 1,
  9915. img: 1,
  9916. sup: 1,
  9917. font: 1,
  9918. big: 1,
  9919. small: 1,
  9920. iframe: 1,
  9921. a: 1,
  9922. br: 1,
  9923. pre: 1,
  9924. }
  9925. htmlstr = htmlstr.replace(new RegExp(domUtils.fillChar, 'g'), '')
  9926. if (!ignoreBlank) {
  9927. htmlstr = htmlstr.replace(
  9928. new RegExp(
  9929. '[\\r\\t\\n' +
  9930. (ignoreBlank ? '' : ' ') +
  9931. ']*</?(\\w+)\\s*(?:[^>]*)>[\\r\\t\\n' +
  9932. (ignoreBlank ? '' : ' ') +
  9933. ']*',
  9934. 'g'
  9935. ),
  9936. function (a, b) {
  9937. //br暂时单独处理
  9938. if (b && allowEmptyTags[b.toLowerCase()]) {
  9939. return a.replace(/(^[\n\r]+)|([\n\r]+$)/g, '')
  9940. }
  9941. return a
  9942. .replace(
  9943. new RegExp('^[\\r\\n' + (ignoreBlank ? '' : ' ') + ']+'),
  9944. ''
  9945. )
  9946. .replace(
  9947. new RegExp('[\\r\\n' + (ignoreBlank ? '' : ' ') + ']+$'),
  9948. ''
  9949. )
  9950. }
  9951. )
  9952. }
  9953. var notTransAttrs = {
  9954. href: 1,
  9955. src: 1,
  9956. }
  9957. var uNode = UE.uNode,
  9958. needParentNode = {
  9959. td: 'tr',
  9960. tr: ['tbody', 'thead', 'tfoot'],
  9961. tbody: 'table',
  9962. th: 'tr',
  9963. thead: 'table',
  9964. tfoot: 'table',
  9965. caption: 'table',
  9966. li: ['ul', 'ol'],
  9967. dt: 'dl',
  9968. dd: 'dl',
  9969. option: 'select',
  9970. },
  9971. needChild = {
  9972. ol: 'li',
  9973. ul: 'li',
  9974. }
  9975. function text(parent, data) {
  9976. if (needChild[parent.tagName]) {
  9977. var tmpNode = uNode.createElement(needChild[parent.tagName])
  9978. parent.appendChild(tmpNode)
  9979. tmpNode.appendChild(uNode.createText(data))
  9980. parent = tmpNode
  9981. } else {
  9982. parent.appendChild(uNode.createText(data))
  9983. }
  9984. }
  9985. function element(parent, tagName, htmlattr) {
  9986. var needParentTag
  9987. if ((needParentTag = needParentNode[tagName])) {
  9988. var tmpParent = parent,
  9989. hasParent
  9990. while (tmpParent.type != 'root') {
  9991. if (
  9992. utils.isArray(needParentTag)
  9993. ? utils.indexOf(needParentTag, tmpParent.tagName) != -1
  9994. : needParentTag == tmpParent.tagName
  9995. ) {
  9996. parent = tmpParent
  9997. hasParent = true
  9998. break
  9999. }
  10000. tmpParent = tmpParent.parentNode
  10001. }
  10002. if (!hasParent) {
  10003. parent = element(
  10004. parent,
  10005. utils.isArray(needParentTag) ? needParentTag[0] : needParentTag
  10006. )
  10007. }
  10008. }
  10009. //按dtd处理嵌套
  10010. // if(parent.type != 'root' && !dtd[parent.tagName][tagName])
  10011. // parent = parent.parentNode;
  10012. var elm = new uNode({
  10013. parentNode: parent,
  10014. type: 'element',
  10015. tagName: tagName.toLowerCase(),
  10016. //是自闭合的处理一下
  10017. children: dtd.$empty[tagName] ? null : [],
  10018. })
  10019. //如果属性存在,处理属性
  10020. if (htmlattr) {
  10021. var attrs = {},
  10022. match
  10023. while ((match = re_attr.exec(htmlattr))) {
  10024. attrs[match[1].toLowerCase()] = notTransAttrs[match[1].toLowerCase()]
  10025. ? match[2] || match[3] || match[4]
  10026. : utils.unhtml(match[2] || match[3] || match[4])
  10027. }
  10028. elm.attrs = attrs
  10029. }
  10030. //trace:3970
  10031. // //如果parent下不能放elm
  10032. // if(dtd.$inline[parent.tagName] && dtd.$block[elm.tagName] && !dtd[parent.tagName][elm.tagName]){
  10033. // parent = parent.parentNode;
  10034. // elm.parentNode = parent;
  10035. // }
  10036. parent.children.push(elm)
  10037. //如果是自闭合节点返回父亲节点
  10038. return dtd.$empty[tagName] ? parent : elm
  10039. }
  10040. function comment(parent, data) {
  10041. parent.children.push(
  10042. new uNode({
  10043. type: 'comment',
  10044. data: data,
  10045. parentNode: parent,
  10046. })
  10047. )
  10048. }
  10049. var match,
  10050. currentIndex = 0,
  10051. nextIndex = 0
  10052. //设置根节点
  10053. var root = new uNode({
  10054. type: 'root',
  10055. children: [],
  10056. })
  10057. var currentParent = root
  10058. while ((match = re_tag.exec(htmlstr))) {
  10059. currentIndex = match.index
  10060. try {
  10061. if (currentIndex > nextIndex) {
  10062. //text node
  10063. text(currentParent, htmlstr.slice(nextIndex, currentIndex))
  10064. }
  10065. if (match[3]) {
  10066. if (dtd.$cdata[currentParent.tagName]) {
  10067. text(currentParent, match[0])
  10068. } else {
  10069. //start tag
  10070. currentParent = element(
  10071. currentParent,
  10072. match[3].toLowerCase(),
  10073. match[4]
  10074. )
  10075. }
  10076. } else if (match[1]) {
  10077. if (currentParent.type != 'root') {
  10078. if (dtd.$cdata[currentParent.tagName] && !dtd.$cdata[match[1]]) {
  10079. text(currentParent, match[0])
  10080. } else {
  10081. var tmpParent = currentParent
  10082. while (
  10083. currentParent.type == 'element' &&
  10084. currentParent.tagName != match[1].toLowerCase()
  10085. ) {
  10086. currentParent = currentParent.parentNode
  10087. if (currentParent.type == 'root') {
  10088. currentParent = tmpParent
  10089. throw 'break'
  10090. }
  10091. }
  10092. //end tag
  10093. currentParent = currentParent.parentNode
  10094. }
  10095. }
  10096. } else if (match[2]) {
  10097. //comment
  10098. comment(currentParent, match[2])
  10099. }
  10100. } catch (e) {}
  10101. nextIndex = re_tag.lastIndex
  10102. }
  10103. //如果结束是文本,就有可能丢掉,所以这里手动判断一下
  10104. //例如 <li>sdfsdfsdf<li>sdfsdfsdfsdf
  10105. if (nextIndex < htmlstr.length) {
  10106. text(currentParent, htmlstr.slice(nextIndex))
  10107. }
  10108. return root
  10109. })
  10110. // core/filternode.js
  10111. /**
  10112. * UE过滤节点的静态方法
  10113. * @file
  10114. */
  10115. /**
  10116. * UEditor公用空间,UEditor所有的功能都挂载在该空间下
  10117. * @module UE
  10118. */
  10119. /**
  10120. * 根据传入节点和过滤规则过滤相应节点
  10121. * @module UE
  10122. * @since 1.2.6.1
  10123. * @method filterNode
  10124. * @param { Object } root 指定root节点
  10125. * @param { Object } rules 过滤规则json对象
  10126. * @example
  10127. * ```javascript
  10128. * UE.filterNode(root,editor.options.filterRules);
  10129. * ```
  10130. */
  10131. var filterNode = (UE.filterNode = (function () {
  10132. function filterNode(node, rules) {
  10133. switch (node.type) {
  10134. case 'text':
  10135. break
  10136. case 'element':
  10137. var val
  10138. if ((val = rules[node.tagName])) {
  10139. if (val === '-') {
  10140. node.parentNode.removeChild(node)
  10141. } else if (utils.isFunction(val)) {
  10142. var parentNode = node.parentNode,
  10143. index = node.getIndex()
  10144. val(node)
  10145. if (node.parentNode) {
  10146. if (node.children) {
  10147. for (var i = 0, ci; (ci = node.children[i]); ) {
  10148. filterNode(ci, rules)
  10149. if (ci.parentNode) {
  10150. i++
  10151. }
  10152. }
  10153. }
  10154. } else {
  10155. for (var i = index, ci; (ci = parentNode.children[i]); ) {
  10156. filterNode(ci, rules)
  10157. if (ci.parentNode) {
  10158. i++
  10159. }
  10160. }
  10161. }
  10162. } else {
  10163. var attrs = val['$']
  10164. if (attrs && node.attrs) {
  10165. var tmpAttrs = {},
  10166. tmpVal
  10167. for (var a in attrs) {
  10168. tmpVal = node.getAttr(a)
  10169. //todo 只先对style单独处理
  10170. if (a == 'style' && utils.isArray(attrs[a])) {
  10171. var tmpCssStyle = []
  10172. utils.each(attrs[a], function (v) {
  10173. var tmp
  10174. if ((tmp = node.getStyle(v))) {
  10175. tmpCssStyle.push(v + ':' + tmp)
  10176. }
  10177. })
  10178. tmpVal = tmpCssStyle.join(';')
  10179. }
  10180. if (tmpVal) {
  10181. tmpAttrs[a] = tmpVal
  10182. }
  10183. }
  10184. node.attrs = tmpAttrs
  10185. }
  10186. if (node.children) {
  10187. for (var i = 0, ci; (ci = node.children[i]); ) {
  10188. filterNode(ci, rules)
  10189. if (ci.parentNode) {
  10190. i++
  10191. }
  10192. }
  10193. }
  10194. }
  10195. } else {
  10196. //如果不在名单里扣出子节点并删除该节点,cdata除外
  10197. if (dtd.$cdata[node.tagName]) {
  10198. node.parentNode.removeChild(node)
  10199. } else {
  10200. var parentNode = node.parentNode,
  10201. index = node.getIndex()
  10202. node.parentNode.removeChild(node, true)
  10203. for (var i = index, ci; (ci = parentNode.children[i]); ) {
  10204. filterNode(ci, rules)
  10205. if (ci.parentNode) {
  10206. i++
  10207. }
  10208. }
  10209. }
  10210. }
  10211. break
  10212. case 'comment':
  10213. node.parentNode.removeChild(node)
  10214. }
  10215. }
  10216. return function (root, rules) {
  10217. if (utils.isEmptyObject(rules)) {
  10218. return root
  10219. }
  10220. var val
  10221. if ((val = rules['-'])) {
  10222. utils.each(val.split(' '), function (k) {
  10223. rules[k] = '-'
  10224. })
  10225. }
  10226. for (var i = 0, ci; (ci = root.children[i]); ) {
  10227. filterNode(ci, rules)
  10228. if (ci.parentNode) {
  10229. i++
  10230. }
  10231. }
  10232. return root
  10233. }
  10234. })())
  10235. // core/plugin.js
  10236. /**
  10237. * Created with JetBrains PhpStorm.
  10238. * User: campaign
  10239. * Date: 10/8/13
  10240. * Time: 6:15 PM
  10241. * To change this template use File | Settings | File Templates.
  10242. */
  10243. UE.plugin = (function () {
  10244. var _plugins = {}
  10245. return {
  10246. register: function (pluginName, fn, oldOptionName, afterDisabled) {
  10247. if (oldOptionName && utils.isFunction(oldOptionName)) {
  10248. afterDisabled = oldOptionName
  10249. oldOptionName = null
  10250. }
  10251. _plugins[pluginName] = {
  10252. optionName: oldOptionName || pluginName,
  10253. execFn: fn,
  10254. //当插件被禁用时执行
  10255. afterDisabled: afterDisabled,
  10256. }
  10257. },
  10258. load: function (editor) {
  10259. utils.each(_plugins, function (plugin) {
  10260. var _export = plugin.execFn.call(editor)
  10261. if (editor.options[plugin.optionName] !== false) {
  10262. if (_export) {
  10263. //后边需要再做扩展
  10264. utils.each(_export, function (v, k) {
  10265. switch (k.toLowerCase()) {
  10266. case 'shortcutkey':
  10267. editor.addshortcutkey(v)
  10268. break
  10269. case 'bindevents':
  10270. utils.each(v, function (fn, eventName) {
  10271. editor.addListener(eventName, fn)
  10272. })
  10273. break
  10274. case 'bindmultievents':
  10275. utils.each(utils.isArray(v) ? v : [v], function (event) {
  10276. var types = utils.trim(event.type).split(/\s+/)
  10277. utils.each(types, function (eventName) {
  10278. editor.addListener(eventName, event.handler)
  10279. })
  10280. })
  10281. break
  10282. case 'commands':
  10283. utils.each(v, function (execFn, execName) {
  10284. editor.commands[execName] = execFn
  10285. })
  10286. break
  10287. case 'outputrule':
  10288. editor.addOutputRule(v)
  10289. break
  10290. case 'inputrule':
  10291. editor.addInputRule(v)
  10292. break
  10293. case 'defaultoptions':
  10294. editor.setOpt(v)
  10295. }
  10296. })
  10297. }
  10298. } else if (plugin.afterDisabled) {
  10299. plugin.afterDisabled.call(editor)
  10300. }
  10301. })
  10302. //向下兼容
  10303. utils.each(UE.plugins, function (plugin) {
  10304. plugin.call(editor)
  10305. })
  10306. },
  10307. run: function (pluginName, editor) {
  10308. var plugin = _plugins[pluginName]
  10309. if (plugin) {
  10310. plugin.exeFn.call(editor)
  10311. }
  10312. },
  10313. }
  10314. })()
  10315. // core/keymap.js
  10316. var keymap = (UE.keymap = {
  10317. Backspace: 8,
  10318. Tab: 9,
  10319. Enter: 13,
  10320. Shift: 16,
  10321. Control: 17,
  10322. Alt: 18,
  10323. CapsLock: 20,
  10324. Esc: 27,
  10325. Spacebar: 32,
  10326. PageUp: 33,
  10327. PageDown: 34,
  10328. End: 35,
  10329. Home: 36,
  10330. Left: 37,
  10331. Up: 38,
  10332. Right: 39,
  10333. Down: 40,
  10334. Insert: 45,
  10335. Del: 46,
  10336. NumLock: 144,
  10337. Cmd: 91,
  10338. '=': 187,
  10339. '-': 189,
  10340. b: 66,
  10341. i: 73,
  10342. //回退
  10343. z: 90,
  10344. y: 89,
  10345. //粘贴
  10346. v: 86,
  10347. x: 88,
  10348. s: 83,
  10349. n: 78,
  10350. })
  10351. // core/localstorage.js
  10352. //存储媒介封装
  10353. var LocalStorage = (UE.LocalStorage = (function () {
  10354. var storage = window.localStorage || getUserData() || null,
  10355. LOCAL_FILE = 'localStorage'
  10356. return {
  10357. saveLocalData: function (key, data) {
  10358. if (storage && data) {
  10359. storage.setItem(key, data)
  10360. return true
  10361. }
  10362. return false
  10363. },
  10364. getLocalData: function (key) {
  10365. if (storage) {
  10366. return storage.getItem(key)
  10367. }
  10368. return null
  10369. },
  10370. removeItem: function (key) {
  10371. storage && storage.removeItem(key)
  10372. },
  10373. }
  10374. function getUserData() {
  10375. var container = document.createElement('div')
  10376. container.style.display = 'none'
  10377. if (!container.addBehavior) {
  10378. return null
  10379. }
  10380. container.addBehavior('#default#userdata')
  10381. return {
  10382. getItem: function (key) {
  10383. var result = null
  10384. try {
  10385. document.body.appendChild(container)
  10386. container.load(LOCAL_FILE)
  10387. result = container.getAttribute(key)
  10388. document.body.removeChild(container)
  10389. } catch (e) {}
  10390. return result
  10391. },
  10392. setItem: function (key, value) {
  10393. document.body.appendChild(container)
  10394. container.setAttribute(key, value)
  10395. container.save(LOCAL_FILE)
  10396. document.body.removeChild(container)
  10397. },
  10398. //// 暂时没有用到
  10399. //clear: function () {
  10400. //
  10401. // var expiresTime = new Date();
  10402. // expiresTime.setFullYear(expiresTime.getFullYear() - 1);
  10403. // document.body.appendChild(container);
  10404. // container.expires = expiresTime.toUTCString();
  10405. // container.save(LOCAL_FILE);
  10406. // document.body.removeChild(container);
  10407. //
  10408. //},
  10409. removeItem: function (key) {
  10410. document.body.appendChild(container)
  10411. container.removeAttribute(key)
  10412. container.save(LOCAL_FILE)
  10413. document.body.removeChild(container)
  10414. },
  10415. }
  10416. }
  10417. })())
  10418. ;(function () {
  10419. var ROOTKEY = 'ueditor_preference'
  10420. UE.Editor.prototype.setPreferences = function (key, value) {
  10421. var obj = {}
  10422. if (utils.isString(key)) {
  10423. obj[key] = value
  10424. } else {
  10425. obj = key
  10426. }
  10427. var data = LocalStorage.getLocalData(ROOTKEY)
  10428. if (data && (data = utils.str2json(data))) {
  10429. utils.extend(data, obj)
  10430. } else {
  10431. data = obj
  10432. }
  10433. data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data))
  10434. }
  10435. UE.Editor.prototype.getPreferences = function (key) {
  10436. var data = LocalStorage.getLocalData(ROOTKEY)
  10437. if (data && (data = utils.str2json(data))) {
  10438. return key ? data[key] : data
  10439. }
  10440. return null
  10441. }
  10442. UE.Editor.prototype.removePreferences = function (key) {
  10443. var data = LocalStorage.getLocalData(ROOTKEY)
  10444. if (data && (data = utils.str2json(data))) {
  10445. data[key] = undefined
  10446. delete data[key]
  10447. }
  10448. data && LocalStorage.saveLocalData(ROOTKEY, utils.json2str(data))
  10449. }
  10450. })()
  10451. // plugins/defaultfilter.js
  10452. ///import core
  10453. ///plugin 编辑器默认的过滤转换机制
  10454. UE.plugins['defaultfilter'] = function () {
  10455. //return //导入word时新增return
  10456. var me = this
  10457. me.setOpt({
  10458. allowDivTransToP: true,
  10459. disabledTableInTable: true,
  10460. })
  10461. //默认的过滤处理
  10462. //进入编辑器的内容处理
  10463. me.addInputRule(function (root) {
  10464. var allowDivTransToP = this.options.allowDivTransToP
  10465. var val
  10466. function tdParent(node) {
  10467. while (node && node.type == 'element') {
  10468. if (node.tagName == 'td') {
  10469. return true
  10470. }
  10471. node = node.parentNode
  10472. }
  10473. return false
  10474. }
  10475. //进行默认的处理
  10476. root.traversal(function (node) {
  10477. if (node.type == 'element') {
  10478. if (
  10479. !dtd.$cdata[node.tagName] &&
  10480. me.options.autoClearEmptyNode &&
  10481. dtd.$inline[node.tagName] &&
  10482. !dtd.$empty[node.tagName] &&
  10483. (!node.attrs || utils.isEmptyObject(node.attrs))
  10484. ) {
  10485. if (!node.firstChild()) node.parentNode.removeChild(node)
  10486. else if (
  10487. node.tagName == 'span' &&
  10488. (!node.attrs || utils.isEmptyObject(node.attrs))
  10489. ) {
  10490. node.parentNode.removeChild(node, true)
  10491. }
  10492. return
  10493. }
  10494. switch (node.tagName) {
  10495. case 'style':
  10496. case 'script':
  10497. node.setAttr({
  10498. cdata_tag: node.tagName,
  10499. cdata_data: node.innerHTML() || '',
  10500. _ue_custom_node_: 'true',
  10501. })
  10502. node.tagName = 'div'
  10503. node.innerHTML('')
  10504. break
  10505. case 'a':
  10506. if ((val = node.getAttr('href'))) {
  10507. node.setAttr('_href', val)
  10508. }
  10509. break
  10510. case 'img':
  10511. //todo base64暂时去掉,后边做远程图片上传后,干掉这个
  10512. if ((val = node.getAttr('src'))) {
  10513. if (/^data:/.test(val)) {
  10514. node.parentNode.removeChild(node)
  10515. break
  10516. }
  10517. }
  10518. node.setAttr('_src', node.getAttr('src'))
  10519. break
  10520. case 'span':
  10521. if (browser.webkit && (val = node.getStyle('white-space'))) {
  10522. if (/nowrap|normal/.test(val)) {
  10523. node.setStyle('white-space', '')
  10524. if (
  10525. me.options.autoClearEmptyNode &&
  10526. utils.isEmptyObject(node.attrs)
  10527. ) {
  10528. node.parentNode.removeChild(node, true)
  10529. }
  10530. }
  10531. }
  10532. val = node.getAttr('id')
  10533. if (val && /^_baidu_bookmark_/i.test(val)) {
  10534. node.parentNode.removeChild(node)
  10535. }
  10536. break
  10537. case 'p':
  10538. if ((val = node.getAttr('align'))) {
  10539. node.setAttr('align')
  10540. node.setStyle('text-align', val)
  10541. }
  10542. //trace:3431
  10543. // var cssStyle = node.getAttr('style');
  10544. // if (cssStyle) {
  10545. // cssStyle = cssStyle.replace(/(margin|padding)[^;]+/g, '');
  10546. // node.setAttr('style', cssStyle)
  10547. //
  10548. // }
  10549. //p标签不允许嵌套
  10550. utils.each(node.children, function (n) {
  10551. if (n.type == 'element' && n.tagName == 'p') {
  10552. var next = n.nextSibling()
  10553. node.parentNode.insertAfter(n, node)
  10554. var last = n
  10555. while (next) {
  10556. var tmp = next.nextSibling()
  10557. node.parentNode.insertAfter(next, last)
  10558. last = next
  10559. next = tmp
  10560. }
  10561. return false
  10562. }
  10563. })
  10564. if (!node.firstChild()) {
  10565. node.innerHTML(browser.ie ? '&nbsp;' : '<br/>')
  10566. }
  10567. break
  10568. case 'div':
  10569. if (node.getAttr('cdata_tag')) {
  10570. break
  10571. }
  10572. //针对代码这里不处理插入代码的div
  10573. val = node.getAttr('class')
  10574. if (val && /^line number\d+/.test(val)) {
  10575. break
  10576. }
  10577. if (!allowDivTransToP) {
  10578. break
  10579. }
  10580. var tmpNode,
  10581. p = UE.uNode.createElement('p')
  10582. while ((tmpNode = node.firstChild())) {
  10583. if (
  10584. tmpNode.type == 'text' ||
  10585. !UE.dom.dtd.$block[tmpNode.tagName]
  10586. ) {
  10587. p.appendChild(tmpNode)
  10588. } else {
  10589. if (p.firstChild()) {
  10590. node.parentNode.insertBefore(p, node)
  10591. p = UE.uNode.createElement('p')
  10592. } else {
  10593. node.parentNode.insertBefore(tmpNode, node)
  10594. }
  10595. }
  10596. }
  10597. if (p.firstChild()) {
  10598. node.parentNode.insertBefore(p, node)
  10599. }
  10600. node.parentNode.removeChild(node)
  10601. break
  10602. case 'dl':
  10603. node.tagName = 'ul'
  10604. break
  10605. case 'dt':
  10606. case 'dd':
  10607. node.tagName = 'li'
  10608. break
  10609. case 'li':
  10610. var className = node.getAttr('class')
  10611. if (!className || !/list\-/.test(className)) {
  10612. node.setAttr()
  10613. }
  10614. var tmpNodes = node.getNodesByTagName('ol ul')
  10615. UE.utils.each(tmpNodes, function (n) {
  10616. node.parentNode.insertAfter(n, node)
  10617. })
  10618. break
  10619. case 'td':
  10620. case 'th':
  10621. case 'caption':
  10622. if (!node.children || !node.children.length) {
  10623. node.appendChild(
  10624. browser.ie11below
  10625. ? UE.uNode.createText(' ')
  10626. : UE.uNode.createElement('br')
  10627. )
  10628. }
  10629. break
  10630. case 'table':
  10631. if (me.options.disabledTableInTable && tdParent(node)) {
  10632. node.parentNode.insertBefore(
  10633. UE.uNode.createText(node.innerText()),
  10634. node
  10635. )
  10636. node.parentNode.removeChild(node)
  10637. }
  10638. }
  10639. }
  10640. // if(node.type == 'comment'){
  10641. // node.parentNode.removeChild(node);
  10642. // }
  10643. })
  10644. })
  10645. //从编辑器出去的内容处理
  10646. me.addOutputRule(function (root) {
  10647. var val
  10648. root.traversal(function (node) {
  10649. if (node.type == 'element') {
  10650. if (
  10651. me.options.autoClearEmptyNode &&
  10652. dtd.$inline[node.tagName] &&
  10653. !dtd.$empty[node.tagName] &&
  10654. (!node.attrs || utils.isEmptyObject(node.attrs))
  10655. ) {
  10656. if (!node.firstChild()) node.parentNode.removeChild(node)
  10657. else if (
  10658. node.tagName == 'span' &&
  10659. (!node.attrs || utils.isEmptyObject(node.attrs))
  10660. ) {
  10661. node.parentNode.removeChild(node, true)
  10662. }
  10663. return
  10664. }
  10665. switch (node.tagName) {
  10666. case 'div':
  10667. if ((val = node.getAttr('cdata_tag'))) {
  10668. node.tagName = val
  10669. node.appendChild(
  10670. UE.uNode.createText(node.getAttr('cdata_data'))
  10671. )
  10672. node.setAttr({
  10673. cdata_tag: '',
  10674. cdata_data: '',
  10675. _ue_custom_node_: '',
  10676. })
  10677. }
  10678. break
  10679. case 'a':
  10680. if ((val = node.getAttr('_href'))) {
  10681. node.setAttr({
  10682. href: utils.html(val),
  10683. _href: '',
  10684. })
  10685. }
  10686. break
  10687. break
  10688. case 'span':
  10689. val = node.getAttr('id')
  10690. if (val && /^_baidu_bookmark_/i.test(val)) {
  10691. node.parentNode.removeChild(node)
  10692. }
  10693. break
  10694. case 'img':
  10695. if ((val = node.getAttr('_src'))) {
  10696. node.setAttr({
  10697. src: node.getAttr('_src'),
  10698. _src: '',
  10699. })
  10700. }
  10701. }
  10702. }
  10703. })
  10704. })
  10705. }
  10706. // plugins/inserthtml.js
  10707. /**
  10708. * 插入html字符串插件
  10709. * @file
  10710. * @since 1.2.6.1
  10711. */
  10712. /**
  10713. * 插入html代码
  10714. * @command inserthtml
  10715. * @method execCommand
  10716. * @param { String } cmd 命令字符串
  10717. * @param { String } html 插入的html字符串
  10718. * @remaind 插入的标签内容是在当前的选区位置上插入,如果当前是闭合状态,那直接插入内容, 如果当前是选中状态,将先清除当前选中内容后,再做插入
  10719. * @warning 注意:该命令会对当前选区的位置,对插入的内容进行过滤转换处理。 过滤的规则遵循html语意化的原则。
  10720. * @example
  10721. * ```javascript
  10722. * //xxx[BB]xxx 当前选区为非闭合选区,选中BB这两个文本
  10723. * //执行命令,插入<b>CC</b>
  10724. * //插入后的效果 xxx<b>CC</b>xxx
  10725. * //<p>xx|xxx</p> 当前选区为闭合状态
  10726. * //插入<p>CC</p>
  10727. * //结果 <p>xx</p><p>CC</p><p>xxx</p>
  10728. * //<p>xxxx</p>|</p>xxx</p> 当前选区在两个p标签之间
  10729. * //插入 xxxx
  10730. * //结果 <p>xxxx</p><p>xxxx</p></p>xxx</p>
  10731. * ```
  10732. */
  10733. UE.commands['inserthtml'] = {
  10734. execCommand: function (command, html, notNeedFilter) {
  10735. var me = this,
  10736. range,
  10737. div
  10738. if (!html) {
  10739. return
  10740. }
  10741. if (me.fireEvent('beforeinserthtml', html) === true) {
  10742. return
  10743. }
  10744. range = me.selection.getRange()
  10745. div = range.document.createElement('div')
  10746. div.style.display = 'inline'
  10747. if (!notNeedFilter) {
  10748. var root = UE.htmlparser(html)
  10749. //如果给了过滤规则就先进行过滤
  10750. if (me.options.filterRules) {
  10751. UE.filterNode(root, me.options.filterRules)
  10752. }
  10753. //执行默认的处理
  10754. me.filterInputRule(root)
  10755. html = root.toHtml()
  10756. }
  10757. div.innerHTML = utils.trim(html)
  10758. if (!range.collapsed) {
  10759. var tmpNode = range.startContainer
  10760. if (domUtils.isFillChar(tmpNode)) {
  10761. range.setStartBefore(tmpNode)
  10762. }
  10763. tmpNode = range.endContainer
  10764. if (domUtils.isFillChar(tmpNode)) {
  10765. range.setEndAfter(tmpNode)
  10766. }
  10767. range.txtToElmBoundary()
  10768. //结束边界可能放到了br的前边,要把br包含进来
  10769. // x[xxx]<br/>
  10770. if (range.endContainer && range.endContainer.nodeType == 1) {
  10771. tmpNode = range.endContainer.childNodes[range.endOffset]
  10772. if (tmpNode && domUtils.isBr(tmpNode)) {
  10773. range.setEndAfter(tmpNode)
  10774. }
  10775. }
  10776. if (range.startOffset == 0) {
  10777. tmpNode = range.startContainer
  10778. if (domUtils.isBoundaryNode(tmpNode, 'firstChild')) {
  10779. tmpNode = range.endContainer
  10780. if (
  10781. range.endOffset ==
  10782. (tmpNode.nodeType == 3
  10783. ? tmpNode.nodeValue.length
  10784. : tmpNode.childNodes.length) &&
  10785. domUtils.isBoundaryNode(tmpNode, 'lastChild')
  10786. ) {
  10787. me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>'
  10788. range.setStart(me.body.firstChild, 0).collapse(true)
  10789. }
  10790. }
  10791. }
  10792. !range.collapsed && range.deleteContents()
  10793. if (range.startContainer.nodeType == 1) {
  10794. var child = range.startContainer.childNodes[range.startOffset],
  10795. pre
  10796. if (
  10797. child &&
  10798. domUtils.isBlockElm(child) &&
  10799. (pre = child.previousSibling) &&
  10800. domUtils.isBlockElm(pre)
  10801. ) {
  10802. range.setEnd(pre, pre.childNodes.length).collapse()
  10803. while (child.firstChild) {
  10804. pre.appendChild(child.firstChild)
  10805. }
  10806. domUtils.remove(child)
  10807. }
  10808. }
  10809. }
  10810. var child,
  10811. parent,
  10812. pre,
  10813. tmp,
  10814. hadBreak = 0,
  10815. nextNode
  10816. //如果当前位置选中了fillchar要干掉,要不会产生空行
  10817. if (range.inFillChar()) {
  10818. child = range.startContainer
  10819. if (domUtils.isFillChar(child)) {
  10820. range.setStartBefore(child).collapse(true)
  10821. domUtils.remove(child)
  10822. } else if (domUtils.isFillChar(child, true)) {
  10823. child.nodeValue = child.nodeValue.replace(fillCharReg, '')
  10824. range.startOffset--
  10825. range.collapsed && range.collapse(true)
  10826. }
  10827. }
  10828. //列表单独处理
  10829. var li = domUtils.findParentByTagName(range.startContainer, 'li', true)
  10830. if (li) {
  10831. var next, last
  10832. while ((child = div.firstChild)) {
  10833. //针对hr单独处理一下先
  10834. while (
  10835. child &&
  10836. (child.nodeType == 3 ||
  10837. !domUtils.isBlockElm(child) ||
  10838. child.tagName == 'HR')
  10839. ) {
  10840. next = child.nextSibling
  10841. range.insertNode(child).collapse()
  10842. last = child
  10843. child = next
  10844. }
  10845. if (child) {
  10846. if (/^(ol|ul)$/i.test(child.tagName)) {
  10847. while (child.firstChild) {
  10848. last = child.firstChild
  10849. domUtils.insertAfter(li, child.firstChild)
  10850. li = li.nextSibling
  10851. }
  10852. domUtils.remove(child)
  10853. } else {
  10854. var tmpLi
  10855. next = child.nextSibling
  10856. tmpLi = me.document.createElement('li')
  10857. domUtils.insertAfter(li, tmpLi)
  10858. tmpLi.appendChild(child)
  10859. last = child
  10860. child = next
  10861. li = tmpLi
  10862. }
  10863. }
  10864. }
  10865. li = domUtils.findParentByTagName(range.startContainer, 'li', true)
  10866. if (domUtils.isEmptyBlock(li)) {
  10867. domUtils.remove(li)
  10868. }
  10869. if (last) {
  10870. range.setStartAfter(last).collapse(true).select(true)
  10871. }
  10872. } else {
  10873. while ((child = div.firstChild)) {
  10874. if (hadBreak) {
  10875. var p = me.document.createElement('p')
  10876. while (
  10877. child &&
  10878. (child.nodeType == 3 || !dtd.$block[child.tagName])
  10879. ) {
  10880. nextNode = child.nextSibling
  10881. p.appendChild(child)
  10882. child = nextNode
  10883. }
  10884. if (p.firstChild) {
  10885. child = p
  10886. }
  10887. }
  10888. range.insertNode(child)
  10889. nextNode = child.nextSibling
  10890. if (
  10891. !hadBreak &&
  10892. child.nodeType == domUtils.NODE_ELEMENT &&
  10893. domUtils.isBlockElm(child)
  10894. ) {
  10895. parent = domUtils.findParent(child, function (node) {
  10896. return domUtils.isBlockElm(node)
  10897. })
  10898. if (
  10899. parent &&
  10900. parent.tagName.toLowerCase() != 'body' &&
  10901. !(
  10902. dtd[parent.tagName][child.nodeName] &&
  10903. child.parentNode === parent
  10904. )
  10905. ) {
  10906. if (!dtd[parent.tagName][child.nodeName]) {
  10907. pre = parent
  10908. } else {
  10909. tmp = child.parentNode
  10910. while (tmp !== parent) {
  10911. pre = tmp
  10912. tmp = tmp.parentNode
  10913. }
  10914. }
  10915. domUtils.breakParent(child, pre || tmp)
  10916. //去掉break后前一个多余的节点 <p>|<[p> ==> <p></p><div></div><p>|</p>
  10917. var pre = child.previousSibling
  10918. domUtils.trimWhiteTextNode(pre)
  10919. if (!pre.childNodes.length) {
  10920. domUtils.remove(pre)
  10921. }
  10922. //trace:2012,在非ie的情况,切开后剩下的节点有可能不能点入光标添加br占位
  10923. if (
  10924. !browser.ie &&
  10925. (next = child.nextSibling) &&
  10926. domUtils.isBlockElm(next) &&
  10927. next.lastChild &&
  10928. !domUtils.isBr(next.lastChild)
  10929. ) {
  10930. next.appendChild(me.document.createElement('br'))
  10931. }
  10932. hadBreak = 1
  10933. }
  10934. }
  10935. var next = child.nextSibling
  10936. if (!div.firstChild && next && domUtils.isBlockElm(next)) {
  10937. range.setStart(next, 0).collapse(true)
  10938. break
  10939. }
  10940. range.setEndAfter(child).collapse()
  10941. }
  10942. child = range.startContainer
  10943. if (nextNode && domUtils.isBr(nextNode)) {
  10944. domUtils.remove(nextNode)
  10945. }
  10946. //用chrome可能有空白展位符
  10947. if (domUtils.isBlockElm(child) && domUtils.isEmptyNode(child)) {
  10948. if ((nextNode = child.nextSibling)) {
  10949. domUtils.remove(child)
  10950. if (nextNode.nodeType == 1 && dtd.$block[nextNode.tagName]) {
  10951. range.setStart(nextNode, 0).collapse(true).shrinkBoundary()
  10952. }
  10953. } else {
  10954. try {
  10955. child.innerHTML = browser.ie ? domUtils.fillChar : '<br/>'
  10956. } catch (e) {
  10957. range.setStartBefore(child)
  10958. domUtils.remove(child)
  10959. }
  10960. }
  10961. }
  10962. //加上true因为在删除表情等时会删两次,第一次是删的fillData
  10963. try {
  10964. range.select(true)
  10965. } catch (e) {}
  10966. }
  10967. setTimeout(function () {
  10968. range = me.selection.getRange()
  10969. range.scrollToView(
  10970. me.autoHeightEnabled,
  10971. me.autoHeightEnabled ? domUtils.getXY(me.iframe).y : 0
  10972. )
  10973. me.fireEvent('afterinserthtml', html)
  10974. }, 200)
  10975. },
  10976. }
  10977. // plugins/autotypeset.js
  10978. /**
  10979. * 自动排版
  10980. * @file
  10981. * @since 1.2.6.1
  10982. */
  10983. /**
  10984. * 对当前编辑器的内容执行自动排版, 排版的行为根据config配置文件里的“autotypeset”选项进行控制。
  10985. * @command autotypeset
  10986. * @method execCommand
  10987. * @param { String } cmd 命令字符串
  10988. * @example
  10989. * ```javascript
  10990. * editor.execCommand( 'autotypeset' );
  10991. * ```
  10992. */
  10993. UE.plugins['autotypeset'] = function () {
  10994. this.setOpt({
  10995. autotypeset: {
  10996. mergeEmptyline: true, //合并空行
  10997. removeClass: true, //去掉冗余的class
  10998. removeEmptyline: false, //去掉空行
  10999. textAlign: 'left', //段落的排版方式,可以是 left,right,center,justify 去掉这个属性表示不执行排版
  11000. imageBlockLine: 'center', //图片的浮动方式,独占一行剧中,左右浮动,默认: center,left,right,none 去掉这个属性表示不执行排版
  11001. pasteFilter: false, //根据规则过滤没事粘贴进来的内容
  11002. clearFontSize: false, //去掉所有的内嵌字号,使用编辑器默认的字号
  11003. clearFontFamily: false, //去掉所有的内嵌字体,使用编辑器默认的字体
  11004. removeEmptyNode: false, // 去掉空节点
  11005. //可以去掉的标签
  11006. removeTagNames: utils.extend({ div: 1 }, dtd.$removeEmpty),
  11007. indent: false, // 行首缩进
  11008. indentValue: '2em', //行首缩进的大小
  11009. bdc2sb: false,
  11010. tobdc: false,
  11011. },
  11012. })
  11013. var me = this,
  11014. opt = me.options.autotypeset,
  11015. remainClass = {
  11016. selectTdClass: 1,
  11017. pagebreak: 1,
  11018. anchorclass: 1,
  11019. },
  11020. remainTag = {
  11021. li: 1,
  11022. },
  11023. tags = {
  11024. div: 1,
  11025. p: 1,
  11026. //trace:2183 这些也认为是行
  11027. blockquote: 1,
  11028. center: 1,
  11029. h1: 1,
  11030. h2: 1,
  11031. h3: 1,
  11032. h4: 1,
  11033. h5: 1,
  11034. h6: 1,
  11035. span: 1,
  11036. },
  11037. highlightCont
  11038. //升级了版本,但配置项目里没有autotypeset
  11039. if (!opt) {
  11040. return
  11041. }
  11042. readLocalOpts()
  11043. function isLine(node, notEmpty) {
  11044. if (!node || node.nodeType == 3) return 0
  11045. if (domUtils.isBr(node)) return 1
  11046. if (node && node.parentNode && tags[node.tagName.toLowerCase()]) {
  11047. if (
  11048. (highlightCont && highlightCont.contains(node)) ||
  11049. node.getAttribute('pagebreak')
  11050. ) {
  11051. return 0
  11052. }
  11053. return notEmpty
  11054. ? !domUtils.isEmptyBlock(node)
  11055. : domUtils.isEmptyBlock(
  11056. node,
  11057. new RegExp('[\\s' + domUtils.fillChar + ']', 'g')
  11058. )
  11059. }
  11060. }
  11061. function removeNotAttributeSpan(node) {
  11062. if (!node.style.cssText) {
  11063. domUtils.removeAttributes(node, ['style'])
  11064. if (
  11065. node.tagName.toLowerCase() == 'span' &&
  11066. domUtils.hasNoAttributes(node)
  11067. ) {
  11068. domUtils.remove(node, true)
  11069. }
  11070. }
  11071. }
  11072. function autotype(type, html) {
  11073. var me = this,
  11074. cont
  11075. if (html) {
  11076. if (!opt.pasteFilter) {
  11077. return
  11078. }
  11079. cont = me.document.createElement('div')
  11080. cont.innerHTML = html.html
  11081. } else {
  11082. cont = me.document.body
  11083. }
  11084. var nodes = domUtils.getElementsByTagName(cont, '*')
  11085. // 行首缩进,段落方向,段间距,段内间距
  11086. for (var i = 0, ci; (ci = nodes[i++]); ) {
  11087. if (me.fireEvent('excludeNodeinautotype', ci) === true) {
  11088. continue
  11089. }
  11090. //font-size
  11091. if (opt.clearFontSize && ci.style.fontSize) {
  11092. domUtils.removeStyle(ci, 'font-size')
  11093. removeNotAttributeSpan(ci)
  11094. }
  11095. //font-family
  11096. if (opt.clearFontFamily && ci.style.fontFamily) {
  11097. domUtils.removeStyle(ci, 'font-family')
  11098. removeNotAttributeSpan(ci)
  11099. }
  11100. if (isLine(ci)) {
  11101. //合并空行
  11102. if (opt.mergeEmptyline) {
  11103. var next = ci.nextSibling,
  11104. tmpNode,
  11105. isBr = domUtils.isBr(ci)
  11106. while (isLine(next)) {
  11107. tmpNode = next
  11108. next = tmpNode.nextSibling
  11109. if (isBr && (!next || (next && !domUtils.isBr(next)))) {
  11110. break
  11111. }
  11112. domUtils.remove(tmpNode)
  11113. }
  11114. }
  11115. //去掉空行,保留占位的空行
  11116. if (
  11117. opt.removeEmptyline &&
  11118. domUtils.inDoc(ci, cont) &&
  11119. !remainTag[ci.parentNode.tagName.toLowerCase()]
  11120. ) {
  11121. if (domUtils.isBr(ci)) {
  11122. next = ci.nextSibling
  11123. if (next && !domUtils.isBr(next)) {
  11124. continue
  11125. }
  11126. }
  11127. domUtils.remove(ci)
  11128. continue
  11129. }
  11130. }
  11131. if (isLine(ci, true) && ci.tagName != 'SPAN') {
  11132. if (opt.indent) {
  11133. ci.style.textIndent = opt.indentValue
  11134. }
  11135. if (opt.textAlign) {
  11136. ci.style.textAlign = opt.textAlign
  11137. }
  11138. // if(opt.lineHeight)
  11139. // ci.style.lineHeight = opt.lineHeight + 'cm';
  11140. }
  11141. //去掉class,保留的class不去掉
  11142. if (
  11143. opt.removeClass &&
  11144. ci.className &&
  11145. !remainClass[ci.className.toLowerCase()]
  11146. ) {
  11147. if (highlightCont && highlightCont.contains(ci)) {
  11148. continue
  11149. }
  11150. domUtils.removeAttributes(ci, ['class'])
  11151. }
  11152. //表情不处理
  11153. if (
  11154. opt.imageBlockLine &&
  11155. ci.tagName.toLowerCase() == 'img' &&
  11156. !ci.getAttribute('emotion')
  11157. ) {
  11158. if (html) {
  11159. var img = ci
  11160. switch (opt.imageBlockLine) {
  11161. case 'left':
  11162. case 'right':
  11163. case 'none':
  11164. var pN = img.parentNode,
  11165. tmpNode,
  11166. pre,
  11167. next
  11168. while (dtd.$inline[pN.tagName] || pN.tagName == 'A') {
  11169. pN = pN.parentNode
  11170. }
  11171. tmpNode = pN
  11172. if (
  11173. tmpNode.tagName == 'P' &&
  11174. domUtils.getStyle(tmpNode, 'text-align') == 'center'
  11175. ) {
  11176. if (
  11177. !domUtils.isBody(tmpNode) &&
  11178. domUtils.getChildCount(tmpNode, function (node) {
  11179. return (
  11180. !domUtils.isBr(node) && !domUtils.isWhitespace(node)
  11181. )
  11182. }) == 1
  11183. ) {
  11184. pre = tmpNode.previousSibling
  11185. next = tmpNode.nextSibling
  11186. if (
  11187. pre &&
  11188. next &&
  11189. pre.nodeType == 1 &&
  11190. next.nodeType == 1 &&
  11191. pre.tagName == next.tagName &&
  11192. domUtils.isBlockElm(pre)
  11193. ) {
  11194. pre.appendChild(tmpNode.firstChild)
  11195. while (next.firstChild) {
  11196. pre.appendChild(next.firstChild)
  11197. }
  11198. domUtils.remove(tmpNode)
  11199. domUtils.remove(next)
  11200. } else {
  11201. domUtils.setStyle(tmpNode, 'text-align', '')
  11202. }
  11203. }
  11204. }
  11205. domUtils.setStyle(img, 'float', opt.imageBlockLine)
  11206. break
  11207. case 'center':
  11208. if (me.queryCommandValue('imagefloat') != 'center') {
  11209. pN = img.parentNode
  11210. domUtils.setStyle(img, 'float', 'none')
  11211. tmpNode = img
  11212. while (
  11213. pN &&
  11214. domUtils.getChildCount(pN, function (node) {
  11215. return (
  11216. !domUtils.isBr(node) && !domUtils.isWhitespace(node)
  11217. )
  11218. }) == 1 &&
  11219. (dtd.$inline[pN.tagName] || pN.tagName == 'A')
  11220. ) {
  11221. tmpNode = pN
  11222. pN = pN.parentNode
  11223. }
  11224. var pNode = me.document.createElement('p')
  11225. domUtils.setAttributes(pNode, {
  11226. style: 'text-align:center',
  11227. })
  11228. tmpNode.parentNode.insertBefore(pNode, tmpNode)
  11229. pNode.appendChild(tmpNode)
  11230. domUtils.setStyle(tmpNode, 'float', '')
  11231. }
  11232. }
  11233. } else {
  11234. var range = me.selection.getRange()
  11235. range.selectNode(ci).select()
  11236. me.execCommand('imagefloat', opt.imageBlockLine)
  11237. }
  11238. }
  11239. //去掉冗余的标签
  11240. if (opt.removeEmptyNode) {
  11241. if (
  11242. opt.removeTagNames[ci.tagName.toLowerCase()] &&
  11243. domUtils.hasNoAttributes(ci) &&
  11244. domUtils.isEmptyBlock(ci)
  11245. ) {
  11246. domUtils.remove(ci)
  11247. }
  11248. }
  11249. }
  11250. if (opt.tobdc) {
  11251. var root = UE.htmlparser(cont.innerHTML)
  11252. root.traversal(function (node) {
  11253. if (node.type == 'text') {
  11254. node.data = ToDBC(node.data)
  11255. }
  11256. })
  11257. cont.innerHTML = root.toHtml()
  11258. }
  11259. if (opt.bdc2sb) {
  11260. var root = UE.htmlparser(cont.innerHTML)
  11261. root.traversal(function (node) {
  11262. if (node.type == 'text') {
  11263. node.data = DBC2SB(node.data)
  11264. }
  11265. })
  11266. cont.innerHTML = root.toHtml()
  11267. }
  11268. if (html) {
  11269. html.html = cont.innerHTML
  11270. }
  11271. }
  11272. if (opt.pasteFilter) {
  11273. me.addListener('beforepaste', autotype)
  11274. }
  11275. function DBC2SB(str) {
  11276. var result = ''
  11277. for (var i = 0; i < str.length; i++) {
  11278. var code = str.charCodeAt(i) //获取当前字符的unicode编码
  11279. if (code >= 65281 && code <= 65373) {
  11280. //在这个unicode编码范围中的是所有的英文字母已经各种字符
  11281. result += String.fromCharCode(str.charCodeAt(i) - 65248) //把全角字符的unicode编码转换为对应半角字符的unicode码
  11282. } else if (code == 12288) {
  11283. //空格
  11284. result += String.fromCharCode(str.charCodeAt(i) - 12288 + 32)
  11285. } else {
  11286. result += str.charAt(i)
  11287. }
  11288. }
  11289. return result
  11290. }
  11291. function ToDBC(txtstring) {
  11292. txtstring = utils.html(txtstring)
  11293. var tmp = ''
  11294. var mark = '' /*用于判断,如果是html尖括里的标记,则不进行全角的转换*/
  11295. for (var i = 0; i < txtstring.length; i++) {
  11296. if (txtstring.charCodeAt(i) == 32) {
  11297. tmp = tmp + String.fromCharCode(12288)
  11298. } else if (txtstring.charCodeAt(i) < 127) {
  11299. tmp = tmp + String.fromCharCode(txtstring.charCodeAt(i) + 65248)
  11300. } else {
  11301. tmp += txtstring.charAt(i)
  11302. }
  11303. }
  11304. return tmp
  11305. }
  11306. function readLocalOpts() {
  11307. var cookieOpt = me.getPreferences('autotypeset')
  11308. utils.extend(me.options.autotypeset, cookieOpt)
  11309. }
  11310. me.commands['autotypeset'] = {
  11311. execCommand: function () {
  11312. me.removeListener('beforepaste', autotype)
  11313. if (opt.pasteFilter) {
  11314. me.addListener('beforepaste', autotype)
  11315. }
  11316. autotype.call(me)
  11317. },
  11318. }
  11319. }
  11320. // plugins/autosubmit.js
  11321. /**
  11322. * 快捷键提交
  11323. * @file
  11324. * @since 1.2.6.1
  11325. */
  11326. /**
  11327. * 提交表单
  11328. * @command autosubmit
  11329. * @method execCommand
  11330. * @param { String } cmd 命令字符串
  11331. * @example
  11332. * ```javascript
  11333. * editor.execCommand( 'autosubmit' );
  11334. * ```
  11335. */
  11336. UE.plugin.register('autosubmit', function () {
  11337. return {
  11338. shortcutkey: {
  11339. autosubmit: 'ctrl+13', //手动提交
  11340. },
  11341. commands: {
  11342. autosubmit: {
  11343. execCommand: function () {
  11344. var me = this,
  11345. form = domUtils.findParentByTagName(me.iframe, 'form', false)
  11346. if (form) {
  11347. if (me.fireEvent('beforesubmit') === false) {
  11348. return
  11349. }
  11350. me.sync()
  11351. form.submit()
  11352. }
  11353. },
  11354. },
  11355. },
  11356. }
  11357. })
  11358. // plugins/background.js
  11359. /**
  11360. * 背景插件,为UEditor提供设置背景功能
  11361. * @file
  11362. * @since 1.2.6.1
  11363. */
  11364. UE.plugin.register('background', function () {
  11365. var me = this,
  11366. cssRuleId = 'editor_background',
  11367. isSetColored,
  11368. reg = new RegExp('body[\\s]*\\{(.+)\\}', 'i')
  11369. function stringToObj(str) {
  11370. var obj = {},
  11371. styles = str.split(';')
  11372. utils.each(styles, function (v) {
  11373. var index = v.indexOf(':'),
  11374. key = utils.trim(v.substr(0, index)).toLowerCase()
  11375. key && (obj[key] = utils.trim(v.substr(index + 1) || ''))
  11376. })
  11377. return obj
  11378. }
  11379. function setBackground(obj) {
  11380. if (obj) {
  11381. var styles = []
  11382. for (var name in obj) {
  11383. if (obj.hasOwnProperty(name)) {
  11384. styles.push(name + ':' + obj[name] + '; ')
  11385. }
  11386. }
  11387. utils.cssRule(
  11388. cssRuleId,
  11389. styles.length ? 'body{' + styles.join('') + '}' : '',
  11390. me.document
  11391. )
  11392. } else {
  11393. utils.cssRule(cssRuleId, '', me.document)
  11394. }
  11395. }
  11396. //重写editor.hasContent方法
  11397. var orgFn = me.hasContents
  11398. me.hasContents = function () {
  11399. if (me.queryCommandValue('background')) {
  11400. return true
  11401. }
  11402. return orgFn.apply(me, arguments)
  11403. }
  11404. return {
  11405. bindEvents: {
  11406. getAllHtml: function (type, headHtml) {
  11407. var body = this.body,
  11408. su = domUtils.getComputedStyle(body, 'background-image'),
  11409. url = ''
  11410. if (su.indexOf(me.options.imagePath) > 0) {
  11411. url = su
  11412. .substring(su.indexOf(me.options.imagePath), su.length - 1)
  11413. .replace(/"|\(|\)/gi, '')
  11414. } else {
  11415. url = su != 'none' ? su.replace(/url\("?|"?\)/gi, '') : ''
  11416. }
  11417. var html = '<style type="text/css">body{'
  11418. var bgObj = {
  11419. 'background-color':
  11420. domUtils.getComputedStyle(body, 'background-color') || '#ffffff',
  11421. 'background-image': url ? 'url(' + url + ')' : '',
  11422. 'background-repeat':
  11423. domUtils.getComputedStyle(body, 'background-repeat') || '',
  11424. 'background-position': browser.ie
  11425. ? domUtils.getComputedStyle(body, 'background-position-x') +
  11426. ' ' +
  11427. domUtils.getComputedStyle(body, 'background-position-y')
  11428. : domUtils.getComputedStyle(body, 'background-position'),
  11429. height: domUtils.getComputedStyle(body, 'height'),
  11430. }
  11431. for (var name in bgObj) {
  11432. if (bgObj.hasOwnProperty(name)) {
  11433. html += name + ':' + bgObj[name] + '; '
  11434. }
  11435. }
  11436. html += '}</style> '
  11437. headHtml.push(html)
  11438. },
  11439. aftersetcontent: function () {
  11440. if (isSetColored == false) setBackground()
  11441. },
  11442. },
  11443. inputRule: function (root) {
  11444. isSetColored = false
  11445. utils.each(root.getNodesByTagName('p'), function (p) {
  11446. var styles = p.getAttr('data-background')
  11447. if (styles) {
  11448. isSetColored = true
  11449. setBackground(stringToObj(styles))
  11450. p.parentNode.removeChild(p)
  11451. }
  11452. })
  11453. },
  11454. outputRule: function (root) {
  11455. var me = this,
  11456. styles = (utils.cssRule(cssRuleId, me.document) || '')
  11457. .replace(/[\n\r]+/g, '')
  11458. .match(reg)
  11459. if (styles) {
  11460. root.appendChild(
  11461. UE.uNode.createElement(
  11462. '<p style="display:none;" data-background="' +
  11463. utils.trim(styles[1].replace(/"/g, '').replace(/[\s]+/g, ' ')) +
  11464. '"><br/></p>'
  11465. )
  11466. )
  11467. }
  11468. },
  11469. commands: {
  11470. background: {
  11471. execCommand: function (cmd, obj) {
  11472. setBackground(obj)
  11473. },
  11474. queryCommandValue: function () {
  11475. var me = this,
  11476. styles = (utils.cssRule(cssRuleId, me.document) || '')
  11477. .replace(/[\n\r]+/g, '')
  11478. .match(reg)
  11479. return styles ? stringToObj(styles[1]) : null
  11480. },
  11481. notNeedUndo: true,
  11482. },
  11483. },
  11484. }
  11485. })
  11486. // plugins/image.js
  11487. /**
  11488. * 图片插入、排版插件
  11489. * @file
  11490. * @since 1.2.6.1
  11491. */
  11492. /**
  11493. * 图片对齐方式
  11494. * @command imagefloat
  11495. * @method execCommand
  11496. * @remind 值center为独占一行居中
  11497. * @param { String } cmd 命令字符串
  11498. * @param { String } align 对齐方式,可传left、right、none、center
  11499. * @remaind center表示图片独占一行
  11500. * @example
  11501. * ```javascript
  11502. * editor.execCommand( 'imagefloat', 'center' );
  11503. * ```
  11504. */
  11505. /**
  11506. * 如果选区所在位置是图片区域
  11507. * @command imagefloat
  11508. * @method queryCommandValue
  11509. * @param { String } cmd 命令字符串
  11510. * @return { String } 返回图片对齐方式
  11511. * @example
  11512. * ```javascript
  11513. * editor.queryCommandValue( 'imagefloat' );
  11514. * ```
  11515. */
  11516. UE.commands['imagefloat'] = {
  11517. execCommand: function (cmd, align) {
  11518. var me = this,
  11519. range = me.selection.getRange()
  11520. if (!range.collapsed) {
  11521. var img = range.getClosedNode()
  11522. if (img && img.tagName == 'IMG') {
  11523. switch (align) {
  11524. case 'left':
  11525. case 'right':
  11526. case 'none':
  11527. var pN = img.parentNode,
  11528. tmpNode,
  11529. pre,
  11530. next
  11531. while (dtd.$inline[pN.tagName] || pN.tagName == 'A') {
  11532. pN = pN.parentNode
  11533. }
  11534. tmpNode = pN
  11535. if (
  11536. tmpNode.tagName == 'P' &&
  11537. domUtils.getStyle(tmpNode, 'text-align') == 'center'
  11538. ) {
  11539. if (
  11540. !domUtils.isBody(tmpNode) &&
  11541. domUtils.getChildCount(tmpNode, function (node) {
  11542. return !domUtils.isBr(node) && !domUtils.isWhitespace(node)
  11543. }) == 1
  11544. ) {
  11545. pre = tmpNode.previousSibling
  11546. next = tmpNode.nextSibling
  11547. if (
  11548. pre &&
  11549. next &&
  11550. pre.nodeType == 1 &&
  11551. next.nodeType == 1 &&
  11552. pre.tagName == next.tagName &&
  11553. domUtils.isBlockElm(pre)
  11554. ) {
  11555. pre.appendChild(tmpNode.firstChild)
  11556. while (next.firstChild) {
  11557. pre.appendChild(next.firstChild)
  11558. }
  11559. domUtils.remove(tmpNode)
  11560. domUtils.remove(next)
  11561. } else {
  11562. domUtils.setStyle(tmpNode, 'text-align', '')
  11563. }
  11564. }
  11565. range.selectNode(img).select()
  11566. }
  11567. domUtils.setStyle(img, 'float', align == 'none' ? '' : align)
  11568. if (align == 'none') {
  11569. domUtils.removeAttributes(img, 'align')
  11570. }
  11571. break
  11572. case 'center':
  11573. if (me.queryCommandValue('imagefloat') != 'center') {
  11574. pN = img.parentNode
  11575. domUtils.setStyle(img, 'float', '')
  11576. domUtils.removeAttributes(img, 'align')
  11577. tmpNode = img
  11578. while (
  11579. pN &&
  11580. domUtils.getChildCount(pN, function (node) {
  11581. return !domUtils.isBr(node) && !domUtils.isWhitespace(node)
  11582. }) == 1 &&
  11583. (dtd.$inline[pN.tagName] || pN.tagName == 'A')
  11584. ) {
  11585. tmpNode = pN
  11586. pN = pN.parentNode
  11587. }
  11588. range.setStartBefore(tmpNode).setCursor(false)
  11589. pN = me.document.createElement('div')
  11590. pN.appendChild(tmpNode)
  11591. domUtils.setStyle(tmpNode, 'float', '')
  11592. me.execCommand(
  11593. 'insertHtml',
  11594. '<p id="_img_parent_tmp" style="text-align:center">' +
  11595. pN.innerHTML +
  11596. '</p>'
  11597. )
  11598. tmpNode = me.document.getElementById('_img_parent_tmp')
  11599. tmpNode.removeAttribute('id')
  11600. tmpNode = tmpNode.firstChild
  11601. range.selectNode(tmpNode).select()
  11602. //去掉后边多余的元素
  11603. next = tmpNode.parentNode.nextSibling
  11604. if (next && domUtils.isEmptyNode(next)) {
  11605. domUtils.remove(next)
  11606. }
  11607. }
  11608. break
  11609. }
  11610. }
  11611. }
  11612. },
  11613. queryCommandValue: function () {
  11614. var range = this.selection.getRange(),
  11615. startNode,
  11616. floatStyle
  11617. if (range.collapsed) {
  11618. return 'none'
  11619. }
  11620. startNode = range.getClosedNode()
  11621. if (startNode && startNode.nodeType == 1 && startNode.tagName == 'IMG') {
  11622. floatStyle =
  11623. domUtils.getComputedStyle(startNode, 'float') ||
  11624. startNode.getAttribute('align')
  11625. if (floatStyle == 'none') {
  11626. floatStyle =
  11627. domUtils.getComputedStyle(startNode.parentNode, 'text-align') ==
  11628. 'center'
  11629. ? 'center'
  11630. : floatStyle
  11631. }
  11632. return {
  11633. left: 1,
  11634. right: 1,
  11635. center: 1,
  11636. }[floatStyle]
  11637. ? floatStyle
  11638. : 'none'
  11639. }
  11640. return 'none'
  11641. },
  11642. queryCommandState: function () {
  11643. var range = this.selection.getRange(),
  11644. startNode
  11645. if (range.collapsed) return -1
  11646. startNode = range.getClosedNode()
  11647. if (startNode && startNode.nodeType == 1 && startNode.tagName == 'IMG') {
  11648. return 0
  11649. }
  11650. return -1
  11651. },
  11652. }
  11653. /**
  11654. * 插入图片
  11655. * @command insertimage
  11656. * @method execCommand
  11657. * @param { String } cmd 命令字符串
  11658. * @param { Object } opt 属性键值对,这些属性都将被复制到当前插入图片
  11659. * @remind 该命令第二个参数可接受一个图片配置项对象的数组,可以插入多张图片,
  11660. * 此时数组的每一个元素都是一个Object类型的图片属性集合。
  11661. * @example
  11662. * ```javascript
  11663. * editor.execCommand( 'insertimage', {
  11664. * src:'a/b/c.jpg',
  11665. * width:'100',
  11666. * height:'100'
  11667. * } );
  11668. * ```
  11669. * @example
  11670. * ```javascript
  11671. * editor.execCommand( 'insertimage', [{
  11672. * src:'a/b/c.jpg',
  11673. * width:'100',
  11674. * height:'100'
  11675. * },{
  11676. * src:'a/b/d.jpg',
  11677. * width:'100',
  11678. * height:'100'
  11679. * }] );
  11680. * ```
  11681. */
  11682. UE.commands['insertimage'] = {
  11683. execCommand: function (cmd, opt) {
  11684. opt = utils.isArray(opt) ? opt : [opt]
  11685. if (!opt.length) {
  11686. return
  11687. }
  11688. var me = this,
  11689. range = me.selection.getRange(),
  11690. img = range.getClosedNode()
  11691. if (me.fireEvent('beforeinsertimage', opt) === true) {
  11692. return
  11693. }
  11694. function unhtmlData(imgCi) {
  11695. utils.each(
  11696. 'width,height,border,hspace,vspace'.split(','),
  11697. function (item) {
  11698. if (imgCi[item]) {
  11699. imgCi[item] = parseInt(imgCi[item], 10) || 0
  11700. }
  11701. }
  11702. )
  11703. utils.each('src,_src'.split(','), function (item) {
  11704. if (imgCi[item]) {
  11705. imgCi[item] = utils.unhtmlForUrl(imgCi[item])
  11706. }
  11707. })
  11708. utils.each('title,alt'.split(','), function (item) {
  11709. if (imgCi[item]) {
  11710. imgCi[item] = utils.unhtml(imgCi[item])
  11711. }
  11712. })
  11713. }
  11714. if (
  11715. img &&
  11716. /img/i.test(img.tagName) &&
  11717. (img.className != 'edui-faked-video' ||
  11718. img.className.indexOf('edui-upload-video') != -1) &&
  11719. !img.getAttribute('word_img')
  11720. ) {
  11721. var first = opt.shift()
  11722. var floatStyle = first['floatStyle']
  11723. delete first['floatStyle']
  11724. //// img.style.border = (first.border||0) +"px solid #000";
  11725. //// img.style.margin = (first.margin||0) +"px";
  11726. // img.style.cssText += ';margin:' + (first.margin||0) +"px;" + 'border:' + (first.border||0) +"px solid #000";
  11727. domUtils.setAttributes(img, first)
  11728. me.execCommand('imagefloat', floatStyle)
  11729. if (opt.length > 0) {
  11730. range.setStartAfter(img).setCursor(false, true)
  11731. me.execCommand('insertimage', opt)
  11732. }
  11733. } else {
  11734. var html = [],
  11735. str = '',
  11736. ci
  11737. ci = opt[0]
  11738. if (opt.length == 1) {
  11739. unhtmlData(ci)
  11740. str =
  11741. '<img src="' +
  11742. ci.src +
  11743. '" ' +
  11744. (ci._src ? ' _src="' + ci._src + '" ' : '') +
  11745. (ci.width ? 'width="' + ci.width + '" ' : '') +
  11746. (ci.height ? ' height="' + ci.height + '" ' : '') +
  11747. (ci['floatStyle'] == 'left' || ci['floatStyle'] == 'right'
  11748. ? ' style="float:' + ci['floatStyle'] + ';"'
  11749. : '') +
  11750. (ci.title && ci.title != '' ? ' title="' + ci.title + '"' : '') +
  11751. (ci.border && ci.border != '0'
  11752. ? ' border="' + ci.border + '"'
  11753. : '') +
  11754. (ci.alt && ci.alt != '' ? ' alt="' + ci.alt + '"' : '') +
  11755. (ci.hspace && ci.hspace != '0'
  11756. ? ' hspace = "' + ci.hspace + '"'
  11757. : '') +
  11758. (ci.vspace && ci.vspace != '0'
  11759. ? ' vspace = "' + ci.vspace + '"'
  11760. : '') +
  11761. '/>'
  11762. if (ci['floatStyle'] == 'center') {
  11763. str = '<p style="text-align: center">' + str + '</p>'
  11764. }
  11765. html.push(str)
  11766. } else {
  11767. for (var i = 0; (ci = opt[i++]); ) {
  11768. unhtmlData(ci)
  11769. str =
  11770. '<p ' +
  11771. (ci['floatStyle'] == 'center'
  11772. ? 'style="text-align: center" '
  11773. : '') +
  11774. '><img src="' +
  11775. ci.src +
  11776. '" ' +
  11777. (ci.width ? 'width="' + ci.width + '" ' : '') +
  11778. (ci._src ? ' _src="' + ci._src + '" ' : '') +
  11779. (ci.height ? ' height="' + ci.height + '" ' : '') +
  11780. ' style="' +
  11781. (ci['floatStyle'] && ci['floatStyle'] != 'center'
  11782. ? 'float:' + ci['floatStyle'] + ';'
  11783. : '') +
  11784. (ci.border || '') +
  11785. '" ' +
  11786. (ci.title ? ' title="' + ci.title + '"' : '') +
  11787. ' /></p>'
  11788. html.push(str)
  11789. }
  11790. }
  11791. me.execCommand('insertHtml', html.join(''))
  11792. }
  11793. me.fireEvent('afterinsertimage', opt)
  11794. },
  11795. }
  11796. // plugins/justify.js
  11797. /**
  11798. * 段落格式
  11799. * @file
  11800. * @since 1.2.6.1
  11801. */
  11802. /**
  11803. * 段落对齐方式
  11804. * @command justify
  11805. * @method execCommand
  11806. * @param { String } cmd 命令字符串
  11807. * @param { String } align 对齐方式:left => 居左,right => 居右,center => 居中,justify => 两端对齐
  11808. * @example
  11809. * ```javascript
  11810. * editor.execCommand( 'justify', 'center' );
  11811. * ```
  11812. */
  11813. /**
  11814. * 如果选区所在位置是段落区域,返回当前段落对齐方式
  11815. * @command justify
  11816. * @method queryCommandValue
  11817. * @param { String } cmd 命令字符串
  11818. * @return { String } 返回段落对齐方式
  11819. * @example
  11820. * ```javascript
  11821. * editor.queryCommandValue( 'justify' );
  11822. * ```
  11823. */
  11824. UE.plugins['justify'] = function () {
  11825. var me = this,
  11826. block = domUtils.isBlockElm,
  11827. defaultValue = {
  11828. left: 1,
  11829. right: 1,
  11830. center: 1,
  11831. justify: 1,
  11832. },
  11833. doJustify = function (range, style) {
  11834. var bookmark = range.createBookmark(),
  11835. filterFn = function (node) {
  11836. return node.nodeType == 1
  11837. ? node.tagName.toLowerCase() != 'br' &&
  11838. !domUtils.isBookmarkNode(node)
  11839. : !domUtils.isWhitespace(node)
  11840. }
  11841. range.enlarge(true)
  11842. var bookmark2 = range.createBookmark(),
  11843. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
  11844. tmpRange = range.cloneRange(),
  11845. tmpNode
  11846. while (
  11847. current &&
  11848. !(
  11849. domUtils.getPosition(current, bookmark2.end) &
  11850. domUtils.POSITION_FOLLOWING
  11851. )
  11852. ) {
  11853. if (current.nodeType == 3 || !block(current)) {
  11854. tmpRange.setStartBefore(current)
  11855. while (current && current !== bookmark2.end && !block(current)) {
  11856. tmpNode = current
  11857. current = domUtils.getNextDomNode(
  11858. current,
  11859. false,
  11860. null,
  11861. function (node) {
  11862. return !block(node)
  11863. }
  11864. )
  11865. }
  11866. tmpRange.setEndAfter(tmpNode)
  11867. var common = tmpRange.getCommonAncestor()
  11868. if (!domUtils.isBody(common) && block(common)) {
  11869. domUtils.setStyles(
  11870. common,
  11871. utils.isString(style) ? { 'text-align': style } : style
  11872. )
  11873. current = common
  11874. } else {
  11875. var p = range.document.createElement('p')
  11876. domUtils.setStyles(
  11877. p,
  11878. utils.isString(style) ? { 'text-align': style } : style
  11879. )
  11880. var frag = tmpRange.extractContents()
  11881. p.appendChild(frag)
  11882. tmpRange.insertNode(p)
  11883. current = p
  11884. }
  11885. current = domUtils.getNextDomNode(current, false, filterFn)
  11886. } else {
  11887. current = domUtils.getNextDomNode(current, true, filterFn)
  11888. }
  11889. }
  11890. return range.moveToBookmark(bookmark2).moveToBookmark(bookmark)
  11891. }
  11892. UE.commands['justify'] = {
  11893. execCommand: function (cmdName, align) {
  11894. var range = this.selection.getRange(),
  11895. txt
  11896. //闭合时单独处理
  11897. if (range.collapsed) {
  11898. txt = this.document.createTextNode('p')
  11899. range.insertNode(txt)
  11900. }
  11901. doJustify(range, align)
  11902. if (txt) {
  11903. range.setStartBefore(txt).collapse(true)
  11904. domUtils.remove(txt)
  11905. }
  11906. range.select()
  11907. return true
  11908. },
  11909. queryCommandValue: function () {
  11910. var startNode = this.selection.getStart(),
  11911. value = domUtils.getComputedStyle(startNode, 'text-align')
  11912. return defaultValue[value] ? value : 'left'
  11913. },
  11914. queryCommandState: function () {
  11915. var start = this.selection.getStart(),
  11916. cell =
  11917. start &&
  11918. domUtils.findParentByTagName(start, ['td', 'th', 'caption'], true)
  11919. return cell ? -1 : 0
  11920. },
  11921. }
  11922. }
  11923. // plugins/font.js
  11924. /**
  11925. * 字体颜色,背景色,字号,字体,下划线,删除线
  11926. * @file
  11927. * @since 1.2.6.1
  11928. */
  11929. /**
  11930. * 字体颜色
  11931. * @command forecolor
  11932. * @method execCommand
  11933. * @param { String } cmd 命令字符串
  11934. * @param { String } value 色值(必须十六进制)
  11935. * @example
  11936. * ```javascript
  11937. * editor.execCommand( 'forecolor', '#000' );
  11938. * ```
  11939. */
  11940. /**
  11941. * 返回选区字体颜色
  11942. * @command forecolor
  11943. * @method queryCommandValue
  11944. * @param { String } cmd 命令字符串
  11945. * @return { String } 返回字体颜色
  11946. * @example
  11947. * ```javascript
  11948. * editor.queryCommandValue( 'forecolor' );
  11949. * ```
  11950. */
  11951. /**
  11952. * 字体背景颜色
  11953. * @command backcolor
  11954. * @method execCommand
  11955. * @param { String } cmd 命令字符串
  11956. * @param { String } value 色值(必须十六进制)
  11957. * @example
  11958. * ```javascript
  11959. * editor.execCommand( 'backcolor', '#000' );
  11960. * ```
  11961. */
  11962. /**
  11963. * 返回选区字体颜色
  11964. * @command backcolor
  11965. * @method queryCommandValue
  11966. * @param { String } cmd 命令字符串
  11967. * @return { String } 返回字体背景颜色
  11968. * @example
  11969. * ```javascript
  11970. * editor.queryCommandValue( 'backcolor' );
  11971. * ```
  11972. */
  11973. /**
  11974. * 字体大小
  11975. * @command fontsize
  11976. * @method execCommand
  11977. * @param { String } cmd 命令字符串
  11978. * @param { String } value 字体大小
  11979. * @example
  11980. * ```javascript
  11981. * editor.execCommand( 'fontsize', '14px' );
  11982. * ```
  11983. */
  11984. /**
  11985. * 返回选区字体大小
  11986. * @command fontsize
  11987. * @method queryCommandValue
  11988. * @param { String } cmd 命令字符串
  11989. * @return { String } 返回字体大小
  11990. * @example
  11991. * ```javascript
  11992. * editor.queryCommandValue( 'fontsize' );
  11993. * ```
  11994. */
  11995. /**
  11996. * 字体样式
  11997. * @command fontfamily
  11998. * @method execCommand
  11999. * @param { String } cmd 命令字符串
  12000. * @param { String } value 字体样式
  12001. * @example
  12002. * ```javascript
  12003. * editor.execCommand( 'fontfamily', '微软雅黑' );
  12004. * ```
  12005. */
  12006. /**
  12007. * 返回选区字体样式
  12008. * @command fontfamily
  12009. * @method queryCommandValue
  12010. * @param { String } cmd 命令字符串
  12011. * @return { String } 返回字体样式
  12012. * @example
  12013. * ```javascript
  12014. * editor.queryCommandValue( 'fontfamily' );
  12015. * ```
  12016. */
  12017. /**
  12018. * 字体下划线,与删除线互斥
  12019. * @command underline
  12020. * @method execCommand
  12021. * @param { String } cmd 命令字符串
  12022. * @example
  12023. * ```javascript
  12024. * editor.execCommand( 'underline' );
  12025. * ```
  12026. */
  12027. /**
  12028. * 字体删除线,与下划线互斥
  12029. * @command strikethrough
  12030. * @method execCommand
  12031. * @param { String } cmd 命令字符串
  12032. * @example
  12033. * ```javascript
  12034. * editor.execCommand( 'strikethrough' );
  12035. * ```
  12036. */
  12037. /**
  12038. * 字体边框
  12039. * @command fontborder
  12040. * @method execCommand
  12041. * @param { String } cmd 命令字符串
  12042. * @example
  12043. * ```javascript
  12044. * editor.execCommand( 'fontborder' );
  12045. * ```
  12046. */
  12047. UE.plugins['font'] = function () {
  12048. var me = this,
  12049. fonts = {
  12050. forecolor: 'color',
  12051. backcolor: 'background-color',
  12052. fontsize: 'font-size',
  12053. fontfamily: 'font-family',
  12054. underline: 'text-decoration',
  12055. strikethrough: 'text-decoration',
  12056. fontborder: 'border',
  12057. },
  12058. needCmd = { underline: 1, strikethrough: 1, fontborder: 1 },
  12059. needSetChild = {
  12060. forecolor: 'color',
  12061. backcolor: 'background-color',
  12062. fontsize: 'font-size',
  12063. fontfamily: 'font-family',
  12064. }
  12065. me.setOpt({
  12066. fontfamily: [
  12067. { name: 'songti', val: '宋体,SimSun' },
  12068. { name: 'yahei', val: '微软雅黑,Microsoft YaHei' },
  12069. { name: 'kaiti', val: '楷体,楷体_GB2312, SimKai' },
  12070. { name: 'heiti', val: '黑体, SimHei' },
  12071. { name: 'lishu', val: '隶书, SimLi' },
  12072. { name: 'andaleMono', val: 'andale mono' },
  12073. { name: 'arial', val: 'arial, helvetica,sans-serif' },
  12074. { name: 'arialBlack', val: 'arial black,avant garde' },
  12075. { name: 'comicSansMs', val: 'comic sans ms' },
  12076. { name: 'impact', val: 'impact,chicago' },
  12077. { name: 'timesNewRoman', val: 'times new roman' },
  12078. ],
  12079. fontsize: [10, 11, 12, 14, 16, 18, 20, 24, 36],
  12080. })
  12081. function mergeWithParent(node) {
  12082. var parent
  12083. while ((parent = node.parentNode)) {
  12084. if (
  12085. parent.tagName == 'SPAN' &&
  12086. domUtils.getChildCount(parent, function (child) {
  12087. return !domUtils.isBookmarkNode(child) && !domUtils.isBr(child)
  12088. }) == 1
  12089. ) {
  12090. parent.style.cssText += node.style.cssText
  12091. domUtils.remove(node, true)
  12092. node = parent
  12093. } else {
  12094. break
  12095. }
  12096. }
  12097. }
  12098. function mergeChild(rng, cmdName, value) {
  12099. if (needSetChild[cmdName]) {
  12100. rng.adjustmentBoundary()
  12101. if (!rng.collapsed && rng.startContainer.nodeType == 1) {
  12102. var start = rng.startContainer.childNodes[rng.startOffset]
  12103. if (start && domUtils.isTagNode(start, 'span')) {
  12104. var bk = rng.createBookmark()
  12105. utils.each(
  12106. domUtils.getElementsByTagName(start, 'span'),
  12107. function (span) {
  12108. if (!span.parentNode || domUtils.isBookmarkNode(span)) return
  12109. if (
  12110. cmdName == 'backcolor' &&
  12111. domUtils
  12112. .getComputedStyle(span, 'background-color')
  12113. .toLowerCase() === value
  12114. ) {
  12115. return
  12116. }
  12117. domUtils.removeStyle(span, needSetChild[cmdName])
  12118. if (span.style.cssText.replace(/^\s+$/, '').length == 0) {
  12119. domUtils.remove(span, true)
  12120. }
  12121. }
  12122. )
  12123. rng.moveToBookmark(bk)
  12124. }
  12125. }
  12126. }
  12127. }
  12128. function mergesibling(rng, cmdName, value) {
  12129. var collapsed = rng.collapsed,
  12130. bk = rng.createBookmark(),
  12131. common
  12132. if (collapsed) {
  12133. common = bk.start.parentNode
  12134. while (dtd.$inline[common.tagName]) {
  12135. common = common.parentNode
  12136. }
  12137. } else {
  12138. common = domUtils.getCommonAncestor(bk.start, bk.end)
  12139. }
  12140. utils.each(
  12141. domUtils.getElementsByTagName(common, 'span'),
  12142. function (span) {
  12143. if (!span.parentNode || domUtils.isBookmarkNode(span)) return
  12144. if (/\s*border\s*:\s*none;?\s*/i.test(span.style.cssText)) {
  12145. if (/^\s*border\s*:\s*none;?\s*$/.test(span.style.cssText)) {
  12146. domUtils.remove(span, true)
  12147. } else {
  12148. domUtils.removeStyle(span, 'border')
  12149. }
  12150. return
  12151. }
  12152. if (
  12153. /border/i.test(span.style.cssText) &&
  12154. span.parentNode.tagName == 'SPAN' &&
  12155. /border/i.test(span.parentNode.style.cssText)
  12156. ) {
  12157. span.style.cssText = span.style.cssText.replace(
  12158. /border[^:]*:[^;]+;?/gi,
  12159. ''
  12160. )
  12161. }
  12162. if (!(cmdName == 'fontborder' && value == 'none')) {
  12163. var next = span.nextSibling
  12164. while (next && next.nodeType == 1 && next.tagName == 'SPAN') {
  12165. if (domUtils.isBookmarkNode(next) && cmdName == 'fontborder') {
  12166. span.appendChild(next)
  12167. next = span.nextSibling
  12168. continue
  12169. }
  12170. if (next.style.cssText == span.style.cssText) {
  12171. domUtils.moveChild(next, span)
  12172. domUtils.remove(next)
  12173. }
  12174. if (span.nextSibling === next) break
  12175. next = span.nextSibling
  12176. }
  12177. }
  12178. mergeWithParent(span)
  12179. if (browser.ie && browser.version > 8) {
  12180. //拷贝父亲们的特别的属性,这里只做背景颜色的处理
  12181. var parent = domUtils.findParent(span, function (n) {
  12182. return (
  12183. n.tagName == 'SPAN' && /background-color/.test(n.style.cssText)
  12184. )
  12185. })
  12186. if (parent && !/background-color/.test(span.style.cssText)) {
  12187. span.style.backgroundColor = parent.style.backgroundColor
  12188. }
  12189. }
  12190. }
  12191. )
  12192. rng.moveToBookmark(bk)
  12193. mergeChild(rng, cmdName, value)
  12194. }
  12195. me.addInputRule(function (root) {
  12196. utils.each(
  12197. root.getNodesByTagName('u s del font strike'),
  12198. function (node) {
  12199. if (node.tagName == 'font') {
  12200. var cssStyle = []
  12201. for (var p in node.attrs) {
  12202. switch (p) {
  12203. case 'size':
  12204. cssStyle.push(
  12205. 'font-size:' +
  12206. ({
  12207. 1: '10',
  12208. 2: '12',
  12209. 3: '16',
  12210. 4: '18',
  12211. 5: '24',
  12212. 6: '32',
  12213. 7: '48',
  12214. }[node.attrs[p]] || node.attrs[p]) +
  12215. 'px'
  12216. )
  12217. break
  12218. case 'color':
  12219. cssStyle.push('color:' + node.attrs[p])
  12220. break
  12221. case 'face':
  12222. cssStyle.push('font-family:' + node.attrs[p])
  12223. break
  12224. case 'style':
  12225. cssStyle.push(node.attrs[p])
  12226. }
  12227. }
  12228. node.attrs = {
  12229. style: cssStyle.join(';'),
  12230. }
  12231. } else {
  12232. var val = node.tagName == 'u' ? 'underline' : 'line-through'
  12233. node.attrs = {
  12234. style:
  12235. (node.getAttr('style') || '') + 'text-decoration:' + val + ';',
  12236. }
  12237. }
  12238. node.tagName = 'span'
  12239. }
  12240. )
  12241. // utils.each(root.getNodesByTagName('span'), function (node) {
  12242. // var val;
  12243. // if(val = node.getAttr('class')){
  12244. // if(/fontstrikethrough/.test(val)){
  12245. // node.setStyle('text-decoration','line-through');
  12246. // if(node.attrs['class']){
  12247. // node.attrs['class'] = node.attrs['class'].replace(/fontstrikethrough/,'');
  12248. // }else{
  12249. // node.setAttr('class')
  12250. // }
  12251. // }
  12252. // if(/fontborder/.test(val)){
  12253. // node.setStyle('border','1px solid #000');
  12254. // if(node.attrs['class']){
  12255. // node.attrs['class'] = node.attrs['class'].replace(/fontborder/,'');
  12256. // }else{
  12257. // node.setAttr('class')
  12258. // }
  12259. // }
  12260. // }
  12261. // });
  12262. })
  12263. // me.addOutputRule(function(root){
  12264. // utils.each(root.getNodesByTagName('span'), function (node) {
  12265. // var val;
  12266. // if(val = node.getStyle('text-decoration')){
  12267. // if(/line-through/.test(val)){
  12268. // if(node.attrs['class']){
  12269. // node.attrs['class'] += ' fontstrikethrough';
  12270. // }else{
  12271. // node.setAttr('class','fontstrikethrough')
  12272. // }
  12273. // }
  12274. //
  12275. // node.setStyle('text-decoration')
  12276. // }
  12277. // if(val = node.getStyle('border')){
  12278. // if(/1px/.test(val) && /solid/.test(val)){
  12279. // if(node.attrs['class']){
  12280. // node.attrs['class'] += ' fontborder';
  12281. //
  12282. // }else{
  12283. // node.setAttr('class','fontborder')
  12284. // }
  12285. // }
  12286. // node.setStyle('border')
  12287. //
  12288. // }
  12289. // });
  12290. // });
  12291. for (var p in fonts) {
  12292. ;(function (cmd, style) {
  12293. UE.commands[cmd] = {
  12294. execCommand: function (cmdName, value) {
  12295. value =
  12296. value ||
  12297. (this.queryCommandState(cmdName)
  12298. ? 'none'
  12299. : cmdName == 'underline'
  12300. ? 'underline'
  12301. : cmdName == 'fontborder'
  12302. ? '1px solid #000'
  12303. : 'line-through')
  12304. var me = this,
  12305. range = this.selection.getRange(),
  12306. text
  12307. if (value == 'default') {
  12308. if (range.collapsed) {
  12309. text = me.document.createTextNode('font')
  12310. range.insertNode(text).select()
  12311. }
  12312. me.execCommand('removeFormat', 'span,a', style)
  12313. if (text) {
  12314. range.setStartBefore(text).collapse(true)
  12315. domUtils.remove(text)
  12316. }
  12317. mergesibling(range, cmdName, value)
  12318. range.select()
  12319. } else {
  12320. if (!range.collapsed) {
  12321. if (needCmd[cmd] && me.queryCommandValue(cmd)) {
  12322. me.execCommand('removeFormat', 'span,a', style)
  12323. }
  12324. range = me.selection.getRange()
  12325. range.applyInlineStyle('span', { style: style + ':' + value })
  12326. mergesibling(range, cmdName, value)
  12327. range.select()
  12328. } else {
  12329. var span = domUtils.findParentByTagName(
  12330. range.startContainer,
  12331. 'span',
  12332. true
  12333. )
  12334. text = me.document.createTextNode('font')
  12335. if (
  12336. span &&
  12337. !span.children.length &&
  12338. !span[browser.ie ? 'innerText' : 'textContent'].replace(
  12339. fillCharReg,
  12340. ''
  12341. ).length
  12342. ) {
  12343. //for ie hack when enter
  12344. range.insertNode(text)
  12345. if (needCmd[cmd]) {
  12346. range.selectNode(text).select()
  12347. me.execCommand('removeFormat', 'span,a', style, null)
  12348. span = domUtils.findParentByTagName(text, 'span', true)
  12349. range.setStartBefore(text)
  12350. }
  12351. span && (span.style.cssText += ';' + style + ':' + value)
  12352. range.collapse(true).select()
  12353. } else {
  12354. range.insertNode(text)
  12355. range.selectNode(text).select()
  12356. span = range.document.createElement('span')
  12357. if (needCmd[cmd]) {
  12358. //a标签内的不处理跳过
  12359. if (domUtils.findParentByTagName(text, 'a', true)) {
  12360. range.setStartBefore(text).setCursor()
  12361. domUtils.remove(text)
  12362. return
  12363. }
  12364. me.execCommand('removeFormat', 'span,a', style)
  12365. }
  12366. span.style.cssText = style + ':' + value
  12367. text.parentNode.insertBefore(span, text)
  12368. //修复,span套span 但样式不继承的问题
  12369. if (!browser.ie || (browser.ie && browser.version == 9)) {
  12370. var spanParent = span.parentNode
  12371. while (!domUtils.isBlockElm(spanParent)) {
  12372. if (spanParent.tagName == 'SPAN') {
  12373. //opera合并style不会加入";"
  12374. span.style.cssText =
  12375. spanParent.style.cssText + ';' + span.style.cssText
  12376. }
  12377. spanParent = spanParent.parentNode
  12378. }
  12379. }
  12380. if (opera) {
  12381. setTimeout(function () {
  12382. range.setStart(span, 0).collapse(true)
  12383. mergesibling(range, cmdName, value)
  12384. range.select()
  12385. })
  12386. } else {
  12387. range.setStart(span, 0).collapse(true)
  12388. mergesibling(range, cmdName, value)
  12389. range.select()
  12390. }
  12391. //trace:981
  12392. //domUtils.mergeToParent(span)
  12393. }
  12394. domUtils.remove(text)
  12395. }
  12396. }
  12397. return true
  12398. },
  12399. queryCommandValue: function (cmdName) {
  12400. var startNode = this.selection.getStart()
  12401. //trace:946
  12402. if (cmdName == 'underline' || cmdName == 'strikethrough') {
  12403. var tmpNode = startNode,
  12404. value
  12405. while (
  12406. tmpNode &&
  12407. !domUtils.isBlockElm(tmpNode) &&
  12408. !domUtils.isBody(tmpNode)
  12409. ) {
  12410. if (tmpNode.nodeType == 1) {
  12411. value = domUtils.getComputedStyle(tmpNode, style)
  12412. if (value != 'none') {
  12413. return value
  12414. }
  12415. }
  12416. tmpNode = tmpNode.parentNode
  12417. }
  12418. return 'none'
  12419. }
  12420. if (cmdName == 'fontborder') {
  12421. var tmp = startNode,
  12422. val
  12423. while (tmp && dtd.$inline[tmp.tagName]) {
  12424. if ((val = domUtils.getComputedStyle(tmp, 'border'))) {
  12425. if (/1px/.test(val) && /solid/.test(val)) {
  12426. return val
  12427. }
  12428. }
  12429. tmp = tmp.parentNode
  12430. }
  12431. return ''
  12432. }
  12433. if (cmdName == 'FontSize') {
  12434. var styleVal = domUtils.getComputedStyle(startNode, style),
  12435. tmp = /^([\d\.]+)(\w+)$/.exec(styleVal)
  12436. if (tmp) {
  12437. return Math.floor(tmp[1]) + tmp[2]
  12438. }
  12439. return styleVal
  12440. }
  12441. return domUtils.getComputedStyle(startNode, style)
  12442. },
  12443. queryCommandState: function (cmdName) {
  12444. if (!needCmd[cmdName]) return 0
  12445. var val = this.queryCommandValue(cmdName)
  12446. if (cmdName == 'fontborder') {
  12447. return /1px/.test(val) && /solid/.test(val)
  12448. } else {
  12449. return cmdName == 'underline'
  12450. ? /underline/.test(val)
  12451. : /line\-through/.test(val)
  12452. }
  12453. },
  12454. }
  12455. })(p, fonts[p])
  12456. }
  12457. }
  12458. // plugins/link.js
  12459. /**
  12460. * 超链接
  12461. * @file
  12462. * @since 1.2.6.1
  12463. */
  12464. /**
  12465. * 插入超链接
  12466. * @command link
  12467. * @method execCommand
  12468. * @param { String } cmd 命令字符串
  12469. * @param { Object } options 设置自定义属性,例如:url、title、target
  12470. * @example
  12471. * ```javascript
  12472. * editor.execCommand( 'link', '{
  12473. * url:'ueditor.baidu.com',
  12474. * title:'ueditor',
  12475. * target:'_blank'
  12476. * }' );
  12477. * ```
  12478. */
  12479. /**
  12480. * 返回当前选中的第一个超链接节点
  12481. * @command link
  12482. * @method queryCommandValue
  12483. * @param { String } cmd 命令字符串
  12484. * @return { Element } 超链接节点
  12485. * @example
  12486. * ```javascript
  12487. * editor.queryCommandValue( 'link' );
  12488. * ```
  12489. */
  12490. /**
  12491. * 取消超链接
  12492. * @command unlink
  12493. * @method execCommand
  12494. * @param { String } cmd 命令字符串
  12495. * @example
  12496. * ```javascript
  12497. * editor.execCommand( 'unlink');
  12498. * ```
  12499. */
  12500. UE.plugins['link'] = function () {
  12501. function optimize(range) {
  12502. var start = range.startContainer,
  12503. end = range.endContainer
  12504. if ((start = domUtils.findParentByTagName(start, 'a', true))) {
  12505. range.setStartBefore(start)
  12506. }
  12507. if ((end = domUtils.findParentByTagName(end, 'a', true))) {
  12508. range.setEndAfter(end)
  12509. }
  12510. }
  12511. UE.commands['unlink'] = {
  12512. execCommand: function () {
  12513. var range = this.selection.getRange(),
  12514. bookmark
  12515. if (
  12516. range.collapsed &&
  12517. !domUtils.findParentByTagName(range.startContainer, 'a', true)
  12518. ) {
  12519. return
  12520. }
  12521. bookmark = range.createBookmark()
  12522. optimize(range)
  12523. range.removeInlineStyle('a').moveToBookmark(bookmark).select()
  12524. },
  12525. queryCommandState: function () {
  12526. return !this.highlight && this.queryCommandValue('link') ? 0 : -1
  12527. },
  12528. }
  12529. function doLink(range, opt, me) {
  12530. var rngClone = range.cloneRange(),
  12531. link = me.queryCommandValue('link')
  12532. optimize((range = range.adjustmentBoundary()))
  12533. var start = range.startContainer
  12534. if (start.nodeType == 1 && link) {
  12535. start = start.childNodes[range.startOffset]
  12536. if (
  12537. start &&
  12538. start.nodeType == 1 &&
  12539. start.tagName == 'A' &&
  12540. /^(?:https?|ftp|file)\s*:\s*\/\//.test(
  12541. start[browser.ie ? 'innerText' : 'textContent']
  12542. )
  12543. ) {
  12544. start[browser.ie ? 'innerText' : 'textContent'] = utils.html(
  12545. opt.textValue || opt.href
  12546. )
  12547. }
  12548. }
  12549. if (!rngClone.collapsed || link) {
  12550. range.removeInlineStyle('a')
  12551. rngClone = range.cloneRange()
  12552. }
  12553. if (rngClone.collapsed) {
  12554. var a = range.document.createElement('a'),
  12555. text = ''
  12556. if (opt.textValue) {
  12557. text = utils.html(opt.textValue)
  12558. delete opt.textValue
  12559. } else {
  12560. text = utils.html(opt.href)
  12561. }
  12562. domUtils.setAttributes(a, opt)
  12563. start = domUtils.findParentByTagName(rngClone.startContainer, 'a', true)
  12564. if (start && domUtils.isInNodeEndBoundary(rngClone, start)) {
  12565. range.setStartAfter(start).collapse(true)
  12566. }
  12567. a[browser.ie ? 'innerText' : 'textContent'] = text
  12568. range.insertNode(a).selectNode(a)
  12569. } else {
  12570. range.applyInlineStyle('a', opt)
  12571. }
  12572. }
  12573. UE.commands['link'] = {
  12574. execCommand: function (cmdName, opt) {
  12575. var range
  12576. opt._href && (opt._href = utils.unhtml(opt._href, /[<">]/g))
  12577. opt.href && (opt.href = utils.unhtml(opt.href, /[<">]/g))
  12578. opt.textValue && (opt.textValue = utils.unhtml(opt.textValue, /[<">]/g))
  12579. doLink((range = this.selection.getRange()), opt, this)
  12580. //闭合都不加占位符,如果加了会在a后边多个占位符节点,导致a是图片背景组成的列表,出现空白问题
  12581. range.collapse().select(true)
  12582. },
  12583. queryCommandValue: function () {
  12584. var range = this.selection.getRange(),
  12585. node
  12586. if (range.collapsed) {
  12587. // node = this.selection.getStart();
  12588. //在ie下getstart()取值偏上了
  12589. node = range.startContainer
  12590. node = node.nodeType == 1 ? node : node.parentNode
  12591. if (
  12592. node &&
  12593. (node = domUtils.findParentByTagName(node, 'a', true)) &&
  12594. !domUtils.isInNodeEndBoundary(range, node)
  12595. ) {
  12596. return node
  12597. }
  12598. } else {
  12599. //trace:1111 如果是<p><a>xx</a></p> startContainer是p就会找不到a
  12600. range.shrinkBoundary()
  12601. var start =
  12602. range.startContainer.nodeType == 3 ||
  12603. !range.startContainer.childNodes[range.startOffset]
  12604. ? range.startContainer
  12605. : range.startContainer.childNodes[range.startOffset],
  12606. end =
  12607. range.endContainer.nodeType == 3 || range.endOffset == 0
  12608. ? range.endContainer
  12609. : range.endContainer.childNodes[range.endOffset - 1],
  12610. common = range.getCommonAncestor()
  12611. node = domUtils.findParentByTagName(common, 'a', true)
  12612. if (!node && common.nodeType == 1) {
  12613. var as = common.getElementsByTagName('a'),
  12614. ps,
  12615. pe
  12616. for (var i = 0, ci; (ci = as[i++]); ) {
  12617. ;(ps = domUtils.getPosition(ci, start)),
  12618. (pe = domUtils.getPosition(ci, end))
  12619. if (
  12620. (ps & domUtils.POSITION_FOLLOWING ||
  12621. ps & domUtils.POSITION_CONTAINS) &&
  12622. (pe & domUtils.POSITION_PRECEDING ||
  12623. pe & domUtils.POSITION_CONTAINS)
  12624. ) {
  12625. node = ci
  12626. break
  12627. }
  12628. }
  12629. }
  12630. return node
  12631. }
  12632. },
  12633. queryCommandState: function () {
  12634. //判断如果是视频的话连接不可用
  12635. //fix 853
  12636. var img = this.selection.getRange().getClosedNode(),
  12637. flag =
  12638. img &&
  12639. (img.className == 'edui-faked-video' ||
  12640. img.className.indexOf('edui-upload-video') != -1)
  12641. return flag ? -1 : 0
  12642. },
  12643. }
  12644. }
  12645. // plugins/iframe.js
  12646. ///import core
  12647. ///import plugins\inserthtml.js
  12648. ///commands 插入框架
  12649. ///commandsName InsertFrame
  12650. ///commandsTitle 插入Iframe
  12651. ///commandsDialog dialogs\insertframe
  12652. UE.plugins['insertframe'] = function () {
  12653. var me = this
  12654. function deleteIframe() {
  12655. me._iframe && delete me._iframe
  12656. }
  12657. me.addListener('selectionchange', function () {
  12658. deleteIframe()
  12659. })
  12660. }
  12661. // plugins/scrawl.js
  12662. ///import core
  12663. ///commands 涂鸦
  12664. ///commandsName Scrawl
  12665. ///commandsTitle 涂鸦
  12666. ///commandsDialog dialogs\scrawl
  12667. UE.commands['scrawl'] = {
  12668. queryCommandState: function () {
  12669. return browser.ie && browser.version <= 8 ? -1 : 0
  12670. },
  12671. }
  12672. // plugins/removeformat.js
  12673. /**
  12674. * 清除格式
  12675. * @file
  12676. * @since 1.2.6.1
  12677. */
  12678. /**
  12679. * 清除文字样式
  12680. * @command removeformat
  12681. * @method execCommand
  12682. * @param { String } cmd 命令字符串
  12683. * @param {String} tags 以逗号隔开的标签。如:strong
  12684. * @param {String} style 样式如:color
  12685. * @param {String} attrs 属性如:width
  12686. * @example
  12687. * ```javascript
  12688. * editor.execCommand( 'removeformat', 'strong','color','width' );
  12689. * ```
  12690. */
  12691. UE.plugins['removeformat'] = function () {
  12692. var me = this
  12693. me.setOpt({
  12694. removeFormatTags:
  12695. 'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var',
  12696. removeFormatAttributes:
  12697. 'class,style,lang,width,height,align,hspace,valign',
  12698. })
  12699. me.commands['removeformat'] = {
  12700. execCommand: function (cmdName, tags, style, attrs, notIncludeA) {
  12701. var tagReg = new RegExp(
  12702. '^(?:' +
  12703. (tags || this.options.removeFormatTags).replace(/,/g, '|') +
  12704. ')$',
  12705. 'i'
  12706. ),
  12707. removeFormatAttributes = style
  12708. ? []
  12709. : (attrs || this.options.removeFormatAttributes).split(','),
  12710. range = new dom.Range(this.document),
  12711. bookmark,
  12712. node,
  12713. parent,
  12714. filter = function (node) {
  12715. return node.nodeType == 1
  12716. }
  12717. function isRedundantSpan(node) {
  12718. if (node.nodeType == 3 || node.tagName.toLowerCase() != 'span') {
  12719. return 0
  12720. }
  12721. if (browser.ie) {
  12722. //ie 下判断实效,所以只能简单用style来判断
  12723. //return node.style.cssText == '' ? 1 : 0;
  12724. var attrs = node.attributes
  12725. if (attrs.length) {
  12726. for (var i = 0, l = attrs.length; i < l; i++) {
  12727. if (attrs[i].specified) {
  12728. return 0
  12729. }
  12730. }
  12731. return 1
  12732. }
  12733. }
  12734. return !node.attributes.length
  12735. }
  12736. function doRemove(range) {
  12737. var bookmark1 = range.createBookmark()
  12738. if (range.collapsed) {
  12739. range.enlarge(true)
  12740. }
  12741. //不能把a标签切了
  12742. if (!notIncludeA) {
  12743. var aNode = domUtils.findParentByTagName(
  12744. range.startContainer,
  12745. 'a',
  12746. true
  12747. )
  12748. if (aNode) {
  12749. range.setStartBefore(aNode)
  12750. }
  12751. aNode = domUtils.findParentByTagName(range.endContainer, 'a', true)
  12752. if (aNode) {
  12753. range.setEndAfter(aNode)
  12754. }
  12755. }
  12756. bookmark = range.createBookmark()
  12757. node = bookmark.start
  12758. //切开始
  12759. while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
  12760. domUtils.breakParent(node, parent)
  12761. domUtils.clearEmptySibling(node)
  12762. }
  12763. if (bookmark.end) {
  12764. //切结束
  12765. node = bookmark.end
  12766. while ((parent = node.parentNode) && !domUtils.isBlockElm(parent)) {
  12767. domUtils.breakParent(node, parent)
  12768. domUtils.clearEmptySibling(node)
  12769. }
  12770. //开始去除样式
  12771. var current = domUtils.getNextDomNode(
  12772. bookmark.start,
  12773. false,
  12774. filter
  12775. ),
  12776. next
  12777. while (current) {
  12778. if (current == bookmark.end) {
  12779. break
  12780. }
  12781. next = domUtils.getNextDomNode(current, true, filter)
  12782. if (
  12783. !dtd.$empty[current.tagName.toLowerCase()] &&
  12784. !domUtils.isBookmarkNode(current)
  12785. ) {
  12786. if (tagReg.test(current.tagName)) {
  12787. if (style) {
  12788. domUtils.removeStyle(current, style)
  12789. if (
  12790. isRedundantSpan(current) &&
  12791. style != 'text-decoration'
  12792. ) {
  12793. domUtils.remove(current, true)
  12794. }
  12795. } else {
  12796. domUtils.remove(current, true)
  12797. }
  12798. } else {
  12799. //trace:939 不能把list上的样式去掉
  12800. if (
  12801. !dtd.$tableContent[current.tagName] &&
  12802. !dtd.$list[current.tagName]
  12803. ) {
  12804. domUtils.removeAttributes(current, removeFormatAttributes)
  12805. if (isRedundantSpan(current)) {
  12806. domUtils.remove(current, true)
  12807. }
  12808. }
  12809. }
  12810. }
  12811. current = next
  12812. }
  12813. }
  12814. //trace:1035
  12815. //trace:1096 不能把td上的样式去掉,比如边框
  12816. var pN = bookmark.start.parentNode
  12817. if (
  12818. domUtils.isBlockElm(pN) &&
  12819. !dtd.$tableContent[pN.tagName] &&
  12820. !dtd.$list[pN.tagName]
  12821. ) {
  12822. domUtils.removeAttributes(pN, removeFormatAttributes)
  12823. }
  12824. pN = bookmark.end.parentNode
  12825. if (
  12826. bookmark.end &&
  12827. domUtils.isBlockElm(pN) &&
  12828. !dtd.$tableContent[pN.tagName] &&
  12829. !dtd.$list[pN.tagName]
  12830. ) {
  12831. domUtils.removeAttributes(pN, removeFormatAttributes)
  12832. }
  12833. range.moveToBookmark(bookmark).moveToBookmark(bookmark1)
  12834. //清除冗余的代码 <b><bookmark></b>
  12835. var node = range.startContainer,
  12836. tmp,
  12837. collapsed = range.collapsed
  12838. while (
  12839. node.nodeType == 1 &&
  12840. domUtils.isEmptyNode(node) &&
  12841. dtd.$removeEmpty[node.tagName]
  12842. ) {
  12843. tmp = node.parentNode
  12844. range.setStartBefore(node)
  12845. //trace:937
  12846. //更新结束边界
  12847. if (range.startContainer === range.endContainer) {
  12848. range.endOffset--
  12849. }
  12850. domUtils.remove(node)
  12851. node = tmp
  12852. }
  12853. if (!collapsed) {
  12854. node = range.endContainer
  12855. while (
  12856. node.nodeType == 1 &&
  12857. domUtils.isEmptyNode(node) &&
  12858. dtd.$removeEmpty[node.tagName]
  12859. ) {
  12860. tmp = node.parentNode
  12861. range.setEndBefore(node)
  12862. domUtils.remove(node)
  12863. node = tmp
  12864. }
  12865. }
  12866. }
  12867. range = this.selection.getRange()
  12868. doRemove(range)
  12869. range.select()
  12870. },
  12871. }
  12872. }
  12873. // plugins/blockquote.js
  12874. /**
  12875. * 添加引用
  12876. * @file
  12877. * @since 1.2.6.1
  12878. */
  12879. /**
  12880. * 添加引用
  12881. * @command blockquote
  12882. * @method execCommand
  12883. * @param { String } cmd 命令字符串
  12884. * @example
  12885. * ```javascript
  12886. * editor.execCommand( 'blockquote' );
  12887. * ```
  12888. */
  12889. /**
  12890. * 添加引用
  12891. * @command blockquote
  12892. * @method execCommand
  12893. * @param { String } cmd 命令字符串
  12894. * @param { Object } attrs 节点属性
  12895. * @example
  12896. * ```javascript
  12897. * editor.execCommand( 'blockquote',{
  12898. * style: "color: red;"
  12899. * } );
  12900. * ```
  12901. */
  12902. UE.plugins['blockquote'] = function () {
  12903. var me = this
  12904. function getObj(editor) {
  12905. return domUtils.filterNodeList(
  12906. editor.selection.getStartElementPath(),
  12907. 'blockquote'
  12908. )
  12909. }
  12910. me.commands['blockquote'] = {
  12911. execCommand: function (cmdName, attrs) {
  12912. var range = this.selection.getRange(),
  12913. obj = getObj(this),
  12914. blockquote = dtd.blockquote,
  12915. bookmark = range.createBookmark()
  12916. if (obj) {
  12917. var start = range.startContainer,
  12918. startBlock = domUtils.isBlockElm(start)
  12919. ? start
  12920. : domUtils.findParent(start, function (node) {
  12921. return domUtils.isBlockElm(node)
  12922. }),
  12923. end = range.endContainer,
  12924. endBlock = domUtils.isBlockElm(end)
  12925. ? end
  12926. : domUtils.findParent(end, function (node) {
  12927. return domUtils.isBlockElm(node)
  12928. })
  12929. //处理一下li
  12930. startBlock =
  12931. domUtils.findParentByTagName(startBlock, 'li', true) || startBlock
  12932. endBlock =
  12933. domUtils.findParentByTagName(endBlock, 'li', true) || endBlock
  12934. if (
  12935. startBlock.tagName == 'LI' ||
  12936. startBlock.tagName == 'TD' ||
  12937. startBlock === obj ||
  12938. domUtils.isBody(startBlock)
  12939. ) {
  12940. domUtils.remove(obj, true)
  12941. } else {
  12942. domUtils.breakParent(startBlock, obj)
  12943. }
  12944. if (startBlock !== endBlock) {
  12945. obj = domUtils.findParentByTagName(endBlock, 'blockquote')
  12946. if (obj) {
  12947. if (
  12948. endBlock.tagName == 'LI' ||
  12949. endBlock.tagName == 'TD' ||
  12950. domUtils.isBody(endBlock)
  12951. ) {
  12952. obj.parentNode && domUtils.remove(obj, true)
  12953. } else {
  12954. domUtils.breakParent(endBlock, obj)
  12955. }
  12956. }
  12957. }
  12958. var blockquotes = domUtils.getElementsByTagName(
  12959. this.document,
  12960. 'blockquote'
  12961. )
  12962. for (var i = 0, bi; (bi = blockquotes[i++]); ) {
  12963. if (!bi.childNodes.length) {
  12964. domUtils.remove(bi)
  12965. } else if (
  12966. domUtils.getPosition(bi, startBlock) &
  12967. domUtils.POSITION_FOLLOWING &&
  12968. domUtils.getPosition(bi, endBlock) & domUtils.POSITION_PRECEDING
  12969. ) {
  12970. domUtils.remove(bi, true)
  12971. }
  12972. }
  12973. } else {
  12974. var tmpRange = range.cloneRange(),
  12975. node =
  12976. tmpRange.startContainer.nodeType == 1
  12977. ? tmpRange.startContainer
  12978. : tmpRange.startContainer.parentNode,
  12979. preNode = node,
  12980. doEnd = 1
  12981. //调整开始
  12982. while (1) {
  12983. if (domUtils.isBody(node)) {
  12984. if (preNode !== node) {
  12985. if (range.collapsed) {
  12986. tmpRange.selectNode(preNode)
  12987. doEnd = 0
  12988. } else {
  12989. tmpRange.setStartBefore(preNode)
  12990. }
  12991. } else {
  12992. tmpRange.setStart(node, 0)
  12993. }
  12994. break
  12995. }
  12996. if (!blockquote[node.tagName]) {
  12997. if (range.collapsed) {
  12998. tmpRange.selectNode(preNode)
  12999. } else {
  13000. tmpRange.setStartBefore(preNode)
  13001. }
  13002. break
  13003. }
  13004. preNode = node
  13005. node = node.parentNode
  13006. }
  13007. //调整结束
  13008. if (doEnd) {
  13009. preNode =
  13010. node =
  13011. node =
  13012. tmpRange.endContainer.nodeType == 1
  13013. ? tmpRange.endContainer
  13014. : tmpRange.endContainer.parentNode
  13015. while (1) {
  13016. if (domUtils.isBody(node)) {
  13017. if (preNode !== node) {
  13018. tmpRange.setEndAfter(preNode)
  13019. } else {
  13020. tmpRange.setEnd(node, node.childNodes.length)
  13021. }
  13022. break
  13023. }
  13024. if (!blockquote[node.tagName]) {
  13025. tmpRange.setEndAfter(preNode)
  13026. break
  13027. }
  13028. preNode = node
  13029. node = node.parentNode
  13030. }
  13031. }
  13032. node = range.document.createElement('blockquote')
  13033. domUtils.setAttributes(node, attrs)
  13034. node.appendChild(tmpRange.extractContents())
  13035. tmpRange.insertNode(node)
  13036. //去除重复的
  13037. var childs = domUtils.getElementsByTagName(node, 'blockquote')
  13038. for (var i = 0, ci; (ci = childs[i++]); ) {
  13039. if (ci.parentNode) {
  13040. domUtils.remove(ci, true)
  13041. }
  13042. }
  13043. }
  13044. range.moveToBookmark(bookmark).select()
  13045. },
  13046. queryCommandState: function () {
  13047. return getObj(this) ? 1 : 0
  13048. },
  13049. }
  13050. }
  13051. // plugins/convertcase.js
  13052. /**
  13053. * 大小写转换
  13054. * @file
  13055. * @since 1.2.6.1
  13056. */
  13057. /**
  13058. * 把选区内文本变大写,与“tolowercase”命令互斥
  13059. * @command touppercase
  13060. * @method execCommand
  13061. * @param { String } cmd 命令字符串
  13062. * @example
  13063. * ```javascript
  13064. * editor.execCommand( 'touppercase' );
  13065. * ```
  13066. */
  13067. /**
  13068. * 把选区内文本变小写,与“touppercase”命令互斥
  13069. * @command tolowercase
  13070. * @method execCommand
  13071. * @param { String } cmd 命令字符串
  13072. * @example
  13073. * ```javascript
  13074. * editor.execCommand( 'tolowercase' );
  13075. * ```
  13076. */
  13077. UE.commands['touppercase'] = UE.commands['tolowercase'] = {
  13078. execCommand: function (cmd) {
  13079. var me = this
  13080. var rng = me.selection.getRange()
  13081. if (rng.collapsed) {
  13082. return rng
  13083. }
  13084. var bk = rng.createBookmark(),
  13085. bkEnd = bk.end,
  13086. filterFn = function (node) {
  13087. return !domUtils.isBr(node) && !domUtils.isWhitespace(node)
  13088. },
  13089. curNode = domUtils.getNextDomNode(bk.start, false, filterFn)
  13090. while (
  13091. curNode &&
  13092. domUtils.getPosition(curNode, bkEnd) & domUtils.POSITION_PRECEDING
  13093. ) {
  13094. if (curNode.nodeType == 3) {
  13095. curNode.nodeValue =
  13096. curNode.nodeValue[
  13097. cmd == 'touppercase' ? 'toUpperCase' : 'toLowerCase'
  13098. ]()
  13099. }
  13100. curNode = domUtils.getNextDomNode(curNode, true, filterFn)
  13101. if (curNode === bkEnd) {
  13102. break
  13103. }
  13104. }
  13105. rng.moveToBookmark(bk).select()
  13106. },
  13107. }
  13108. // plugins/indent.js
  13109. /**
  13110. * 首行缩进
  13111. * @file
  13112. * @since 1.2.6.1
  13113. */
  13114. /**
  13115. * 缩进
  13116. * @command indent
  13117. * @method execCommand
  13118. * @param { String } cmd 命令字符串
  13119. * @example
  13120. * ```javascript
  13121. * editor.execCommand( 'indent' );
  13122. * ```
  13123. */
  13124. UE.commands['indent'] = {
  13125. execCommand: function () {
  13126. var me = this,
  13127. value = me.queryCommandState('indent')
  13128. ? '0em'
  13129. : me.options.indentValue || '2em'
  13130. me.execCommand('Paragraph', 'p', { style: 'text-indent:' + value })
  13131. },
  13132. queryCommandState: function () {
  13133. var pN = domUtils.filterNodeList(
  13134. this.selection.getStartElementPath(),
  13135. 'p h1 h2 h3 h4 h5 h6'
  13136. )
  13137. return pN && pN.style.textIndent && parseInt(pN.style.textIndent) ? 1 : 0
  13138. },
  13139. }
  13140. // plugins/print.js
  13141. /**
  13142. * 打印
  13143. * @file
  13144. * @since 1.2.6.1
  13145. */
  13146. /**
  13147. * 打印
  13148. * @command print
  13149. * @method execCommand
  13150. * @param { String } cmd 命令字符串
  13151. * @example
  13152. * ```javascript
  13153. * editor.execCommand( 'print' );
  13154. * ```
  13155. */
  13156. UE.commands['print'] = {
  13157. execCommand: function () {
  13158. this.window.print()
  13159. },
  13160. notNeedUndo: 1,
  13161. }
  13162. // plugins/preview.js
  13163. /**
  13164. * 预览
  13165. * @file
  13166. * @since 1.2.6.1
  13167. */
  13168. /**
  13169. * 预览
  13170. * @command preview
  13171. * @method execCommand
  13172. * @param { String } cmd 命令字符串
  13173. * @example
  13174. * ```javascript
  13175. * editor.execCommand( 'preview' );
  13176. * ```
  13177. */
  13178. UE.commands['preview'] = {
  13179. execCommand: function () {
  13180. var w = window.open('', '_blank', ''),
  13181. d = w.document
  13182. d.open()
  13183. d.write(
  13184. '<!DOCTYPE html><html><head><meta charset="utf-8"/><script src="' +
  13185. this.options.UEDITOR_HOME_URL +
  13186. 'ueditor.parse.js"></script><script>' +
  13187. "setTimeout(function(){uParse('div',{rootPath: '" +
  13188. this.options.UEDITOR_HOME_URL +
  13189. "'})},300)" +
  13190. '</script></head><body><div>' +
  13191. this.getContent(null, null, true) +
  13192. '</div></body></html>'
  13193. )
  13194. d.close()
  13195. },
  13196. notNeedUndo: 1,
  13197. }
  13198. // plugins/selectall.js
  13199. /**
  13200. * 全选
  13201. * @file
  13202. * @since 1.2.6.1
  13203. */
  13204. /**
  13205. * 选中所有内容
  13206. * @command selectall
  13207. * @method execCommand
  13208. * @param { String } cmd 命令字符串
  13209. * @example
  13210. * ```javascript
  13211. * editor.execCommand( 'selectall' );
  13212. * ```
  13213. */
  13214. UE.plugins['selectall'] = function () {
  13215. var me = this
  13216. me.commands['selectall'] = {
  13217. execCommand: function () {
  13218. //去掉了原生的selectAll,因为会出现报错和当内容为空时,不能出现闭合状态的光标
  13219. var me = this,
  13220. body = me.body,
  13221. range = me.selection.getRange()
  13222. range.selectNodeContents(body)
  13223. if (domUtils.isEmptyBlock(body)) {
  13224. //opera不能自动合并到元素的里边,要手动处理一下
  13225. if (
  13226. browser.opera &&
  13227. body.firstChild &&
  13228. body.firstChild.nodeType == 1
  13229. ) {
  13230. range.setStartAtFirst(body.firstChild)
  13231. }
  13232. range.collapse(true)
  13233. }
  13234. range.select(true)
  13235. },
  13236. notNeedUndo: 1,
  13237. }
  13238. //快捷键
  13239. me.addshortcutkey({
  13240. selectAll: 'ctrl+65',
  13241. })
  13242. }
  13243. // plugins/paragraph.js
  13244. /**
  13245. * 段落样式
  13246. * @file
  13247. * @since 1.2.6.1
  13248. */
  13249. /**
  13250. * 段落格式
  13251. * @command paragraph
  13252. * @method execCommand
  13253. * @param { String } cmd 命令字符串
  13254. * @param {String} style 标签值为:'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
  13255. * @param {Object} attrs 标签的属性
  13256. * @example
  13257. * ```javascript
  13258. * editor.execCommand( 'Paragraph','h1','{
  13259. * class:'test'
  13260. * }' );
  13261. * ```
  13262. */
  13263. /**
  13264. * 返回选区内节点标签名
  13265. * @command paragraph
  13266. * @method queryCommandValue
  13267. * @param { String } cmd 命令字符串
  13268. * @return { String } 节点标签名
  13269. * @example
  13270. * ```javascript
  13271. * editor.queryCommandValue( 'Paragraph' );
  13272. * ```
  13273. */
  13274. UE.plugins['paragraph'] = function () {
  13275. var me = this,
  13276. block = domUtils.isBlockElm,
  13277. notExchange = ['TD', 'LI', 'PRE'],
  13278. doParagraph = function (range, style, attrs, sourceCmdName) {
  13279. var bookmark = range.createBookmark(),
  13280. filterFn = function (node) {
  13281. return node.nodeType == 1
  13282. ? node.tagName.toLowerCase() != 'br' &&
  13283. !domUtils.isBookmarkNode(node)
  13284. : !domUtils.isWhitespace(node)
  13285. },
  13286. para
  13287. range.enlarge(true)
  13288. var bookmark2 = range.createBookmark(),
  13289. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
  13290. tmpRange = range.cloneRange(),
  13291. tmpNode
  13292. while (
  13293. current &&
  13294. !(
  13295. domUtils.getPosition(current, bookmark2.end) &
  13296. domUtils.POSITION_FOLLOWING
  13297. )
  13298. ) {
  13299. if (current.nodeType == 3 || !block(current)) {
  13300. tmpRange.setStartBefore(current)
  13301. while (current && current !== bookmark2.end && !block(current)) {
  13302. tmpNode = current
  13303. current = domUtils.getNextDomNode(
  13304. current,
  13305. false,
  13306. null,
  13307. function (node) {
  13308. return !block(node)
  13309. }
  13310. )
  13311. }
  13312. tmpRange.setEndAfter(tmpNode)
  13313. para = range.document.createElement(style)
  13314. if (attrs) {
  13315. domUtils.setAttributes(para, attrs)
  13316. if (
  13317. sourceCmdName &&
  13318. sourceCmdName == 'customstyle' &&
  13319. attrs.style
  13320. ) {
  13321. para.style.cssText = attrs.style
  13322. }
  13323. }
  13324. para.appendChild(tmpRange.extractContents())
  13325. //需要内容占位
  13326. if (domUtils.isEmptyNode(para)) {
  13327. domUtils.fillChar(range.document, para)
  13328. }
  13329. tmpRange.insertNode(para)
  13330. var parent = para.parentNode
  13331. //如果para上一级是一个block元素且不是body,td就删除它
  13332. if (
  13333. block(parent) &&
  13334. !domUtils.isBody(para.parentNode) &&
  13335. utils.indexOf(notExchange, parent.tagName) == -1
  13336. ) {
  13337. //存储dir,style
  13338. if (!(sourceCmdName && sourceCmdName == 'customstyle')) {
  13339. parent.getAttribute('dir') &&
  13340. para.setAttribute('dir', parent.getAttribute('dir'))
  13341. //trace:1070
  13342. parent.style.cssText &&
  13343. (para.style.cssText =
  13344. parent.style.cssText + ';' + para.style.cssText)
  13345. //trace:1030
  13346. parent.style.textAlign &&
  13347. !para.style.textAlign &&
  13348. (para.style.textAlign = parent.style.textAlign)
  13349. parent.style.textIndent &&
  13350. !para.style.textIndent &&
  13351. (para.style.textIndent = parent.style.textIndent)
  13352. parent.style.padding &&
  13353. !para.style.padding &&
  13354. (para.style.padding = parent.style.padding)
  13355. }
  13356. //trace:1706 选择的就是h1-6要删除
  13357. if (
  13358. attrs &&
  13359. /h\d/i.test(parent.tagName) &&
  13360. !/h\d/i.test(para.tagName)
  13361. ) {
  13362. domUtils.setAttributes(parent, attrs)
  13363. if (
  13364. sourceCmdName &&
  13365. sourceCmdName == 'customstyle' &&
  13366. attrs.style
  13367. ) {
  13368. parent.style.cssText = attrs.style
  13369. }
  13370. domUtils.remove(para, true)
  13371. para = parent
  13372. } else {
  13373. domUtils.remove(para.parentNode, true)
  13374. }
  13375. }
  13376. if (utils.indexOf(notExchange, parent.tagName) != -1) {
  13377. current = parent
  13378. } else {
  13379. current = para
  13380. }
  13381. current = domUtils.getNextDomNode(current, false, filterFn)
  13382. } else {
  13383. current = domUtils.getNextDomNode(current, true, filterFn)
  13384. }
  13385. }
  13386. return range.moveToBookmark(bookmark2).moveToBookmark(bookmark)
  13387. }
  13388. me.setOpt('paragraph', {
  13389. p: '',
  13390. h1: '',
  13391. h2: '',
  13392. h3: '',
  13393. h4: '',
  13394. h5: '',
  13395. h6: '',
  13396. })
  13397. me.commands['paragraph'] = {
  13398. execCommand: function (cmdName, style, attrs, sourceCmdName) {
  13399. var range = this.selection.getRange()
  13400. //闭合时单独处理
  13401. if (range.collapsed) {
  13402. var txt = this.document.createTextNode('p')
  13403. range.insertNode(txt)
  13404. //去掉冗余的fillchar
  13405. if (browser.ie) {
  13406. var node = txt.previousSibling
  13407. if (node && domUtils.isWhitespace(node)) {
  13408. domUtils.remove(node)
  13409. }
  13410. node = txt.nextSibling
  13411. if (node && domUtils.isWhitespace(node)) {
  13412. domUtils.remove(node)
  13413. }
  13414. }
  13415. }
  13416. range = doParagraph(range, style, attrs, sourceCmdName)
  13417. if (txt) {
  13418. range.setStartBefore(txt).collapse(true)
  13419. pN = txt.parentNode
  13420. domUtils.remove(txt)
  13421. if (domUtils.isBlockElm(pN) && domUtils.isEmptyNode(pN)) {
  13422. domUtils.fillNode(this.document, pN)
  13423. }
  13424. }
  13425. if (
  13426. browser.gecko &&
  13427. range.collapsed &&
  13428. range.startContainer.nodeType == 1
  13429. ) {
  13430. var child = range.startContainer.childNodes[range.startOffset]
  13431. if (
  13432. child &&
  13433. child.nodeType == 1 &&
  13434. child.tagName.toLowerCase() == style
  13435. ) {
  13436. range.setStart(child, 0).collapse(true)
  13437. }
  13438. }
  13439. //trace:1097 原来有true,原因忘了,但去了就不能清除多余的占位符了
  13440. range.select()
  13441. return true
  13442. },
  13443. queryCommandValue: function () {
  13444. var node = domUtils.filterNodeList(
  13445. this.selection.getStartElementPath(),
  13446. 'p h1 h2 h3 h4 h5 h6'
  13447. )
  13448. return node ? node.tagName.toLowerCase() : ''
  13449. },
  13450. }
  13451. }
  13452. // plugins/directionality.js
  13453. /**
  13454. * 设置文字输入的方向的插件
  13455. * @file
  13456. * @since 1.2.6.1
  13457. */
  13458. ;(function () {
  13459. var block = domUtils.isBlockElm,
  13460. getObj = function (editor) {
  13461. // var startNode = editor.selection.getStart(),
  13462. // parents;
  13463. // if ( startNode ) {
  13464. // //查找所有的是block的父亲节点
  13465. // parents = domUtils.findParents( startNode, true, block, true );
  13466. // for ( var i = 0,ci; ci = parents[i++]; ) {
  13467. // if ( ci.getAttribute( 'dir' ) ) {
  13468. // return ci;
  13469. // }
  13470. // }
  13471. // }
  13472. return domUtils.filterNodeList(
  13473. editor.selection.getStartElementPath(),
  13474. function (n) {
  13475. return n && n.nodeType == 1 && n.getAttribute('dir')
  13476. }
  13477. )
  13478. },
  13479. doDirectionality = function (range, editor, forward) {
  13480. var bookmark,
  13481. filterFn = function (node) {
  13482. return node.nodeType == 1
  13483. ? !domUtils.isBookmarkNode(node)
  13484. : !domUtils.isWhitespace(node)
  13485. },
  13486. obj = getObj(editor)
  13487. if (obj && range.collapsed) {
  13488. obj.setAttribute('dir', forward)
  13489. return range
  13490. }
  13491. bookmark = range.createBookmark()
  13492. range.enlarge(true)
  13493. var bookmark2 = range.createBookmark(),
  13494. current = domUtils.getNextDomNode(bookmark2.start, false, filterFn),
  13495. tmpRange = range.cloneRange(),
  13496. tmpNode
  13497. while (
  13498. current &&
  13499. !(
  13500. domUtils.getPosition(current, bookmark2.end) &
  13501. domUtils.POSITION_FOLLOWING
  13502. )
  13503. ) {
  13504. if (current.nodeType == 3 || !block(current)) {
  13505. tmpRange.setStartBefore(current)
  13506. while (current && current !== bookmark2.end && !block(current)) {
  13507. tmpNode = current
  13508. current = domUtils.getNextDomNode(
  13509. current,
  13510. false,
  13511. null,
  13512. function (node) {
  13513. return !block(node)
  13514. }
  13515. )
  13516. }
  13517. tmpRange.setEndAfter(tmpNode)
  13518. var common = tmpRange.getCommonAncestor()
  13519. if (!domUtils.isBody(common) && block(common)) {
  13520. //遍历到了block节点
  13521. common.setAttribute('dir', forward)
  13522. current = common
  13523. } else {
  13524. //没有遍历到,添加一个block节点
  13525. var p = range.document.createElement('p')
  13526. p.setAttribute('dir', forward)
  13527. var frag = tmpRange.extractContents()
  13528. p.appendChild(frag)
  13529. tmpRange.insertNode(p)
  13530. current = p
  13531. }
  13532. current = domUtils.getNextDomNode(current, false, filterFn)
  13533. } else {
  13534. current = domUtils.getNextDomNode(current, true, filterFn)
  13535. }
  13536. }
  13537. return range.moveToBookmark(bookmark2).moveToBookmark(bookmark)
  13538. }
  13539. /**
  13540. * 文字输入方向
  13541. * @command directionality
  13542. * @method execCommand
  13543. * @param { String } cmdName 命令字符串
  13544. * @param { String } forward 传入'ltr'表示从左向右输入,传入'rtl'表示从右向左输入
  13545. * @example
  13546. * ```javascript
  13547. * editor.execCommand( 'directionality', 'ltr');
  13548. * ```
  13549. */
  13550. /**
  13551. * 查询当前选区的文字输入方向
  13552. * @command directionality
  13553. * @method queryCommandValue
  13554. * @param { String } cmdName 命令字符串
  13555. * @return { String } 返回'ltr'表示从左向右输入,返回'rtl'表示从右向左输入
  13556. * @example
  13557. * ```javascript
  13558. * editor.queryCommandValue( 'directionality');
  13559. * ```
  13560. */
  13561. UE.commands['directionality'] = {
  13562. execCommand: function (cmdName, forward) {
  13563. var range = this.selection.getRange()
  13564. //闭合时单独处理
  13565. if (range.collapsed) {
  13566. var txt = this.document.createTextNode('d')
  13567. range.insertNode(txt)
  13568. }
  13569. doDirectionality(range, this, forward)
  13570. if (txt) {
  13571. range.setStartBefore(txt).collapse(true)
  13572. domUtils.remove(txt)
  13573. }
  13574. range.select()
  13575. return true
  13576. },
  13577. queryCommandValue: function () {
  13578. var node = getObj(this)
  13579. return node ? node.getAttribute('dir') : 'ltr'
  13580. },
  13581. }
  13582. })()
  13583. // plugins/horizontal.js
  13584. /**
  13585. * 插入分割线插件
  13586. * @file
  13587. * @since 1.2.6.1
  13588. */
  13589. /**
  13590. * 插入分割线
  13591. * @command horizontal
  13592. * @method execCommand
  13593. * @param { String } cmdName 命令字符串
  13594. * @example
  13595. * ```javascript
  13596. * editor.execCommand( 'horizontal' );
  13597. * ```
  13598. */
  13599. UE.plugins['horizontal'] = function () {
  13600. var me = this
  13601. me.commands['horizontal'] = {
  13602. execCommand: function (cmdName) {
  13603. var me = this
  13604. if (me.queryCommandState(cmdName) !== -1) {
  13605. me.execCommand('insertHtml', '<hr>')
  13606. var range = me.selection.getRange(),
  13607. start = range.startContainer
  13608. if (start.nodeType == 1 && !start.childNodes[range.startOffset]) {
  13609. var tmp
  13610. if ((tmp = start.childNodes[range.startOffset - 1])) {
  13611. if (tmp.nodeType == 1 && tmp.tagName == 'HR') {
  13612. if (me.options.enterTag == 'p') {
  13613. tmp = me.document.createElement('p')
  13614. range.insertNode(tmp)
  13615. range.setStart(tmp, 0).setCursor()
  13616. } else {
  13617. tmp = me.document.createElement('br')
  13618. range.insertNode(tmp)
  13619. range.setStartBefore(tmp).setCursor()
  13620. }
  13621. }
  13622. }
  13623. }
  13624. return true
  13625. }
  13626. },
  13627. //边界在table里不能加分隔线
  13628. queryCommandState: function () {
  13629. return domUtils.filterNodeList(
  13630. this.selection.getStartElementPath(),
  13631. 'table'
  13632. )
  13633. ? -1
  13634. : 0
  13635. },
  13636. }
  13637. // me.addListener('delkeyup',function(){
  13638. // var rng = this.selection.getRange();
  13639. // if(browser.ie && browser.version > 8){
  13640. // rng.txtToElmBoundary(true);
  13641. // if(domUtils.isStartInblock(rng)){
  13642. // var tmpNode = rng.startContainer;
  13643. // var pre = tmpNode.previousSibling;
  13644. // if(pre && domUtils.isTagNode(pre,'hr')){
  13645. // domUtils.remove(pre);
  13646. // rng.select();
  13647. // return;
  13648. // }
  13649. // }
  13650. // }
  13651. // if(domUtils.isBody(rng.startContainer)){
  13652. // var hr = rng.startContainer.childNodes[rng.startOffset -1];
  13653. // if(hr && hr.nodeName == 'HR'){
  13654. // var next = hr.nextSibling;
  13655. // if(next){
  13656. // rng.setStart(next,0)
  13657. // }else if(hr.previousSibling){
  13658. // rng.setStartAtLast(hr.previousSibling)
  13659. // }else{
  13660. // var p = this.document.createElement('p');
  13661. // hr.parentNode.insertBefore(p,hr);
  13662. // domUtils.fillNode(this.document,p);
  13663. // rng.setStart(p,0);
  13664. // }
  13665. // domUtils.remove(hr);
  13666. // rng.setCursor(false,true);
  13667. // }
  13668. // }
  13669. // })
  13670. me.addListener('delkeydown', function (name, evt) {
  13671. var rng = this.selection.getRange()
  13672. rng.txtToElmBoundary(true)
  13673. if (domUtils.isStartInblock(rng)) {
  13674. var tmpNode = rng.startContainer
  13675. var pre = tmpNode.previousSibling
  13676. if (pre && domUtils.isTagNode(pre, 'hr')) {
  13677. domUtils.remove(pre)
  13678. rng.select()
  13679. domUtils.preventDefault(evt)
  13680. return true
  13681. }
  13682. }
  13683. })
  13684. }
  13685. // plugins/time.js
  13686. /**
  13687. * 插入时间和日期
  13688. * @file
  13689. * @since 1.2.6.1
  13690. */
  13691. /**
  13692. * 插入时间,默认格式:12:59:59
  13693. * @command time
  13694. * @method execCommand
  13695. * @param { String } cmd 命令字符串
  13696. * @example
  13697. * ```javascript
  13698. * editor.execCommand( 'time');
  13699. * ```
  13700. */
  13701. /**
  13702. * 插入日期,默认格式:2013-08-30
  13703. * @command date
  13704. * @method execCommand
  13705. * @param { String } cmd 命令字符串
  13706. * @example
  13707. * ```javascript
  13708. * editor.execCommand( 'date');
  13709. * ```
  13710. */
  13711. UE.commands['time'] = UE.commands['date'] = {
  13712. execCommand: function (cmd, format) {
  13713. var date = new Date()
  13714. function formatTime(date, format) {
  13715. var hh = ('0' + date.getHours()).slice(-2),
  13716. ii = ('0' + date.getMinutes()).slice(-2),
  13717. ss = ('0' + date.getSeconds()).slice(-2)
  13718. format = format || 'hh:ii:ss'
  13719. return format
  13720. .replace(/hh/gi, hh)
  13721. .replace(/ii/gi, ii)
  13722. .replace(/ss/gi, ss)
  13723. }
  13724. function formatDate(date, format) {
  13725. var yyyy = ('000' + date.getFullYear()).slice(-4),
  13726. yy = yyyy.slice(-2),
  13727. mm = ('0' + (date.getMonth() + 1)).slice(-2),
  13728. dd = ('0' + date.getDate()).slice(-2)
  13729. format = format || 'yyyy-mm-dd'
  13730. return format
  13731. .replace(/yyyy/gi, yyyy)
  13732. .replace(/yy/gi, yy)
  13733. .replace(/mm/gi, mm)
  13734. .replace(/dd/gi, dd)
  13735. }
  13736. this.execCommand(
  13737. 'insertHtml',
  13738. cmd == 'time' ? formatTime(date, format) : formatDate(date, format)
  13739. )
  13740. },
  13741. }
  13742. // plugins/rowspacing.js
  13743. /**
  13744. * 段前段后间距插件
  13745. * @file
  13746. * @since 1.2.6.1
  13747. */
  13748. /**
  13749. * 设置段间距
  13750. * @command rowspacing
  13751. * @method execCommand
  13752. * @param { String } cmd 命令字符串
  13753. * @param { String } value 段间距的值,以px为单位
  13754. * @param { String } dir 间距位置,top或bottom,分别表示段前和段后
  13755. * @example
  13756. * ```javascript
  13757. * editor.execCommand( 'rowspacing', '10', 'top' );
  13758. * ```
  13759. */
  13760. UE.plugins['rowspacing'] = function () {
  13761. var me = this
  13762. me.setOpt({
  13763. rowspacingtop: ['5', '10', '15', '20', '25'],
  13764. rowspacingbottom: ['5', '10', '15', '20', '25'],
  13765. })
  13766. me.commands['rowspacing'] = {
  13767. execCommand: function (cmdName, value, dir) {
  13768. this.execCommand('paragraph', 'p', {
  13769. style: 'margin-' + dir + ':' + value + 'px',
  13770. })
  13771. return true
  13772. },
  13773. queryCommandValue: function (cmdName, dir) {
  13774. var pN = domUtils.filterNodeList(
  13775. this.selection.getStartElementPath(),
  13776. function (node) {
  13777. return domUtils.isBlockElm(node)
  13778. }
  13779. ),
  13780. value
  13781. //trace:1026
  13782. if (pN) {
  13783. value = domUtils
  13784. .getComputedStyle(pN, 'margin-' + dir)
  13785. .replace(/[^\d]/g, '')
  13786. return !value ? 0 : value
  13787. }
  13788. return 0
  13789. },
  13790. }
  13791. }
  13792. // plugins/lineheight.js
  13793. /**
  13794. * 设置行内间距
  13795. * @file
  13796. * @since 1.2.6.1
  13797. */
  13798. UE.plugins['lineheight'] = function () {
  13799. var me = this
  13800. me.setOpt({ lineheight: ['1', '1.5', '1.75', '2', '3', '4', '5'] })
  13801. /**
  13802. * 行距
  13803. * @command lineheight
  13804. * @method execCommand
  13805. * @param { String } cmdName 命令字符串
  13806. * @param { String } value 传入的行高值, 该值是当前字体的倍数, 例如: 1.5, 1.75
  13807. * @example
  13808. * ```javascript
  13809. * editor.execCommand( 'lineheight', 1.5);
  13810. * ```
  13811. */
  13812. /**
  13813. * 查询当前选区内容的行高大小
  13814. * @command lineheight
  13815. * @method queryCommandValue
  13816. * @param { String } cmd 命令字符串
  13817. * @return { String } 返回当前行高大小
  13818. * @example
  13819. * ```javascript
  13820. * editor.queryCommandValue( 'lineheight' );
  13821. * ```
  13822. */
  13823. me.commands['lineheight'] = {
  13824. execCommand: function (cmdName, value) {
  13825. this.execCommand('paragraph', 'p', {
  13826. style: 'line-height:' + (value == '1' ? 'normal' : value + 'em'),
  13827. })
  13828. return true
  13829. },
  13830. queryCommandValue: function () {
  13831. var pN = domUtils.filterNodeList(
  13832. this.selection.getStartElementPath(),
  13833. function (node) {
  13834. return domUtils.isBlockElm(node)
  13835. }
  13836. )
  13837. if (pN) {
  13838. var value = domUtils.getComputedStyle(pN, 'line-height')
  13839. return value == 'normal' ? 1 : value.replace(/[^\d.]*/gi, '')
  13840. }
  13841. },
  13842. }
  13843. }
  13844. // plugins/insertcode.js
  13845. /**
  13846. * 插入代码插件
  13847. * @file
  13848. * @since 1.2.6.1
  13849. */
  13850. UE.plugins['insertcode'] = function () {
  13851. var me = this
  13852. me.ready(function () {
  13853. utils.cssRule(
  13854. 'pre',
  13855. 'pre{margin:.5em 0;padding:.4em .6em;border-radius:8px;background:#f8f8f8;}',
  13856. me.document
  13857. )
  13858. })
  13859. me.setOpt('insertcode', {
  13860. as3: 'ActionScript3',
  13861. bash: 'Bash/Shell',
  13862. cpp: 'C/C++',
  13863. css: 'Css',
  13864. cf: 'CodeFunction',
  13865. 'c#': 'C#',
  13866. delphi: 'Delphi',
  13867. diff: 'Diff',
  13868. erlang: 'Erlang',
  13869. groovy: 'Groovy',
  13870. html: 'Html',
  13871. java: 'Java',
  13872. jfx: 'JavaFx',
  13873. js: 'Javascript',
  13874. pl: 'Perl',
  13875. php: 'Php',
  13876. plain: 'Plain Text',
  13877. ps: 'PowerShell',
  13878. python: 'Python',
  13879. ruby: 'Ruby',
  13880. scala: 'Scala',
  13881. sql: 'Sql',
  13882. vb: 'Vb',
  13883. xml: 'Xml',
  13884. })
  13885. /**
  13886. * 插入代码
  13887. * @command insertcode
  13888. * @method execCommand
  13889. * @param { String } cmd 命令字符串
  13890. * @param { String } lang 插入代码的语言
  13891. * @example
  13892. * ```javascript
  13893. * editor.execCommand( 'insertcode', 'javascript' );
  13894. * ```
  13895. */
  13896. /**
  13897. * 如果选区所在位置是插入插入代码区域,返回代码的语言
  13898. * @command insertcode
  13899. * @method queryCommandValue
  13900. * @param { String } cmd 命令字符串
  13901. * @return { String } 返回代码的语言
  13902. * @example
  13903. * ```javascript
  13904. * editor.queryCommandValue( 'insertcode' );
  13905. * ```
  13906. */
  13907. me.commands['insertcode'] = {
  13908. execCommand: function (cmd, lang) {
  13909. var me = this,
  13910. rng = me.selection.getRange(),
  13911. pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true)
  13912. if (pre) {
  13913. pre.className = 'brush:' + lang + ';toolbar:false;'
  13914. } else {
  13915. var code = ''
  13916. if (rng.collapsed) {
  13917. code =
  13918. browser.ie && browser.ie11below
  13919. ? browser.version <= 8
  13920. ? '&nbsp;'
  13921. : ''
  13922. : '<br/>'
  13923. } else {
  13924. var frag = rng.extractContents()
  13925. var div = me.document.createElement('div')
  13926. div.appendChild(frag)
  13927. utils.each(
  13928. UE.filterNode(
  13929. UE.htmlparser(div.innerHTML.replace(/[\r\t]/g, '')),
  13930. me.options.filterTxtRules
  13931. ).children,
  13932. function (node) {
  13933. if (browser.ie && browser.ie11below && browser.version > 8) {
  13934. if (node.type == 'element') {
  13935. if (node.tagName == 'br') {
  13936. code += '\n'
  13937. } else if (!dtd.$empty[node.tagName]) {
  13938. utils.each(node.children, function (cn) {
  13939. if (cn.type == 'element') {
  13940. if (cn.tagName == 'br') {
  13941. code += '\n'
  13942. } else if (!dtd.$empty[node.tagName]) {
  13943. code += cn.innerText()
  13944. }
  13945. } else {
  13946. code += cn.data
  13947. }
  13948. })
  13949. if (!/\n$/.test(code)) {
  13950. code += '\n'
  13951. }
  13952. }
  13953. } else {
  13954. code += node.data + '\n'
  13955. }
  13956. if (!node.nextSibling() && /\n$/.test(code)) {
  13957. code = code.replace(/\n$/, '')
  13958. }
  13959. } else {
  13960. if (browser.ie && browser.ie11below) {
  13961. if (node.type == 'element') {
  13962. if (node.tagName == 'br') {
  13963. code += '<br>'
  13964. } else if (!dtd.$empty[node.tagName]) {
  13965. utils.each(node.children, function (cn) {
  13966. if (cn.type == 'element') {
  13967. if (cn.tagName == 'br') {
  13968. code += '<br>'
  13969. } else if (!dtd.$empty[node.tagName]) {
  13970. code += cn.innerText()
  13971. }
  13972. } else {
  13973. code += cn.data
  13974. }
  13975. })
  13976. if (!/br>$/.test(code)) {
  13977. code += '<br>'
  13978. }
  13979. }
  13980. } else {
  13981. code += node.data + '<br>'
  13982. }
  13983. if (!node.nextSibling() && /<br>$/.test(code)) {
  13984. code = code.replace(/<br>$/, '')
  13985. }
  13986. } else {
  13987. code +=
  13988. node.type == 'element'
  13989. ? dtd.$empty[node.tagName]
  13990. ? ''
  13991. : node.innerText()
  13992. : node.data
  13993. if (!/br\/?\s*>$/.test(code)) {
  13994. if (!node.nextSibling()) return
  13995. code += '<br>'
  13996. }
  13997. }
  13998. }
  13999. }
  14000. )
  14001. }
  14002. me.execCommand(
  14003. 'inserthtml',
  14004. '<pre id="coder"class="brush:' +
  14005. lang +
  14006. ';toolbar:false">' +
  14007. code +
  14008. '</pre>',
  14009. true
  14010. )
  14011. pre = me.document.getElementById('coder')
  14012. domUtils.removeAttributes(pre, 'id')
  14013. var tmpNode = pre.previousSibling
  14014. if (
  14015. tmpNode &&
  14016. ((tmpNode.nodeType == 3 &&
  14017. tmpNode.nodeValue.length == 1 &&
  14018. browser.ie &&
  14019. browser.version == 6) ||
  14020. domUtils.isEmptyBlock(tmpNode))
  14021. ) {
  14022. domUtils.remove(tmpNode)
  14023. }
  14024. var rng = me.selection.getRange()
  14025. if (domUtils.isEmptyBlock(pre)) {
  14026. rng.setStart(pre, 0).setCursor(false, true)
  14027. } else {
  14028. rng.selectNodeContents(pre).select()
  14029. }
  14030. }
  14031. },
  14032. queryCommandValue: function () {
  14033. var path = this.selection.getStartElementPath()
  14034. var lang = ''
  14035. utils.each(path, function (node) {
  14036. if (node.nodeName == 'PRE') {
  14037. var match = node.className.match(/brush:([^;]+)/)
  14038. lang = match && match[1] ? match[1] : ''
  14039. return false
  14040. }
  14041. })
  14042. return lang
  14043. },
  14044. }
  14045. me.addInputRule(function (root) {
  14046. utils.each(root.getNodesByTagName('pre'), function (pre) {
  14047. var brs = pre.getNodesByTagName('br')
  14048. if (brs.length) {
  14049. browser.ie &&
  14050. browser.ie11below &&
  14051. browser.version > 8 &&
  14052. utils.each(brs, function (br) {
  14053. var txt = UE.uNode.createText('\n')
  14054. br.parentNode.insertBefore(txt, br)
  14055. br.parentNode.removeChild(br)
  14056. })
  14057. return
  14058. }
  14059. if (browser.ie && browser.ie11below && browser.version > 8) return
  14060. var code = pre.innerText().split(/\n/)
  14061. pre.innerHTML('')
  14062. utils.each(code, function (c) {
  14063. if (c.length) {
  14064. pre.appendChild(UE.uNode.createText(c))
  14065. }
  14066. pre.appendChild(UE.uNode.createElement('br'))
  14067. })
  14068. })
  14069. })
  14070. me.addOutputRule(function (root) {
  14071. utils.each(root.getNodesByTagName('pre'), function (pre) {
  14072. var code = ''
  14073. utils.each(pre.children, function (n) {
  14074. if (n.type == 'text') {
  14075. //在ie下文本内容有可能末尾带有\n要去掉
  14076. //trace:3396
  14077. code += n.data.replace(/[ ]/g, '&nbsp;').replace(/\n$/, '')
  14078. } else {
  14079. if (n.tagName == 'br') {
  14080. code += '\n'
  14081. } else {
  14082. code += !dtd.$empty[n.tagName] ? '' : n.innerText()
  14083. }
  14084. }
  14085. })
  14086. pre.innerText(code.replace(/(&nbsp;|\n)+$/, ''))
  14087. })
  14088. })
  14089. //不需要判断highlight的command列表
  14090. me.notNeedCodeQuery = {
  14091. help: 1,
  14092. undo: 1,
  14093. redo: 1,
  14094. source: 1,
  14095. print: 1,
  14096. searchreplace: 1,
  14097. fullscreen: 1,
  14098. preview: 1,
  14099. insertparagraph: 1,
  14100. elementpath: 1,
  14101. insertcode: 1,
  14102. inserthtml: 1,
  14103. selectall: 1,
  14104. }
  14105. //将queyCommamndState重置
  14106. var orgQuery = me.queryCommandState
  14107. me.queryCommandState = function (cmd) {
  14108. var me = this
  14109. if (
  14110. !me.notNeedCodeQuery[cmd.toLowerCase()] &&
  14111. me.selection &&
  14112. me.queryCommandValue('insertcode')
  14113. ) {
  14114. return -1
  14115. }
  14116. return UE.Editor.prototype.queryCommandState.apply(this, arguments)
  14117. }
  14118. me.addListener('beforeenterkeydown', function () {
  14119. var rng = me.selection.getRange()
  14120. var pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true)
  14121. if (pre) {
  14122. me.fireEvent('saveScene')
  14123. if (!rng.collapsed) {
  14124. rng.deleteContents()
  14125. }
  14126. if (!browser.ie || browser.ie9above) {
  14127. var tmpNode = me.document.createElement('br'),
  14128. pre
  14129. rng.insertNode(tmpNode).setStartAfter(tmpNode).collapse(true)
  14130. var next = tmpNode.nextSibling
  14131. if (!next && (!browser.ie || browser.version > 10)) {
  14132. rng.insertNode(tmpNode.cloneNode(false))
  14133. } else {
  14134. rng.setStartAfter(tmpNode)
  14135. }
  14136. pre = tmpNode.previousSibling
  14137. var tmp
  14138. while (pre) {
  14139. tmp = pre
  14140. pre = pre.previousSibling
  14141. if (!pre || pre.nodeName == 'BR') {
  14142. pre = tmp
  14143. break
  14144. }
  14145. }
  14146. if (pre) {
  14147. var str = ''
  14148. while (
  14149. pre &&
  14150. pre.nodeName != 'BR' &&
  14151. new RegExp('^[\\s' + domUtils.fillChar + ']*$').test(
  14152. pre.nodeValue
  14153. )
  14154. ) {
  14155. str += pre.nodeValue
  14156. pre = pre.nextSibling
  14157. }
  14158. if (pre.nodeName != 'BR') {
  14159. var match = pre.nodeValue.match(
  14160. new RegExp('^([\\s' + domUtils.fillChar + ']+)')
  14161. )
  14162. if (match && match[1]) {
  14163. str += match[1]
  14164. }
  14165. }
  14166. if (str) {
  14167. str = me.document.createTextNode(str)
  14168. rng.insertNode(str).setStartAfter(str)
  14169. }
  14170. }
  14171. rng.collapse(true).select(true)
  14172. } else {
  14173. if (browser.version > 8) {
  14174. var txt = me.document.createTextNode('\n')
  14175. var start = rng.startContainer
  14176. if (rng.startOffset == 0) {
  14177. var preNode = start.previousSibling
  14178. if (preNode) {
  14179. rng.insertNode(txt)
  14180. var fillchar = me.document.createTextNode(' ')
  14181. rng
  14182. .setStartAfter(txt)
  14183. .insertNode(fillchar)
  14184. .setStart(fillchar, 0)
  14185. .collapse(true)
  14186. .select(true)
  14187. }
  14188. } else {
  14189. rng.insertNode(txt).setStartAfter(txt)
  14190. var fillchar = me.document.createTextNode(' ')
  14191. start = rng.startContainer.childNodes[rng.startOffset]
  14192. if (start && !/^\n/.test(start.nodeValue)) {
  14193. rng.setStartBefore(txt)
  14194. }
  14195. rng
  14196. .insertNode(fillchar)
  14197. .setStart(fillchar, 0)
  14198. .collapse(true)
  14199. .select(true)
  14200. }
  14201. } else {
  14202. var tmpNode = me.document.createElement('br')
  14203. rng.insertNode(tmpNode)
  14204. rng.insertNode(me.document.createTextNode(domUtils.fillChar))
  14205. rng.setStartAfter(tmpNode)
  14206. pre = tmpNode.previousSibling
  14207. var tmp
  14208. while (pre) {
  14209. tmp = pre
  14210. pre = pre.previousSibling
  14211. if (!pre || pre.nodeName == 'BR') {
  14212. pre = tmp
  14213. break
  14214. }
  14215. }
  14216. if (pre) {
  14217. var str = ''
  14218. while (
  14219. pre &&
  14220. pre.nodeName != 'BR' &&
  14221. new RegExp('^[ ' + domUtils.fillChar + ']*$').test(
  14222. pre.nodeValue
  14223. )
  14224. ) {
  14225. str += pre.nodeValue
  14226. pre = pre.nextSibling
  14227. }
  14228. if (pre.nodeName != 'BR') {
  14229. var match = pre.nodeValue.match(
  14230. new RegExp('^([ ' + domUtils.fillChar + ']+)')
  14231. )
  14232. if (match && match[1]) {
  14233. str += match[1]
  14234. }
  14235. }
  14236. str = me.document.createTextNode(str)
  14237. rng.insertNode(str).setStartAfter(str)
  14238. }
  14239. rng.collapse(true).select()
  14240. }
  14241. }
  14242. me.fireEvent('saveScene')
  14243. return true
  14244. }
  14245. })
  14246. me.addListener('tabkeydown', function (cmd, evt) {
  14247. var rng = me.selection.getRange()
  14248. var pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true)
  14249. if (pre) {
  14250. me.fireEvent('saveScene')
  14251. if (evt.shiftKey) {
  14252. } else {
  14253. if (!rng.collapsed) {
  14254. var bk = rng.createBookmark()
  14255. var start = bk.start.previousSibling
  14256. while (start) {
  14257. if (pre.firstChild === start && !domUtils.isBr(start)) {
  14258. pre.insertBefore(me.document.createTextNode(' '), start)
  14259. break
  14260. }
  14261. if (domUtils.isBr(start)) {
  14262. pre.insertBefore(
  14263. me.document.createTextNode(' '),
  14264. start.nextSibling
  14265. )
  14266. break
  14267. }
  14268. start = start.previousSibling
  14269. }
  14270. var end = bk.end
  14271. start = bk.start.nextSibling
  14272. if (pre.firstChild === bk.start) {
  14273. pre.insertBefore(
  14274. me.document.createTextNode(' '),
  14275. start.nextSibling
  14276. )
  14277. }
  14278. while (start && start !== end) {
  14279. if (domUtils.isBr(start) && start.nextSibling) {
  14280. if (start.nextSibling === end) {
  14281. break
  14282. }
  14283. pre.insertBefore(
  14284. me.document.createTextNode(' '),
  14285. start.nextSibling
  14286. )
  14287. }
  14288. start = start.nextSibling
  14289. }
  14290. rng.moveToBookmark(bk).select()
  14291. } else {
  14292. var tmpNode = me.document.createTextNode(' ')
  14293. rng
  14294. .insertNode(tmpNode)
  14295. .setStartAfter(tmpNode)
  14296. .collapse(true)
  14297. .select(true)
  14298. }
  14299. }
  14300. me.fireEvent('saveScene')
  14301. return true
  14302. }
  14303. })
  14304. me.addListener('beforeinserthtml', function (evtName, html) {
  14305. var me = this,
  14306. rng = me.selection.getRange(),
  14307. pre = domUtils.findParentByTagName(rng.startContainer, 'pre', true)
  14308. if (pre) {
  14309. if (!rng.collapsed) {
  14310. rng.deleteContents()
  14311. }
  14312. var htmlstr = ''
  14313. if (browser.ie && browser.version > 8) {
  14314. utils.each(
  14315. UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules)
  14316. .children,
  14317. function (node) {
  14318. if (node.type == 'element') {
  14319. if (node.tagName == 'br') {
  14320. htmlstr += '\n'
  14321. } else if (!dtd.$empty[node.tagName]) {
  14322. utils.each(node.children, function (cn) {
  14323. if (cn.type == 'element') {
  14324. if (cn.tagName == 'br') {
  14325. htmlstr += '\n'
  14326. } else if (!dtd.$empty[node.tagName]) {
  14327. htmlstr += cn.innerText()
  14328. }
  14329. } else {
  14330. htmlstr += cn.data
  14331. }
  14332. })
  14333. if (!/\n$/.test(htmlstr)) {
  14334. htmlstr += '\n'
  14335. }
  14336. }
  14337. } else {
  14338. htmlstr += node.data + '\n'
  14339. }
  14340. if (!node.nextSibling() && /\n$/.test(htmlstr)) {
  14341. htmlstr = htmlstr.replace(/\n$/, '')
  14342. }
  14343. }
  14344. )
  14345. var tmpNode = me.document.createTextNode(
  14346. utils.html(htmlstr.replace(/&nbsp;/g, ' '))
  14347. )
  14348. rng.insertNode(tmpNode).selectNode(tmpNode).select()
  14349. } else {
  14350. var frag = me.document.createDocumentFragment()
  14351. utils.each(
  14352. UE.filterNode(UE.htmlparser(html), me.options.filterTxtRules)
  14353. .children,
  14354. function (node) {
  14355. if (node.type == 'element') {
  14356. if (node.tagName == 'br') {
  14357. frag.appendChild(me.document.createElement('br'))
  14358. } else if (!dtd.$empty[node.tagName]) {
  14359. utils.each(node.children, function (cn) {
  14360. if (cn.type == 'element') {
  14361. if (cn.tagName == 'br') {
  14362. frag.appendChild(me.document.createElement('br'))
  14363. } else if (!dtd.$empty[node.tagName]) {
  14364. frag.appendChild(
  14365. me.document.createTextNode(
  14366. utils.html(cn.innerText().replace(/&nbsp;/g, ' '))
  14367. )
  14368. )
  14369. }
  14370. } else {
  14371. frag.appendChild(
  14372. me.document.createTextNode(
  14373. utils.html(cn.data.replace(/&nbsp;/g, ' '))
  14374. )
  14375. )
  14376. }
  14377. })
  14378. if (frag.lastChild.nodeName != 'BR') {
  14379. frag.appendChild(me.document.createElement('br'))
  14380. }
  14381. }
  14382. } else {
  14383. frag.appendChild(
  14384. me.document.createTextNode(
  14385. utils.html(node.data.replace(/&nbsp;/g, ' '))
  14386. )
  14387. )
  14388. }
  14389. if (!node.nextSibling() && frag.lastChild.nodeName == 'BR') {
  14390. frag.removeChild(frag.lastChild)
  14391. }
  14392. }
  14393. )
  14394. rng.insertNode(frag).select()
  14395. }
  14396. return true
  14397. }
  14398. })
  14399. //方向键的处理
  14400. me.addListener('keydown', function (cmd, evt) {
  14401. var me = this,
  14402. keyCode = evt.keyCode || evt.which
  14403. if (keyCode == 40) {
  14404. var rng = me.selection.getRange(),
  14405. pre,
  14406. start = rng.startContainer
  14407. if (
  14408. rng.collapsed &&
  14409. (pre = domUtils.findParentByTagName(
  14410. rng.startContainer,
  14411. 'pre',
  14412. true
  14413. )) &&
  14414. !pre.nextSibling
  14415. ) {
  14416. var last = pre.lastChild
  14417. while (last && last.nodeName == 'BR') {
  14418. last = last.previousSibling
  14419. }
  14420. if (
  14421. last === start ||
  14422. (rng.startContainer === pre &&
  14423. rng.startOffset == pre.childNodes.length)
  14424. ) {
  14425. me.execCommand('insertparagraph')
  14426. domUtils.preventDefault(evt)
  14427. }
  14428. }
  14429. }
  14430. })
  14431. //trace:3395
  14432. me.addListener('delkeydown', function (type, evt) {
  14433. var rng = this.selection.getRange()
  14434. rng.txtToElmBoundary(true)
  14435. var start = rng.startContainer
  14436. if (
  14437. domUtils.isTagNode(start, 'pre') &&
  14438. rng.collapsed &&
  14439. domUtils.isStartInblock(rng)
  14440. ) {
  14441. var p = me.document.createElement('p')
  14442. domUtils.fillNode(me.document, p)
  14443. start.parentNode.insertBefore(p, start)
  14444. domUtils.remove(start)
  14445. rng.setStart(p, 0).setCursor(false, true)
  14446. domUtils.preventDefault(evt)
  14447. return true
  14448. }
  14449. })
  14450. }
  14451. // plugins/cleardoc.js
  14452. /**
  14453. * 清空文档插件
  14454. * @file
  14455. * @since 1.2.6.1
  14456. */
  14457. /**
  14458. * 清空文档
  14459. * @command cleardoc
  14460. * @method execCommand
  14461. * @param { String } cmd 命令字符串
  14462. * @example
  14463. * ```javascript
  14464. * //editor 是编辑器实例
  14465. * editor.execCommand('cleardoc');
  14466. * ```
  14467. */
  14468. UE.commands['cleardoc'] = {
  14469. execCommand: function (cmdName) {
  14470. var me = this,
  14471. enterTag = me.options.enterTag,
  14472. range = me.selection.getRange()
  14473. if (enterTag == 'br') {
  14474. me.body.innerHTML = '<br/>'
  14475. range.setStart(me.body, 0).setCursor()
  14476. } else {
  14477. me.body.innerHTML = '<p>' + (ie ? '' : '<br/>') + '</p>'
  14478. range.setStart(me.body.firstChild, 0).setCursor(false, true)
  14479. }
  14480. setTimeout(function () {
  14481. me.fireEvent('clearDoc')
  14482. }, 0)
  14483. },
  14484. }
  14485. // plugins/anchor.js
  14486. /**
  14487. * 锚点插件,为UEditor提供插入锚点支持
  14488. * @file
  14489. * @since 1.2.6.1
  14490. */
  14491. UE.plugin.register('anchor', function () {
  14492. return {
  14493. bindEvents: {
  14494. ready: function () {
  14495. utils.cssRule(
  14496. 'anchor',
  14497. ".anchorclass{background: url('" +
  14498. this.options.themePath +
  14499. this.options.theme +
  14500. "/images/anchor.gif') no-repeat scroll left center transparent;cursor: auto;display: inline-block;height: 16px;width: 15px;}",
  14501. this.document
  14502. )
  14503. },
  14504. },
  14505. outputRule: function (root) {
  14506. utils.each(root.getNodesByTagName('img'), function (a) {
  14507. var val
  14508. if ((val = a.getAttr('anchorname'))) {
  14509. a.tagName = 'a'
  14510. a.setAttr({
  14511. anchorname: '',
  14512. name: val,
  14513. class: '',
  14514. })
  14515. }
  14516. })
  14517. },
  14518. inputRule: function (root) {
  14519. utils.each(root.getNodesByTagName('a'), function (a) {
  14520. var val
  14521. if ((val = a.getAttr('name')) && !a.getAttr('href')) {
  14522. a.tagName = 'img'
  14523. a.setAttr({
  14524. anchorname: a.getAttr('name'),
  14525. class: 'anchorclass',
  14526. })
  14527. a.setAttr('name')
  14528. }
  14529. })
  14530. },
  14531. commands: {
  14532. /**
  14533. * 插入锚点
  14534. * @command anchor
  14535. * @method execCommand
  14536. * @param { String } cmd 命令字符串
  14537. * @param { String } name 锚点名称字符串
  14538. * @example
  14539. * ```javascript
  14540. * //editor 是编辑器实例
  14541. * editor.execCommand('anchor', 'anchor1');
  14542. * ```
  14543. */
  14544. anchor: {
  14545. execCommand: function (cmd, name) {
  14546. var range = this.selection.getRange(),
  14547. img = range.getClosedNode()
  14548. if (img && img.getAttribute('anchorname')) {
  14549. if (name) {
  14550. img.setAttribute('anchorname', name)
  14551. } else {
  14552. range.setStartBefore(img).setCursor()
  14553. domUtils.remove(img)
  14554. }
  14555. } else {
  14556. if (name) {
  14557. //只在选区的开始插入
  14558. var anchor = this.document.createElement('img')
  14559. range.collapse(true)
  14560. domUtils.setAttributes(anchor, {
  14561. anchorname: name,
  14562. class: 'anchorclass',
  14563. })
  14564. range
  14565. .insertNode(anchor)
  14566. .setStartAfter(anchor)
  14567. .setCursor(false, true)
  14568. }
  14569. }
  14570. },
  14571. },
  14572. },
  14573. }
  14574. })
  14575. // plugins/wordcount.js
  14576. ///import core
  14577. ///commands 字数统计
  14578. ///commandsName WordCount,wordCount
  14579. ///commandsTitle 字数统计
  14580. /*
  14581. * Created by JetBrains WebStorm.
  14582. * User: taoqili
  14583. * Date: 11-9-7
  14584. * Time: 下午8:18
  14585. * To change this template use File | Settings | File Templates.
  14586. */
  14587. UE.plugins['wordcount'] = function () {
  14588. var me = this
  14589. me.setOpt('wordCount', true)
  14590. me.addListener('contentchange', function () {
  14591. me.fireEvent('wordcount')
  14592. })
  14593. var timer
  14594. me.addListener('ready', function () {
  14595. var me = this
  14596. domUtils.on(me.body, 'keyup', function (evt) {
  14597. var code = evt.keyCode || evt.which,
  14598. //忽略的按键,ctr,alt,shift,方向键
  14599. ignores = { 16: 1, 18: 1, 20: 1, 37: 1, 38: 1, 39: 1, 40: 1 }
  14600. if (code in ignores) return
  14601. clearTimeout(timer)
  14602. timer = setTimeout(function () {
  14603. me.fireEvent('wordcount')
  14604. }, 200)
  14605. })
  14606. })
  14607. }
  14608. // plugins/pagebreak.js
  14609. /**
  14610. * 分页功能插件
  14611. * @file
  14612. * @since 1.2.6.1
  14613. */
  14614. UE.plugins['pagebreak'] = function () {
  14615. var me = this,
  14616. notBreakTags = ['td']
  14617. me.setOpt('pageBreakTag', '_ueditor_page_break_tag_')
  14618. function fillNode(node) {
  14619. if (domUtils.isEmptyBlock(node)) {
  14620. var firstChild = node.firstChild,
  14621. tmpNode
  14622. while (
  14623. firstChild &&
  14624. firstChild.nodeType == 1 &&
  14625. domUtils.isEmptyBlock(firstChild)
  14626. ) {
  14627. tmpNode = firstChild
  14628. firstChild = firstChild.firstChild
  14629. }
  14630. !tmpNode && (tmpNode = node)
  14631. domUtils.fillNode(me.document, tmpNode)
  14632. }
  14633. }
  14634. //分页符样式添加
  14635. me.ready(function () {
  14636. utils.cssRule(
  14637. 'pagebreak',
  14638. '.pagebreak{display:block;clear:both !important;cursor:default !important;width: 100% !important;margin:0;}',
  14639. me.document
  14640. )
  14641. })
  14642. function isHr(node) {
  14643. return (
  14644. node &&
  14645. node.nodeType == 1 &&
  14646. node.tagName == 'HR' &&
  14647. node.className == 'pagebreak'
  14648. )
  14649. }
  14650. me.addInputRule(function (root) {
  14651. root.traversal(function (node) {
  14652. if (node.type == 'text' && node.data == me.options.pageBreakTag) {
  14653. var hr = UE.uNode.createElement(
  14654. '<hr class="pagebreak" noshade="noshade" size="5" style="-webkit-user-select: none;">'
  14655. )
  14656. node.parentNode.insertBefore(hr, node)
  14657. node.parentNode.removeChild(node)
  14658. }
  14659. })
  14660. })
  14661. me.addOutputRule(function (node) {
  14662. utils.each(node.getNodesByTagName('hr'), function (n) {
  14663. if (n.getAttr('class') == 'pagebreak') {
  14664. var txt = UE.uNode.createText(me.options.pageBreakTag)
  14665. n.parentNode.insertBefore(txt, n)
  14666. n.parentNode.removeChild(n)
  14667. }
  14668. })
  14669. })
  14670. /**
  14671. * 插入分页符
  14672. * @command pagebreak
  14673. * @method execCommand
  14674. * @param { String } cmd 命令字符串
  14675. * @remind 在表格中插入分页符会把表格切分成两部分
  14676. * @remind 获取编辑器内的数据时, 编辑器会把分页符转换成“_ueditor_page_break_tag_”字符串,
  14677. * 以便于提交数据到服务器端后处理分页。
  14678. * @example
  14679. * ```javascript
  14680. * editor.execCommand( 'pagebreak'); //插入一个hr标签,带有样式类名pagebreak
  14681. * ```
  14682. */
  14683. me.commands['pagebreak'] = {
  14684. execCommand: function () {
  14685. var range = me.selection.getRange(),
  14686. hr = me.document.createElement('hr')
  14687. domUtils.setAttributes(hr, {
  14688. class: 'pagebreak',
  14689. noshade: 'noshade',
  14690. size: '5',
  14691. })
  14692. domUtils.unSelectable(hr)
  14693. //table单独处理
  14694. var node = domUtils.findParentByTagName(
  14695. range.startContainer,
  14696. notBreakTags,
  14697. true
  14698. ),
  14699. parents = [],
  14700. pN
  14701. if (node) {
  14702. switch (node.tagName) {
  14703. case 'TD':
  14704. pN = node.parentNode
  14705. if (!pN.previousSibling) {
  14706. var table = domUtils.findParentByTagName(pN, 'table')
  14707. // var tableWrapDiv = table.parentNode;
  14708. // if(tableWrapDiv && tableWrapDiv.nodeType == 1
  14709. // && tableWrapDiv.tagName == 'DIV'
  14710. // && tableWrapDiv.getAttribute('dropdrag')
  14711. // ){
  14712. // domUtils.remove(tableWrapDiv,true);
  14713. // }
  14714. table.parentNode.insertBefore(hr, table)
  14715. parents = domUtils.findParents(hr, true)
  14716. } else {
  14717. pN.parentNode.insertBefore(hr, pN)
  14718. parents = domUtils.findParents(hr)
  14719. }
  14720. pN = parents[1]
  14721. if (hr !== pN) {
  14722. domUtils.breakParent(hr, pN)
  14723. }
  14724. //table要重写绑定一下拖拽
  14725. me.fireEvent('afteradjusttable', me.document)
  14726. }
  14727. } else {
  14728. if (!range.collapsed) {
  14729. range.deleteContents()
  14730. var start = range.startContainer
  14731. while (
  14732. !domUtils.isBody(start) &&
  14733. domUtils.isBlockElm(start) &&
  14734. domUtils.isEmptyNode(start)
  14735. ) {
  14736. range.setStartBefore(start).collapse(true)
  14737. domUtils.remove(start)
  14738. start = range.startContainer
  14739. }
  14740. }
  14741. range.insertNode(hr)
  14742. var pN = hr.parentNode,
  14743. nextNode
  14744. while (!domUtils.isBody(pN)) {
  14745. domUtils.breakParent(hr, pN)
  14746. nextNode = hr.nextSibling
  14747. if (nextNode && domUtils.isEmptyBlock(nextNode)) {
  14748. domUtils.remove(nextNode)
  14749. }
  14750. pN = hr.parentNode
  14751. }
  14752. nextNode = hr.nextSibling
  14753. var pre = hr.previousSibling
  14754. if (isHr(pre)) {
  14755. domUtils.remove(pre)
  14756. } else {
  14757. pre && fillNode(pre)
  14758. }
  14759. if (!nextNode) {
  14760. var p = me.document.createElement('p')
  14761. hr.parentNode.appendChild(p)
  14762. domUtils.fillNode(me.document, p)
  14763. range.setStart(p, 0).collapse(true)
  14764. } else {
  14765. if (isHr(nextNode)) {
  14766. domUtils.remove(nextNode)
  14767. } else {
  14768. fillNode(nextNode)
  14769. }
  14770. range.setEndAfter(hr).collapse(false)
  14771. }
  14772. range.select(true)
  14773. }
  14774. },
  14775. }
  14776. }
  14777. // plugins/wordimage.js
  14778. ///import core
  14779. ///commands 本地图片引导上传
  14780. ///commandsName WordImage
  14781. ///commandsTitle 本地图片引导上传
  14782. ///commandsDialog dialogs\wordimage
  14783. UE.plugin.register('wordimage', function () {
  14784. var me = this,
  14785. images = []
  14786. return {
  14787. commands: {
  14788. wordimage: {
  14789. execCommand: function () {
  14790. var images = domUtils.getElementsByTagName(me.body, 'img')
  14791. var urlList = []
  14792. for (var i = 0, ci; (ci = images[i++]); ) {
  14793. var url = ci.getAttribute('word_img')
  14794. url && urlList.push(url)
  14795. }
  14796. return urlList
  14797. },
  14798. queryCommandState: function () {
  14799. images = domUtils.getElementsByTagName(me.body, 'img')
  14800. for (var i = 0, ci; (ci = images[i++]); ) {
  14801. if (ci.getAttribute('word_img')) {
  14802. return 1
  14803. }
  14804. }
  14805. return -1
  14806. },
  14807. notNeedUndo: true,
  14808. },
  14809. },
  14810. inputRule: function (root) {
  14811. utils.each(root.getNodesByTagName('img'), function (img) {
  14812. var attrs = img.attrs,
  14813. flag = parseInt(attrs.width) < 128 || parseInt(attrs.height) < 43,
  14814. opt = me.options,
  14815. src = opt.UEDITOR_HOME_URL + 'themes/default/images/spacer.gif'
  14816. if (attrs['src'] && /^(?:(file:\/+))/.test(attrs['src'])) {
  14817. img.setAttr({
  14818. width: attrs.width,
  14819. height: attrs.height,
  14820. alt: attrs.alt,
  14821. word_img: attrs.src,
  14822. src: src,
  14823. style:
  14824. 'background:url(' +
  14825. (flag
  14826. ? opt.themePath + opt.theme + '/images/word.gif'
  14827. : opt.langPath + opt.lang + '/images/localimage.png') +
  14828. ') no-repeat center center;border:1px solid #ddd',
  14829. })
  14830. }
  14831. })
  14832. },
  14833. }
  14834. })
  14835. // plugins/dragdrop.js
  14836. UE.plugins['dragdrop'] = function () {
  14837. var me = this
  14838. me.ready(function () {
  14839. domUtils.on(this.body, 'dragend', function () {
  14840. var rng = me.selection.getRange()
  14841. var node = rng.getClosedNode() || me.selection.getStart()
  14842. if (node && node.tagName == 'IMG') {
  14843. var pre = node.previousSibling,
  14844. next
  14845. while ((next = node.nextSibling)) {
  14846. if (
  14847. next.nodeType == 1 &&
  14848. next.tagName == 'SPAN' &&
  14849. !next.firstChild
  14850. ) {
  14851. domUtils.remove(next)
  14852. } else {
  14853. break
  14854. }
  14855. }
  14856. if (
  14857. ((pre && pre.nodeType == 1 && !domUtils.isEmptyBlock(pre)) ||
  14858. !pre) &&
  14859. (!next || (next && !domUtils.isEmptyBlock(next)))
  14860. ) {
  14861. if (pre && pre.tagName == 'P' && !domUtils.isEmptyBlock(pre)) {
  14862. pre.appendChild(node)
  14863. domUtils.moveChild(next, pre)
  14864. domUtils.remove(next)
  14865. } else if (
  14866. next &&
  14867. next.tagName == 'P' &&
  14868. !domUtils.isEmptyBlock(next)
  14869. ) {
  14870. next.insertBefore(node, next.firstChild)
  14871. }
  14872. if (pre && pre.tagName == 'P' && domUtils.isEmptyBlock(pre)) {
  14873. domUtils.remove(pre)
  14874. }
  14875. if (next && next.tagName == 'P' && domUtils.isEmptyBlock(next)) {
  14876. domUtils.remove(next)
  14877. }
  14878. rng.selectNode(node).select()
  14879. me.fireEvent('saveScene')
  14880. }
  14881. }
  14882. })
  14883. })
  14884. me.addListener('keyup', function (type, evt) {
  14885. var keyCode = evt.keyCode || evt.which
  14886. if (keyCode == 13) {
  14887. var rng = me.selection.getRange(),
  14888. node
  14889. if (
  14890. (node = domUtils.findParentByTagName(rng.startContainer, 'p', true))
  14891. ) {
  14892. if (domUtils.getComputedStyle(node, 'text-align') == 'center') {
  14893. domUtils.removeStyle(node, 'text-align')
  14894. }
  14895. }
  14896. }
  14897. })
  14898. }
  14899. // plugins/undo.js
  14900. /**
  14901. * undo redo
  14902. * @file
  14903. * @since 1.2.6.1
  14904. */
  14905. /**
  14906. * 撤销上一次执行的命令
  14907. * @command undo
  14908. * @method execCommand
  14909. * @param { String } cmd 命令字符串
  14910. * @example
  14911. * ```javascript
  14912. * editor.execCommand( 'undo' );
  14913. * ```
  14914. */
  14915. /**
  14916. * 重做上一次执行的命令
  14917. * @command redo
  14918. * @method execCommand
  14919. * @param { String } cmd 命令字符串
  14920. * @example
  14921. * ```javascript
  14922. * editor.execCommand( 'redo' );
  14923. * ```
  14924. */
  14925. UE.plugins['undo'] = function () {
  14926. var saveSceneTimer
  14927. var me = this,
  14928. maxUndoCount = me.options.maxUndoCount || 20,
  14929. maxInputCount = me.options.maxInputCount || 20,
  14930. fillchar = new RegExp(domUtils.fillChar + '|</hr>', 'gi') // ie会产生多余的</hr>
  14931. var noNeedFillCharTags = {
  14932. ol: 1,
  14933. ul: 1,
  14934. table: 1,
  14935. tbody: 1,
  14936. tr: 1,
  14937. body: 1,
  14938. }
  14939. var orgState = me.options.autoClearEmptyNode
  14940. function compareAddr(indexA, indexB) {
  14941. if (indexA.length != indexB.length) return 0
  14942. for (var i = 0, l = indexA.length; i < l; i++) {
  14943. if (indexA[i] != indexB[i]) return 0
  14944. }
  14945. return 1
  14946. }
  14947. function compareRangeAddress(rngAddrA, rngAddrB) {
  14948. if (rngAddrA.collapsed != rngAddrB.collapsed) {
  14949. return 0
  14950. }
  14951. if (
  14952. !compareAddr(rngAddrA.startAddress, rngAddrB.startAddress) ||
  14953. !compareAddr(rngAddrA.endAddress, rngAddrB.endAddress)
  14954. ) {
  14955. return 0
  14956. }
  14957. return 1
  14958. }
  14959. function UndoManager() {
  14960. this.list = []
  14961. this.index = 0
  14962. this.hasUndo = false
  14963. this.hasRedo = false
  14964. this.undo = function () {
  14965. if (this.hasUndo) {
  14966. if (!this.list[this.index - 1] && this.list.length == 1) {
  14967. this.reset()
  14968. return
  14969. }
  14970. while (
  14971. this.list[this.index].content == this.list[this.index - 1].content
  14972. ) {
  14973. this.index--
  14974. if (this.index == 0) {
  14975. return this.restore(0)
  14976. }
  14977. }
  14978. this.restore(--this.index)
  14979. }
  14980. }
  14981. this.redo = function () {
  14982. if (this.hasRedo) {
  14983. while (
  14984. this.list[this.index].content == this.list[this.index + 1].content
  14985. ) {
  14986. this.index++
  14987. if (this.index == this.list.length - 1) {
  14988. return this.restore(this.index)
  14989. }
  14990. }
  14991. this.restore(++this.index)
  14992. }
  14993. }
  14994. this.restore = function () {
  14995. var me = this.editor
  14996. var scene = this.list[this.index]
  14997. var root = UE.htmlparser(scene.content.replace(fillchar, ''))
  14998. me.options.autoClearEmptyNode = false
  14999. me.filterInputRule(root)
  15000. me.options.autoClearEmptyNode = orgState
  15001. //trace:873
  15002. //去掉展位符
  15003. me.document.body.innerHTML = root.toHtml()
  15004. me.fireEvent('afterscencerestore')
  15005. //处理undo后空格不展位的问题
  15006. if (browser.ie) {
  15007. utils.each(
  15008. domUtils.getElementsByTagName(me.document, 'td th caption p'),
  15009. function (node) {
  15010. if (domUtils.isEmptyNode(node)) {
  15011. domUtils.fillNode(me.document, node)
  15012. }
  15013. }
  15014. )
  15015. }
  15016. try {
  15017. var rng = new dom.Range(me.document).moveToAddress(scene.address)
  15018. rng.select(
  15019. noNeedFillCharTags[rng.startContainer.nodeName.toLowerCase()]
  15020. )
  15021. } catch (e) {}
  15022. this.update()
  15023. this.clearKey()
  15024. //不能把自己reset了
  15025. me.fireEvent('reset', true)
  15026. }
  15027. this.getScene = function () {
  15028. var me = this.editor
  15029. var rng = me.selection.getRange(),
  15030. rngAddress = rng.createAddress(false, true)
  15031. me.fireEvent('beforegetscene')
  15032. var root = UE.htmlparser(me.body.innerHTML)
  15033. me.options.autoClearEmptyNode = false
  15034. me.filterOutputRule(root)
  15035. me.options.autoClearEmptyNode = orgState
  15036. var cont = root.toHtml()
  15037. //trace:3461
  15038. //这个会引起回退时导致空格丢失的情况
  15039. // browser.ie && (cont = cont.replace(/>&nbsp;</g, '><').replace(/\s*</g, '<').replace(/>\s*/g, '>'));
  15040. me.fireEvent('aftergetscene')
  15041. return {
  15042. address: rngAddress,
  15043. content: cont,
  15044. }
  15045. }
  15046. this.save = function (notCompareRange, notSetCursor) {
  15047. clearTimeout(saveSceneTimer)
  15048. var currentScene = this.getScene(notSetCursor),
  15049. lastScene = this.list[this.index]
  15050. if (lastScene && lastScene.content != currentScene.content) {
  15051. me.trigger('contentchange')
  15052. }
  15053. //内容相同位置相同不存
  15054. if (
  15055. lastScene &&
  15056. lastScene.content == currentScene.content &&
  15057. (notCompareRange
  15058. ? 1
  15059. : compareRangeAddress(lastScene.address, currentScene.address))
  15060. ) {
  15061. return
  15062. }
  15063. this.list = this.list.slice(0, this.index + 1)
  15064. this.list.push(currentScene)
  15065. //如果大于最大数量了,就把最前的剔除
  15066. if (this.list.length > maxUndoCount) {
  15067. this.list.shift()
  15068. }
  15069. this.index = this.list.length - 1
  15070. this.clearKey()
  15071. //跟新undo/redo状态
  15072. this.update()
  15073. }
  15074. this.update = function () {
  15075. this.hasRedo = !!this.list[this.index + 1]
  15076. this.hasUndo = !!this.list[this.index - 1]
  15077. }
  15078. this.reset = function () {
  15079. this.list = []
  15080. this.index = 0
  15081. this.hasUndo = false
  15082. this.hasRedo = false
  15083. this.clearKey()
  15084. }
  15085. this.clearKey = function () {
  15086. keycont = 0
  15087. lastKeyCode = null
  15088. }
  15089. }
  15090. me.undoManger = new UndoManager()
  15091. me.undoManger.editor = me
  15092. function saveScene() {
  15093. this.undoManger.save()
  15094. }
  15095. me.addListener('saveScene', function () {
  15096. var args = Array.prototype.splice.call(arguments, 1)
  15097. this.undoManger.save.apply(this.undoManger, args)
  15098. })
  15099. // me.addListener('beforeexeccommand', saveScene);
  15100. // me.addListener('afterexeccommand', saveScene);
  15101. me.addListener('reset', function (type, exclude) {
  15102. if (!exclude) {
  15103. this.undoManger.reset()
  15104. }
  15105. })
  15106. me.commands['redo'] = me.commands['undo'] = {
  15107. execCommand: function (cmdName) {
  15108. this.undoManger[cmdName]()
  15109. },
  15110. queryCommandState: function (cmdName) {
  15111. return this.undoManger[
  15112. 'has' + (cmdName.toLowerCase() == 'undo' ? 'Undo' : 'Redo')
  15113. ]
  15114. ? 0
  15115. : -1
  15116. },
  15117. notNeedUndo: 1,
  15118. }
  15119. var keys = {
  15120. // /*Backspace*/ 8:1, /*Delete*/ 46:1,
  15121. /*Shift*/ 16: 1,
  15122. /*Ctrl*/ 17: 1,
  15123. /*Alt*/ 18: 1,
  15124. 37: 1,
  15125. 38: 1,
  15126. 39: 1,
  15127. 40: 1,
  15128. },
  15129. keycont = 0,
  15130. lastKeyCode
  15131. //输入法状态下不计算字符数
  15132. var inputType = false
  15133. me.addListener('ready', function () {
  15134. domUtils.on(this.body, 'compositionstart', function () {
  15135. inputType = true
  15136. })
  15137. domUtils.on(this.body, 'compositionend', function () {
  15138. inputType = false
  15139. })
  15140. })
  15141. //快捷键
  15142. me.addshortcutkey({
  15143. Undo: 'ctrl+90', //undo
  15144. Redo: 'ctrl+89', //redo
  15145. })
  15146. var isCollapsed = true
  15147. me.addListener('keydown', function (type, evt) {
  15148. var me = this
  15149. var keyCode = evt.keyCode || evt.which
  15150. if (
  15151. !keys[keyCode] &&
  15152. !evt.ctrlKey &&
  15153. !evt.metaKey &&
  15154. !evt.shiftKey &&
  15155. !evt.altKey
  15156. ) {
  15157. if (inputType) return
  15158. if (!me.selection.getRange().collapsed) {
  15159. me.undoManger.save(false, true)
  15160. isCollapsed = false
  15161. return
  15162. }
  15163. if (me.undoManger.list.length == 0) {
  15164. me.undoManger.save(true)
  15165. }
  15166. clearTimeout(saveSceneTimer)
  15167. function save(cont) {
  15168. cont.undoManger.save(false, true)
  15169. cont.fireEvent('selectionchange')
  15170. }
  15171. saveSceneTimer = setTimeout(function () {
  15172. if (inputType) {
  15173. var interalTimer = setInterval(function () {
  15174. if (!inputType) {
  15175. save(me)
  15176. clearInterval(interalTimer)
  15177. }
  15178. }, 300)
  15179. return
  15180. }
  15181. save(me)
  15182. }, 200)
  15183. lastKeyCode = keyCode
  15184. keycont++
  15185. if (keycont >= maxInputCount) {
  15186. save(me)
  15187. }
  15188. }
  15189. })
  15190. me.addListener('keyup', function (type, evt) {
  15191. var keyCode = evt.keyCode || evt.which
  15192. if (
  15193. !keys[keyCode] &&
  15194. !evt.ctrlKey &&
  15195. !evt.metaKey &&
  15196. !evt.shiftKey &&
  15197. !evt.altKey
  15198. ) {
  15199. if (inputType) return
  15200. if (!isCollapsed) {
  15201. this.undoManger.save(false, true)
  15202. isCollapsed = true
  15203. }
  15204. }
  15205. })
  15206. //扩展实例,添加关闭和开启命令undo
  15207. me.stopCmdUndo = function () {
  15208. me.__hasEnterExecCommand = true
  15209. }
  15210. me.startCmdUndo = function () {
  15211. me.__hasEnterExecCommand = false
  15212. }
  15213. }
  15214. // plugins/copy.js
  15215. UE.plugin.register('copy', function () {
  15216. var me = this
  15217. function initZeroClipboard() {
  15218. ZeroClipboard.config({
  15219. debug: false,
  15220. swfPath:
  15221. me.options.UEDITOR_HOME_URL +
  15222. 'third-party/zeroclipboard/ZeroClipboard.swf',
  15223. })
  15224. var client = (me.zeroclipboard = new ZeroClipboard())
  15225. // 复制内容
  15226. client.on('copy', function (e) {
  15227. var client = e.client,
  15228. rng = me.selection.getRange(),
  15229. div = document.createElement('div')
  15230. div.appendChild(rng.cloneContents())
  15231. client.setText(div.innerText || div.textContent)
  15232. client.setHtml(div.innerHTML)
  15233. rng.select()
  15234. })
  15235. // hover事件传递到target
  15236. client.on('mouseover mouseout', function (e) {
  15237. var target = e.target
  15238. if (e.type == 'mouseover') {
  15239. domUtils.addClass(target, 'edui-state-hover')
  15240. } else if (e.type == 'mouseout') {
  15241. domUtils.removeClasses(target, 'edui-state-hover')
  15242. }
  15243. })
  15244. // flash加载不成功
  15245. client.on('wrongflash noflash', function () {
  15246. ZeroClipboard.destroy()
  15247. })
  15248. }
  15249. return {
  15250. bindEvents: {
  15251. ready: function () {
  15252. if (!browser.ie) {
  15253. if (window.ZeroClipboard) {
  15254. initZeroClipboard()
  15255. } else {
  15256. utils.loadFile(
  15257. document,
  15258. {
  15259. src:
  15260. me.options.UEDITOR_HOME_URL +
  15261. 'third-party/zeroclipboard/ZeroClipboard.js',
  15262. tag: 'script',
  15263. type: 'text/javascript',
  15264. defer: 'defer',
  15265. },
  15266. function () {
  15267. initZeroClipboard()
  15268. }
  15269. )
  15270. }
  15271. }
  15272. },
  15273. },
  15274. commands: {
  15275. copy: {
  15276. execCommand: function (cmd) {
  15277. if (!me.document.execCommand('copy')) {
  15278. alert(me.getLang('copymsg'))
  15279. }
  15280. },
  15281. },
  15282. },
  15283. }
  15284. })
  15285. // plugins/paste.js
  15286. ///import core
  15287. ///import plugins/inserthtml.js
  15288. ///import plugins/undo.js
  15289. ///import plugins/serialize.js
  15290. ///commands 粘贴
  15291. ///commandsName PastePlain
  15292. ///commandsTitle 纯文本粘贴模式
  15293. /**
  15294. * @description 粘贴
  15295. * @author zhanyi
  15296. */
  15297. UE.plugins['paste'] = function () {
  15298. function getClipboardData(callback) {
  15299. var doc = this.document
  15300. if (doc.getElementById('baidu_pastebin')) {
  15301. return
  15302. }
  15303. var range = this.selection.getRange(),
  15304. bk = range.createBookmark(),
  15305. //创建剪贴的容器div
  15306. pastebin = doc.createElement('div')
  15307. pastebin.id = 'baidu_pastebin'
  15308. // Safari 要求div必须有内容,才能粘贴内容进来
  15309. browser.webkit &&
  15310. pastebin.appendChild(
  15311. doc.createTextNode(domUtils.fillChar + domUtils.fillChar)
  15312. )
  15313. doc.body.appendChild(pastebin)
  15314. //trace:717 隐藏的span不能得到top
  15315. //bk.start.innerHTML = '&nbsp;';
  15316. bk.start.style.display = ''
  15317. pastebin.style.cssText =
  15318. 'position:absolute;width:1px;height:1px;overflow:hidden;left:-1000px;white-space:nowrap;top:' +
  15319. //要在现在光标平行的位置加入,否则会出现跳动的问题
  15320. domUtils.getXY(bk.start).y +
  15321. 'px'
  15322. range.selectNodeContents(pastebin).select(true)
  15323. setTimeout(function () {
  15324. if (browser.webkit) {
  15325. for (
  15326. var i = 0, pastebins = doc.querySelectorAll('#baidu_pastebin'), pi;
  15327. (pi = pastebins[i++]);
  15328. ) {
  15329. if (domUtils.isEmptyNode(pi)) {
  15330. domUtils.remove(pi)
  15331. } else {
  15332. pastebin = pi
  15333. break
  15334. }
  15335. }
  15336. }
  15337. try {
  15338. pastebin.parentNode.removeChild(pastebin)
  15339. } catch (e) {}
  15340. range.moveToBookmark(bk).select(true)
  15341. callback(pastebin)
  15342. }, 0)
  15343. }
  15344. var me = this
  15345. me.setOpt({
  15346. retainOnlyLabelPasted: false,
  15347. })
  15348. var txtContent, htmlContent, address
  15349. function getPureHtml(html) {
  15350. return html.replace(
  15351. /<(\/?)([\w\-]+)([^>]*)>/gi,
  15352. function (a, b, tagName, attrs) {
  15353. tagName = tagName.toLowerCase()
  15354. if ({ img: 1 }[tagName]) {
  15355. return a
  15356. }
  15357. attrs = attrs.replace(
  15358. /([\w\-]*?)\s*=\s*(("([^"]*)")|('([^']*)')|([^\s>]+))/gi,
  15359. function (str, atr, val) {
  15360. if (
  15361. {
  15362. src: 1,
  15363. href: 1,
  15364. name: 1,
  15365. }[atr.toLowerCase()]
  15366. ) {
  15367. return atr + '=' + val + ' '
  15368. }
  15369. return ''
  15370. }
  15371. )
  15372. if (
  15373. {
  15374. span: 1,
  15375. div: 1,
  15376. }[tagName]
  15377. ) {
  15378. return ''
  15379. } else {
  15380. return '<' + b + tagName + ' ' + utils.trim(attrs) + '>'
  15381. }
  15382. }
  15383. )
  15384. }
  15385. function filter(div) {
  15386. var html
  15387. if (div.firstChild) {
  15388. //去掉cut中添加的边界值
  15389. var nodes = domUtils.getElementsByTagName(div, 'span')
  15390. for (var i = 0, ni; (ni = nodes[i++]); ) {
  15391. if (ni.id == '_baidu_cut_start' || ni.id == '_baidu_cut_end') {
  15392. domUtils.remove(ni)
  15393. }
  15394. }
  15395. if (browser.webkit) {
  15396. var brs = div.querySelectorAll('div br')
  15397. for (var i = 0, bi; (bi = brs[i++]); ) {
  15398. var pN = bi.parentNode
  15399. if (pN.tagName == 'DIV' && pN.childNodes.length == 1) {
  15400. pN.innerHTML = '<p><br/></p>'
  15401. domUtils.remove(pN)
  15402. }
  15403. }
  15404. var divs = div.querySelectorAll('#baidu_pastebin')
  15405. for (var i = 0, di; (di = divs[i++]); ) {
  15406. var tmpP = me.document.createElement('p')
  15407. di.parentNode.insertBefore(tmpP, di)
  15408. while (di.firstChild) {
  15409. tmpP.appendChild(di.firstChild)
  15410. }
  15411. domUtils.remove(di)
  15412. }
  15413. var metas = div.querySelectorAll('meta')
  15414. for (var i = 0, ci; (ci = metas[i++]); ) {
  15415. domUtils.remove(ci)
  15416. }
  15417. var brs = div.querySelectorAll('br')
  15418. for (i = 0; (ci = brs[i++]); ) {
  15419. if (/^apple-/i.test(ci.className)) {
  15420. domUtils.remove(ci)
  15421. }
  15422. }
  15423. }
  15424. if (browser.gecko) {
  15425. var dirtyNodes = div.querySelectorAll('[_moz_dirty]')
  15426. for (i = 0; (ci = dirtyNodes[i++]); ) {
  15427. ci.removeAttribute('_moz_dirty')
  15428. }
  15429. }
  15430. if (!browser.ie) {
  15431. var spans = div.querySelectorAll('span.Apple-style-span')
  15432. for (var i = 0, ci; (ci = spans[i++]); ) {
  15433. domUtils.remove(ci, true)
  15434. }
  15435. }
  15436. //ie下使用innerHTML会产生多余的\r\n字符,也会产生&nbsp;这里过滤掉
  15437. html = div.innerHTML //.replace(/>(?:(\s|&nbsp;)*?)</g,'><');
  15438. //过滤word粘贴过来的冗余属性
  15439. html = UE.filterWord(html)
  15440. //取消了忽略空白的第二个参数,粘贴过来的有些是有空白的,会被套上相关的标签
  15441. var root = UE.htmlparser(html)
  15442. //如果给了过滤规则就先进行过滤
  15443. if (me.options.filterRules) {
  15444. UE.filterNode(root, me.options.filterRules)
  15445. }
  15446. //执行默认的处理
  15447. me.filterInputRule(root)
  15448. //针对chrome的处理
  15449. if (browser.webkit) {
  15450. var br = root.lastChild()
  15451. if (br && br.type == 'element' && br.tagName == 'br') {
  15452. root.removeChild(br)
  15453. }
  15454. utils.each(me.body.querySelectorAll('div'), function (node) {
  15455. if (domUtils.isEmptyBlock(node)) {
  15456. domUtils.remove(node, true)
  15457. }
  15458. })
  15459. }
  15460. html = { html: root.toHtml() }
  15461. me.fireEvent('beforepaste', html, root)
  15462. //抢了默认的粘贴,那后边的内容就不执行了,比如表格粘贴
  15463. if (!html.html) {
  15464. return
  15465. }
  15466. root = UE.htmlparser(html.html, true)
  15467. //如果开启了纯文本模式
  15468. if (me.queryCommandState('pasteplain') === 1) {
  15469. me.execCommand(
  15470. 'insertHtml',
  15471. UE.filterNode(root, me.options.filterTxtRules).toHtml(),
  15472. true
  15473. )
  15474. } else {
  15475. //文本模式
  15476. UE.filterNode(root, me.options.filterTxtRules)
  15477. txtContent = root.toHtml()
  15478. //完全模式
  15479. htmlContent = html.html
  15480. address = me.selection.getRange().createAddress(true)
  15481. me.execCommand(
  15482. 'insertHtml',
  15483. me.getOpt('retainOnlyLabelPasted') === true
  15484. ? getPureHtml(htmlContent)
  15485. : htmlContent,
  15486. true
  15487. )
  15488. }
  15489. me.fireEvent('afterpaste', html)
  15490. }
  15491. }
  15492. me.addListener('pasteTransfer', function (cmd, plainType) {
  15493. if (address && txtContent && htmlContent && txtContent != htmlContent) {
  15494. var range = me.selection.getRange()
  15495. range.moveToAddress(address, true)
  15496. if (!range.collapsed) {
  15497. while (!domUtils.isBody(range.startContainer)) {
  15498. var start = range.startContainer
  15499. if (start.nodeType == 1) {
  15500. start = start.childNodes[range.startOffset]
  15501. if (!start) {
  15502. range.setStartBefore(range.startContainer)
  15503. continue
  15504. }
  15505. var pre = start.previousSibling
  15506. if (
  15507. pre &&
  15508. pre.nodeType == 3 &&
  15509. new RegExp('^[\n\r\t ' + domUtils.fillChar + ']*$').test(
  15510. pre.nodeValue
  15511. )
  15512. ) {
  15513. range.setStartBefore(pre)
  15514. }
  15515. }
  15516. if (range.startOffset == 0) {
  15517. range.setStartBefore(range.startContainer)
  15518. } else {
  15519. break
  15520. }
  15521. }
  15522. while (!domUtils.isBody(range.endContainer)) {
  15523. var end = range.endContainer
  15524. if (end.nodeType == 1) {
  15525. end = end.childNodes[range.endOffset]
  15526. if (!end) {
  15527. range.setEndAfter(range.endContainer)
  15528. continue
  15529. }
  15530. var next = end.nextSibling
  15531. if (
  15532. next &&
  15533. next.nodeType == 3 &&
  15534. new RegExp('^[\n\r\t' + domUtils.fillChar + ']*$').test(
  15535. next.nodeValue
  15536. )
  15537. ) {
  15538. range.setEndAfter(next)
  15539. }
  15540. }
  15541. if (
  15542. range.endOffset ==
  15543. range.endContainer[
  15544. range.endContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'
  15545. ].length
  15546. ) {
  15547. range.setEndAfter(range.endContainer)
  15548. } else {
  15549. break
  15550. }
  15551. }
  15552. }
  15553. range.deleteContents()
  15554. range.select(true)
  15555. me.__hasEnterExecCommand = true
  15556. var html = htmlContent
  15557. if (plainType === 2) {
  15558. html = getPureHtml(html)
  15559. } else if (plainType) {
  15560. html = txtContent
  15561. }
  15562. me.execCommand('inserthtml', html, true)
  15563. me.__hasEnterExecCommand = false
  15564. var rng = me.selection.getRange()
  15565. while (
  15566. !domUtils.isBody(rng.startContainer) &&
  15567. !rng.startOffset &&
  15568. rng.startContainer[
  15569. rng.startContainer.nodeType == 3 ? 'nodeValue' : 'childNodes'
  15570. ].length
  15571. ) {
  15572. rng.setStartBefore(rng.startContainer)
  15573. }
  15574. var tmpAddress = rng.createAddress(true)
  15575. address.endAddress = tmpAddress.startAddress
  15576. }
  15577. })
  15578. me.addListener('ready', function () {
  15579. domUtils.on(me.body, 'cut', function () {
  15580. var range = me.selection.getRange()
  15581. if (!range.collapsed && me.undoManger) {
  15582. me.undoManger.save()
  15583. }
  15584. })
  15585. //ie下beforepaste在点击右键时也会触发,所以用监控键盘才处理
  15586. domUtils.on(
  15587. me.body,
  15588. browser.ie || browser.opera ? 'keydown' : 'paste',
  15589. function (e) {
  15590. if (
  15591. (browser.ie || browser.opera) &&
  15592. ((!e.ctrlKey && !e.metaKey) || e.keyCode != '86')
  15593. ) {
  15594. return
  15595. }
  15596. getClipboardData.call(me, function (div) {
  15597. filter(div)
  15598. })
  15599. }
  15600. )
  15601. })
  15602. me.commands['paste'] = {
  15603. execCommand: function (cmd) {
  15604. if (browser.ie) {
  15605. getClipboardData.call(me, function (div) {
  15606. filter(div)
  15607. })
  15608. me.document.execCommand('paste')
  15609. } else {
  15610. alert(me.getLang('pastemsg'))
  15611. }
  15612. },
  15613. }
  15614. }
  15615. // plugins/puretxtpaste.js
  15616. /**
  15617. * 纯文本粘贴插件
  15618. * @file
  15619. * @since 1.2.6.1
  15620. */
  15621. UE.plugins['pasteplain'] = function () {
  15622. var me = this
  15623. me.setOpt({
  15624. pasteplain: false,
  15625. filterTxtRules: (function () {
  15626. function transP(node) {
  15627. node.tagName = 'p'
  15628. node.setStyle()
  15629. }
  15630. function removeNode(node) {
  15631. node.parentNode.removeChild(node, true)
  15632. }
  15633. return {
  15634. //直接删除及其字节点内容
  15635. '-': 'script style object iframe embed input select',
  15636. p: { $: {} },
  15637. br: { $: {} },
  15638. div: function (node) {
  15639. var tmpNode,
  15640. p = UE.uNode.createElement('p')
  15641. while ((tmpNode = node.firstChild())) {
  15642. if (
  15643. tmpNode.type == 'text' ||
  15644. !UE.dom.dtd.$block[tmpNode.tagName]
  15645. ) {
  15646. p.appendChild(tmpNode)
  15647. } else {
  15648. if (p.firstChild()) {
  15649. node.parentNode.insertBefore(p, node)
  15650. p = UE.uNode.createElement('p')
  15651. } else {
  15652. node.parentNode.insertBefore(tmpNode, node)
  15653. }
  15654. }
  15655. }
  15656. if (p.firstChild()) {
  15657. node.parentNode.insertBefore(p, node)
  15658. }
  15659. node.parentNode.removeChild(node)
  15660. },
  15661. ol: removeNode,
  15662. ul: removeNode,
  15663. dl: removeNode,
  15664. dt: removeNode,
  15665. dd: removeNode,
  15666. li: removeNode,
  15667. caption: transP,
  15668. th: transP,
  15669. tr: transP,
  15670. h1: transP,
  15671. h2: transP,
  15672. h3: transP,
  15673. h4: transP,
  15674. h5: transP,
  15675. h6: transP,
  15676. td: function (node) {
  15677. //没有内容的td直接删掉
  15678. var txt = !!node.innerText()
  15679. if (txt) {
  15680. node.parentNode.insertAfter(
  15681. UE.uNode.createText(' &nbsp; &nbsp;'),
  15682. node
  15683. )
  15684. }
  15685. node.parentNode.removeChild(node, node.innerText())
  15686. },
  15687. }
  15688. })(),
  15689. })
  15690. //暂时这里支持一下老版本的属性
  15691. var pasteplain = me.options.pasteplain
  15692. /**
  15693. * 启用或取消纯文本粘贴模式
  15694. * @command pasteplain
  15695. * @method execCommand
  15696. * @param { String } cmd 命令字符串
  15697. * @example
  15698. * ```javascript
  15699. * editor.queryCommandState( 'pasteplain' );
  15700. * ```
  15701. */
  15702. /**
  15703. * 查询当前是否处于纯文本粘贴模式
  15704. * @command pasteplain
  15705. * @method queryCommandState
  15706. * @param { String } cmd 命令字符串
  15707. * @return { int } 如果处于纯文本模式,返回1,否则,返回0
  15708. * @example
  15709. * ```javascript
  15710. * editor.queryCommandState( 'pasteplain' );
  15711. * ```
  15712. */
  15713. me.commands['pasteplain'] = {
  15714. queryCommandState: function () {
  15715. return pasteplain ? 1 : 0
  15716. },
  15717. execCommand: function () {
  15718. pasteplain = !pasteplain | 0
  15719. },
  15720. notNeedUndo: 1,
  15721. }
  15722. }
  15723. // plugins/list.js
  15724. /**
  15725. * 有序列表,无序列表插件
  15726. * @file
  15727. * @since 1.2.6.1
  15728. */
  15729. UE.plugins['list'] = function () {
  15730. var me = this,
  15731. notExchange = {
  15732. TD: 1,
  15733. PRE: 1,
  15734. BLOCKQUOTE: 1,
  15735. }
  15736. var customStyle = {
  15737. cn: 'cn-1-',
  15738. cn1: 'cn-2-',
  15739. cn2: 'cn-3-',
  15740. num: 'num-1-',
  15741. num1: 'num-2-',
  15742. num2: 'num-3-',
  15743. dash: 'dash',
  15744. dot: 'dot',
  15745. }
  15746. me.setOpt({
  15747. autoTransWordToList: false,
  15748. insertorderedlist: {
  15749. num: '',
  15750. num1: '',
  15751. num2: '',
  15752. cn: '',
  15753. cn1: '',
  15754. cn2: '',
  15755. decimal: '',
  15756. 'lower-alpha': '',
  15757. 'lower-roman': '',
  15758. 'upper-alpha': '',
  15759. 'upper-roman': '',
  15760. },
  15761. insertunorderedlist: {
  15762. circle: '',
  15763. disc: '',
  15764. square: '',
  15765. dash: '',
  15766. dot: '',
  15767. },
  15768. listDefaultPaddingLeft: '30',
  15769. listiconpath: 'http://bs.baidu.com/listicon/',
  15770. maxListLevel: -1, //-1不限制
  15771. disablePInList: false,
  15772. })
  15773. function listToArray(list) {
  15774. var arr = []
  15775. for (var p in list) {
  15776. arr.push(p)
  15777. }
  15778. return arr
  15779. }
  15780. var listStyle = {
  15781. OL: listToArray(me.options.insertorderedlist),
  15782. UL: listToArray(me.options.insertunorderedlist),
  15783. }
  15784. var liiconpath = me.options.listiconpath
  15785. //根据用户配置,调整customStyle
  15786. for (var s in customStyle) {
  15787. if (
  15788. !me.options.insertorderedlist.hasOwnProperty(s) &&
  15789. !me.options.insertunorderedlist.hasOwnProperty(s)
  15790. ) {
  15791. delete customStyle[s]
  15792. }
  15793. }
  15794. me.ready(function () {
  15795. var customCss = []
  15796. for (var p in customStyle) {
  15797. if (p == 'dash' || p == 'dot') {
  15798. customCss.push(
  15799. 'li.list-' +
  15800. customStyle[p] +
  15801. '{background-image:url(' +
  15802. liiconpath +
  15803. customStyle[p] +
  15804. '.gif)}'
  15805. )
  15806. customCss.push(
  15807. 'ul.custom_' +
  15808. p +
  15809. '{list-style:none;}ul.custom_' +
  15810. p +
  15811. ' li{background-position:0 3px;background-repeat:no-repeat}'
  15812. )
  15813. } else {
  15814. for (var i = 0; i < 99; i++) {
  15815. customCss.push(
  15816. 'li.list-' +
  15817. customStyle[p] +
  15818. i +
  15819. '{background-image:url(' +
  15820. liiconpath +
  15821. 'list-' +
  15822. customStyle[p] +
  15823. i +
  15824. '.gif)}'
  15825. )
  15826. }
  15827. customCss.push(
  15828. 'ol.custom_' +
  15829. p +
  15830. '{list-style:none;}ol.custom_' +
  15831. p +
  15832. ' li{background-position:0 3px;background-repeat:no-repeat}'
  15833. )
  15834. }
  15835. switch (p) {
  15836. case 'cn':
  15837. customCss.push('li.list-' + p + '-paddingleft-1{padding-left:25px}')
  15838. customCss.push('li.list-' + p + '-paddingleft-2{padding-left:40px}')
  15839. customCss.push('li.list-' + p + '-paddingleft-3{padding-left:55px}')
  15840. break
  15841. case 'cn1':
  15842. customCss.push('li.list-' + p + '-paddingleft-1{padding-left:30px}')
  15843. customCss.push('li.list-' + p + '-paddingleft-2{padding-left:40px}')
  15844. customCss.push('li.list-' + p + '-paddingleft-3{padding-left:55px}')
  15845. break
  15846. case 'cn2':
  15847. customCss.push('li.list-' + p + '-paddingleft-1{padding-left:40px}')
  15848. customCss.push('li.list-' + p + '-paddingleft-2{padding-left:55px}')
  15849. customCss.push('li.list-' + p + '-paddingleft-3{padding-left:68px}')
  15850. break
  15851. case 'num':
  15852. case 'num1':
  15853. customCss.push('li.list-' + p + '-paddingleft-1{padding-left:25px}')
  15854. break
  15855. case 'num2':
  15856. customCss.push('li.list-' + p + '-paddingleft-1{padding-left:35px}')
  15857. customCss.push('li.list-' + p + '-paddingleft-2{padding-left:40px}')
  15858. break
  15859. case 'dash':
  15860. customCss.push('li.list-' + p + '-paddingleft{padding-left:35px}')
  15861. break
  15862. case 'dot':
  15863. customCss.push('li.list-' + p + '-paddingleft{padding-left:20px}')
  15864. }
  15865. }
  15866. customCss.push('.list-paddingleft-1{padding-left:0}')
  15867. customCss.push(
  15868. '.list-paddingleft-2{padding-left:' +
  15869. me.options.listDefaultPaddingLeft +
  15870. 'px}'
  15871. )
  15872. customCss.push(
  15873. '.list-paddingleft-3{padding-left:' +
  15874. me.options.listDefaultPaddingLeft * 2 +
  15875. 'px}'
  15876. )
  15877. //如果不给宽度会在自定应样式里出现滚动条
  15878. utils.cssRule(
  15879. 'list',
  15880. 'ol,ul{margin:0;pading:0;' +
  15881. (browser.ie ? '' : 'width:95%') +
  15882. '}li{clear:both;}' +
  15883. customCss.join('\n'),
  15884. me.document
  15885. )
  15886. })
  15887. //单独处理剪切的问题
  15888. me.ready(function () {
  15889. domUtils.on(me.body, 'cut', function () {
  15890. setTimeout(function () {
  15891. var rng = me.selection.getRange(),
  15892. li
  15893. //trace:3416
  15894. if (!rng.collapsed) {
  15895. if (
  15896. (li = domUtils.findParentByTagName(
  15897. rng.startContainer,
  15898. 'li',
  15899. true
  15900. ))
  15901. ) {
  15902. if (!li.nextSibling && domUtils.isEmptyBlock(li)) {
  15903. var pn = li.parentNode,
  15904. node
  15905. if ((node = pn.previousSibling)) {
  15906. domUtils.remove(pn)
  15907. rng.setStartAtLast(node).collapse(true)
  15908. rng.select(true)
  15909. } else if ((node = pn.nextSibling)) {
  15910. domUtils.remove(pn)
  15911. rng.setStartAtFirst(node).collapse(true)
  15912. rng.select(true)
  15913. } else {
  15914. var tmpNode = me.document.createElement('p')
  15915. domUtils.fillNode(me.document, tmpNode)
  15916. pn.parentNode.insertBefore(tmpNode, pn)
  15917. domUtils.remove(pn)
  15918. rng.setStart(tmpNode, 0).collapse(true)
  15919. rng.select(true)
  15920. }
  15921. }
  15922. }
  15923. }
  15924. })
  15925. })
  15926. })
  15927. function getStyle(node) {
  15928. var cls = node.className
  15929. if (domUtils.hasClass(node, /custom_/)) {
  15930. return cls.match(/custom_(\w+)/)[1]
  15931. }
  15932. return domUtils.getStyle(node, 'list-style-type')
  15933. }
  15934. me.addListener('beforepaste', function (type, html) {
  15935. var me = this,
  15936. rng = me.selection.getRange(),
  15937. li
  15938. var root = UE.htmlparser(html.html, true)
  15939. if ((li = domUtils.findParentByTagName(rng.startContainer, 'li', true))) {
  15940. var list = li.parentNode,
  15941. tagName = list.tagName == 'OL' ? 'ul' : 'ol'
  15942. utils.each(root.getNodesByTagName(tagName), function (n) {
  15943. n.tagName = list.tagName
  15944. n.setAttr()
  15945. if (n.parentNode === root) {
  15946. type = getStyle(list) || (list.tagName == 'OL' ? 'decimal' : 'disc')
  15947. } else {
  15948. var className = n.parentNode.getAttr('class')
  15949. if (className && /custom_/.test(className)) {
  15950. type = className.match(/custom_(\w+)/)[1]
  15951. } else {
  15952. type = n.parentNode.getStyle('list-style-type')
  15953. }
  15954. if (!type) {
  15955. type = list.tagName == 'OL' ? 'decimal' : 'disc'
  15956. }
  15957. }
  15958. var index = utils.indexOf(listStyle[list.tagName], type)
  15959. if (n.parentNode !== root)
  15960. index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1
  15961. var currentStyle = listStyle[list.tagName][index]
  15962. if (customStyle[currentStyle]) {
  15963. n.setAttr('class', 'custom_' + currentStyle)
  15964. } else {
  15965. n.setStyle('list-style-type', currentStyle)
  15966. }
  15967. })
  15968. }
  15969. html.html = root.toHtml()
  15970. })
  15971. //导出时,去掉p标签
  15972. me.getOpt('disablePInList') === true &&
  15973. me.addOutputRule(function (root) {
  15974. utils.each(root.getNodesByTagName('li'), function (li) {
  15975. var newChildrens = [],
  15976. index = 0
  15977. utils.each(li.children, function (n) {
  15978. if (n.tagName == 'p') {
  15979. var tmpNode
  15980. while ((tmpNode = n.children.pop())) {
  15981. newChildrens.splice(index, 0, tmpNode)
  15982. tmpNode.parentNode = li
  15983. lastNode = tmpNode
  15984. }
  15985. tmpNode = newChildrens[newChildrens.length - 1]
  15986. if (
  15987. !tmpNode ||
  15988. tmpNode.type != 'element' ||
  15989. tmpNode.tagName != 'br'
  15990. ) {
  15991. var br = UE.uNode.createElement('br')
  15992. br.parentNode = li
  15993. newChildrens.push(br)
  15994. }
  15995. index = newChildrens.length
  15996. }
  15997. })
  15998. if (newChildrens.length) {
  15999. li.children = newChildrens
  16000. }
  16001. })
  16002. })
  16003. //进入编辑器的li要套p标签
  16004. me.addInputRule(function (root) {
  16005. utils.each(root.getNodesByTagName('li'), function (li) {
  16006. var tmpP = UE.uNode.createElement('p')
  16007. for (var i = 0, ci; (ci = li.children[i]); ) {
  16008. if (ci.type == 'text' || dtd.p[ci.tagName]) {
  16009. tmpP.appendChild(ci)
  16010. } else {
  16011. if (tmpP.firstChild()) {
  16012. li.insertBefore(tmpP, ci)
  16013. tmpP = UE.uNode.createElement('p')
  16014. i = i + 2
  16015. } else {
  16016. i++
  16017. }
  16018. }
  16019. }
  16020. if ((tmpP.firstChild() && !tmpP.parentNode) || !li.firstChild()) {
  16021. li.appendChild(tmpP)
  16022. }
  16023. //trace:3357
  16024. //p不能为空
  16025. if (!tmpP.firstChild()) {
  16026. tmpP.innerHTML(browser.ie ? '&nbsp;' : '<br/>')
  16027. }
  16028. //去掉末尾的空白
  16029. var p = li.firstChild()
  16030. var lastChild = p.lastChild()
  16031. if (
  16032. lastChild &&
  16033. lastChild.type == 'text' &&
  16034. /^\s*$/.test(lastChild.data)
  16035. ) {
  16036. p.removeChild(lastChild)
  16037. }
  16038. })
  16039. if (me.options.autoTransWordToList) {
  16040. var orderlisttype = {
  16041. num1: /^\d+\)/,
  16042. decimal: /^\d+\./,
  16043. 'lower-alpha': /^[a-z]+\)/,
  16044. 'upper-alpha': /^[A-Z]+\./,
  16045. cn: /^[\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+[\u3001]/,
  16046. cn2: /^\([\u4E00\u4E8C\u4E09\u56DB\u516d\u4e94\u4e03\u516b\u4e5d]+\)/,
  16047. },
  16048. unorderlisttype = {
  16049. square: 'n',
  16050. }
  16051. function checkListType(content, container) {
  16052. var span = container.firstChild()
  16053. if (
  16054. span &&
  16055. span.type == 'element' &&
  16056. span.tagName == 'span' &&
  16057. /Wingdings|Symbol/.test(span.getStyle('font-family'))
  16058. ) {
  16059. for (var p in unorderlisttype) {
  16060. if (unorderlisttype[p] == span.data) {
  16061. return p
  16062. }
  16063. }
  16064. return 'disc'
  16065. }
  16066. for (var p in orderlisttype) {
  16067. if (orderlisttype[p].test(content)) {
  16068. return p
  16069. }
  16070. }
  16071. }
  16072. utils.each(root.getNodesByTagName('p'), function (node) {
  16073. if (node.getAttr('class') != 'MsoListParagraph') {
  16074. return
  16075. }
  16076. //word粘贴过来的会带有margin要去掉,但这样也可能会误命中一些央视
  16077. node.setStyle('margin', '')
  16078. node.setStyle('margin-left', '')
  16079. node.setAttr('class', '')
  16080. function appendLi(list, p, type) {
  16081. if (list.tagName == 'ol') {
  16082. if (browser.ie) {
  16083. var first = p.firstChild()
  16084. if (
  16085. first.type == 'element' &&
  16086. first.tagName == 'span' &&
  16087. orderlisttype[type].test(first.innerText())
  16088. ) {
  16089. p.removeChild(first)
  16090. }
  16091. } else {
  16092. p.innerHTML(p.innerHTML().replace(orderlisttype[type], ''))
  16093. }
  16094. } else {
  16095. p.removeChild(p.firstChild())
  16096. }
  16097. var li = UE.uNode.createElement('li')
  16098. li.appendChild(p)
  16099. list.appendChild(li)
  16100. }
  16101. var tmp = node,
  16102. type,
  16103. cacheNode = node
  16104. if (
  16105. node.parentNode.tagName != 'li' &&
  16106. (type = checkListType(node.innerText(), node))
  16107. ) {
  16108. var list = UE.uNode.createElement(
  16109. me.options.insertorderedlist.hasOwnProperty(type) ? 'ol' : 'ul'
  16110. )
  16111. if (customStyle[type]) {
  16112. list.setAttr('class', 'custom_' + type)
  16113. } else {
  16114. list.setStyle('list-style-type', type)
  16115. }
  16116. while (
  16117. node &&
  16118. node.parentNode.tagName != 'li' &&
  16119. checkListType(node.innerText(), node)
  16120. ) {
  16121. tmp = node.nextSibling()
  16122. if (!tmp) {
  16123. node.parentNode.insertBefore(list, node)
  16124. }
  16125. appendLi(list, node, type)
  16126. node = tmp
  16127. }
  16128. if (!list.parentNode && node && node.parentNode) {
  16129. node.parentNode.insertBefore(list, node)
  16130. }
  16131. }
  16132. var span = cacheNode.firstChild()
  16133. if (
  16134. span &&
  16135. span.type == 'element' &&
  16136. span.tagName == 'span' &&
  16137. /^\s*(&nbsp;)+\s*$/.test(span.innerText())
  16138. ) {
  16139. span.parentNode.removeChild(span)
  16140. }
  16141. })
  16142. }
  16143. })
  16144. //调整索引标签
  16145. me.addListener('contentchange', function () {
  16146. adjustListStyle(me.document)
  16147. })
  16148. function adjustListStyle(doc, ignore) {
  16149. utils.each(domUtils.getElementsByTagName(doc, 'ol ul'), function (node) {
  16150. if (!domUtils.inDoc(node, doc)) return
  16151. var parent = node.parentNode
  16152. if (parent.tagName == node.tagName) {
  16153. var nodeStyleType =
  16154. getStyle(node) || (node.tagName == 'OL' ? 'decimal' : 'disc'),
  16155. parentStyleType =
  16156. getStyle(parent) || (parent.tagName == 'OL' ? 'decimal' : 'disc')
  16157. if (nodeStyleType == parentStyleType) {
  16158. var styleIndex = utils.indexOf(
  16159. listStyle[node.tagName],
  16160. nodeStyleType
  16161. )
  16162. styleIndex =
  16163. styleIndex + 1 == listStyle[node.tagName].length
  16164. ? 0
  16165. : styleIndex + 1
  16166. setListStyle(node, listStyle[node.tagName][styleIndex])
  16167. }
  16168. }
  16169. var index = 0,
  16170. type = 2
  16171. if (domUtils.hasClass(node, /custom_/)) {
  16172. if (
  16173. !(
  16174. /[ou]l/i.test(parent.tagName) &&
  16175. domUtils.hasClass(parent, /custom_/)
  16176. )
  16177. ) {
  16178. type = 1
  16179. }
  16180. } else {
  16181. if (
  16182. /[ou]l/i.test(parent.tagName) &&
  16183. domUtils.hasClass(parent, /custom_/)
  16184. ) {
  16185. type = 3
  16186. }
  16187. }
  16188. var style = domUtils.getStyle(node, 'list-style-type')
  16189. style && (node.style.cssText = 'list-style-type:' + style)
  16190. node.className =
  16191. utils.trim(node.className.replace(/list-paddingleft-\w+/, '')) +
  16192. ' list-paddingleft-' +
  16193. type
  16194. utils.each(domUtils.getElementsByTagName(node, 'li'), function (li) {
  16195. li.style.cssText && (li.style.cssText = '')
  16196. if (!li.firstChild) {
  16197. domUtils.remove(li)
  16198. return
  16199. }
  16200. if (li.parentNode !== node) {
  16201. return
  16202. }
  16203. index++
  16204. if (domUtils.hasClass(node, /custom_/)) {
  16205. var paddingLeft = 1,
  16206. currentStyle = getStyle(node)
  16207. if (node.tagName == 'OL') {
  16208. if (currentStyle) {
  16209. switch (currentStyle) {
  16210. case 'cn':
  16211. case 'cn1':
  16212. case 'cn2':
  16213. if (
  16214. index > 10 &&
  16215. (index % 10 == 0 || (index > 10 && index < 20))
  16216. ) {
  16217. paddingLeft = 2
  16218. } else if (index > 20) {
  16219. paddingLeft = 3
  16220. }
  16221. break
  16222. case 'num2':
  16223. if (index > 9) {
  16224. paddingLeft = 2
  16225. }
  16226. }
  16227. }
  16228. li.className =
  16229. 'list-' +
  16230. customStyle[currentStyle] +
  16231. index +
  16232. ' ' +
  16233. 'list-' +
  16234. currentStyle +
  16235. '-paddingleft-' +
  16236. paddingLeft
  16237. } else {
  16238. li.className =
  16239. 'list-' +
  16240. customStyle[currentStyle] +
  16241. ' ' +
  16242. 'list-' +
  16243. currentStyle +
  16244. '-paddingleft'
  16245. }
  16246. } else {
  16247. li.className = li.className.replace(/list-[\w\-]+/gi, '')
  16248. }
  16249. var className = li.getAttribute('class')
  16250. if (className !== null && !className.replace(/\s/g, '')) {
  16251. domUtils.removeAttributes(li, 'class')
  16252. }
  16253. })
  16254. !ignore &&
  16255. adjustList(
  16256. node,
  16257. node.tagName.toLowerCase(),
  16258. getStyle(node) || domUtils.getStyle(node, 'list-style-type'),
  16259. true
  16260. )
  16261. })
  16262. }
  16263. function adjustList(list, tag, style, ignoreEmpty) {
  16264. var nextList = list.nextSibling
  16265. if (
  16266. nextList &&
  16267. nextList.nodeType == 1 &&
  16268. nextList.tagName.toLowerCase() == tag &&
  16269. (getStyle(nextList) ||
  16270. domUtils.getStyle(nextList, 'list-style-type') ||
  16271. (tag == 'ol' ? 'decimal' : 'disc')) == style
  16272. ) {
  16273. domUtils.moveChild(nextList, list)
  16274. if (nextList.childNodes.length == 0) {
  16275. domUtils.remove(nextList)
  16276. }
  16277. }
  16278. if (nextList && domUtils.isFillChar(nextList)) {
  16279. domUtils.remove(nextList)
  16280. }
  16281. var preList = list.previousSibling
  16282. if (
  16283. preList &&
  16284. preList.nodeType == 1 &&
  16285. preList.tagName.toLowerCase() == tag &&
  16286. (getStyle(preList) ||
  16287. domUtils.getStyle(preList, 'list-style-type') ||
  16288. (tag == 'ol' ? 'decimal' : 'disc')) == style
  16289. ) {
  16290. domUtils.moveChild(list, preList)
  16291. }
  16292. if (preList && domUtils.isFillChar(preList)) {
  16293. domUtils.remove(preList)
  16294. }
  16295. !ignoreEmpty && domUtils.isEmptyBlock(list) && domUtils.remove(list)
  16296. if (getStyle(list)) {
  16297. adjustListStyle(list.ownerDocument, true)
  16298. }
  16299. }
  16300. function setListStyle(list, style) {
  16301. if (customStyle[style]) {
  16302. list.className = 'custom_' + style
  16303. }
  16304. try {
  16305. domUtils.setStyle(list, 'list-style-type', style)
  16306. } catch (e) {}
  16307. }
  16308. function clearEmptySibling(node) {
  16309. var tmpNode = node.previousSibling
  16310. if (tmpNode && domUtils.isEmptyBlock(tmpNode)) {
  16311. domUtils.remove(tmpNode)
  16312. }
  16313. tmpNode = node.nextSibling
  16314. if (tmpNode && domUtils.isEmptyBlock(tmpNode)) {
  16315. domUtils.remove(tmpNode)
  16316. }
  16317. }
  16318. me.addListener('keydown', function (type, evt) {
  16319. function preventAndSave() {
  16320. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false)
  16321. me.fireEvent('contentchange')
  16322. me.undoManger && me.undoManger.save()
  16323. }
  16324. function findList(node, filterFn) {
  16325. while (node && !domUtils.isBody(node)) {
  16326. if (filterFn(node)) {
  16327. return null
  16328. }
  16329. if (node.nodeType == 1 && /[ou]l/i.test(node.tagName)) {
  16330. return node
  16331. }
  16332. node = node.parentNode
  16333. }
  16334. return null
  16335. }
  16336. var keyCode = evt.keyCode || evt.which
  16337. if (keyCode == 13 && !evt.shiftKey) {
  16338. //回车
  16339. var rng = me.selection.getRange(),
  16340. parent = domUtils.findParent(
  16341. rng.startContainer,
  16342. function (node) {
  16343. return domUtils.isBlockElm(node)
  16344. },
  16345. true
  16346. ),
  16347. li = domUtils.findParentByTagName(rng.startContainer, 'li', true)
  16348. if (parent && parent.tagName != 'PRE' && !li) {
  16349. var html = parent.innerHTML.replace(
  16350. new RegExp(domUtils.fillChar, 'g'),
  16351. ''
  16352. )
  16353. if (/^\s*1\s*\.[^\d]/.test(html)) {
  16354. parent.innerHTML = html.replace(/^\s*1\s*\./, '')
  16355. rng.setStartAtLast(parent).collapse(true).select()
  16356. me.__hasEnterExecCommand = true
  16357. me.execCommand('insertorderedlist')
  16358. me.__hasEnterExecCommand = false
  16359. }
  16360. }
  16361. var range = me.selection.getRange(),
  16362. start = findList(range.startContainer, function (node) {
  16363. return node.tagName == 'TABLE'
  16364. }),
  16365. end = range.collapsed
  16366. ? start
  16367. : findList(range.endContainer, function (node) {
  16368. return node.tagName == 'TABLE'
  16369. })
  16370. if (start && end && start === end) {
  16371. if (!range.collapsed) {
  16372. start = domUtils.findParentByTagName(
  16373. range.startContainer,
  16374. 'li',
  16375. true
  16376. )
  16377. end = domUtils.findParentByTagName(range.endContainer, 'li', true)
  16378. if (start && end && start === end) {
  16379. range.deleteContents()
  16380. li = domUtils.findParentByTagName(
  16381. range.startContainer,
  16382. 'li',
  16383. true
  16384. )
  16385. if (li && domUtils.isEmptyBlock(li)) {
  16386. pre = li.previousSibling
  16387. next = li.nextSibling
  16388. p = me.document.createElement('p')
  16389. domUtils.fillNode(me.document, p)
  16390. parentList = li.parentNode
  16391. if (pre && next) {
  16392. range.setStart(next, 0).collapse(true).select(true)
  16393. domUtils.remove(li)
  16394. } else {
  16395. if ((!pre && !next) || !pre) {
  16396. parentList.parentNode.insertBefore(p, parentList)
  16397. } else {
  16398. li.parentNode.parentNode.insertBefore(
  16399. p,
  16400. parentList.nextSibling
  16401. )
  16402. }
  16403. domUtils.remove(li)
  16404. if (!parentList.firstChild) {
  16405. domUtils.remove(parentList)
  16406. }
  16407. range.setStart(p, 0).setCursor()
  16408. }
  16409. preventAndSave()
  16410. return
  16411. }
  16412. } else {
  16413. var tmpRange = range.cloneRange(),
  16414. bk = tmpRange.collapse(false).createBookmark()
  16415. range.deleteContents()
  16416. tmpRange.moveToBookmark(bk)
  16417. var li = domUtils.findParentByTagName(
  16418. tmpRange.startContainer,
  16419. 'li',
  16420. true
  16421. )
  16422. clearEmptySibling(li)
  16423. tmpRange.select()
  16424. preventAndSave()
  16425. return
  16426. }
  16427. }
  16428. li = domUtils.findParentByTagName(range.startContainer, 'li', true)
  16429. if (li) {
  16430. if (domUtils.isEmptyBlock(li)) {
  16431. bk = range.createBookmark()
  16432. var parentList = li.parentNode
  16433. if (li !== parentList.lastChild) {
  16434. domUtils.breakParent(li, parentList)
  16435. clearEmptySibling(li)
  16436. } else {
  16437. parentList.parentNode.insertBefore(li, parentList.nextSibling)
  16438. if (domUtils.isEmptyNode(parentList)) {
  16439. domUtils.remove(parentList)
  16440. }
  16441. }
  16442. //嵌套不处理
  16443. if (!dtd.$list[li.parentNode.tagName]) {
  16444. if (!domUtils.isBlockElm(li.firstChild)) {
  16445. p = me.document.createElement('p')
  16446. li.parentNode.insertBefore(p, li)
  16447. while (li.firstChild) {
  16448. p.appendChild(li.firstChild)
  16449. }
  16450. domUtils.remove(li)
  16451. } else {
  16452. domUtils.remove(li, true)
  16453. }
  16454. }
  16455. range.moveToBookmark(bk).select()
  16456. } else {
  16457. var first = li.firstChild
  16458. if (!first || !domUtils.isBlockElm(first)) {
  16459. var p = me.document.createElement('p')
  16460. !li.firstChild && domUtils.fillNode(me.document, p)
  16461. while (li.firstChild) {
  16462. p.appendChild(li.firstChild)
  16463. }
  16464. li.appendChild(p)
  16465. first = p
  16466. }
  16467. var span = me.document.createElement('span')
  16468. range.insertNode(span)
  16469. domUtils.breakParent(span, li)
  16470. var nextLi = span.nextSibling
  16471. first = nextLi.firstChild
  16472. if (!first) {
  16473. p = me.document.createElement('p')
  16474. domUtils.fillNode(me.document, p)
  16475. nextLi.appendChild(p)
  16476. first = p
  16477. }
  16478. if (domUtils.isEmptyNode(first)) {
  16479. first.innerHTML = ''
  16480. domUtils.fillNode(me.document, first)
  16481. }
  16482. range.setStart(first, 0).collapse(true).shrinkBoundary().select()
  16483. domUtils.remove(span)
  16484. var pre = nextLi.previousSibling
  16485. if (pre && domUtils.isEmptyBlock(pre)) {
  16486. pre.innerHTML = '<p></p>'
  16487. domUtils.fillNode(me.document, pre.firstChild)
  16488. }
  16489. }
  16490. // }
  16491. preventAndSave()
  16492. }
  16493. }
  16494. }
  16495. if (keyCode == 8) {
  16496. //修中ie中li下的问题
  16497. range = me.selection.getRange()
  16498. if (range.collapsed && domUtils.isStartInblock(range)) {
  16499. tmpRange = range.cloneRange().trimBoundary()
  16500. li = domUtils.findParentByTagName(range.startContainer, 'li', true)
  16501. //要在li的最左边,才能处理
  16502. if (li && domUtils.isStartInblock(tmpRange)) {
  16503. start = domUtils.findParentByTagName(
  16504. range.startContainer,
  16505. 'p',
  16506. true
  16507. )
  16508. if (start && start !== li.firstChild) {
  16509. var parentList = domUtils.findParentByTagName(start, ['ol', 'ul'])
  16510. domUtils.breakParent(start, parentList)
  16511. clearEmptySibling(start)
  16512. me.fireEvent('contentchange')
  16513. range.setStart(start, 0).setCursor(false, true)
  16514. me.fireEvent('saveScene')
  16515. domUtils.preventDefault(evt)
  16516. return
  16517. }
  16518. if (li && (pre = li.previousSibling)) {
  16519. if (keyCode == 46 && li.childNodes.length) {
  16520. return
  16521. }
  16522. //有可能上边的兄弟节点是个2级菜单,要追加到2级菜单的最后的li
  16523. if (dtd.$list[pre.tagName]) {
  16524. pre = pre.lastChild
  16525. }
  16526. me.undoManger && me.undoManger.save()
  16527. first = li.firstChild
  16528. if (domUtils.isBlockElm(first)) {
  16529. if (domUtils.isEmptyNode(first)) {
  16530. // range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
  16531. pre.appendChild(first)
  16532. range.setStart(first, 0).setCursor(false, true)
  16533. //first不是唯一的节点
  16534. while (li.firstChild) {
  16535. pre.appendChild(li.firstChild)
  16536. }
  16537. } else {
  16538. span = me.document.createElement('span')
  16539. range.insertNode(span)
  16540. //判断pre是否是空的节点,如果是<p><br/></p>类型的空节点,干掉p标签防止它占位
  16541. if (domUtils.isEmptyBlock(pre)) {
  16542. pre.innerHTML = ''
  16543. }
  16544. domUtils.moveChild(li, pre)
  16545. range.setStartBefore(span).collapse(true).select(true)
  16546. domUtils.remove(span)
  16547. }
  16548. } else {
  16549. if (domUtils.isEmptyNode(li)) {
  16550. var p = me.document.createElement('p')
  16551. pre.appendChild(p)
  16552. range.setStart(p, 0).setCursor()
  16553. // range.setEnd(pre, pre.childNodes.length).shrinkBoundary().collapse().select(true);
  16554. } else {
  16555. range
  16556. .setEnd(pre, pre.childNodes.length)
  16557. .collapse()
  16558. .select(true)
  16559. while (li.firstChild) {
  16560. pre.appendChild(li.firstChild)
  16561. }
  16562. }
  16563. }
  16564. domUtils.remove(li)
  16565. me.fireEvent('contentchange')
  16566. me.fireEvent('saveScene')
  16567. domUtils.preventDefault(evt)
  16568. return
  16569. }
  16570. //trace:980
  16571. if (li && !li.previousSibling) {
  16572. var parentList = li.parentNode
  16573. var bk = range.createBookmark()
  16574. if (domUtils.isTagNode(parentList.parentNode, 'ol ul')) {
  16575. parentList.parentNode.insertBefore(li, parentList)
  16576. if (domUtils.isEmptyNode(parentList)) {
  16577. domUtils.remove(parentList)
  16578. }
  16579. } else {
  16580. while (li.firstChild) {
  16581. parentList.parentNode.insertBefore(li.firstChild, parentList)
  16582. }
  16583. domUtils.remove(li)
  16584. if (domUtils.isEmptyNode(parentList)) {
  16585. domUtils.remove(parentList)
  16586. }
  16587. }
  16588. range.moveToBookmark(bk).setCursor(false, true)
  16589. me.fireEvent('contentchange')
  16590. me.fireEvent('saveScene')
  16591. domUtils.preventDefault(evt)
  16592. return
  16593. }
  16594. }
  16595. }
  16596. }
  16597. })
  16598. me.addListener('keyup', function (type, evt) {
  16599. var keyCode = evt.keyCode || evt.which
  16600. if (keyCode == 8) {
  16601. var rng = me.selection.getRange(),
  16602. list
  16603. if (
  16604. (list = domUtils.findParentByTagName(
  16605. rng.startContainer,
  16606. ['ol', 'ul'],
  16607. true
  16608. ))
  16609. ) {
  16610. adjustList(
  16611. list,
  16612. list.tagName.toLowerCase(),
  16613. getStyle(list) ||
  16614. domUtils.getComputedStyle(list, 'list-style-type'),
  16615. true
  16616. )
  16617. }
  16618. }
  16619. })
  16620. //处理tab键
  16621. me.addListener('tabkeydown', function () {
  16622. var range = me.selection.getRange()
  16623. //控制级数
  16624. function checkLevel(li) {
  16625. if (me.options.maxListLevel != -1) {
  16626. var level = li.parentNode,
  16627. levelNum = 0
  16628. while (/[ou]l/i.test(level.tagName)) {
  16629. levelNum++
  16630. level = level.parentNode
  16631. }
  16632. if (levelNum >= me.options.maxListLevel) {
  16633. return true
  16634. }
  16635. }
  16636. }
  16637. //只以开始为准
  16638. //todo 后续改进
  16639. var li = domUtils.findParentByTagName(range.startContainer, 'li', true)
  16640. if (li) {
  16641. var bk
  16642. if (range.collapsed) {
  16643. if (checkLevel(li)) return true
  16644. var parentLi = li.parentNode,
  16645. list = me.document.createElement(parentLi.tagName),
  16646. index = utils.indexOf(
  16647. listStyle[list.tagName],
  16648. getStyle(parentLi) ||
  16649. domUtils.getComputedStyle(parentLi, 'list-style-type')
  16650. )
  16651. index = index + 1 == listStyle[list.tagName].length ? 0 : index + 1
  16652. var currentStyle = listStyle[list.tagName][index]
  16653. setListStyle(list, currentStyle)
  16654. if (domUtils.isStartInblock(range)) {
  16655. me.fireEvent('saveScene')
  16656. bk = range.createBookmark()
  16657. parentLi.insertBefore(list, li)
  16658. list.appendChild(li)
  16659. adjustList(list, list.tagName.toLowerCase(), currentStyle)
  16660. me.fireEvent('contentchange')
  16661. range.moveToBookmark(bk).select(true)
  16662. return true
  16663. }
  16664. } else {
  16665. me.fireEvent('saveScene')
  16666. bk = range.createBookmark()
  16667. for (
  16668. var i = 0, closeList, parents = domUtils.findParents(li), ci;
  16669. (ci = parents[i++]);
  16670. ) {
  16671. if (domUtils.isTagNode(ci, 'ol ul')) {
  16672. closeList = ci
  16673. break
  16674. }
  16675. }
  16676. var current = li
  16677. if (bk.end) {
  16678. while (
  16679. current &&
  16680. !(
  16681. domUtils.getPosition(current, bk.end) &
  16682. domUtils.POSITION_FOLLOWING
  16683. )
  16684. ) {
  16685. if (checkLevel(current)) {
  16686. current = domUtils.getNextDomNode(
  16687. current,
  16688. false,
  16689. null,
  16690. function (node) {
  16691. return node !== closeList
  16692. }
  16693. )
  16694. continue
  16695. }
  16696. var parentLi = current.parentNode,
  16697. list = me.document.createElement(parentLi.tagName),
  16698. index = utils.indexOf(
  16699. listStyle[list.tagName],
  16700. getStyle(parentLi) ||
  16701. domUtils.getComputedStyle(parentLi, 'list-style-type')
  16702. )
  16703. var currentIndex =
  16704. index + 1 == listStyle[list.tagName].length ? 0 : index + 1
  16705. var currentStyle = listStyle[list.tagName][currentIndex]
  16706. setListStyle(list, currentStyle)
  16707. parentLi.insertBefore(list, current)
  16708. while (
  16709. current &&
  16710. !(
  16711. domUtils.getPosition(current, bk.end) &
  16712. domUtils.POSITION_FOLLOWING
  16713. )
  16714. ) {
  16715. li = current.nextSibling
  16716. list.appendChild(current)
  16717. if (!li || domUtils.isTagNode(li, 'ol ul')) {
  16718. if (li) {
  16719. while ((li = li.firstChild)) {
  16720. if (li.tagName == 'LI') {
  16721. break
  16722. }
  16723. }
  16724. } else {
  16725. li = domUtils.getNextDomNode(
  16726. current,
  16727. false,
  16728. null,
  16729. function (node) {
  16730. return node !== closeList
  16731. }
  16732. )
  16733. }
  16734. break
  16735. }
  16736. current = li
  16737. }
  16738. adjustList(list, list.tagName.toLowerCase(), currentStyle)
  16739. current = li
  16740. }
  16741. }
  16742. me.fireEvent('contentchange')
  16743. range.moveToBookmark(bk).select()
  16744. return true
  16745. }
  16746. }
  16747. })
  16748. function getLi(start) {
  16749. while (start && !domUtils.isBody(start)) {
  16750. if (start.nodeName == 'TABLE') {
  16751. return null
  16752. }
  16753. if (start.nodeName == 'LI') {
  16754. return start
  16755. }
  16756. start = start.parentNode
  16757. }
  16758. }
  16759. /**
  16760. * 有序列表,与“insertunorderedlist”命令互斥
  16761. * @command insertorderedlist
  16762. * @method execCommand
  16763. * @param { String } command 命令字符串
  16764. * @param { String } style 插入的有序列表类型,值为:decimal,lower-alpha,lower-roman,upper-alpha,upper-roman,cn,cn1,cn2,num,num1,num2
  16765. * @example
  16766. * ```javascript
  16767. * editor.execCommand( 'insertorderedlist','decimal');
  16768. * ```
  16769. */
  16770. /**
  16771. * 查询当前选区内容是否有序列表
  16772. * @command insertorderedlist
  16773. * @method queryCommandState
  16774. * @param { String } cmd 命令字符串
  16775. * @return { int } 如果当前选区是有序列表返回1,否则返回0
  16776. * @example
  16777. * ```javascript
  16778. * editor.queryCommandState( 'insertorderedlist' );
  16779. * ```
  16780. */
  16781. /**
  16782. * 查询当前选区内容是否有序列表
  16783. * @command insertorderedlist
  16784. * @method queryCommandValue
  16785. * @param { String } cmd 命令字符串
  16786. * @return { String } 返回当前有序列表的类型,值为null或decimal,lower-alpha,lower-roman,upper-alpha,upper-roman,cn,cn1,cn2,num,num1,num2
  16787. * @example
  16788. * ```javascript
  16789. * editor.queryCommandValue( 'insertorderedlist' );
  16790. * ```
  16791. */
  16792. /**
  16793. * 无序列表,与“insertorderedlist”命令互斥
  16794. * @command insertunorderedlist
  16795. * @method execCommand
  16796. * @param { String } command 命令字符串
  16797. * @param { String } style 插入的无序列表类型,值为:circle,disc,square,dash,dot
  16798. * @example
  16799. * ```javascript
  16800. * editor.execCommand( 'insertunorderedlist','circle');
  16801. * ```
  16802. */
  16803. /**
  16804. * 查询当前是否有word文档粘贴进来的图片
  16805. * @command insertunorderedlist
  16806. * @method insertunorderedlist
  16807. * @param { String } command 命令字符串
  16808. * @return { int } 如果当前选区是无序列表返回1,否则返回0
  16809. * @example
  16810. * ```javascript
  16811. * editor.queryCommandState( 'insertunorderedlist' );
  16812. * ```
  16813. */
  16814. /**
  16815. * 查询当前选区内容是否有序列表
  16816. * @command insertunorderedlist
  16817. * @method queryCommandValue
  16818. * @param { String } command 命令字符串
  16819. * @return { String } 返回当前无序列表的类型,值为null或circle,disc,square,dash,dot
  16820. * @example
  16821. * ```javascript
  16822. * editor.queryCommandValue( 'insertunorderedlist' );
  16823. * ```
  16824. */
  16825. me.commands['insertorderedlist'] = me.commands['insertunorderedlist'] = {
  16826. execCommand: function (command, style) {
  16827. if (!style) {
  16828. style =
  16829. command.toLowerCase() == 'insertorderedlist' ? 'decimal' : 'disc'
  16830. }
  16831. var me = this,
  16832. range = this.selection.getRange(),
  16833. filterFn = function (node) {
  16834. return node.nodeType == 1
  16835. ? node.tagName.toLowerCase() != 'br'
  16836. : !domUtils.isWhitespace(node)
  16837. },
  16838. tag = command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul',
  16839. frag = me.document.createDocumentFragment()
  16840. //去掉是因为会出现选到末尾,导致adjustmentBoundary缩到ol/ul的位置
  16841. //range.shrinkBoundary();//.adjustmentBoundary();
  16842. range.adjustmentBoundary().shrinkBoundary()
  16843. var bko = range.createBookmark(true),
  16844. start = getLi(me.document.getElementById(bko.start)),
  16845. modifyStart = 0,
  16846. end = getLi(me.document.getElementById(bko.end)),
  16847. modifyEnd = 0,
  16848. startParent,
  16849. endParent,
  16850. list,
  16851. tmp
  16852. if (start || end) {
  16853. start && (startParent = start.parentNode)
  16854. if (!bko.end) {
  16855. end = start
  16856. }
  16857. end && (endParent = end.parentNode)
  16858. if (startParent === endParent) {
  16859. while (start !== end) {
  16860. tmp = start
  16861. start = start.nextSibling
  16862. if (!domUtils.isBlockElm(tmp.firstChild)) {
  16863. var p = me.document.createElement('p')
  16864. while (tmp.firstChild) {
  16865. p.appendChild(tmp.firstChild)
  16866. }
  16867. tmp.appendChild(p)
  16868. }
  16869. frag.appendChild(tmp)
  16870. }
  16871. tmp = me.document.createElement('span')
  16872. startParent.insertBefore(tmp, end)
  16873. if (!domUtils.isBlockElm(end.firstChild)) {
  16874. p = me.document.createElement('p')
  16875. while (end.firstChild) {
  16876. p.appendChild(end.firstChild)
  16877. }
  16878. end.appendChild(p)
  16879. }
  16880. frag.appendChild(end)
  16881. domUtils.breakParent(tmp, startParent)
  16882. if (domUtils.isEmptyNode(tmp.previousSibling)) {
  16883. domUtils.remove(tmp.previousSibling)
  16884. }
  16885. if (domUtils.isEmptyNode(tmp.nextSibling)) {
  16886. domUtils.remove(tmp.nextSibling)
  16887. }
  16888. var nodeStyle =
  16889. getStyle(startParent) ||
  16890. domUtils.getComputedStyle(startParent, 'list-style-type') ||
  16891. (command.toLowerCase() == 'insertorderedlist'
  16892. ? 'decimal'
  16893. : 'disc')
  16894. if (
  16895. startParent.tagName.toLowerCase() == tag &&
  16896. nodeStyle == style
  16897. ) {
  16898. for (
  16899. var i = 0, ci, tmpFrag = me.document.createDocumentFragment();
  16900. (ci = frag.firstChild);
  16901. ) {
  16902. if (domUtils.isTagNode(ci, 'ol ul')) {
  16903. // 删除时,子列表不处理
  16904. // utils.each(domUtils.getElementsByTagName(ci,'li'),function(li){
  16905. // while(li.firstChild){
  16906. // tmpFrag.appendChild(li.firstChild);
  16907. // }
  16908. //
  16909. // });
  16910. tmpFrag.appendChild(ci)
  16911. } else {
  16912. while (ci.firstChild) {
  16913. tmpFrag.appendChild(ci.firstChild)
  16914. domUtils.remove(ci)
  16915. }
  16916. }
  16917. }
  16918. tmp.parentNode.insertBefore(tmpFrag, tmp)
  16919. } else {
  16920. list = me.document.createElement(tag)
  16921. setListStyle(list, style)
  16922. list.appendChild(frag)
  16923. tmp.parentNode.insertBefore(list, tmp)
  16924. }
  16925. domUtils.remove(tmp)
  16926. list && adjustList(list, tag, style)
  16927. range.moveToBookmark(bko).select()
  16928. return
  16929. }
  16930. //开始
  16931. if (start) {
  16932. while (start) {
  16933. tmp = start.nextSibling
  16934. if (domUtils.isTagNode(start, 'ol ul')) {
  16935. frag.appendChild(start)
  16936. } else {
  16937. var tmpfrag = me.document.createDocumentFragment(),
  16938. hasBlock = 0
  16939. while (start.firstChild) {
  16940. if (domUtils.isBlockElm(start.firstChild)) {
  16941. hasBlock = 1
  16942. }
  16943. tmpfrag.appendChild(start.firstChild)
  16944. }
  16945. if (!hasBlock) {
  16946. var tmpP = me.document.createElement('p')
  16947. tmpP.appendChild(tmpfrag)
  16948. frag.appendChild(tmpP)
  16949. } else {
  16950. frag.appendChild(tmpfrag)
  16951. }
  16952. domUtils.remove(start)
  16953. }
  16954. start = tmp
  16955. }
  16956. startParent.parentNode.insertBefore(frag, startParent.nextSibling)
  16957. if (domUtils.isEmptyNode(startParent)) {
  16958. range.setStartBefore(startParent)
  16959. domUtils.remove(startParent)
  16960. } else {
  16961. range.setStartAfter(startParent)
  16962. }
  16963. modifyStart = 1
  16964. }
  16965. if (end && domUtils.inDoc(endParent, me.document)) {
  16966. //结束
  16967. start = endParent.firstChild
  16968. while (start && start !== end) {
  16969. tmp = start.nextSibling
  16970. if (domUtils.isTagNode(start, 'ol ul')) {
  16971. frag.appendChild(start)
  16972. } else {
  16973. tmpfrag = me.document.createDocumentFragment()
  16974. hasBlock = 0
  16975. while (start.firstChild) {
  16976. if (domUtils.isBlockElm(start.firstChild)) {
  16977. hasBlock = 1
  16978. }
  16979. tmpfrag.appendChild(start.firstChild)
  16980. }
  16981. if (!hasBlock) {
  16982. tmpP = me.document.createElement('p')
  16983. tmpP.appendChild(tmpfrag)
  16984. frag.appendChild(tmpP)
  16985. } else {
  16986. frag.appendChild(tmpfrag)
  16987. }
  16988. domUtils.remove(start)
  16989. }
  16990. start = tmp
  16991. }
  16992. var tmpDiv = domUtils.createElement(me.document, 'div', {
  16993. tmpDiv: 1,
  16994. })
  16995. domUtils.moveChild(end, tmpDiv)
  16996. frag.appendChild(tmpDiv)
  16997. domUtils.remove(end)
  16998. endParent.parentNode.insertBefore(frag, endParent)
  16999. range.setEndBefore(endParent)
  17000. if (domUtils.isEmptyNode(endParent)) {
  17001. domUtils.remove(endParent)
  17002. }
  17003. modifyEnd = 1
  17004. }
  17005. }
  17006. if (!modifyStart) {
  17007. range.setStartBefore(me.document.getElementById(bko.start))
  17008. }
  17009. if (bko.end && !modifyEnd) {
  17010. range.setEndAfter(me.document.getElementById(bko.end))
  17011. }
  17012. range.enlarge(true, function (node) {
  17013. return notExchange[node.tagName]
  17014. })
  17015. frag = me.document.createDocumentFragment()
  17016. var bk = range.createBookmark(),
  17017. current = domUtils.getNextDomNode(bk.start, false, filterFn),
  17018. tmpRange = range.cloneRange(),
  17019. tmpNode,
  17020. block = domUtils.isBlockElm
  17021. while (
  17022. current &&
  17023. current !== bk.end &&
  17024. domUtils.getPosition(current, bk.end) & domUtils.POSITION_PRECEDING
  17025. ) {
  17026. if (current.nodeType == 3 || dtd.li[current.tagName]) {
  17027. if (current.nodeType == 1 && dtd.$list[current.tagName]) {
  17028. while (current.firstChild) {
  17029. frag.appendChild(current.firstChild)
  17030. }
  17031. tmpNode = domUtils.getNextDomNode(current, false, filterFn)
  17032. domUtils.remove(current)
  17033. current = tmpNode
  17034. continue
  17035. }
  17036. tmpNode = current
  17037. tmpRange.setStartBefore(current)
  17038. while (
  17039. current &&
  17040. current !== bk.end &&
  17041. (!block(current) || domUtils.isBookmarkNode(current))
  17042. ) {
  17043. tmpNode = current
  17044. current = domUtils.getNextDomNode(
  17045. current,
  17046. false,
  17047. null,
  17048. function (node) {
  17049. return !notExchange[node.tagName]
  17050. }
  17051. )
  17052. }
  17053. if (current && block(current)) {
  17054. tmp = domUtils.getNextDomNode(tmpNode, false, filterFn)
  17055. if (tmp && domUtils.isBookmarkNode(tmp)) {
  17056. current = domUtils.getNextDomNode(tmp, false, filterFn)
  17057. tmpNode = tmp
  17058. }
  17059. }
  17060. tmpRange.setEndAfter(tmpNode)
  17061. current = domUtils.getNextDomNode(tmpNode, false, filterFn)
  17062. var li = range.document.createElement('li')
  17063. li.appendChild(tmpRange.extractContents())
  17064. if (domUtils.isEmptyNode(li)) {
  17065. var tmpNode = range.document.createElement('p')
  17066. while (li.firstChild) {
  17067. tmpNode.appendChild(li.firstChild)
  17068. }
  17069. li.appendChild(tmpNode)
  17070. }
  17071. frag.appendChild(li)
  17072. } else {
  17073. current = domUtils.getNextDomNode(current, true, filterFn)
  17074. }
  17075. }
  17076. range.moveToBookmark(bk).collapse(true)
  17077. list = me.document.createElement(tag)
  17078. setListStyle(list, style)
  17079. list.appendChild(frag)
  17080. range.insertNode(list)
  17081. //当前list上下看能否合并
  17082. adjustList(list, tag, style)
  17083. //去掉冗余的tmpDiv
  17084. for (
  17085. var i = 0, ci, tmpDivs = domUtils.getElementsByTagName(list, 'div');
  17086. (ci = tmpDivs[i++]);
  17087. ) {
  17088. if (ci.getAttribute('tmpDiv')) {
  17089. domUtils.remove(ci, true)
  17090. }
  17091. }
  17092. range.moveToBookmark(bko).select()
  17093. },
  17094. queryCommandState: function (command) {
  17095. var tag = command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul'
  17096. var path = this.selection.getStartElementPath()
  17097. for (var i = 0, ci; (ci = path[i++]); ) {
  17098. if (ci.nodeName == 'TABLE') {
  17099. return 0
  17100. }
  17101. if (tag == ci.nodeName.toLowerCase()) {
  17102. return 1
  17103. }
  17104. }
  17105. return 0
  17106. },
  17107. queryCommandValue: function (command) {
  17108. var tag = command.toLowerCase() == 'insertorderedlist' ? 'ol' : 'ul'
  17109. var path = this.selection.getStartElementPath(),
  17110. node
  17111. for (var i = 0, ci; (ci = path[i++]); ) {
  17112. if (ci.nodeName == 'TABLE') {
  17113. node = null
  17114. break
  17115. }
  17116. if (tag == ci.nodeName.toLowerCase()) {
  17117. node = ci
  17118. break
  17119. }
  17120. }
  17121. return node
  17122. ? getStyle(node) || domUtils.getComputedStyle(node, 'list-style-type')
  17123. : null
  17124. },
  17125. }
  17126. }
  17127. // plugins/source.js
  17128. /**
  17129. * 源码编辑插件
  17130. * @file
  17131. * @since 1.2.6.1
  17132. */
  17133. ;(function () {
  17134. var sourceEditors = {
  17135. textarea: function (editor, holder) {
  17136. var textarea = holder.ownerDocument.createElement('textarea')
  17137. textarea.style.cssText =
  17138. 'position:absolute;resize:none;width:100%;height:100%;border:0;padding:0;margin:0;overflow-y:auto;'
  17139. // todo: IE下只有onresize属性可用... 很纠结
  17140. if (browser.ie && browser.version < 8) {
  17141. textarea.style.width = holder.offsetWidth + 'px'
  17142. textarea.style.height = holder.offsetHeight + 'px'
  17143. holder.onresize = function () {
  17144. textarea.style.width = holder.offsetWidth + 'px'
  17145. textarea.style.height = holder.offsetHeight + 'px'
  17146. }
  17147. }
  17148. holder.appendChild(textarea)
  17149. return {
  17150. setContent: function (content) {
  17151. textarea.value = content
  17152. },
  17153. getContent: function () {
  17154. return textarea.value
  17155. },
  17156. select: function () {
  17157. var range
  17158. if (browser.ie) {
  17159. range = textarea.createTextRange()
  17160. range.collapse(true)
  17161. range.select()
  17162. } else {
  17163. //todo: chrome下无法设置焦点
  17164. textarea.setSelectionRange(0, 0)
  17165. textarea.focus()
  17166. }
  17167. },
  17168. dispose: function () {
  17169. holder.removeChild(textarea)
  17170. // todo
  17171. holder.onresize = null
  17172. textarea = null
  17173. holder = null
  17174. },
  17175. }
  17176. },
  17177. codemirror: function (editor, holder) {
  17178. var codeEditor = window.CodeMirror(holder, {
  17179. mode: 'text/html',
  17180. tabMode: 'indent',
  17181. lineNumbers: true,
  17182. lineWrapping: true,
  17183. })
  17184. var dom = codeEditor.getWrapperElement()
  17185. dom.style.cssText =
  17186. 'position:absolute;left:0;top:0;width:100%;height:100%;font-family:consolas,"Courier new",monospace;font-size:13px;'
  17187. codeEditor.getScrollerElement().style.cssText =
  17188. 'position:absolute;left:0;top:0;width:100%;height:100%;'
  17189. codeEditor.refresh()
  17190. return {
  17191. getCodeMirror: function () {
  17192. return codeEditor
  17193. },
  17194. setContent: function (content) {
  17195. codeEditor.setValue(content)
  17196. },
  17197. getContent: function () {
  17198. return codeEditor.getValue()
  17199. },
  17200. select: function () {
  17201. codeEditor.focus()
  17202. },
  17203. dispose: function () {
  17204. holder.removeChild(dom)
  17205. dom = null
  17206. codeEditor = null
  17207. },
  17208. }
  17209. },
  17210. }
  17211. UE.plugins['source'] = function () {
  17212. var me = this
  17213. var opt = this.options
  17214. var sourceMode = false
  17215. var sourceEditor
  17216. var orgSetContent
  17217. opt.sourceEditor = browser.ie
  17218. ? 'textarea'
  17219. : opt.sourceEditor || 'codemirror'
  17220. me.setOpt({
  17221. sourceEditorFirst: false,
  17222. })
  17223. function createSourceEditor(holder) {
  17224. return sourceEditors[
  17225. opt.sourceEditor == 'codemirror' && window.CodeMirror
  17226. ? 'codemirror'
  17227. : 'textarea'
  17228. ](me, holder)
  17229. }
  17230. var bakCssText
  17231. //解决在源码模式下getContent不能得到最新的内容问题
  17232. var oldGetContent, bakAddress
  17233. /**
  17234. * 切换源码模式和编辑模式
  17235. * @command source
  17236. * @method execCommand
  17237. * @param { String } cmd 命令字符串
  17238. * @example
  17239. * ```javascript
  17240. * editor.execCommand( 'source');
  17241. * ```
  17242. */
  17243. /**
  17244. * 查询当前编辑区域的状态是源码模式还是可视化模式
  17245. * @command source
  17246. * @method queryCommandState
  17247. * @param { String } cmd 命令字符串
  17248. * @return { int } 如果当前是源码编辑模式,返回1,否则返回0
  17249. * @example
  17250. * ```javascript
  17251. * editor.queryCommandState( 'source' );
  17252. * ```
  17253. */
  17254. me.commands['source'] = {
  17255. execCommand: function () {
  17256. sourceMode = !sourceMode
  17257. if (sourceMode) {
  17258. bakAddress = me.selection.getRange().createAddress(false, true)
  17259. me.undoManger && me.undoManger.save(true)
  17260. if (browser.gecko) {
  17261. me.body.contentEditable = false
  17262. }
  17263. bakCssText = me.iframe.style.cssText
  17264. me.iframe.style.cssText +=
  17265. 'position:absolute;left:-32768px;top:-32768px;'
  17266. me.fireEvent('beforegetcontent')
  17267. var root = UE.htmlparser(me.body.innerHTML)
  17268. me.filterOutputRule(root)
  17269. root.traversal(function (node) {
  17270. if (node.type == 'element') {
  17271. switch (node.tagName) {
  17272. case 'td':
  17273. case 'th':
  17274. case 'caption':
  17275. if (node.children && node.children.length == 1) {
  17276. if (node.firstChild().tagName == 'br') {
  17277. node.removeChild(node.firstChild())
  17278. }
  17279. }
  17280. break
  17281. case 'pre':
  17282. node.innerText(node.innerText().replace(/&nbsp;/g, ' '))
  17283. }
  17284. }
  17285. })
  17286. me.fireEvent('aftergetcontent')
  17287. var content = root.toHtml(true)
  17288. sourceEditor = createSourceEditor(me.iframe.parentNode)
  17289. sourceEditor.setContent(content)
  17290. orgSetContent = me.setContent
  17291. me.setContent = function (html) {
  17292. //这里暂时不触发事件,防止报错
  17293. var root = UE.htmlparser(html)
  17294. me.filterInputRule(root)
  17295. html = root.toHtml()
  17296. sourceEditor.setContent(html)
  17297. }
  17298. setTimeout(function () {
  17299. sourceEditor.select()
  17300. me.addListener('fullscreenchanged', function () {
  17301. try {
  17302. sourceEditor.getCodeMirror().refresh()
  17303. } catch (e) {}
  17304. })
  17305. })
  17306. //重置getContent,源码模式下取值也能是最新的数据
  17307. oldGetContent = me.getContent
  17308. me.getContent = function () {
  17309. return (
  17310. sourceEditor.getContent() ||
  17311. '<p>' + (browser.ie ? '' : '<br/>') + '</p>'
  17312. )
  17313. }
  17314. } else {
  17315. me.iframe.style.cssText = bakCssText
  17316. var cont =
  17317. sourceEditor.getContent() ||
  17318. '<p>' + (browser.ie ? '' : '<br/>') + '</p>'
  17319. //处理掉block节点前后的空格,有可能会误命中,暂时不考虑
  17320. cont = cont.replace(
  17321. new RegExp('[\\r\\t\\n ]*</?(\\w+)\\s*(?:[^>]*)>', 'g'),
  17322. function (a, b) {
  17323. if (b && !dtd.$inlineWithA[b.toLowerCase()]) {
  17324. return a.replace(/(^[\n\r\t ]*)|([\n\r\t ]*$)/g, '')
  17325. }
  17326. return a.replace(/(^[\n\r\t]*)|([\n\r\t]*$)/g, '')
  17327. }
  17328. )
  17329. me.setContent = orgSetContent
  17330. me.setContent(cont)
  17331. sourceEditor.dispose()
  17332. sourceEditor = null
  17333. //还原getContent方法
  17334. me.getContent = oldGetContent
  17335. var first = me.body.firstChild
  17336. //trace:1106 都删除空了,下边会报错,所以补充一个p占位
  17337. if (!first) {
  17338. me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>'
  17339. first = me.body.firstChild
  17340. }
  17341. //要在ifm为显示时ff才能取到selection,否则报错
  17342. //这里不能比较位置了
  17343. me.undoManger && me.undoManger.save(true)
  17344. if (browser.gecko) {
  17345. var input = document.createElement('input')
  17346. input.style.cssText = 'position:absolute;left:0;top:-32768px'
  17347. document.body.appendChild(input)
  17348. me.body.contentEditable = false
  17349. setTimeout(function () {
  17350. domUtils.setViewportOffset(input, { left: -32768, top: 0 })
  17351. input.focus()
  17352. setTimeout(function () {
  17353. me.body.contentEditable = true
  17354. me.selection.getRange().moveToAddress(bakAddress).select(true)
  17355. domUtils.remove(input)
  17356. })
  17357. })
  17358. } else {
  17359. //ie下有可能报错,比如在代码顶头的情况
  17360. try {
  17361. me.selection.getRange().moveToAddress(bakAddress).select(true)
  17362. } catch (e) {}
  17363. }
  17364. }
  17365. this.fireEvent('sourcemodechanged', sourceMode)
  17366. },
  17367. queryCommandState: function () {
  17368. return sourceMode | 0
  17369. },
  17370. notNeedUndo: 1,
  17371. }
  17372. var oldQueryCommandState = me.queryCommandState
  17373. me.queryCommandState = function (cmdName) {
  17374. cmdName = cmdName.toLowerCase()
  17375. if (sourceMode) {
  17376. //源码模式下可以开启的命令
  17377. return cmdName in
  17378. {
  17379. source: 1,
  17380. fullscreen: 1,
  17381. }
  17382. ? 1
  17383. : -1
  17384. }
  17385. return oldQueryCommandState.apply(this, arguments)
  17386. }
  17387. if (opt.sourceEditor == 'codemirror') {
  17388. me.addListener('ready', function () {
  17389. utils.loadFile(
  17390. document,
  17391. {
  17392. src:
  17393. opt.codeMirrorJsUrl ||
  17394. opt.UEDITOR_HOME_URL + 'third-party/codemirror/codemirror.js',
  17395. tag: 'script',
  17396. type: 'text/javascript',
  17397. defer: 'defer',
  17398. },
  17399. function () {
  17400. if (opt.sourceEditorFirst) {
  17401. setTimeout(function () {
  17402. me.execCommand('source')
  17403. }, 0)
  17404. }
  17405. }
  17406. )
  17407. utils.loadFile(document, {
  17408. tag: 'link',
  17409. rel: 'stylesheet',
  17410. type: 'text/css',
  17411. href:
  17412. opt.codeMirrorCssUrl ||
  17413. opt.UEDITOR_HOME_URL + 'third-party/codemirror/codemirror.css',
  17414. })
  17415. })
  17416. }
  17417. }
  17418. })()
  17419. // plugins/enterkey.js
  17420. ///import core
  17421. ///import plugins/undo.js
  17422. ///commands 设置回车标签p或br
  17423. ///commandsName EnterKey
  17424. ///commandsTitle 设置回车标签p或br
  17425. /**
  17426. * @description 处理回车
  17427. * @author zhanyi
  17428. */
  17429. UE.plugins['enterkey'] = function () {
  17430. var hTag,
  17431. me = this,
  17432. tag = me.options.enterTag
  17433. me.addListener('keyup', function (type, evt) {
  17434. var keyCode = evt.keyCode || evt.which
  17435. if (keyCode == 13) {
  17436. var range = me.selection.getRange(),
  17437. start = range.startContainer,
  17438. doSave
  17439. //修正在h1-h6里边回车后不能嵌套p的问题
  17440. if (!browser.ie) {
  17441. if (/h\d/i.test(hTag)) {
  17442. if (browser.gecko) {
  17443. var h = domUtils.findParentByTagName(
  17444. start,
  17445. [
  17446. 'h1',
  17447. 'h2',
  17448. 'h3',
  17449. 'h4',
  17450. 'h5',
  17451. 'h6',
  17452. 'blockquote',
  17453. 'caption',
  17454. 'table',
  17455. ],
  17456. true
  17457. )
  17458. if (!h) {
  17459. me.document.execCommand('formatBlock', false, '<p>')
  17460. doSave = 1
  17461. }
  17462. } else {
  17463. //chrome remove div
  17464. if (start.nodeType == 1) {
  17465. var tmp = me.document.createTextNode(''),
  17466. div
  17467. range.insertNode(tmp)
  17468. div = domUtils.findParentByTagName(tmp, 'div', true)
  17469. if (div) {
  17470. var p = me.document.createElement('p')
  17471. while (div.firstChild) {
  17472. p.appendChild(div.firstChild)
  17473. }
  17474. div.parentNode.insertBefore(p, div)
  17475. domUtils.remove(div)
  17476. range.setStartBefore(tmp).setCursor()
  17477. doSave = 1
  17478. }
  17479. domUtils.remove(tmp)
  17480. }
  17481. }
  17482. if (me.undoManger && doSave) {
  17483. me.undoManger.save()
  17484. }
  17485. }
  17486. //没有站位符,会出现多行的问题
  17487. browser.opera && range.select()
  17488. } else {
  17489. me.fireEvent('saveScene', true, true)
  17490. }
  17491. }
  17492. })
  17493. me.addListener('keydown', function (type, evt) {
  17494. var keyCode = evt.keyCode || evt.which
  17495. if (keyCode == 13) {
  17496. //回车
  17497. if (me.fireEvent('beforeenterkeydown')) {
  17498. domUtils.preventDefault(evt)
  17499. return
  17500. }
  17501. me.fireEvent('saveScene', true, true)
  17502. hTag = ''
  17503. var range = me.selection.getRange()
  17504. if (!range.collapsed) {
  17505. //跨td不能删
  17506. var start = range.startContainer,
  17507. end = range.endContainer,
  17508. startTd = domUtils.findParentByTagName(start, 'td', true),
  17509. endTd = domUtils.findParentByTagName(end, 'td', true)
  17510. if (
  17511. (startTd && endTd && startTd !== endTd) ||
  17512. (!startTd && endTd) ||
  17513. (startTd && !endTd)
  17514. ) {
  17515. evt.preventDefault
  17516. ? evt.preventDefault()
  17517. : (evt.returnValue = false)
  17518. return
  17519. }
  17520. }
  17521. if (tag == 'p') {
  17522. if (!browser.ie) {
  17523. start = domUtils.findParentByTagName(
  17524. range.startContainer,
  17525. [
  17526. 'ol',
  17527. 'ul',
  17528. 'p',
  17529. 'h1',
  17530. 'h2',
  17531. 'h3',
  17532. 'h4',
  17533. 'h5',
  17534. 'h6',
  17535. 'blockquote',
  17536. 'caption',
  17537. ],
  17538. true
  17539. )
  17540. //opera下执行formatblock会在table的场景下有问题,回车在opera原生支持很好,所以暂时在opera去掉调用这个原生的command
  17541. //trace:2431
  17542. if (!start && !browser.opera) {
  17543. me.document.execCommand('formatBlock', false, '<p>')
  17544. if (browser.gecko) {
  17545. range = me.selection.getRange()
  17546. start = domUtils.findParentByTagName(
  17547. range.startContainer,
  17548. 'p',
  17549. true
  17550. )
  17551. start && domUtils.removeDirtyAttr(start)
  17552. }
  17553. } else {
  17554. hTag = start.tagName
  17555. start.tagName.toLowerCase() == 'p' &&
  17556. browser.gecko &&
  17557. domUtils.removeDirtyAttr(start)
  17558. }
  17559. }
  17560. } else {
  17561. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false)
  17562. if (!range.collapsed) {
  17563. range.deleteContents()
  17564. start = range.startContainer
  17565. if (
  17566. start.nodeType == 1 &&
  17567. (start = start.childNodes[range.startOffset])
  17568. ) {
  17569. while (start.nodeType == 1) {
  17570. if (dtd.$empty[start.tagName]) {
  17571. range.setStartBefore(start).setCursor()
  17572. if (me.undoManger) {
  17573. me.undoManger.save()
  17574. }
  17575. return false
  17576. }
  17577. if (!start.firstChild) {
  17578. var br = range.document.createElement('br')
  17579. start.appendChild(br)
  17580. range.setStart(start, 0).setCursor()
  17581. if (me.undoManger) {
  17582. me.undoManger.save()
  17583. }
  17584. return false
  17585. }
  17586. start = start.firstChild
  17587. }
  17588. if (
  17589. start === range.startContainer.childNodes[range.startOffset]
  17590. ) {
  17591. br = range.document.createElement('br')
  17592. range.insertNode(br).setCursor()
  17593. } else {
  17594. range.setStart(start, 0).setCursor()
  17595. }
  17596. } else {
  17597. br = range.document.createElement('br')
  17598. range.insertNode(br).setStartAfter(br).setCursor()
  17599. }
  17600. } else {
  17601. br = range.document.createElement('br')
  17602. range.insertNode(br)
  17603. var parent = br.parentNode
  17604. if (parent.lastChild === br) {
  17605. br.parentNode.insertBefore(br.cloneNode(true), br)
  17606. range.setStartBefore(br)
  17607. } else {
  17608. range.setStartAfter(br)
  17609. }
  17610. range.setCursor()
  17611. }
  17612. }
  17613. }
  17614. })
  17615. }
  17616. // plugins/keystrokes.js
  17617. /* 处理特殊键的兼容性问题 */
  17618. UE.plugins['keystrokes'] = function () {
  17619. var me = this
  17620. var collapsed = true
  17621. me.addListener('keydown', function (type, evt) {
  17622. var keyCode = evt.keyCode || evt.which,
  17623. rng = me.selection.getRange()
  17624. //处理全选的情况
  17625. if (
  17626. !rng.collapsed &&
  17627. !(evt.ctrlKey || evt.shiftKey || evt.altKey || evt.metaKey) &&
  17628. ((keyCode >= 65 && keyCode <= 90) ||
  17629. (keyCode >= 48 && keyCode <= 57) ||
  17630. (keyCode >= 96 && keyCode <= 111) ||
  17631. {
  17632. 13: 1,
  17633. 8: 1,
  17634. 46: 1,
  17635. }[keyCode])
  17636. ) {
  17637. var tmpNode = rng.startContainer
  17638. if (domUtils.isFillChar(tmpNode)) {
  17639. rng.setStartBefore(tmpNode)
  17640. }
  17641. tmpNode = rng.endContainer
  17642. if (domUtils.isFillChar(tmpNode)) {
  17643. rng.setEndAfter(tmpNode)
  17644. }
  17645. rng.txtToElmBoundary()
  17646. //结束边界可能放到了br的前边,要把br包含进来
  17647. // x[xxx]<br/>
  17648. if (rng.endContainer && rng.endContainer.nodeType == 1) {
  17649. tmpNode = rng.endContainer.childNodes[rng.endOffset]
  17650. if (tmpNode && domUtils.isBr(tmpNode)) {
  17651. rng.setEndAfter(tmpNode)
  17652. }
  17653. }
  17654. if (rng.startOffset == 0) {
  17655. tmpNode = rng.startContainer
  17656. if (domUtils.isBoundaryNode(tmpNode, 'firstChild')) {
  17657. tmpNode = rng.endContainer
  17658. if (
  17659. rng.endOffset ==
  17660. (tmpNode.nodeType == 3
  17661. ? tmpNode.nodeValue.length
  17662. : tmpNode.childNodes.length) &&
  17663. domUtils.isBoundaryNode(tmpNode, 'lastChild')
  17664. ) {
  17665. me.fireEvent('saveScene')
  17666. me.body.innerHTML = '<p>' + (browser.ie ? '' : '<br/>') + '</p>'
  17667. rng.setStart(me.body.firstChild, 0).setCursor(false, true)
  17668. me._selectionChange()
  17669. return
  17670. }
  17671. }
  17672. }
  17673. }
  17674. //处理backspace
  17675. if (keyCode == keymap.Backspace) {
  17676. rng = me.selection.getRange()
  17677. collapsed = rng.collapsed
  17678. if (me.fireEvent('delkeydown', evt)) {
  17679. return
  17680. }
  17681. var start, end
  17682. //避免按两次删除才能生效的问题
  17683. if (rng.collapsed && rng.inFillChar()) {
  17684. start = rng.startContainer
  17685. if (domUtils.isFillChar(start)) {
  17686. rng.setStartBefore(start).shrinkBoundary(true).collapse(true)
  17687. domUtils.remove(start)
  17688. } else {
  17689. start.nodeValue = start.nodeValue.replace(
  17690. new RegExp('^' + domUtils.fillChar),
  17691. ''
  17692. )
  17693. rng.startOffset--
  17694. rng.collapse(true).select(true)
  17695. }
  17696. }
  17697. //解决选中control元素不能删除的问题
  17698. if ((start = rng.getClosedNode())) {
  17699. me.fireEvent('saveScene')
  17700. rng.setStartBefore(start)
  17701. domUtils.remove(start)
  17702. rng.setCursor()
  17703. me.fireEvent('saveScene')
  17704. domUtils.preventDefault(evt)
  17705. return
  17706. }
  17707. //阻止在table上的删除
  17708. if (!browser.ie) {
  17709. start = domUtils.findParentByTagName(
  17710. rng.startContainer,
  17711. 'table',
  17712. true
  17713. )
  17714. end = domUtils.findParentByTagName(rng.endContainer, 'table', true)
  17715. if ((start && !end) || (!start && end) || start !== end) {
  17716. evt.preventDefault()
  17717. return
  17718. }
  17719. }
  17720. }
  17721. //处理tab键的逻辑
  17722. if (keyCode == keymap.Tab) {
  17723. //不处理以下标签
  17724. var excludeTagNameForTabKey = {
  17725. ol: 1,
  17726. ul: 1,
  17727. table: 1,
  17728. }
  17729. //处理组件里的tab按下事件
  17730. if (me.fireEvent('tabkeydown', evt)) {
  17731. domUtils.preventDefault(evt)
  17732. return
  17733. }
  17734. var range = me.selection.getRange()
  17735. me.fireEvent('saveScene')
  17736. for (
  17737. var i = 0,
  17738. txt = '',
  17739. tabSize = me.options.tabSize || 4,
  17740. tabNode = me.options.tabNode || '&nbsp;';
  17741. i < tabSize;
  17742. i++
  17743. ) {
  17744. txt += tabNode
  17745. }
  17746. var span = me.document.createElement('span')
  17747. span.innerHTML = txt + domUtils.fillChar
  17748. if (range.collapsed) {
  17749. range.insertNode(span.cloneNode(true).firstChild).setCursor(true)
  17750. } else {
  17751. var filterFn = function (node) {
  17752. return (
  17753. domUtils.isBlockElm(node) &&
  17754. !excludeTagNameForTabKey[node.tagName.toLowerCase()]
  17755. )
  17756. }
  17757. //普通的情况
  17758. start = domUtils.findParent(range.startContainer, filterFn, true)
  17759. end = domUtils.findParent(range.endContainer, filterFn, true)
  17760. if (start && end && start === end) {
  17761. range.deleteContents()
  17762. range.insertNode(span.cloneNode(true).firstChild).setCursor(true)
  17763. } else {
  17764. var bookmark = range.createBookmark()
  17765. range.enlarge(true)
  17766. var bookmark2 = range.createBookmark(),
  17767. current = domUtils.getNextDomNode(
  17768. bookmark2.start,
  17769. false,
  17770. filterFn
  17771. )
  17772. while (
  17773. current &&
  17774. !(
  17775. domUtils.getPosition(current, bookmark2.end) &
  17776. domUtils.POSITION_FOLLOWING
  17777. )
  17778. ) {
  17779. current.insertBefore(
  17780. span.cloneNode(true).firstChild,
  17781. current.firstChild
  17782. )
  17783. current = domUtils.getNextDomNode(current, false, filterFn)
  17784. }
  17785. range.moveToBookmark(bookmark2).moveToBookmark(bookmark).select()
  17786. }
  17787. }
  17788. domUtils.preventDefault(evt)
  17789. }
  17790. //trace:1634
  17791. //ff的del键在容器空的时候,也会删除
  17792. if (browser.gecko && keyCode == 46) {
  17793. range = me.selection.getRange()
  17794. if (range.collapsed) {
  17795. start = range.startContainer
  17796. if (domUtils.isEmptyBlock(start)) {
  17797. var parent = start.parentNode
  17798. while (
  17799. domUtils.getChildCount(parent) == 1 &&
  17800. !domUtils.isBody(parent)
  17801. ) {
  17802. start = parent
  17803. parent = parent.parentNode
  17804. }
  17805. if (start === parent.lastChild) evt.preventDefault()
  17806. return
  17807. }
  17808. }
  17809. }
  17810. })
  17811. me.addListener('keyup', function (type, evt) {
  17812. var keyCode = evt.keyCode || evt.which,
  17813. rng,
  17814. me = this
  17815. if (keyCode == keymap.Backspace) {
  17816. if (me.fireEvent('delkeyup')) {
  17817. return
  17818. }
  17819. rng = me.selection.getRange()
  17820. if (rng.collapsed) {
  17821. var tmpNode,
  17822. autoClearTagName = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
  17823. if (
  17824. (tmpNode = domUtils.findParentByTagName(
  17825. rng.startContainer,
  17826. autoClearTagName,
  17827. true
  17828. ))
  17829. ) {
  17830. if (domUtils.isEmptyBlock(tmpNode)) {
  17831. var pre = tmpNode.previousSibling
  17832. if (pre && pre.nodeName != 'TABLE') {
  17833. domUtils.remove(tmpNode)
  17834. rng.setStartAtLast(pre).setCursor(false, true)
  17835. return
  17836. } else {
  17837. var next = tmpNode.nextSibling
  17838. if (next && next.nodeName != 'TABLE') {
  17839. domUtils.remove(tmpNode)
  17840. rng.setStartAtFirst(next).setCursor(false, true)
  17841. return
  17842. }
  17843. }
  17844. }
  17845. }
  17846. //处理当删除到body时,要重新给p标签展位
  17847. if (domUtils.isBody(rng.startContainer)) {
  17848. var tmpNode = domUtils.createElement(me.document, 'p', {
  17849. innerHTML: browser.ie ? domUtils.fillChar : '<br/>',
  17850. })
  17851. rng.insertNode(tmpNode).setStart(tmpNode, 0).setCursor(false, true)
  17852. }
  17853. }
  17854. //chrome下如果删除了inline标签,浏览器会有记忆,在输入文字还是会套上刚才删除的标签,所以这里再选一次就不会了
  17855. if (
  17856. !collapsed &&
  17857. (rng.startContainer.nodeType == 3 ||
  17858. (rng.startContainer.nodeType == 1 &&
  17859. domUtils.isEmptyBlock(rng.startContainer)))
  17860. ) {
  17861. if (browser.ie) {
  17862. var span = rng.document.createElement('span')
  17863. rng.insertNode(span).setStartBefore(span).collapse(true)
  17864. rng.select()
  17865. domUtils.remove(span)
  17866. } else {
  17867. rng.select()
  17868. }
  17869. }
  17870. }
  17871. })
  17872. }
  17873. // plugins/fiximgclick.js
  17874. ///import core
  17875. ///commands 修复chrome下图片不能点击的问题,出现八个角可改变大小
  17876. ///commandsName FixImgClick
  17877. ///commandsTitle 修复chrome下图片不能点击的问题,出现八个角可改变大小
  17878. //修复chrome下图片不能点击的问题,出现八个角可改变大小
  17879. UE.plugins['fiximgclick'] = (function () {
  17880. var elementUpdated = false
  17881. function Scale() {
  17882. this.editor = null
  17883. this.resizer = null
  17884. this.cover = null
  17885. this.doc = document
  17886. this.prePos = { x: 0, y: 0 }
  17887. this.startPos = { x: 0, y: 0 }
  17888. }
  17889. ;(function () {
  17890. var rect = [
  17891. //[left, top, width, height]
  17892. [0, 0, -1, -1],
  17893. [0, 0, 0, -1],
  17894. [0, 0, 1, -1],
  17895. [0, 0, -1, 0],
  17896. [0, 0, 1, 0],
  17897. [0, 0, -1, 1],
  17898. [0, 0, 0, 1],
  17899. [0, 0, 1, 1],
  17900. ]
  17901. Scale.prototype = {
  17902. init: function (editor) {
  17903. var me = this
  17904. me.editor = editor
  17905. me.startPos = this.prePos = { x: 0, y: 0 }
  17906. me.dragId = -1
  17907. var hands = [],
  17908. cover = (me.cover = document.createElement('div')),
  17909. resizer = (me.resizer = document.createElement('div'))
  17910. cover.id = me.editor.ui.id + '_imagescale_cover'
  17911. cover.style.cssText =
  17912. 'position:absolute;display:none;z-index:' +
  17913. me.editor.options.zIndex +
  17914. ';filter:alpha(opacity=0); opacity:0;background:#CCC;'
  17915. domUtils.on(cover, 'mousedown click', function () {
  17916. me.hide()
  17917. })
  17918. for (i = 0; i < 8; i++) {
  17919. hands.push(
  17920. '<span class="edui-editor-imagescale-hand' + i + '"></span>'
  17921. )
  17922. }
  17923. resizer.id = me.editor.ui.id + '_imagescale'
  17924. resizer.className = 'edui-editor-imagescale'
  17925. resizer.innerHTML = hands.join('')
  17926. resizer.style.cssText +=
  17927. ';display:none;border:1px solid #3b77ff;z-index:' +
  17928. me.editor.options.zIndex +
  17929. ';'
  17930. me.editor.ui.getDom().appendChild(cover)
  17931. me.editor.ui.getDom().appendChild(resizer)
  17932. me.initStyle()
  17933. me.initEvents()
  17934. },
  17935. initStyle: function () {
  17936. utils.cssRule(
  17937. 'imagescale',
  17938. '.edui-editor-imagescale{display:none;position:absolute;border:1px solid #38B2CE;cursor:hand;-webkit-box-sizing: content-box;-moz-box-sizing: content-box;box-sizing: content-box;}' +
  17939. '.edui-editor-imagescale span{position:absolute;width:6px;height:6px;overflow:hidden;font-size:0px;display:block;background-color:#3C9DD0;}' +
  17940. '.edui-editor-imagescale .edui-editor-imagescale-hand0{cursor:nw-resize;top:0;margin-top:-4px;left:0;margin-left:-4px;}' +
  17941. '.edui-editor-imagescale .edui-editor-imagescale-hand1{cursor:n-resize;top:0;margin-top:-4px;left:50%;margin-left:-4px;}' +
  17942. '.edui-editor-imagescale .edui-editor-imagescale-hand2{cursor:ne-resize;top:0;margin-top:-4px;left:100%;margin-left:-3px;}' +
  17943. '.edui-editor-imagescale .edui-editor-imagescale-hand3{cursor:w-resize;top:50%;margin-top:-4px;left:0;margin-left:-4px;}' +
  17944. '.edui-editor-imagescale .edui-editor-imagescale-hand4{cursor:e-resize;top:50%;margin-top:-4px;left:100%;margin-left:-3px;}' +
  17945. '.edui-editor-imagescale .edui-editor-imagescale-hand5{cursor:sw-resize;top:100%;margin-top:-3px;left:0;margin-left:-4px;}' +
  17946. '.edui-editor-imagescale .edui-editor-imagescale-hand6{cursor:s-resize;top:100%;margin-top:-3px;left:50%;margin-left:-4px;}' +
  17947. '.edui-editor-imagescale .edui-editor-imagescale-hand7{cursor:se-resize;top:100%;margin-top:-3px;left:100%;margin-left:-3px;}'
  17948. )
  17949. },
  17950. initEvents: function () {
  17951. var me = this
  17952. me.startPos.x = me.startPos.y = 0
  17953. me.isDraging = false
  17954. },
  17955. _eventHandler: function (e) {
  17956. var me = this
  17957. switch (e.type) {
  17958. case 'mousedown':
  17959. var hand = e.target || e.srcElement,
  17960. hand
  17961. if (
  17962. hand.className.indexOf('edui-editor-imagescale-hand') != -1 &&
  17963. me.dragId == -1
  17964. ) {
  17965. me.dragId = hand.className.slice(-1)
  17966. me.startPos.x = me.prePos.x = e.clientX
  17967. me.startPos.y = me.prePos.y = e.clientY
  17968. domUtils.on(me.doc, 'mousemove', me.proxy(me._eventHandler, me))
  17969. }
  17970. break
  17971. case 'mousemove':
  17972. if (me.dragId != -1) {
  17973. me.updateContainerStyle(me.dragId, {
  17974. x: e.clientX - me.prePos.x,
  17975. y: e.clientY - me.prePos.y,
  17976. })
  17977. me.prePos.x = e.clientX
  17978. me.prePos.y = e.clientY
  17979. elementUpdated = true
  17980. me.updateTargetElement()
  17981. }
  17982. break
  17983. case 'mouseup':
  17984. if (me.dragId != -1) {
  17985. me.updateContainerStyle(me.dragId, {
  17986. x: e.clientX - me.prePos.x,
  17987. y: e.clientY - me.prePos.y,
  17988. })
  17989. me.updateTargetElement()
  17990. if (me.target.parentNode) me.attachTo(me.target)
  17991. me.dragId = -1
  17992. }
  17993. domUtils.un(me.doc, 'mousemove', me.proxy(me._eventHandler, me))
  17994. //修复只是点击挪动点,但没有改变大小,不应该触发contentchange
  17995. if (elementUpdated) {
  17996. elementUpdated = false
  17997. me.editor.fireEvent('contentchange')
  17998. }
  17999. break
  18000. default:
  18001. break
  18002. }
  18003. },
  18004. updateTargetElement: function () {
  18005. var me = this
  18006. domUtils.setStyles(me.target, {
  18007. width: me.resizer.style.width,
  18008. height: me.resizer.style.height,
  18009. })
  18010. me.target.width = parseInt(me.resizer.style.width)
  18011. me.target.height = parseInt(me.resizer.style.height)
  18012. me.attachTo(me.target)
  18013. },
  18014. updateContainerStyle: function (dir, offset) {
  18015. var me = this,
  18016. dom = me.resizer,
  18017. tmp
  18018. if (rect[dir][0] != 0) {
  18019. tmp = parseInt(dom.style.left) + offset.x
  18020. dom.style.left = me._validScaledProp('left', tmp) + 'px'
  18021. }
  18022. if (rect[dir][1] != 0) {
  18023. tmp = parseInt(dom.style.top) + offset.y
  18024. dom.style.top = me._validScaledProp('top', tmp) + 'px'
  18025. }
  18026. if (rect[dir][2] != 0) {
  18027. tmp = dom.clientWidth + rect[dir][2] * offset.x
  18028. dom.style.width = me._validScaledProp('width', tmp) + 'px'
  18029. }
  18030. if (rect[dir][3] != 0) {
  18031. tmp = dom.clientHeight + rect[dir][3] * offset.y
  18032. dom.style.height = me._validScaledProp('height', tmp) + 'px'
  18033. }
  18034. },
  18035. _validScaledProp: function (prop, value) {
  18036. var ele = this.resizer,
  18037. wrap = document
  18038. value = isNaN(value) ? 0 : value
  18039. switch (prop) {
  18040. case 'left':
  18041. return value < 0
  18042. ? 0
  18043. : value + ele.clientWidth > wrap.clientWidth
  18044. ? wrap.clientWidth - ele.clientWidth
  18045. : value
  18046. case 'top':
  18047. return value < 0
  18048. ? 0
  18049. : value + ele.clientHeight > wrap.clientHeight
  18050. ? wrap.clientHeight - ele.clientHeight
  18051. : value
  18052. case 'width':
  18053. return value <= 0
  18054. ? 1
  18055. : value + ele.offsetLeft > wrap.clientWidth
  18056. ? wrap.clientWidth - ele.offsetLeft
  18057. : value
  18058. case 'height':
  18059. return value <= 0
  18060. ? 1
  18061. : value + ele.offsetTop > wrap.clientHeight
  18062. ? wrap.clientHeight - ele.offsetTop
  18063. : value
  18064. }
  18065. },
  18066. hideCover: function () {
  18067. this.cover.style.display = 'none'
  18068. },
  18069. showCover: function () {
  18070. var me = this,
  18071. editorPos = domUtils.getXY(me.editor.ui.getDom()),
  18072. iframePos = domUtils.getXY(me.editor.iframe)
  18073. domUtils.setStyles(me.cover, {
  18074. width: me.editor.iframe.offsetWidth + 'px',
  18075. height: me.editor.iframe.offsetHeight + 'px',
  18076. top: iframePos.y - editorPos.y + 'px',
  18077. left: iframePos.x - editorPos.x + 'px',
  18078. position: 'absolute',
  18079. display: '',
  18080. })
  18081. },
  18082. show: function (targetObj) {
  18083. var me = this
  18084. me.resizer.style.display = 'block'
  18085. if (targetObj) me.attachTo(targetObj)
  18086. domUtils.on(this.resizer, 'mousedown', me.proxy(me._eventHandler, me))
  18087. domUtils.on(me.doc, 'mouseup', me.proxy(me._eventHandler, me))
  18088. me.showCover()
  18089. me.editor.fireEvent('afterscaleshow', me)
  18090. me.editor.fireEvent('saveScene')
  18091. },
  18092. hide: function () {
  18093. var me = this
  18094. me.hideCover()
  18095. me.resizer.style.display = 'none'
  18096. domUtils.un(me.resizer, 'mousedown', me.proxy(me._eventHandler, me))
  18097. domUtils.un(me.doc, 'mouseup', me.proxy(me._eventHandler, me))
  18098. me.editor.fireEvent('afterscalehide', me)
  18099. },
  18100. proxy: function (fn, context) {
  18101. return function (e) {
  18102. return fn.apply(context || this, arguments)
  18103. }
  18104. },
  18105. attachTo: function (targetObj) {
  18106. var me = this,
  18107. target = (me.target = targetObj),
  18108. resizer = this.resizer,
  18109. imgPos = domUtils.getXY(target),
  18110. iframePos = domUtils.getXY(me.editor.iframe),
  18111. editorPos = domUtils.getXY(resizer.parentNode)
  18112. domUtils.setStyles(resizer, {
  18113. width: target.width + 'px',
  18114. height: target.height + 'px',
  18115. left:
  18116. iframePos.x +
  18117. imgPos.x -
  18118. me.editor.document.body.scrollLeft -
  18119. editorPos.x -
  18120. parseInt(resizer.style.borderLeftWidth) +
  18121. 'px',
  18122. top:
  18123. iframePos.y +
  18124. imgPos.y -
  18125. me.editor.document.body.scrollTop -
  18126. editorPos.y -
  18127. parseInt(resizer.style.borderTopWidth) +
  18128. 'px',
  18129. })
  18130. },
  18131. }
  18132. })()
  18133. return function () {
  18134. var me = this,
  18135. imageScale
  18136. me.setOpt('imageScaleEnabled', true)
  18137. if (!browser.ie && me.options.imageScaleEnabled) {
  18138. me.addListener('click', function (type, e) {
  18139. var range = me.selection.getRange(),
  18140. img = range.getClosedNode()
  18141. if (
  18142. img &&
  18143. img.tagName == 'IMG' &&
  18144. me.body.contentEditable != 'false'
  18145. ) {
  18146. if (
  18147. img.className.indexOf('edui-faked-music') != -1 ||
  18148. img.getAttribute('anchorname') ||
  18149. domUtils.hasClass(img, 'loadingclass') ||
  18150. domUtils.hasClass(img, 'loaderrorclass')
  18151. ) {
  18152. return
  18153. }
  18154. if (!imageScale) {
  18155. imageScale = new Scale()
  18156. imageScale.init(me)
  18157. me.ui.getDom().appendChild(imageScale.resizer)
  18158. var _keyDownHandler = function (e) {
  18159. imageScale.hide()
  18160. if (imageScale.target)
  18161. me.selection
  18162. .getRange()
  18163. .selectNode(imageScale.target)
  18164. .select()
  18165. },
  18166. _mouseDownHandler = function (e) {
  18167. var ele = e.target || e.srcElement
  18168. if (
  18169. ele &&
  18170. (ele.className === undefined ||
  18171. ele.className.indexOf('edui-editor-imagescale') == -1)
  18172. ) {
  18173. _keyDownHandler(e)
  18174. }
  18175. },
  18176. timer
  18177. me.addListener('afterscaleshow', function (e) {
  18178. me.addListener('beforekeydown', _keyDownHandler)
  18179. me.addListener('beforemousedown', _mouseDownHandler)
  18180. domUtils.on(document, 'keydown', _keyDownHandler)
  18181. domUtils.on(document, 'mousedown', _mouseDownHandler)
  18182. me.selection.getNative().removeAllRanges()
  18183. })
  18184. me.addListener('afterscalehide', function (e) {
  18185. me.removeListener('beforekeydown', _keyDownHandler)
  18186. me.removeListener('beforemousedown', _mouseDownHandler)
  18187. domUtils.un(document, 'keydown', _keyDownHandler)
  18188. domUtils.un(document, 'mousedown', _mouseDownHandler)
  18189. var target = imageScale.target
  18190. if (target.parentNode) {
  18191. me.selection.getRange().selectNode(target).select()
  18192. }
  18193. })
  18194. //TODO 有iframe的情况,mousedown不能往下传。。
  18195. domUtils.on(imageScale.resizer, 'mousedown', function (e) {
  18196. me.selection.getNative().removeAllRanges()
  18197. var ele = e.target || e.srcElement
  18198. if (
  18199. ele &&
  18200. ele.className.indexOf('edui-editor-imagescale-hand') == -1
  18201. ) {
  18202. timer = setTimeout(function () {
  18203. imageScale.hide()
  18204. if (imageScale.target)
  18205. me.selection.getRange().selectNode(ele).select()
  18206. }, 200)
  18207. }
  18208. })
  18209. domUtils.on(imageScale.resizer, 'mouseup', function (e) {
  18210. var ele = e.target || e.srcElement
  18211. if (
  18212. ele &&
  18213. ele.className.indexOf('edui-editor-imagescale-hand') == -1
  18214. ) {
  18215. clearTimeout(timer)
  18216. }
  18217. })
  18218. }
  18219. imageScale.show(img)
  18220. } else {
  18221. if (imageScale && imageScale.resizer.style.display != 'none')
  18222. imageScale.hide()
  18223. }
  18224. })
  18225. }
  18226. if (browser.webkit) {
  18227. me.addListener('click', function (type, e) {
  18228. if (e.target.tagName == 'IMG' && me.body.contentEditable != 'false') {
  18229. var range = new dom.Range(me.document)
  18230. range.selectNode(e.target).select()
  18231. }
  18232. })
  18233. }
  18234. }
  18235. })()
  18236. // plugins/autolink.js
  18237. ///import core
  18238. ///commands 为非ie浏览器自动添加a标签
  18239. ///commandsName AutoLink
  18240. ///commandsTitle 自动增加链接
  18241. /**
  18242. * @description 为非ie浏览器自动添加a标签
  18243. * @author zhanyi
  18244. */
  18245. UE.plugin.register(
  18246. 'autolink',
  18247. function () {
  18248. var cont = 0
  18249. return !browser.ie
  18250. ? {
  18251. bindEvents: {
  18252. reset: function () {
  18253. cont = 0
  18254. },
  18255. keydown: function (type, evt) {
  18256. var me = this
  18257. var keyCode = evt.keyCode || evt.which
  18258. if (keyCode == 32 || keyCode == 13) {
  18259. var sel = me.selection.getNative(),
  18260. range = sel.getRangeAt(0).cloneRange(),
  18261. offset,
  18262. charCode
  18263. var start = range.startContainer
  18264. while (start.nodeType == 1 && range.startOffset > 0) {
  18265. start =
  18266. range.startContainer.childNodes[range.startOffset - 1]
  18267. if (!start) {
  18268. break
  18269. }
  18270. range.setStart(
  18271. start,
  18272. start.nodeType == 1
  18273. ? start.childNodes.length
  18274. : start.nodeValue.length
  18275. )
  18276. range.collapse(true)
  18277. start = range.startContainer
  18278. }
  18279. do {
  18280. if (range.startOffset == 0) {
  18281. start = range.startContainer.previousSibling
  18282. while (start && start.nodeType == 1) {
  18283. start = start.lastChild
  18284. }
  18285. if (!start || domUtils.isFillChar(start)) {
  18286. break
  18287. }
  18288. offset = start.nodeValue.length
  18289. } else {
  18290. start = range.startContainer
  18291. offset = range.startOffset
  18292. }
  18293. range.setStart(start, offset - 1)
  18294. charCode = range.toString().charCodeAt(0)
  18295. } while (charCode != 160 && charCode != 32)
  18296. if (
  18297. range
  18298. .toString()
  18299. .replace(new RegExp(domUtils.fillChar, 'g'), '')
  18300. .match(/(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i)
  18301. ) {
  18302. while (range.toString().length) {
  18303. if (
  18304. /^(?:https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.)/i.test(
  18305. range.toString()
  18306. )
  18307. ) {
  18308. break
  18309. }
  18310. try {
  18311. range.setStart(
  18312. range.startContainer,
  18313. range.startOffset + 1
  18314. )
  18315. } catch (e) {
  18316. //trace:2121
  18317. var start = range.startContainer
  18318. while (!(next = start.nextSibling)) {
  18319. if (domUtils.isBody(start)) {
  18320. return
  18321. }
  18322. start = start.parentNode
  18323. }
  18324. range.setStart(next, 0)
  18325. }
  18326. }
  18327. //range的开始边界已经在a标签里的不再处理
  18328. if (
  18329. domUtils.findParentByTagName(
  18330. range.startContainer,
  18331. 'a',
  18332. true
  18333. )
  18334. ) {
  18335. return
  18336. }
  18337. var a = me.document.createElement('a'),
  18338. text = me.document.createTextNode(' '),
  18339. href
  18340. me.undoManger && me.undoManger.save()
  18341. a.appendChild(range.extractContents())
  18342. a.href = a.innerHTML = a.innerHTML.replace(/<[^>]+>/g, '')
  18343. href = a
  18344. .getAttribute('href')
  18345. .replace(new RegExp(domUtils.fillChar, 'g'), '')
  18346. href = /^(?:https?:\/\/)/gi.test(href)
  18347. ? href
  18348. : 'http://' + href
  18349. a.setAttribute('_src', utils.html(href))
  18350. a.href = utils.html(href)
  18351. range.insertNode(a)
  18352. a.parentNode.insertBefore(text, a.nextSibling)
  18353. range.setStart(text, 0)
  18354. range.collapse(true)
  18355. sel.removeAllRanges()
  18356. sel.addRange(range)
  18357. me.undoManger && me.undoManger.save()
  18358. }
  18359. }
  18360. },
  18361. },
  18362. }
  18363. : {}
  18364. },
  18365. function () {
  18366. var keyCodes = {
  18367. 37: 1,
  18368. 38: 1,
  18369. 39: 1,
  18370. 40: 1,
  18371. 13: 1,
  18372. 32: 1,
  18373. }
  18374. function checkIsCludeLink(node) {
  18375. if (node.nodeType == 3) {
  18376. return null
  18377. }
  18378. if (node.nodeName == 'A') {
  18379. return node
  18380. }
  18381. var lastChild = node.lastChild
  18382. while (lastChild) {
  18383. if (lastChild.nodeName == 'A') {
  18384. return lastChild
  18385. }
  18386. if (lastChild.nodeType == 3) {
  18387. if (domUtils.isWhitespace(lastChild)) {
  18388. lastChild = lastChild.previousSibling
  18389. continue
  18390. }
  18391. return null
  18392. }
  18393. lastChild = lastChild.lastChild
  18394. }
  18395. }
  18396. browser.ie &&
  18397. this.addListener('keyup', function (cmd, evt) {
  18398. var me = this,
  18399. keyCode = evt.keyCode
  18400. if (keyCodes[keyCode]) {
  18401. var rng = me.selection.getRange()
  18402. var start = rng.startContainer
  18403. if (keyCode == 13) {
  18404. while (
  18405. start &&
  18406. !domUtils.isBody(start) &&
  18407. !domUtils.isBlockElm(start)
  18408. ) {
  18409. start = start.parentNode
  18410. }
  18411. if (start && !domUtils.isBody(start) && start.nodeName == 'P') {
  18412. var pre = start.previousSibling
  18413. if (pre && pre.nodeType == 1) {
  18414. var pre = checkIsCludeLink(pre)
  18415. if (pre && !pre.getAttribute('_href')) {
  18416. domUtils.remove(pre, true)
  18417. }
  18418. }
  18419. }
  18420. } else if (keyCode == 32) {
  18421. if (start.nodeType == 3 && /^\s$/.test(start.nodeValue)) {
  18422. start = start.previousSibling
  18423. if (
  18424. start &&
  18425. start.nodeName == 'A' &&
  18426. !start.getAttribute('_href')
  18427. ) {
  18428. domUtils.remove(start, true)
  18429. }
  18430. }
  18431. } else {
  18432. start = domUtils.findParentByTagName(start, 'a', true)
  18433. if (start && !start.getAttribute('_href')) {
  18434. var bk = rng.createBookmark()
  18435. domUtils.remove(start, true)
  18436. rng.moveToBookmark(bk).select(true)
  18437. }
  18438. }
  18439. }
  18440. })
  18441. }
  18442. )
  18443. // plugins/autoheight.js
  18444. ///import core
  18445. ///commands 当输入内容超过编辑器高度时,编辑器自动增高
  18446. ///commandsName AutoHeight,autoHeightEnabled
  18447. ///commandsTitle 自动增高
  18448. /**
  18449. * @description 自动伸展
  18450. * @author zhanyi
  18451. */
  18452. UE.plugins['autoheight'] = function () {
  18453. var me = this
  18454. //提供开关,就算加载也可以关闭
  18455. me.autoHeightEnabled = me.options.autoHeightEnabled !== false
  18456. if (!me.autoHeightEnabled) {
  18457. return
  18458. }
  18459. var bakOverflow,
  18460. lastHeight = 0,
  18461. options = me.options,
  18462. currentHeight,
  18463. timer
  18464. function adjustHeight() {
  18465. var me = this
  18466. clearTimeout(timer)
  18467. if (isFullscreen) return
  18468. if (
  18469. !me.queryCommandState ||
  18470. (me.queryCommandState && me.queryCommandState('source') != 1)
  18471. ) {
  18472. timer = setTimeout(function () {
  18473. var node = me.body.lastChild
  18474. while (node && node.nodeType != 1) {
  18475. node = node.previousSibling
  18476. }
  18477. if (node && node.nodeType == 1) {
  18478. node.style.clear = 'both'
  18479. currentHeight = Math.max(
  18480. domUtils.getXY(node).y + node.offsetHeight + 25,
  18481. Math.max(options.minFrameHeight, options.initialFrameHeight)
  18482. )
  18483. if (currentHeight != lastHeight) {
  18484. if (
  18485. currentHeight !== parseInt(me.iframe.parentNode.style.height)
  18486. ) {
  18487. me.iframe.parentNode.style.height = currentHeight + 'px'
  18488. }
  18489. me.body.style.height = currentHeight + 'px'
  18490. lastHeight = currentHeight
  18491. }
  18492. domUtils.removeStyle(node, 'clear')
  18493. }
  18494. }, 50)
  18495. }
  18496. }
  18497. var isFullscreen
  18498. me.addListener('fullscreenchanged', function (cmd, f) {
  18499. isFullscreen = f
  18500. })
  18501. me.addListener('destroy', function () {
  18502. me.removeListener(
  18503. 'contentchange afterinserthtml keyup mouseup',
  18504. adjustHeight
  18505. )
  18506. })
  18507. me.enableAutoHeight = function () {
  18508. var me = this
  18509. if (!me.autoHeightEnabled) {
  18510. return
  18511. }
  18512. var doc = me.document
  18513. me.autoHeightEnabled = true
  18514. bakOverflow = doc.body.style.overflowY
  18515. doc.body.style.overflowY = 'hidden'
  18516. me.addListener(
  18517. 'contentchange afterinserthtml keyup mouseup',
  18518. adjustHeight
  18519. )
  18520. //ff不给事件算得不对
  18521. setTimeout(
  18522. function () {
  18523. adjustHeight.call(me)
  18524. },
  18525. browser.gecko ? 100 : 0
  18526. )
  18527. me.fireEvent('autoheightchanged', me.autoHeightEnabled)
  18528. }
  18529. me.disableAutoHeight = function () {
  18530. me.body.style.overflowY = bakOverflow || ''
  18531. me.removeListener('contentchange', adjustHeight)
  18532. me.removeListener('keyup', adjustHeight)
  18533. me.removeListener('mouseup', adjustHeight)
  18534. me.autoHeightEnabled = false
  18535. me.fireEvent('autoheightchanged', me.autoHeightEnabled)
  18536. }
  18537. me.on('setHeight', function () {
  18538. me.disableAutoHeight()
  18539. })
  18540. me.addListener('ready', function () {
  18541. me.enableAutoHeight()
  18542. //trace:1764
  18543. var timer
  18544. domUtils.on(
  18545. browser.ie ? me.body : me.document,
  18546. browser.webkit ? 'dragover' : 'drop',
  18547. function () {
  18548. clearTimeout(timer)
  18549. timer = setTimeout(function () {
  18550. //trace:3681
  18551. adjustHeight.call(me)
  18552. }, 100)
  18553. }
  18554. )
  18555. //修复内容过多时,回到顶部,顶部内容被工具栏遮挡问题
  18556. var lastScrollY
  18557. window.onscroll = function () {
  18558. if (lastScrollY === null) {
  18559. lastScrollY = this.scrollY
  18560. } else if (this.scrollY == 0 && lastScrollY != 0) {
  18561. me.window.scrollTo(0, 0)
  18562. lastScrollY = null
  18563. }
  18564. }
  18565. })
  18566. }
  18567. // plugins/autofloat.js
  18568. ///import core
  18569. ///commands 悬浮工具栏
  18570. ///commandsName AutoFloat,autoFloatEnabled
  18571. ///commandsTitle 悬浮工具栏
  18572. /**
  18573. * modified by chengchao01
  18574. * 注意: 引入此功能后,在IE6下会将body的背景图片覆盖掉!
  18575. */
  18576. UE.plugins['autofloat'] = function () {
  18577. var me = this,
  18578. lang = me.getLang()
  18579. me.setOpt({
  18580. topOffset: 0,
  18581. })
  18582. var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false,
  18583. topOffset = me.options.topOffset
  18584. //如果不固定toolbar的位置,则直接退出
  18585. if (!optsAutoFloatEnabled) {
  18586. return
  18587. }
  18588. var uiUtils = UE.ui.uiUtils,
  18589. LteIE6 = browser.ie && browser.version <= 6,
  18590. quirks = browser.quirks
  18591. function checkHasUI() {
  18592. if (!UE.ui) {
  18593. alert(lang.autofloatMsg)
  18594. return 0
  18595. }
  18596. return 1
  18597. }
  18598. function fixIE6FixedPos() {
  18599. var docStyle = document.body.style
  18600. docStyle.backgroundImage = 'url("about:blank")'
  18601. docStyle.backgroundAttachment = 'fixed'
  18602. }
  18603. var bakCssText,
  18604. placeHolder = document.createElement('div'),
  18605. toolbarBox,
  18606. orgTop,
  18607. getPosition,
  18608. flag = true //ie7模式下需要偏移
  18609. function setFloating() {
  18610. var toobarBoxPos = domUtils.getXY(toolbarBox),
  18611. origalFloat = domUtils.getComputedStyle(toolbarBox, 'position'),
  18612. origalLeft = domUtils.getComputedStyle(toolbarBox, 'left')
  18613. toolbarBox.style.width = toolbarBox.offsetWidth + 'px'
  18614. toolbarBox.style.zIndex = me.options.zIndex * 1 + 1
  18615. toolbarBox.parentNode.insertBefore(placeHolder, toolbarBox)
  18616. if (LteIE6 || (quirks && browser.ie)) {
  18617. if (toolbarBox.style.position != 'absolute') {
  18618. toolbarBox.style.position = 'absolute'
  18619. }
  18620. toolbarBox.style.top =
  18621. (document.body.scrollTop || document.documentElement.scrollTop) -
  18622. orgTop +
  18623. topOffset +
  18624. 'px'
  18625. } else {
  18626. if (browser.ie7Compat && flag) {
  18627. flag = false
  18628. toolbarBox.style.left =
  18629. domUtils.getXY(toolbarBox).x -
  18630. document.documentElement.getBoundingClientRect().left +
  18631. 2 +
  18632. 'px'
  18633. }
  18634. if (toolbarBox.style.position != 'fixed') {
  18635. toolbarBox.style.position = 'fixed'
  18636. toolbarBox.style.top = topOffset + 'px'
  18637. ;(origalFloat == 'absolute' || origalFloat == 'relative') &&
  18638. parseFloat(origalLeft) &&
  18639. (toolbarBox.style.left = toobarBoxPos.x + 'px')
  18640. }
  18641. }
  18642. }
  18643. function unsetFloating() {
  18644. flag = true
  18645. if (placeHolder.parentNode) {
  18646. placeHolder.parentNode.removeChild(placeHolder)
  18647. }
  18648. toolbarBox.style.cssText = bakCssText
  18649. }
  18650. function updateFloating() {
  18651. var rect3 = getPosition(me.container)
  18652. var offset = me.options.toolbarTopOffset || 0
  18653. if (rect3.top < 0 && rect3.bottom - toolbarBox.offsetHeight > offset) {
  18654. setFloating()
  18655. } else {
  18656. unsetFloating()
  18657. }
  18658. }
  18659. var defer_updateFloating = utils.defer(
  18660. function () {
  18661. updateFloating()
  18662. },
  18663. browser.ie ? 200 : 100,
  18664. true
  18665. )
  18666. me.addListener('destroy', function () {
  18667. domUtils.un(window, ['scroll', 'resize'], updateFloating)
  18668. me.removeListener('keydown', defer_updateFloating)
  18669. })
  18670. me.addListener('ready', function () {
  18671. if (checkHasUI(me)) {
  18672. //加载了ui组件,但在new时,没有加载ui,导致编辑器实例上没有ui类,所以这里做判断
  18673. if (!me.ui) {
  18674. return
  18675. }
  18676. getPosition = uiUtils.getClientRect
  18677. toolbarBox = me.ui.getDom('toolbarbox')
  18678. orgTop = getPosition(toolbarBox).top
  18679. bakCssText = toolbarBox.style.cssText
  18680. placeHolder.style.height = toolbarBox.offsetHeight + 'px'
  18681. if (LteIE6) {
  18682. fixIE6FixedPos()
  18683. }
  18684. domUtils.on(window, ['scroll', 'resize'], updateFloating)
  18685. me.addListener('keydown', defer_updateFloating)
  18686. me.addListener('beforefullscreenchange', function (t, enabled) {
  18687. if (enabled) {
  18688. unsetFloating()
  18689. }
  18690. })
  18691. me.addListener('fullscreenchanged', function (t, enabled) {
  18692. if (!enabled) {
  18693. updateFloating()
  18694. }
  18695. })
  18696. me.addListener('sourcemodechanged', function (t, enabled) {
  18697. setTimeout(function () {
  18698. updateFloating()
  18699. }, 0)
  18700. })
  18701. me.addListener('clearDoc', function () {
  18702. setTimeout(function () {
  18703. updateFloating()
  18704. }, 0)
  18705. })
  18706. }
  18707. })
  18708. }
  18709. // plugins/video.js
  18710. /**
  18711. * video插件, 为UEditor提供视频插入支持
  18712. * @file
  18713. * @since 1.2.6.1
  18714. */
  18715. UE.plugins['video'] = function () {
  18716. var me = this
  18717. /**
  18718. * 创建插入视频字符窜
  18719. * @param url 视频地址
  18720. * @param width 视频宽度
  18721. * @param height 视频高度
  18722. * @param align 视频对齐
  18723. * @param toEmbed 是否以flash代替显示
  18724. * @param addParagraph 是否需要添加P 标签
  18725. */
  18726. function creatInsertStr(url, width, height, id, align, classname, type) {
  18727. url = utils.unhtmlForUrl(url)
  18728. align = utils.unhtml(align)
  18729. classname = utils.unhtml(classname).trim()
  18730. width = parseInt(width, 10) || 0
  18731. height = parseInt(height, 10) || 0
  18732. var str
  18733. switch (type) {
  18734. case 'image':
  18735. str =
  18736. '<img ' +
  18737. (id ? 'id="' + id + '"' : '') +
  18738. ' width="' +
  18739. width +
  18740. '" height="' +
  18741. height +
  18742. '" _url="' +
  18743. url +
  18744. '" class="' +
  18745. classname.replace(/\bvideo-js\b/, '') +
  18746. '"' +
  18747. ' src="' +
  18748. me.options.UEDITOR_HOME_URL +
  18749. 'themes/default/images/spacer.gif" style="background:url(' +
  18750. me.options.UEDITOR_HOME_URL +
  18751. 'themes/default/images/videologo.gif) no-repeat center center; border:1px solid gray;' +
  18752. (align ? 'float:' + align + ';' : '') +
  18753. '" />'
  18754. break
  18755. case 'embed':
  18756. str =
  18757. '<embed type="application/x-shockwave-flash" class="' +
  18758. classname +
  18759. '" pluginspage="http://www.macromedia.com/go/getflashplayer"' +
  18760. ' src="' +
  18761. utils.html(url) +
  18762. '" width="' +
  18763. width +
  18764. '" height="' +
  18765. height +
  18766. '"' +
  18767. (align ? ' style="float:' + align + '"' : '') +
  18768. ' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >'
  18769. break
  18770. case 'video':
  18771. var ext = url.substr(url.lastIndexOf('.') + 1)
  18772. if (ext == 'ogv') ext = 'ogg'
  18773. str =
  18774. '<video' +
  18775. (id ? ' id="' + id + '"' : '') +
  18776. ' class="' +
  18777. classname +
  18778. ' video-js" ' +
  18779. (align ? ' style="float:' + align + '"' : '') +
  18780. ' controls preload="none" width="' +
  18781. width +
  18782. '" height="' +
  18783. height +
  18784. '" src="' +
  18785. url +
  18786. '" data-setup="{}">' +
  18787. '<source src="' +
  18788. url +
  18789. '" type="video/' +
  18790. ext +
  18791. '" /></video>'
  18792. break
  18793. }
  18794. return str
  18795. }
  18796. function switchImgAndVideo(root, img2video) {
  18797. utils.each(
  18798. root.getNodesByTagName(img2video ? 'img' : 'embed video'),
  18799. function (node) {
  18800. var className = node.getAttr('class')
  18801. if (className && className.indexOf('edui-faked-video') != -1) {
  18802. var html = creatInsertStr(
  18803. img2video ? node.getAttr('_url') : node.getAttr('src'),
  18804. node.getAttr('width'),
  18805. node.getAttr('height'),
  18806. null,
  18807. node.getStyle('float') || '',
  18808. className,
  18809. img2video ? 'embed' : 'image'
  18810. )
  18811. node.parentNode.replaceChild(UE.uNode.createElement(html), node)
  18812. }
  18813. if (className && className.indexOf('edui-upload-video') != -1) {
  18814. var html = creatInsertStr(
  18815. img2video ? node.getAttr('_url') : node.getAttr('src'),
  18816. node.getAttr('width'),
  18817. node.getAttr('height'),
  18818. null,
  18819. node.getStyle('float') || '',
  18820. className,
  18821. img2video ? 'video' : 'image'
  18822. )
  18823. node.parentNode.replaceChild(UE.uNode.createElement(html), node)
  18824. }
  18825. }
  18826. )
  18827. }
  18828. me.addOutputRule(function (root) {
  18829. switchImgAndVideo(root, true)
  18830. })
  18831. me.addInputRule(function (root) {
  18832. switchImgAndVideo(root)
  18833. })
  18834. /**
  18835. * 插入视频
  18836. * @command insertvideo
  18837. * @method execCommand
  18838. * @param { String } cmd 命令字符串
  18839. * @param { Object } videoAttr 键值对对象, 描述一个视频的所有属性
  18840. * @example
  18841. * ```javascript
  18842. *
  18843. * var videoAttr = {
  18844. * //视频地址
  18845. * url: 'http://www.youku.com/xxx',
  18846. * //视频宽高值, 单位px
  18847. * width: 200,
  18848. * height: 100
  18849. * };
  18850. *
  18851. * //editor 是编辑器实例
  18852. * //向编辑器插入单个视频
  18853. * editor.execCommand( 'insertvideo', videoAttr );
  18854. * ```
  18855. */
  18856. /**
  18857. * 插入视频
  18858. * @command insertvideo
  18859. * @method execCommand
  18860. * @param { String } cmd 命令字符串
  18861. * @param { Array } videoArr 需要插入的视频的数组, 其中的每一个元素都是一个键值对对象, 描述了一个视频的所有属性
  18862. * @example
  18863. * ```javascript
  18864. *
  18865. * var videoAttr1 = {
  18866. * //视频地址
  18867. * url: 'http://www.youku.com/xxx',
  18868. * //视频宽高值, 单位px
  18869. * width: 200,
  18870. * height: 100
  18871. * },
  18872. * videoAttr2 = {
  18873. * //视频地址
  18874. * url: 'http://www.youku.com/xxx',
  18875. * //视频宽高值, 单位px
  18876. * width: 200,
  18877. * height: 100
  18878. * }
  18879. *
  18880. * //editor 是编辑器实例
  18881. * //该方法将会向编辑器内插入两个视频
  18882. * editor.execCommand( 'insertvideo', [ videoAttr1, videoAttr2 ] );
  18883. * ```
  18884. */
  18885. /**
  18886. * 查询当前光标所在处是否是一个视频
  18887. * @command insertvideo
  18888. * @method queryCommandState
  18889. * @param { String } cmd 需要查询的命令字符串
  18890. * @return { int } 如果当前光标所在处的元素是一个视频对象, 则返回1,否则返回0
  18891. * @example
  18892. * ```javascript
  18893. *
  18894. * //editor 是编辑器实例
  18895. * editor.queryCommandState( 'insertvideo' );
  18896. * ```
  18897. */
  18898. me.commands['insertvideo'] = {
  18899. execCommand: function (cmd, videoObjs, type) {
  18900. videoObjs = utils.isArray(videoObjs) ? videoObjs : [videoObjs]
  18901. var html = [],
  18902. id = 'tmpVedio',
  18903. cl
  18904. for (var i = 0, vi, len = videoObjs.length; i < len; i++) {
  18905. vi = videoObjs[i]
  18906. cl =
  18907. type == 'upload'
  18908. ? 'edui-upload-video video-js vjs-default-skin'
  18909. : 'edui-faked-video'
  18910. html.push(
  18911. creatInsertStr(
  18912. vi.url,
  18913. vi.width || 420,
  18914. vi.height || 280,
  18915. id + i,
  18916. null,
  18917. cl,
  18918. 'image'
  18919. )
  18920. )
  18921. }
  18922. me.execCommand('inserthtml', html.join(''), true)
  18923. var rng = this.selection.getRange()
  18924. for (var i = 0, len = videoObjs.length; i < len; i++) {
  18925. var img = this.document.getElementById('tmpVedio' + i)
  18926. domUtils.removeAttributes(img, 'id')
  18927. rng.selectNode(img).select()
  18928. me.execCommand('imagefloat', videoObjs[i].align)
  18929. }
  18930. },
  18931. queryCommandState: function () {
  18932. var img = me.selection.getRange().getClosedNode(),
  18933. flag =
  18934. img &&
  18935. (img.className == 'edui-faked-video' ||
  18936. img.className.indexOf('edui-upload-video') != -1)
  18937. return flag ? 1 : 0
  18938. },
  18939. }
  18940. }
  18941. // plugins/table.core.js
  18942. /**
  18943. * Created with JetBrains WebStorm.
  18944. * User: taoqili
  18945. * Date: 13-1-18
  18946. * Time: 上午11:09
  18947. * To change this template use File | Settings | File Templates.
  18948. */
  18949. /**
  18950. * UE表格操作类
  18951. * @param table
  18952. * @constructor
  18953. */
  18954. ;(function () {
  18955. var UETable = (UE.UETable = function (table) {
  18956. this.table = table
  18957. this.indexTable = []
  18958. this.selectedTds = []
  18959. this.cellsRange = {}
  18960. this.update(table)
  18961. })
  18962. //===以下为静态工具方法===
  18963. UETable.removeSelectedClass = function (cells) {
  18964. utils.each(cells, function (cell) {
  18965. domUtils.removeClasses(cell, 'selectTdClass')
  18966. })
  18967. }
  18968. UETable.addSelectedClass = function (cells) {
  18969. utils.each(cells, function (cell) {
  18970. domUtils.addClass(cell, 'selectTdClass')
  18971. })
  18972. }
  18973. UETable.isEmptyBlock = function (node) {
  18974. var reg = new RegExp(domUtils.fillChar, 'g')
  18975. if (
  18976. node[browser.ie ? 'innerText' : 'textContent']
  18977. .replace(/^\s*$/, '')
  18978. .replace(reg, '').length > 0
  18979. ) {
  18980. return 0
  18981. }
  18982. for (var i in dtd.$isNotEmpty)
  18983. if (dtd.$isNotEmpty.hasOwnProperty(i)) {
  18984. if (node.getElementsByTagName(i).length) {
  18985. return 0
  18986. }
  18987. }
  18988. return 1
  18989. }
  18990. UETable.getWidth = function (cell) {
  18991. if (!cell) return 0
  18992. return parseInt(domUtils.getComputedStyle(cell, 'width'), 10)
  18993. }
  18994. /**
  18995. * 获取单元格或者单元格组的“对齐”状态。 如果当前的检测对象是一个单元格组, 只有在满足所有单元格的 水平和竖直 对齐属性都相同的
  18996. * 条件时才会返回其状态值,否则将返回null; 如果当前只检测了一个单元格, 则直接返回当前单元格的对齐状态;
  18997. * @param table cell or table cells , 支持单个单元格dom对象 或者 单元格dom对象数组
  18998. * @return { align: 'left' || 'right' || 'center', valign: 'top' || 'middle' || 'bottom' } 或者 null
  18999. */
  19000. UETable.getTableCellAlignState = function (cells) {
  19001. !utils.isArray(cells) && (cells = [cells])
  19002. var result = {},
  19003. status = ['align', 'valign'],
  19004. tempStatus = null,
  19005. isSame = true //状态是否相同
  19006. utils.each(cells, function (cellNode) {
  19007. utils.each(status, function (currentState) {
  19008. tempStatus = cellNode.getAttribute(currentState)
  19009. if (!result[currentState] && tempStatus) {
  19010. result[currentState] = tempStatus
  19011. } else if (
  19012. !result[currentState] ||
  19013. tempStatus !== result[currentState]
  19014. ) {
  19015. isSame = false
  19016. return false
  19017. }
  19018. })
  19019. return isSame
  19020. })
  19021. return isSame ? result : null
  19022. }
  19023. /**
  19024. * 根据当前选区获取相关的table信息
  19025. * @return {Object}
  19026. */
  19027. UETable.getTableItemsByRange = function (editor) {
  19028. var start = editor.selection.getStart()
  19029. //ff下会选中bookmark
  19030. if (
  19031. start &&
  19032. start.id &&
  19033. start.id.indexOf('_baidu_bookmark_start_') === 0 &&
  19034. start.nextSibling
  19035. ) {
  19036. start = start.nextSibling
  19037. }
  19038. //在table或者td边缘有可能存在选中tr的情况
  19039. var cell =
  19040. start && domUtils.findParentByTagName(start, ['td', 'th'], true),
  19041. tr = cell && cell.parentNode,
  19042. caption = start && domUtils.findParentByTagName(start, 'caption', true),
  19043. table = caption ? caption.parentNode : tr && tr.parentNode.parentNode
  19044. return {
  19045. cell: cell,
  19046. tr: tr,
  19047. table: table,
  19048. caption: caption,
  19049. }
  19050. }
  19051. UETable.getUETableBySelected = function (editor) {
  19052. var table = UETable.getTableItemsByRange(editor).table
  19053. if (table && table.ueTable && table.ueTable.selectedTds.length) {
  19054. return table.ueTable
  19055. }
  19056. return null
  19057. }
  19058. UETable.getDefaultValue = function (editor, table) {
  19059. var borderMap = {
  19060. thin: '0px',
  19061. medium: '1px',
  19062. thick: '2px',
  19063. },
  19064. tableBorder,
  19065. tdPadding,
  19066. tdBorder,
  19067. tmpValue
  19068. if (!table) {
  19069. table = editor.document.createElement('table')
  19070. table.insertRow(0).insertCell(0).innerHTML = 'xxx'
  19071. editor.body.appendChild(table)
  19072. var td = table.getElementsByTagName('td')[0]
  19073. tmpValue = domUtils.getComputedStyle(table, 'border-left-width')
  19074. tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10)
  19075. tmpValue = domUtils.getComputedStyle(td, 'padding-left')
  19076. tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10)
  19077. tmpValue = domUtils.getComputedStyle(td, 'border-left-width')
  19078. tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10)
  19079. domUtils.remove(table)
  19080. return {
  19081. tableBorder: tableBorder,
  19082. tdPadding: tdPadding,
  19083. tdBorder: tdBorder,
  19084. }
  19085. } else {
  19086. td = table.getElementsByTagName('td')[0]
  19087. tmpValue = domUtils.getComputedStyle(table, 'border-left-width')
  19088. tableBorder = parseInt(borderMap[tmpValue] || tmpValue, 10)
  19089. tmpValue = domUtils.getComputedStyle(td, 'padding-left')
  19090. tdPadding = parseInt(borderMap[tmpValue] || tmpValue, 10)
  19091. tmpValue = domUtils.getComputedStyle(td, 'border-left-width')
  19092. tdBorder = parseInt(borderMap[tmpValue] || tmpValue, 10)
  19093. return {
  19094. tableBorder: tableBorder,
  19095. tdPadding: tdPadding,
  19096. tdBorder: tdBorder,
  19097. }
  19098. }
  19099. }
  19100. /**
  19101. * 根据当前点击的td或者table获取索引对象
  19102. * @param tdOrTable
  19103. */
  19104. UETable.getUETable = function (tdOrTable) {
  19105. var tag = tdOrTable.tagName.toLowerCase()
  19106. tdOrTable =
  19107. tag == 'td' || tag == 'th' || tag == 'caption'
  19108. ? domUtils.findParentByTagName(tdOrTable, 'table', true)
  19109. : tdOrTable
  19110. if (!tdOrTable.ueTable) {
  19111. tdOrTable.ueTable = new UETable(tdOrTable)
  19112. }
  19113. return tdOrTable.ueTable
  19114. }
  19115. UETable.cloneCell = function (cell, ignoreMerge, keepPro) {
  19116. if (!cell || utils.isString(cell)) {
  19117. return this.table.ownerDocument.createElement(cell || 'td')
  19118. }
  19119. var flag = domUtils.hasClass(cell, 'selectTdClass')
  19120. flag && domUtils.removeClasses(cell, 'selectTdClass')
  19121. var tmpCell = cell.cloneNode(true)
  19122. if (ignoreMerge) {
  19123. tmpCell.rowSpan = tmpCell.colSpan = 1
  19124. }
  19125. //去掉宽高
  19126. !keepPro && domUtils.removeAttributes(tmpCell, 'width height')
  19127. !keepPro && domUtils.removeAttributes(tmpCell, 'style')
  19128. tmpCell.style.borderLeftStyle = ''
  19129. tmpCell.style.borderTopStyle = ''
  19130. tmpCell.style.borderLeftColor = cell.style.borderRightColor
  19131. tmpCell.style.borderLeftWidth = cell.style.borderRightWidth
  19132. tmpCell.style.borderTopColor = cell.style.borderBottomColor
  19133. tmpCell.style.borderTopWidth = cell.style.borderBottomWidth
  19134. flag && domUtils.addClass(cell, 'selectTdClass')
  19135. return tmpCell
  19136. }
  19137. UETable.prototype = {
  19138. getMaxRows: function () {
  19139. var rows = this.table.rows,
  19140. maxLen = 1
  19141. for (var i = 0, row; (row = rows[i]); i++) {
  19142. var currentMax = 1
  19143. for (var j = 0, cj; (cj = row.cells[j++]); ) {
  19144. currentMax = Math.max(cj.rowSpan || 1, currentMax)
  19145. }
  19146. maxLen = Math.max(currentMax + i, maxLen)
  19147. }
  19148. return maxLen
  19149. },
  19150. /**
  19151. * 获取当前表格的最大列数
  19152. */
  19153. getMaxCols: function () {
  19154. var rows = this.table.rows,
  19155. maxLen = 0,
  19156. cellRows = {}
  19157. for (var i = 0, row; (row = rows[i]); i++) {
  19158. var cellsNum = 0
  19159. for (var j = 0, cj; (cj = row.cells[j++]); ) {
  19160. cellsNum += cj.colSpan || 1
  19161. if (cj.rowSpan && cj.rowSpan > 1) {
  19162. for (var k = 1; k < cj.rowSpan; k++) {
  19163. if (!cellRows['row_' + (i + k)]) {
  19164. cellRows['row_' + (i + k)] = cj.colSpan || 1
  19165. } else {
  19166. cellRows['row_' + (i + k)]++
  19167. }
  19168. }
  19169. }
  19170. }
  19171. cellsNum += cellRows['row_' + i] || 0
  19172. maxLen = Math.max(cellsNum, maxLen)
  19173. }
  19174. return maxLen
  19175. },
  19176. getCellColIndex: function (cell) {},
  19177. /**
  19178. * 获取当前cell旁边的单元格,
  19179. * @param cell
  19180. * @param right
  19181. */
  19182. getHSideCell: function (cell, right) {
  19183. try {
  19184. var cellInfo = this.getCellInfo(cell),
  19185. previewRowIndex,
  19186. previewColIndex
  19187. var len = this.selectedTds.length,
  19188. range = this.cellsRange
  19189. //首行或者首列没有前置单元格
  19190. if (
  19191. (!right && (!len ? !cellInfo.colIndex : !range.beginColIndex)) ||
  19192. (right &&
  19193. (!len
  19194. ? cellInfo.colIndex == this.colsNum - 1
  19195. : range.endColIndex == this.colsNum - 1))
  19196. )
  19197. return null
  19198. previewRowIndex = !len ? cellInfo.rowIndex : range.beginRowIndex
  19199. previewColIndex = !right
  19200. ? !len
  19201. ? cellInfo.colIndex < 1
  19202. ? 0
  19203. : cellInfo.colIndex - 1
  19204. : range.beginColIndex - 1
  19205. : !len
  19206. ? cellInfo.colIndex + 1
  19207. : range.endColIndex + 1
  19208. return this.getCell(
  19209. this.indexTable[previewRowIndex][previewColIndex].rowIndex,
  19210. this.indexTable[previewRowIndex][previewColIndex].cellIndex
  19211. )
  19212. } catch (e) {
  19213. showError(e)
  19214. }
  19215. },
  19216. getTabNextCell: function (cell, preRowIndex) {
  19217. var cellInfo = this.getCellInfo(cell),
  19218. rowIndex = preRowIndex || cellInfo.rowIndex,
  19219. colIndex = cellInfo.colIndex + 1 + (cellInfo.colSpan - 1),
  19220. nextCell
  19221. try {
  19222. nextCell = this.getCell(
  19223. this.indexTable[rowIndex][colIndex].rowIndex,
  19224. this.indexTable[rowIndex][colIndex].cellIndex
  19225. )
  19226. } catch (e) {
  19227. try {
  19228. rowIndex = rowIndex * 1 + 1
  19229. colIndex = 0
  19230. nextCell = this.getCell(
  19231. this.indexTable[rowIndex][colIndex].rowIndex,
  19232. this.indexTable[rowIndex][colIndex].cellIndex
  19233. )
  19234. } catch (e) {}
  19235. }
  19236. return nextCell
  19237. },
  19238. /**
  19239. * 获取视觉上的后置单元格
  19240. * @param cell
  19241. * @param bottom
  19242. */
  19243. getVSideCell: function (cell, bottom, ignoreRange) {
  19244. try {
  19245. var cellInfo = this.getCellInfo(cell),
  19246. nextRowIndex,
  19247. nextColIndex
  19248. var len = this.selectedTds.length && !ignoreRange,
  19249. range = this.cellsRange
  19250. //末行或者末列没有后置单元格
  19251. if (
  19252. (!bottom && cellInfo.rowIndex == 0) ||
  19253. (bottom &&
  19254. (!len
  19255. ? cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1
  19256. : range.endRowIndex == this.rowsNum - 1))
  19257. )
  19258. return null
  19259. nextRowIndex = !bottom
  19260. ? !len
  19261. ? cellInfo.rowIndex - 1
  19262. : range.beginRowIndex - 1
  19263. : !len
  19264. ? cellInfo.rowIndex + cellInfo.rowSpan
  19265. : range.endRowIndex + 1
  19266. nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex
  19267. return this.getCell(
  19268. this.indexTable[nextRowIndex][nextColIndex].rowIndex,
  19269. this.indexTable[nextRowIndex][nextColIndex].cellIndex
  19270. )
  19271. } catch (e) {
  19272. showError(e)
  19273. }
  19274. },
  19275. /**
  19276. * 获取相同结束位置的单元格,xOrY指代了是获取x轴相同还是y轴相同
  19277. */
  19278. getSameEndPosCells: function (cell, xOrY) {
  19279. try {
  19280. var flag = xOrY.toLowerCase() === 'x',
  19281. end =
  19282. domUtils.getXY(cell)[flag ? 'x' : 'y'] +
  19283. cell['offset' + (flag ? 'Width' : 'Height')],
  19284. rows = this.table.rows,
  19285. cells = null,
  19286. returns = []
  19287. for (var i = 0; i < this.rowsNum; i++) {
  19288. cells = rows[i].cells
  19289. for (var j = 0, tmpCell; (tmpCell = cells[j++]); ) {
  19290. var tmpEnd =
  19291. domUtils.getXY(tmpCell)[flag ? 'x' : 'y'] +
  19292. tmpCell['offset' + (flag ? 'Width' : 'Height')]
  19293. //对应行的td已经被上面行rowSpan了
  19294. if (tmpEnd > end && flag) break
  19295. if (cell == tmpCell || end == tmpEnd) {
  19296. //只获取单一的单元格
  19297. //todo 仅获取单一单元格在特定情况下会造成returns为空,从而影响后续的拖拽实现,修正这个。需考虑性能
  19298. if (tmpCell[flag ? 'colSpan' : 'rowSpan'] == 1) {
  19299. returns.push(tmpCell)
  19300. }
  19301. if (flag) break
  19302. }
  19303. }
  19304. }
  19305. return returns
  19306. } catch (e) {
  19307. showError(e)
  19308. }
  19309. },
  19310. setCellContent: function (cell, content) {
  19311. cell.innerHTML = content || (browser.ie ? domUtils.fillChar : '<br />')
  19312. },
  19313. cloneCell: UETable.cloneCell,
  19314. /**
  19315. * 获取跟当前单元格的右边竖线为左边的所有未合并单元格
  19316. */
  19317. getSameStartPosXCells: function (cell) {
  19318. try {
  19319. var start = domUtils.getXY(cell).x + cell.offsetWidth,
  19320. rows = this.table.rows,
  19321. cells,
  19322. returns = []
  19323. for (var i = 0; i < this.rowsNum; i++) {
  19324. cells = rows[i].cells
  19325. for (var j = 0, tmpCell; (tmpCell = cells[j++]); ) {
  19326. var tmpStart = domUtils.getXY(tmpCell).x
  19327. if (tmpStart > start) break
  19328. if (tmpStart == start && tmpCell.colSpan == 1) {
  19329. returns.push(tmpCell)
  19330. break
  19331. }
  19332. }
  19333. }
  19334. return returns
  19335. } catch (e) {
  19336. showError(e)
  19337. }
  19338. },
  19339. /**
  19340. * 更新table对应的索引表
  19341. */
  19342. update: function (table) {
  19343. this.table = table || this.table
  19344. this.selectedTds = []
  19345. this.cellsRange = {}
  19346. this.indexTable = []
  19347. var rows = this.table.rows,
  19348. rowsNum = this.getMaxRows(),
  19349. dNum = rowsNum - rows.length,
  19350. colsNum = this.getMaxCols()
  19351. while (dNum--) {
  19352. this.table.insertRow(rows.length)
  19353. }
  19354. this.rowsNum = rowsNum
  19355. this.colsNum = colsNum
  19356. for (var i = 0, len = rows.length; i < len; i++) {
  19357. this.indexTable[i] = new Array(colsNum)
  19358. }
  19359. //填充索引表
  19360. for (var rowIndex = 0, row; (row = rows[rowIndex]); rowIndex++) {
  19361. for (
  19362. var cellIndex = 0, cell, cells = row.cells;
  19363. (cell = cells[cellIndex]);
  19364. cellIndex++
  19365. ) {
  19366. //修正整行被rowSpan时导致的行数计算错误
  19367. if (cell.rowSpan > rowsNum) {
  19368. cell.rowSpan = rowsNum
  19369. }
  19370. var colIndex = cellIndex,
  19371. rowSpan = cell.rowSpan || 1,
  19372. colSpan = cell.colSpan || 1
  19373. //当已经被上一行rowSpan或者被前一列colSpan了,则跳到下一个单元格进行
  19374. while (this.indexTable[rowIndex][colIndex]) colIndex++
  19375. for (var j = 0; j < rowSpan; j++) {
  19376. for (var k = 0; k < colSpan; k++) {
  19377. this.indexTable[rowIndex + j][colIndex + k] = {
  19378. rowIndex: rowIndex,
  19379. cellIndex: cellIndex,
  19380. colIndex: colIndex,
  19381. rowSpan: rowSpan,
  19382. colSpan: colSpan,
  19383. }
  19384. }
  19385. }
  19386. }
  19387. }
  19388. //修复残缺td
  19389. for (j = 0; j < rowsNum; j++) {
  19390. for (k = 0; k < colsNum; k++) {
  19391. if (this.indexTable[j][k] === undefined) {
  19392. row = rows[j]
  19393. cell = row.cells[row.cells.length - 1]
  19394. cell = cell
  19395. ? cell.cloneNode(true)
  19396. : this.table.ownerDocument.createElement('td')
  19397. this.setCellContent(cell)
  19398. if (cell.colSpan !== 1) cell.colSpan = 1
  19399. if (cell.rowSpan !== 1) cell.rowSpan = 1
  19400. row.appendChild(cell)
  19401. this.indexTable[j][k] = {
  19402. rowIndex: j,
  19403. cellIndex: cell.cellIndex,
  19404. colIndex: k,
  19405. rowSpan: 1,
  19406. colSpan: 1,
  19407. }
  19408. }
  19409. }
  19410. }
  19411. //当框选后删除行或者列后撤销,需要重建选区。
  19412. var tds = domUtils.getElementsByTagName(this.table, 'td'),
  19413. selectTds = []
  19414. utils.each(tds, function (td) {
  19415. if (domUtils.hasClass(td, 'selectTdClass')) {
  19416. selectTds.push(td)
  19417. }
  19418. })
  19419. if (selectTds.length) {
  19420. var start = selectTds[0],
  19421. end = selectTds[selectTds.length - 1],
  19422. startInfo = this.getCellInfo(start),
  19423. endInfo = this.getCellInfo(end)
  19424. this.selectedTds = selectTds
  19425. this.cellsRange = {
  19426. beginRowIndex: startInfo.rowIndex,
  19427. beginColIndex: startInfo.colIndex,
  19428. endRowIndex: endInfo.rowIndex + endInfo.rowSpan - 1,
  19429. endColIndex: endInfo.colIndex + endInfo.colSpan - 1,
  19430. }
  19431. }
  19432. //给第一行设置firstRow的样式名称,在排序图标的样式上使用到
  19433. if (!domUtils.hasClass(this.table.rows[0], 'firstRow')) {
  19434. domUtils.addClass(this.table.rows[0], 'firstRow')
  19435. for (var i = 1; i < this.table.rows.length; i++) {
  19436. domUtils.removeClasses(this.table.rows[i], 'firstRow')
  19437. }
  19438. }
  19439. },
  19440. /**
  19441. * 获取单元格的索引信息
  19442. */
  19443. getCellInfo: function (cell) {
  19444. if (!cell) return
  19445. var cellIndex = cell.cellIndex,
  19446. rowIndex = cell.parentNode.rowIndex,
  19447. rowInfo = this.indexTable[rowIndex],
  19448. numCols = this.colsNum
  19449. for (var colIndex = cellIndex; colIndex < numCols; colIndex++) {
  19450. var cellInfo = rowInfo[colIndex]
  19451. if (
  19452. cellInfo.rowIndex === rowIndex &&
  19453. cellInfo.cellIndex === cellIndex
  19454. ) {
  19455. return cellInfo
  19456. }
  19457. }
  19458. },
  19459. /**
  19460. * 根据行列号获取单元格
  19461. */
  19462. getCell: function (rowIndex, cellIndex) {
  19463. return (
  19464. (rowIndex < this.rowsNum &&
  19465. this.table.rows[rowIndex].cells[cellIndex]) ||
  19466. null
  19467. )
  19468. },
  19469. /**
  19470. * 删除单元格
  19471. */
  19472. deleteCell: function (cell, rowIndex) {
  19473. rowIndex =
  19474. typeof rowIndex == 'number' ? rowIndex : cell.parentNode.rowIndex
  19475. var row = this.table.rows[rowIndex]
  19476. row.deleteCell(cell.cellIndex)
  19477. },
  19478. /**
  19479. * 根据始末两个单元格获取被框选的所有单元格范围
  19480. */
  19481. getCellsRange: function (cellA, cellB) {
  19482. function checkRange(
  19483. beginRowIndex,
  19484. beginColIndex,
  19485. endRowIndex,
  19486. endColIndex
  19487. ) {
  19488. var tmpBeginRowIndex = beginRowIndex,
  19489. tmpBeginColIndex = beginColIndex,
  19490. tmpEndRowIndex = endRowIndex,
  19491. tmpEndColIndex = endColIndex,
  19492. cellInfo,
  19493. colIndex,
  19494. rowIndex
  19495. // 通过indexTable检查是否存在超出TableRange上边界的情况
  19496. if (beginRowIndex > 0) {
  19497. for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
  19498. cellInfo = me.indexTable[beginRowIndex][colIndex]
  19499. rowIndex = cellInfo.rowIndex
  19500. if (rowIndex < beginRowIndex) {
  19501. tmpBeginRowIndex = Math.min(rowIndex, tmpBeginRowIndex)
  19502. }
  19503. }
  19504. }
  19505. // 通过indexTable检查是否存在超出TableRange右边界的情况
  19506. if (endColIndex < me.colsNum) {
  19507. for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
  19508. cellInfo = me.indexTable[rowIndex][endColIndex]
  19509. colIndex = cellInfo.colIndex + cellInfo.colSpan - 1
  19510. if (colIndex > endColIndex) {
  19511. tmpEndColIndex = Math.max(colIndex, tmpEndColIndex)
  19512. }
  19513. }
  19514. }
  19515. // 检查是否有超出TableRange下边界的情况
  19516. if (endRowIndex < me.rowsNum) {
  19517. for (colIndex = beginColIndex; colIndex < endColIndex; colIndex++) {
  19518. cellInfo = me.indexTable[endRowIndex][colIndex]
  19519. rowIndex = cellInfo.rowIndex + cellInfo.rowSpan - 1
  19520. if (rowIndex > endRowIndex) {
  19521. tmpEndRowIndex = Math.max(rowIndex, tmpEndRowIndex)
  19522. }
  19523. }
  19524. }
  19525. // 检查是否有超出TableRange左边界的情况
  19526. if (beginColIndex > 0) {
  19527. for (rowIndex = beginRowIndex; rowIndex < endRowIndex; rowIndex++) {
  19528. cellInfo = me.indexTable[rowIndex][beginColIndex]
  19529. colIndex = cellInfo.colIndex
  19530. if (colIndex < beginColIndex) {
  19531. tmpBeginColIndex = Math.min(cellInfo.colIndex, tmpBeginColIndex)
  19532. }
  19533. }
  19534. }
  19535. //递归调用直至所有完成所有框选单元格的扩展
  19536. if (
  19537. tmpBeginRowIndex != beginRowIndex ||
  19538. tmpBeginColIndex != beginColIndex ||
  19539. tmpEndRowIndex != endRowIndex ||
  19540. tmpEndColIndex != endColIndex
  19541. ) {
  19542. return checkRange(
  19543. tmpBeginRowIndex,
  19544. tmpBeginColIndex,
  19545. tmpEndRowIndex,
  19546. tmpEndColIndex
  19547. )
  19548. } else {
  19549. // 不需要扩展TableRange的情况
  19550. return {
  19551. beginRowIndex: beginRowIndex,
  19552. beginColIndex: beginColIndex,
  19553. endRowIndex: endRowIndex,
  19554. endColIndex: endColIndex,
  19555. }
  19556. }
  19557. }
  19558. try {
  19559. var me = this,
  19560. cellAInfo = me.getCellInfo(cellA)
  19561. if (cellA === cellB) {
  19562. return {
  19563. beginRowIndex: cellAInfo.rowIndex,
  19564. beginColIndex: cellAInfo.colIndex,
  19565. endRowIndex: cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
  19566. endColIndex: cellAInfo.colIndex + cellAInfo.colSpan - 1,
  19567. }
  19568. }
  19569. var cellBInfo = me.getCellInfo(cellB)
  19570. // 计算TableRange的四个边
  19571. var beginRowIndex = Math.min(cellAInfo.rowIndex, cellBInfo.rowIndex),
  19572. beginColIndex = Math.min(cellAInfo.colIndex, cellBInfo.colIndex),
  19573. endRowIndex = Math.max(
  19574. cellAInfo.rowIndex + cellAInfo.rowSpan - 1,
  19575. cellBInfo.rowIndex + cellBInfo.rowSpan - 1
  19576. ),
  19577. endColIndex = Math.max(
  19578. cellAInfo.colIndex + cellAInfo.colSpan - 1,
  19579. cellBInfo.colIndex + cellBInfo.colSpan - 1
  19580. )
  19581. return checkRange(
  19582. beginRowIndex,
  19583. beginColIndex,
  19584. endRowIndex,
  19585. endColIndex
  19586. )
  19587. } catch (e) {
  19588. //throw e;
  19589. }
  19590. },
  19591. /**
  19592. * 依据cellsRange获取对应的单元格集合
  19593. */
  19594. getCells: function (range) {
  19595. //每次获取cells之前必须先清除上次的选择,否则会对后续获取操作造成影响
  19596. this.clearSelected()
  19597. var beginRowIndex = range.beginRowIndex,
  19598. beginColIndex = range.beginColIndex,
  19599. endRowIndex = range.endRowIndex,
  19600. endColIndex = range.endColIndex,
  19601. cellInfo,
  19602. rowIndex,
  19603. colIndex,
  19604. tdHash = {},
  19605. returnTds = []
  19606. for (var i = beginRowIndex; i <= endRowIndex; i++) {
  19607. for (var j = beginColIndex; j <= endColIndex; j++) {
  19608. cellInfo = this.indexTable[i][j]
  19609. rowIndex = cellInfo.rowIndex
  19610. colIndex = cellInfo.colIndex
  19611. // 如果Cells里已经包含了此Cell则跳过
  19612. var key = rowIndex + '|' + colIndex
  19613. if (tdHash[key]) continue
  19614. tdHash[key] = 1
  19615. if (
  19616. rowIndex < i ||
  19617. colIndex < j ||
  19618. rowIndex + cellInfo.rowSpan - 1 > endRowIndex ||
  19619. colIndex + cellInfo.colSpan - 1 > endColIndex
  19620. ) {
  19621. return null
  19622. }
  19623. returnTds.push(this.getCell(rowIndex, cellInfo.cellIndex))
  19624. }
  19625. }
  19626. return returnTds
  19627. },
  19628. /**
  19629. * 清理已经选中的单元格
  19630. */
  19631. clearSelected: function () {
  19632. UETable.removeSelectedClass(this.selectedTds)
  19633. this.selectedTds = []
  19634. this.cellsRange = {}
  19635. },
  19636. /**
  19637. * 根据range设置已经选中的单元格
  19638. */
  19639. setSelected: function (range) {
  19640. var cells = this.getCells(range)
  19641. UETable.addSelectedClass(cells)
  19642. this.selectedTds = cells
  19643. this.cellsRange = range
  19644. },
  19645. isFullRow: function () {
  19646. var range = this.cellsRange
  19647. return range.endColIndex - range.beginColIndex + 1 == this.colsNum
  19648. },
  19649. isFullCol: function () {
  19650. var range = this.cellsRange,
  19651. table = this.table,
  19652. ths = table.getElementsByTagName('th'),
  19653. rows = range.endRowIndex - range.beginRowIndex + 1
  19654. return !ths.length
  19655. ? rows == this.rowsNum
  19656. : rows == this.rowsNum || rows == this.rowsNum - 1
  19657. },
  19658. /**
  19659. * 获取视觉上的前置单元格,默认是左边,top传入时
  19660. * @param cell
  19661. * @param top
  19662. */
  19663. getNextCell: function (cell, bottom, ignoreRange) {
  19664. try {
  19665. var cellInfo = this.getCellInfo(cell),
  19666. nextRowIndex,
  19667. nextColIndex
  19668. var len = this.selectedTds.length && !ignoreRange,
  19669. range = this.cellsRange
  19670. //末行或者末列没有后置单元格
  19671. if (
  19672. (!bottom && cellInfo.rowIndex == 0) ||
  19673. (bottom &&
  19674. (!len
  19675. ? cellInfo.rowIndex + cellInfo.rowSpan > this.rowsNum - 1
  19676. : range.endRowIndex == this.rowsNum - 1))
  19677. )
  19678. return null
  19679. nextRowIndex = !bottom
  19680. ? !len
  19681. ? cellInfo.rowIndex - 1
  19682. : range.beginRowIndex - 1
  19683. : !len
  19684. ? cellInfo.rowIndex + cellInfo.rowSpan
  19685. : range.endRowIndex + 1
  19686. nextColIndex = !len ? cellInfo.colIndex : range.beginColIndex
  19687. return this.getCell(
  19688. this.indexTable[nextRowIndex][nextColIndex].rowIndex,
  19689. this.indexTable[nextRowIndex][nextColIndex].cellIndex
  19690. )
  19691. } catch (e) {
  19692. showError(e)
  19693. }
  19694. },
  19695. getPreviewCell: function (cell, top) {
  19696. try {
  19697. var cellInfo = this.getCellInfo(cell),
  19698. previewRowIndex,
  19699. previewColIndex
  19700. var len = this.selectedTds.length,
  19701. range = this.cellsRange
  19702. //首行或者首列没有前置单元格
  19703. if (
  19704. (!top && (!len ? !cellInfo.colIndex : !range.beginColIndex)) ||
  19705. (top &&
  19706. (!len
  19707. ? cellInfo.rowIndex > this.colsNum - 1
  19708. : range.endColIndex == this.colsNum - 1))
  19709. )
  19710. return null
  19711. previewRowIndex = !top
  19712. ? !len
  19713. ? cellInfo.rowIndex
  19714. : range.beginRowIndex
  19715. : !len
  19716. ? cellInfo.rowIndex < 1
  19717. ? 0
  19718. : cellInfo.rowIndex - 1
  19719. : range.beginRowIndex
  19720. previewColIndex = !top
  19721. ? !len
  19722. ? cellInfo.colIndex < 1
  19723. ? 0
  19724. : cellInfo.colIndex - 1
  19725. : range.beginColIndex - 1
  19726. : !len
  19727. ? cellInfo.colIndex
  19728. : range.endColIndex + 1
  19729. return this.getCell(
  19730. this.indexTable[previewRowIndex][previewColIndex].rowIndex,
  19731. this.indexTable[previewRowIndex][previewColIndex].cellIndex
  19732. )
  19733. } catch (e) {
  19734. showError(e)
  19735. }
  19736. },
  19737. /**
  19738. * 移动单元格中的内容
  19739. */
  19740. moveContent: function (cellTo, cellFrom) {
  19741. if (UETable.isEmptyBlock(cellFrom)) return
  19742. if (UETable.isEmptyBlock(cellTo)) {
  19743. cellTo.innerHTML = cellFrom.innerHTML
  19744. return
  19745. }
  19746. var child = cellTo.lastChild
  19747. if (child.nodeType == 3 || !dtd.$block[child.tagName]) {
  19748. cellTo.appendChild(cellTo.ownerDocument.createElement('br'))
  19749. }
  19750. while ((child = cellFrom.firstChild)) {
  19751. cellTo.appendChild(child)
  19752. }
  19753. },
  19754. /**
  19755. * 向右合并单元格
  19756. */
  19757. mergeRight: function (cell) {
  19758. var cellInfo = this.getCellInfo(cell),
  19759. rightColIndex = cellInfo.colIndex + cellInfo.colSpan,
  19760. rightCellInfo = this.indexTable[cellInfo.rowIndex][rightColIndex],
  19761. rightCell = this.getCell(
  19762. rightCellInfo.rowIndex,
  19763. rightCellInfo.cellIndex
  19764. )
  19765. //合并
  19766. cell.colSpan = cellInfo.colSpan + rightCellInfo.colSpan
  19767. //被合并的单元格不应存在宽度属性
  19768. cell.removeAttribute('width')
  19769. //移动内容
  19770. this.moveContent(cell, rightCell)
  19771. //删掉被合并的Cell
  19772. this.deleteCell(rightCell, rightCellInfo.rowIndex)
  19773. this.update()
  19774. },
  19775. /**
  19776. * 向下合并单元格
  19777. */
  19778. mergeDown: function (cell) {
  19779. var cellInfo = this.getCellInfo(cell),
  19780. downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan,
  19781. downCellInfo = this.indexTable[downRowIndex][cellInfo.colIndex],
  19782. downCell = this.getCell(downCellInfo.rowIndex, downCellInfo.cellIndex)
  19783. cell.rowSpan = cellInfo.rowSpan + downCellInfo.rowSpan
  19784. cell.removeAttribute('height')
  19785. this.moveContent(cell, downCell)
  19786. this.deleteCell(downCell, downCellInfo.rowIndex)
  19787. this.update()
  19788. },
  19789. /**
  19790. * 合并整个range中的内容
  19791. */
  19792. mergeRange: function () {
  19793. //由于合并操作可以在任意时刻进行,所以无法通过鼠标位置等信息实时生成range,只能通过缓存实例中的cellsRange对象来访问
  19794. var range = this.cellsRange,
  19795. leftTopCell = this.getCell(
  19796. range.beginRowIndex,
  19797. this.indexTable[range.beginRowIndex][range.beginColIndex].cellIndex
  19798. )
  19799. if (
  19800. leftTopCell.tagName == 'TH' &&
  19801. range.endRowIndex !== range.beginRowIndex
  19802. ) {
  19803. var index = this.indexTable,
  19804. info = this.getCellInfo(leftTopCell)
  19805. leftTopCell = this.getCell(1, index[1][info.colIndex].cellIndex)
  19806. range = this.getCellsRange(
  19807. leftTopCell,
  19808. this.getCell(
  19809. index[this.rowsNum - 1][info.colIndex].rowIndex,
  19810. index[this.rowsNum - 1][info.colIndex].cellIndex
  19811. )
  19812. )
  19813. }
  19814. // 删除剩余的Cells
  19815. var cells = this.getCells(range)
  19816. for (var i = 0, ci; (ci = cells[i++]); ) {
  19817. if (ci !== leftTopCell) {
  19818. this.moveContent(leftTopCell, ci)
  19819. this.deleteCell(ci)
  19820. }
  19821. }
  19822. // 修改左上角Cell的rowSpan和colSpan,并调整宽度属性设置
  19823. leftTopCell.rowSpan = range.endRowIndex - range.beginRowIndex + 1
  19824. leftTopCell.rowSpan > 1 && leftTopCell.removeAttribute('height')
  19825. leftTopCell.colSpan = range.endColIndex - range.beginColIndex + 1
  19826. leftTopCell.colSpan > 1 && leftTopCell.removeAttribute('width')
  19827. if (leftTopCell.rowSpan == this.rowsNum && leftTopCell.colSpan != 1) {
  19828. leftTopCell.colSpan = 1
  19829. }
  19830. if (leftTopCell.colSpan == this.colsNum && leftTopCell.rowSpan != 1) {
  19831. var rowIndex = leftTopCell.parentNode.rowIndex
  19832. //解决IE下的表格操作问题
  19833. if (this.table.deleteRow) {
  19834. for (
  19835. var i = rowIndex + 1,
  19836. curIndex = rowIndex + 1,
  19837. len = leftTopCell.rowSpan;
  19838. i < len;
  19839. i++
  19840. ) {
  19841. this.table.deleteRow(curIndex)
  19842. }
  19843. } else {
  19844. for (var i = 0, len = leftTopCell.rowSpan - 1; i < len; i++) {
  19845. var row = this.table.rows[rowIndex + 1]
  19846. row.parentNode.removeChild(row)
  19847. }
  19848. }
  19849. leftTopCell.rowSpan = 1
  19850. }
  19851. this.update()
  19852. },
  19853. /**
  19854. * 插入一行单元格
  19855. */
  19856. insertRow: function (rowIndex, sourceCell) {
  19857. var numCols = this.colsNum,
  19858. table = this.table,
  19859. row = table.insertRow(rowIndex),
  19860. cell,
  19861. isInsertTitle =
  19862. typeof sourceCell == 'string' && sourceCell.toUpperCase() == 'TH'
  19863. function replaceTdToTh(colIndex, cell, tableRow) {
  19864. if (colIndex == 0) {
  19865. var tr = tableRow.nextSibling || tableRow.previousSibling,
  19866. th = tr.cells[colIndex]
  19867. if (th.tagName == 'TH') {
  19868. th = cell.ownerDocument.createElement('th')
  19869. th.appendChild(cell.firstChild)
  19870. tableRow.insertBefore(th, cell)
  19871. domUtils.remove(cell)
  19872. }
  19873. } else {
  19874. if (cell.tagName == 'TH') {
  19875. var td = cell.ownerDocument.createElement('td')
  19876. td.appendChild(cell.firstChild)
  19877. tableRow.insertBefore(td, cell)
  19878. domUtils.remove(cell)
  19879. }
  19880. }
  19881. }
  19882. //首行直接插入,无需考虑部分单元格被rowspan的情况
  19883. if (rowIndex == 0 || rowIndex == this.rowsNum) {
  19884. for (var colIndex = 0; colIndex < numCols; colIndex++) {
  19885. cell = this.cloneCell(sourceCell, true)
  19886. this.setCellContent(cell)
  19887. cell.getAttribute('vAlign') &&
  19888. cell.setAttribute('vAlign', cell.getAttribute('vAlign'))
  19889. row.appendChild(cell)
  19890. if (!isInsertTitle) replaceTdToTh(colIndex, cell, row)
  19891. }
  19892. } else {
  19893. var infoRow = this.indexTable[rowIndex],
  19894. cellIndex = 0
  19895. for (colIndex = 0; colIndex < numCols; colIndex++) {
  19896. var cellInfo = infoRow[colIndex]
  19897. //如果存在某个单元格的rowspan穿过待插入行的位置,则修改该单元格的rowspan即可,无需插入单元格
  19898. if (cellInfo.rowIndex < rowIndex) {
  19899. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex)
  19900. cell.rowSpan = cellInfo.rowSpan + 1
  19901. } else {
  19902. cell = this.cloneCell(sourceCell, true)
  19903. this.setCellContent(cell)
  19904. row.appendChild(cell)
  19905. }
  19906. if (!isInsertTitle) replaceTdToTh(colIndex, cell, row)
  19907. }
  19908. }
  19909. //框选时插入不触发contentchange,需要手动更新索引。
  19910. this.update()
  19911. return row
  19912. },
  19913. /**
  19914. * 删除一行单元格
  19915. * @param rowIndex
  19916. */
  19917. deleteRow: function (rowIndex) {
  19918. var row = this.table.rows[rowIndex],
  19919. infoRow = this.indexTable[rowIndex],
  19920. colsNum = this.colsNum,
  19921. count = 0 //处理计数
  19922. for (var colIndex = 0; colIndex < colsNum; ) {
  19923. var cellInfo = infoRow[colIndex],
  19924. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex)
  19925. if (cell.rowSpan > 1) {
  19926. if (cellInfo.rowIndex == rowIndex) {
  19927. var clone = cell.cloneNode(true)
  19928. clone.rowSpan = cell.rowSpan - 1
  19929. clone.innerHTML = ''
  19930. cell.rowSpan = 1
  19931. var nextRowIndex = rowIndex + 1,
  19932. nextRow = this.table.rows[nextRowIndex],
  19933. insertCellIndex,
  19934. preMerged =
  19935. this.getPreviewMergedCellsNum(nextRowIndex, colIndex) - count
  19936. if (preMerged < colIndex) {
  19937. insertCellIndex = colIndex - preMerged - 1
  19938. //nextRow.insertCell(insertCellIndex);
  19939. domUtils.insertAfter(nextRow.cells[insertCellIndex], clone)
  19940. } else {
  19941. if (nextRow.cells.length)
  19942. nextRow.insertBefore(clone, nextRow.cells[0])
  19943. }
  19944. count += 1
  19945. //cell.parentNode.removeChild(cell);
  19946. }
  19947. }
  19948. colIndex += cell.colSpan || 1
  19949. }
  19950. var deleteTds = [],
  19951. cacheMap = {}
  19952. for (colIndex = 0; colIndex < colsNum; colIndex++) {
  19953. var tmpRowIndex = infoRow[colIndex].rowIndex,
  19954. tmpCellIndex = infoRow[colIndex].cellIndex,
  19955. key = tmpRowIndex + '_' + tmpCellIndex
  19956. if (cacheMap[key]) continue
  19957. cacheMap[key] = 1
  19958. cell = this.getCell(tmpRowIndex, tmpCellIndex)
  19959. deleteTds.push(cell)
  19960. }
  19961. var mergeTds = []
  19962. utils.each(deleteTds, function (td) {
  19963. if (td.rowSpan == 1) {
  19964. td.parentNode.removeChild(td)
  19965. } else {
  19966. mergeTds.push(td)
  19967. }
  19968. })
  19969. utils.each(mergeTds, function (td) {
  19970. td.rowSpan--
  19971. })
  19972. row.parentNode.removeChild(row)
  19973. //浏览器方法本身存在bug,采用自定义方法删除
  19974. //this.table.deleteRow(rowIndex);
  19975. this.update()
  19976. },
  19977. insertCol: function (colIndex, sourceCell, defaultValue) {
  19978. var rowsNum = this.rowsNum,
  19979. rowIndex = 0,
  19980. tableRow,
  19981. cell,
  19982. backWidth = parseInt(
  19983. (this.table.offsetWidth -
  19984. (this.colsNum + 1) * 20 -
  19985. (this.colsNum + 1)) /
  19986. (this.colsNum + 1),
  19987. 10
  19988. ),
  19989. isInsertTitleCol =
  19990. typeof sourceCell == 'string' && sourceCell.toUpperCase() == 'TH'
  19991. function replaceTdToTh(rowIndex, cell, tableRow) {
  19992. if (rowIndex == 0) {
  19993. var th = cell.nextSibling || cell.previousSibling
  19994. if (th.tagName == 'TH') {
  19995. th = cell.ownerDocument.createElement('th')
  19996. th.appendChild(cell.firstChild)
  19997. tableRow.insertBefore(th, cell)
  19998. domUtils.remove(cell)
  19999. }
  20000. } else {
  20001. if (cell.tagName == 'TH') {
  20002. var td = cell.ownerDocument.createElement('td')
  20003. td.appendChild(cell.firstChild)
  20004. tableRow.insertBefore(td, cell)
  20005. domUtils.remove(cell)
  20006. }
  20007. }
  20008. }
  20009. var preCell
  20010. if (colIndex == 0 || colIndex == this.colsNum) {
  20011. for (; rowIndex < rowsNum; rowIndex++) {
  20012. tableRow = this.table.rows[rowIndex]
  20013. preCell =
  20014. tableRow.cells[colIndex == 0 ? colIndex : tableRow.cells.length]
  20015. cell = this.cloneCell(sourceCell, true) //tableRow.insertCell(colIndex == 0 ? colIndex : tableRow.cells.length);
  20016. this.setCellContent(cell)
  20017. cell.setAttribute('vAlign', cell.getAttribute('vAlign'))
  20018. preCell && cell.setAttribute('width', preCell.getAttribute('width'))
  20019. if (!colIndex) {
  20020. tableRow.insertBefore(cell, tableRow.cells[0])
  20021. } else {
  20022. domUtils.insertAfter(
  20023. tableRow.cells[tableRow.cells.length - 1],
  20024. cell
  20025. )
  20026. }
  20027. if (!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow)
  20028. }
  20029. } else {
  20030. for (; rowIndex < rowsNum; rowIndex++) {
  20031. var cellInfo = this.indexTable[rowIndex][colIndex]
  20032. if (cellInfo.colIndex < colIndex) {
  20033. cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex)
  20034. cell.colSpan = cellInfo.colSpan + 1
  20035. } else {
  20036. tableRow = this.table.rows[rowIndex]
  20037. preCell = tableRow.cells[cellInfo.cellIndex]
  20038. cell = this.cloneCell(sourceCell, true) //tableRow.insertCell(cellInfo.cellIndex);
  20039. this.setCellContent(cell)
  20040. cell.setAttribute('vAlign', cell.getAttribute('vAlign'))
  20041. preCell &&
  20042. cell.setAttribute('width', preCell.getAttribute('width'))
  20043. //防止IE下报错
  20044. preCell
  20045. ? tableRow.insertBefore(cell, preCell)
  20046. : tableRow.appendChild(cell)
  20047. }
  20048. if (!isInsertTitleCol) replaceTdToTh(rowIndex, cell, tableRow)
  20049. }
  20050. }
  20051. //框选时插入不触发contentchange,需要手动更新索引
  20052. this.update()
  20053. this.updateWidth(
  20054. backWidth,
  20055. defaultValue || { tdPadding: 10, tdBorder: 1 }
  20056. )
  20057. },
  20058. updateWidth: function (width, defaultValue) {
  20059. var table = this.table,
  20060. tmpWidth =
  20061. UETable.getWidth(table) -
  20062. defaultValue.tdPadding * 2 -
  20063. defaultValue.tdBorder +
  20064. width
  20065. if (tmpWidth < table.ownerDocument.body.offsetWidth) {
  20066. table.setAttribute('width', tmpWidth)
  20067. return
  20068. }
  20069. var tds = domUtils.getElementsByTagName(this.table, 'td th')
  20070. utils.each(tds, function (td) {
  20071. td.setAttribute('width', width)
  20072. })
  20073. },
  20074. deleteCol: function (colIndex) {
  20075. var indexTable = this.indexTable,
  20076. tableRows = this.table.rows,
  20077. backTableWidth = this.table.getAttribute('width'),
  20078. backTdWidth = 0,
  20079. rowsNum = this.rowsNum,
  20080. cacheMap = {}
  20081. for (var rowIndex = 0; rowIndex < rowsNum; ) {
  20082. var infoRow = indexTable[rowIndex],
  20083. cellInfo = infoRow[colIndex],
  20084. key = cellInfo.rowIndex + '_' + cellInfo.colIndex
  20085. // 跳过已经处理过的Cell
  20086. if (cacheMap[key]) continue
  20087. cacheMap[key] = 1
  20088. var cell = this.getCell(cellInfo.rowIndex, cellInfo.cellIndex)
  20089. if (!backTdWidth)
  20090. backTdWidth =
  20091. cell && parseInt(cell.offsetWidth / cell.colSpan, 10).toFixed(0)
  20092. // 如果Cell的colSpan大于1, 就修改colSpan, 否则就删掉这个Cell
  20093. if (cell.colSpan > 1) {
  20094. cell.colSpan--
  20095. } else {
  20096. tableRows[rowIndex].deleteCell(cellInfo.cellIndex)
  20097. }
  20098. rowIndex += cellInfo.rowSpan || 1
  20099. }
  20100. this.table.setAttribute('width', backTableWidth - backTdWidth)
  20101. this.update()
  20102. },
  20103. splitToCells: function (cell) {
  20104. var me = this,
  20105. cells = this.splitToRows(cell)
  20106. utils.each(cells, function (cell) {
  20107. me.splitToCols(cell)
  20108. })
  20109. },
  20110. splitToRows: function (cell) {
  20111. var cellInfo = this.getCellInfo(cell),
  20112. rowIndex = cellInfo.rowIndex,
  20113. colIndex = cellInfo.colIndex,
  20114. results = []
  20115. // 修改Cell的rowSpan
  20116. cell.rowSpan = 1
  20117. results.push(cell)
  20118. // 补齐单元格
  20119. for (
  20120. var i = rowIndex, endRow = rowIndex + cellInfo.rowSpan;
  20121. i < endRow;
  20122. i++
  20123. ) {
  20124. if (i == rowIndex) continue
  20125. var tableRow = this.table.rows[i],
  20126. tmpCell = tableRow.insertCell(
  20127. colIndex - this.getPreviewMergedCellsNum(i, colIndex)
  20128. )
  20129. tmpCell.colSpan = cellInfo.colSpan
  20130. this.setCellContent(tmpCell)
  20131. tmpCell.setAttribute('vAlign', cell.getAttribute('vAlign'))
  20132. tmpCell.setAttribute('align', cell.getAttribute('align'))
  20133. if (cell.style.cssText) {
  20134. tmpCell.style.cssText = cell.style.cssText
  20135. }
  20136. results.push(tmpCell)
  20137. }
  20138. this.update()
  20139. return results
  20140. },
  20141. getPreviewMergedCellsNum: function (rowIndex, colIndex) {
  20142. var indexRow = this.indexTable[rowIndex],
  20143. num = 0
  20144. for (var i = 0; i < colIndex; ) {
  20145. var colSpan = indexRow[i].colSpan,
  20146. tmpRowIndex = indexRow[i].rowIndex
  20147. num += colSpan - (tmpRowIndex == rowIndex ? 1 : 0)
  20148. i += colSpan
  20149. }
  20150. return num
  20151. },
  20152. splitToCols: function (cell) {
  20153. var backWidth = (cell.offsetWidth / cell.colSpan - 22).toFixed(0),
  20154. cellInfo = this.getCellInfo(cell),
  20155. rowIndex = cellInfo.rowIndex,
  20156. colIndex = cellInfo.colIndex,
  20157. results = []
  20158. // 修改Cell的rowSpan
  20159. cell.colSpan = 1
  20160. cell.setAttribute('width', backWidth)
  20161. results.push(cell)
  20162. // 补齐单元格
  20163. for (
  20164. var j = colIndex, endCol = colIndex + cellInfo.colSpan;
  20165. j < endCol;
  20166. j++
  20167. ) {
  20168. if (j == colIndex) continue
  20169. var tableRow = this.table.rows[rowIndex],
  20170. tmpCell = tableRow.insertCell(
  20171. this.indexTable[rowIndex][j].cellIndex + 1
  20172. )
  20173. tmpCell.rowSpan = cellInfo.rowSpan
  20174. this.setCellContent(tmpCell)
  20175. tmpCell.setAttribute('vAlign', cell.getAttribute('vAlign'))
  20176. tmpCell.setAttribute('align', cell.getAttribute('align'))
  20177. tmpCell.setAttribute('width', backWidth)
  20178. if (cell.style.cssText) {
  20179. tmpCell.style.cssText = cell.style.cssText
  20180. }
  20181. //处理th的情况
  20182. if (cell.tagName == 'TH') {
  20183. var th = cell.ownerDocument.createElement('th')
  20184. th.appendChild(tmpCell.firstChild)
  20185. th.setAttribute('vAlign', cell.getAttribute('vAlign'))
  20186. th.rowSpan = tmpCell.rowSpan
  20187. tableRow.insertBefore(th, tmpCell)
  20188. domUtils.remove(tmpCell)
  20189. }
  20190. results.push(tmpCell)
  20191. }
  20192. this.update()
  20193. return results
  20194. },
  20195. isLastCell: function (cell, rowsNum, colsNum) {
  20196. rowsNum = rowsNum || this.rowsNum
  20197. colsNum = colsNum || this.colsNum
  20198. var cellInfo = this.getCellInfo(cell)
  20199. return (
  20200. cellInfo.rowIndex + cellInfo.rowSpan == rowsNum &&
  20201. cellInfo.colIndex + cellInfo.colSpan == colsNum
  20202. )
  20203. },
  20204. getLastCell: function (cells) {
  20205. cells = cells || this.table.getElementsByTagName('td')
  20206. var firstInfo = this.getCellInfo(cells[0])
  20207. var me = this,
  20208. last = cells[0],
  20209. tr = last.parentNode,
  20210. cellsNum = 0,
  20211. cols = 0,
  20212. rows
  20213. utils.each(cells, function (cell) {
  20214. if (cell.parentNode == tr) cols += cell.colSpan || 1
  20215. cellsNum += cell.rowSpan * cell.colSpan || 1
  20216. })
  20217. rows = cellsNum / cols
  20218. utils.each(cells, function (cell) {
  20219. if (me.isLastCell(cell, rows, cols)) {
  20220. last = cell
  20221. return false
  20222. }
  20223. })
  20224. return last
  20225. },
  20226. selectRow: function (rowIndex) {
  20227. var indexRow = this.indexTable[rowIndex],
  20228. start = this.getCell(indexRow[0].rowIndex, indexRow[0].cellIndex),
  20229. end = this.getCell(
  20230. indexRow[this.colsNum - 1].rowIndex,
  20231. indexRow[this.colsNum - 1].cellIndex
  20232. ),
  20233. range = this.getCellsRange(start, end)
  20234. this.setSelected(range)
  20235. },
  20236. selectTable: function () {
  20237. var tds = this.table.getElementsByTagName('td'),
  20238. range = this.getCellsRange(tds[0], tds[tds.length - 1])
  20239. this.setSelected(range)
  20240. },
  20241. setBackground: function (cells, value) {
  20242. if (typeof value === 'string') {
  20243. utils.each(cells, function (cell) {
  20244. cell.style.backgroundColor = value
  20245. })
  20246. } else if (typeof value === 'object') {
  20247. value = utils.extend(
  20248. {
  20249. repeat: true,
  20250. colorList: ['#ddd', '#fff'],
  20251. },
  20252. value
  20253. )
  20254. var rowIndex = this.getCellInfo(cells[0]).rowIndex,
  20255. count = 0,
  20256. colors = value.colorList,
  20257. getColor = function (list, index, repeat) {
  20258. return list[index]
  20259. ? list[index]
  20260. : repeat
  20261. ? list[index % list.length]
  20262. : ''
  20263. }
  20264. for (var i = 0, cell; (cell = cells[i++]); ) {
  20265. var cellInfo = this.getCellInfo(cell)
  20266. cell.style.backgroundColor = getColor(
  20267. colors,
  20268. rowIndex + count == cellInfo.rowIndex ? count : ++count,
  20269. value.repeat
  20270. )
  20271. }
  20272. }
  20273. },
  20274. removeBackground: function (cells) {
  20275. utils.each(cells, function (cell) {
  20276. cell.style.backgroundColor = ''
  20277. })
  20278. },
  20279. }
  20280. function showError(e) {}
  20281. })()
  20282. // plugins/table.cmds.js
  20283. /**
  20284. * Created with JetBrains PhpStorm.
  20285. * User: taoqili
  20286. * Date: 13-2-20
  20287. * Time: 下午6:25
  20288. * To change this template use File | Settings | File Templates.
  20289. */
  20290. ;(function () {
  20291. var UT = UE.UETable,
  20292. getTableItemsByRange = function (editor) {
  20293. return UT.getTableItemsByRange(editor)
  20294. },
  20295. getUETableBySelected = function (editor) {
  20296. return UT.getUETableBySelected(editor)
  20297. },
  20298. getDefaultValue = function (editor, table) {
  20299. return UT.getDefaultValue(editor, table)
  20300. },
  20301. getUETable = function (tdOrTable) {
  20302. return UT.getUETable(tdOrTable)
  20303. }
  20304. UE.commands['inserttable'] = {
  20305. queryCommandState: function () {
  20306. return getTableItemsByRange(this).table ? -1 : 0
  20307. },
  20308. execCommand: function (cmd, opt) {
  20309. function createTable(opt, tdWidth) {
  20310. var html = [],
  20311. rowsNum = opt.numRows,
  20312. colsNum = opt.numCols
  20313. for (var r = 0; r < rowsNum; r++) {
  20314. html.push('<tr' + (r == 0 ? ' class="firstRow"' : '') + '>')
  20315. for (var c = 0; c < colsNum; c++) {
  20316. html.push(
  20317. '<td width="' +
  20318. tdWidth +
  20319. '" vAlign="' +
  20320. opt.tdvalign +
  20321. '" >' +
  20322. (browser.ie && browser.version < 11
  20323. ? domUtils.fillChar
  20324. : '<br/>') +
  20325. '</td>'
  20326. )
  20327. }
  20328. html.push('</tr>')
  20329. }
  20330. //禁止指定table-width
  20331. return '<table><tbody>' + html.join('') + '</tbody></table>'
  20332. }
  20333. if (!opt) {
  20334. opt = utils.extend(
  20335. {},
  20336. {
  20337. numCols: this.options.defaultCols,
  20338. numRows: this.options.defaultRows,
  20339. tdvalign: this.options.tdvalign,
  20340. }
  20341. )
  20342. }
  20343. var me = this
  20344. var range = this.selection.getRange(),
  20345. start = range.startContainer,
  20346. firstParentBlock =
  20347. domUtils.findParent(
  20348. start,
  20349. function (node) {
  20350. return domUtils.isBlockElm(node)
  20351. },
  20352. true
  20353. ) || me.body
  20354. var defaultValue = getDefaultValue(me),
  20355. tableWidth = firstParentBlock.offsetWidth,
  20356. tdWidth = Math.floor(
  20357. tableWidth / opt.numCols -
  20358. defaultValue.tdPadding * 2 -
  20359. defaultValue.tdBorder
  20360. )
  20361. //todo其他属性
  20362. !opt.tdvalign && (opt.tdvalign = me.options.tdvalign)
  20363. me.execCommand('inserthtml', createTable(opt, tdWidth))
  20364. },
  20365. }
  20366. UE.commands['insertparagraphbeforetable'] = {
  20367. queryCommandState: function () {
  20368. return getTableItemsByRange(this).cell ? 0 : -1
  20369. },
  20370. execCommand: function () {
  20371. var table = getTableItemsByRange(this).table
  20372. if (table) {
  20373. var p = this.document.createElement('p')
  20374. p.innerHTML = browser.ie ? '&nbsp;' : '<br />'
  20375. table.parentNode.insertBefore(p, table)
  20376. this.selection.getRange().setStart(p, 0).setCursor()
  20377. }
  20378. },
  20379. }
  20380. UE.commands['deletetable'] = {
  20381. queryCommandState: function () {
  20382. var rng = this.selection.getRange()
  20383. return domUtils.findParentByTagName(rng.startContainer, 'table', true)
  20384. ? 0
  20385. : -1
  20386. },
  20387. execCommand: function (cmd, table) {
  20388. var rng = this.selection.getRange()
  20389. table =
  20390. table ||
  20391. domUtils.findParentByTagName(rng.startContainer, 'table', true)
  20392. if (table) {
  20393. var next = table.nextSibling
  20394. if (!next) {
  20395. next = domUtils.createElement(this.document, 'p', {
  20396. innerHTML: browser.ie ? domUtils.fillChar : '<br/>',
  20397. })
  20398. table.parentNode.insertBefore(next, table)
  20399. }
  20400. domUtils.remove(table)
  20401. rng = this.selection.getRange()
  20402. if (next.nodeType == 3) {
  20403. rng.setStartBefore(next)
  20404. } else {
  20405. rng.setStart(next, 0)
  20406. }
  20407. rng.setCursor(false, true)
  20408. this.fireEvent('tablehasdeleted')
  20409. }
  20410. },
  20411. }
  20412. UE.commands['cellalign'] = {
  20413. queryCommandState: function () {
  20414. return getSelectedArr(this).length ? 0 : -1
  20415. },
  20416. execCommand: function (cmd, align) {
  20417. var selectedTds = getSelectedArr(this)
  20418. if (selectedTds.length) {
  20419. for (var i = 0, ci; (ci = selectedTds[i++]); ) {
  20420. ci.setAttribute('align', align)
  20421. }
  20422. }
  20423. },
  20424. }
  20425. UE.commands['cellvalign'] = {
  20426. queryCommandState: function () {
  20427. return getSelectedArr(this).length ? 0 : -1
  20428. },
  20429. execCommand: function (cmd, valign) {
  20430. var selectedTds = getSelectedArr(this)
  20431. if (selectedTds.length) {
  20432. for (var i = 0, ci; (ci = selectedTds[i++]); ) {
  20433. ci.setAttribute('vAlign', valign)
  20434. }
  20435. }
  20436. },
  20437. }
  20438. UE.commands['insertcaption'] = {
  20439. queryCommandState: function () {
  20440. var table = getTableItemsByRange(this).table
  20441. if (table) {
  20442. return table.getElementsByTagName('caption').length == 0 ? 1 : -1
  20443. }
  20444. return -1
  20445. },
  20446. execCommand: function () {
  20447. var table = getTableItemsByRange(this).table
  20448. if (table) {
  20449. var caption = this.document.createElement('caption')
  20450. caption.innerHTML = browser.ie ? domUtils.fillChar : '<br/>'
  20451. table.insertBefore(caption, table.firstChild)
  20452. var range = this.selection.getRange()
  20453. range.setStart(caption, 0).setCursor()
  20454. }
  20455. },
  20456. }
  20457. UE.commands['deletecaption'] = {
  20458. queryCommandState: function () {
  20459. var rng = this.selection.getRange(),
  20460. table = domUtils.findParentByTagName(rng.startContainer, 'table')
  20461. if (table) {
  20462. return table.getElementsByTagName('caption').length == 0 ? -1 : 1
  20463. }
  20464. return -1
  20465. },
  20466. execCommand: function () {
  20467. var rng = this.selection.getRange(),
  20468. table = domUtils.findParentByTagName(rng.startContainer, 'table')
  20469. if (table) {
  20470. domUtils.remove(table.getElementsByTagName('caption')[0])
  20471. var range = this.selection.getRange()
  20472. range.setStart(table.rows[0].cells[0], 0).setCursor()
  20473. }
  20474. },
  20475. }
  20476. UE.commands['inserttitle'] = {
  20477. queryCommandState: function () {
  20478. var table = getTableItemsByRange(this).table
  20479. if (table) {
  20480. var firstRow = table.rows[0]
  20481. return firstRow.cells[
  20482. firstRow.cells.length - 1
  20483. ].tagName.toLowerCase() != 'th'
  20484. ? 0
  20485. : -1
  20486. }
  20487. return -1
  20488. },
  20489. execCommand: function () {
  20490. var table = getTableItemsByRange(this).table
  20491. if (table) {
  20492. getUETable(table).insertRow(0, 'th')
  20493. }
  20494. var th = table.getElementsByTagName('th')[0]
  20495. this.selection.getRange().setStart(th, 0).setCursor(false, true)
  20496. },
  20497. }
  20498. UE.commands['deletetitle'] = {
  20499. queryCommandState: function () {
  20500. var table = getTableItemsByRange(this).table
  20501. if (table) {
  20502. var firstRow = table.rows[0]
  20503. return firstRow.cells[
  20504. firstRow.cells.length - 1
  20505. ].tagName.toLowerCase() == 'th'
  20506. ? 0
  20507. : -1
  20508. }
  20509. return -1
  20510. },
  20511. execCommand: function () {
  20512. var table = getTableItemsByRange(this).table
  20513. if (table) {
  20514. domUtils.remove(table.rows[0])
  20515. }
  20516. var td = table.getElementsByTagName('td')[0]
  20517. this.selection.getRange().setStart(td, 0).setCursor(false, true)
  20518. },
  20519. }
  20520. UE.commands['inserttitlecol'] = {
  20521. queryCommandState: function () {
  20522. var table = getTableItemsByRange(this).table
  20523. if (table) {
  20524. var lastRow = table.rows[table.rows.length - 1]
  20525. return lastRow.getElementsByTagName('th').length ? -1 : 0
  20526. }
  20527. return -1
  20528. },
  20529. execCommand: function (cmd) {
  20530. var table = getTableItemsByRange(this).table
  20531. if (table) {
  20532. getUETable(table).insertCol(0, 'th')
  20533. }
  20534. resetTdWidth(table, this)
  20535. var th = table.getElementsByTagName('th')[0]
  20536. this.selection.getRange().setStart(th, 0).setCursor(false, true)
  20537. },
  20538. }
  20539. UE.commands['deletetitlecol'] = {
  20540. queryCommandState: function () {
  20541. var table = getTableItemsByRange(this).table
  20542. if (table) {
  20543. var lastRow = table.rows[table.rows.length - 1]
  20544. return lastRow.getElementsByTagName('th').length ? 0 : -1
  20545. }
  20546. return -1
  20547. },
  20548. execCommand: function () {
  20549. var table = getTableItemsByRange(this).table
  20550. if (table) {
  20551. for (var i = 0; i < table.rows.length; i++) {
  20552. domUtils.remove(table.rows[i].children[0])
  20553. }
  20554. }
  20555. resetTdWidth(table, this)
  20556. var td = table.getElementsByTagName('td')[0]
  20557. this.selection.getRange().setStart(td, 0).setCursor(false, true)
  20558. },
  20559. }
  20560. UE.commands['mergeright'] = {
  20561. queryCommandState: function (cmd) {
  20562. var tableItems = getTableItemsByRange(this),
  20563. table = tableItems.table,
  20564. cell = tableItems.cell
  20565. if (!table || !cell) return -1
  20566. var ut = getUETable(table)
  20567. if (ut.selectedTds.length) return -1
  20568. var cellInfo = ut.getCellInfo(cell),
  20569. rightColIndex = cellInfo.colIndex + cellInfo.colSpan
  20570. if (rightColIndex >= ut.colsNum) return -1 // 如果处于最右边则不能向右合并
  20571. var rightCellInfo = ut.indexTable[cellInfo.rowIndex][rightColIndex],
  20572. rightCell =
  20573. table.rows[rightCellInfo.rowIndex].cells[rightCellInfo.cellIndex]
  20574. if (!rightCell || cell.tagName != rightCell.tagName) return -1 // TH和TD不能相互合并
  20575. // 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
  20576. return rightCellInfo.rowIndex == cellInfo.rowIndex &&
  20577. rightCellInfo.rowSpan == cellInfo.rowSpan
  20578. ? 0
  20579. : -1
  20580. },
  20581. execCommand: function (cmd) {
  20582. var rng = this.selection.getRange(),
  20583. bk = rng.createBookmark(true)
  20584. var cell = getTableItemsByRange(this).cell,
  20585. ut = getUETable(cell)
  20586. ut.mergeRight(cell)
  20587. rng.moveToBookmark(bk).select()
  20588. },
  20589. }
  20590. UE.commands['mergedown'] = {
  20591. queryCommandState: function (cmd) {
  20592. var tableItems = getTableItemsByRange(this),
  20593. table = tableItems.table,
  20594. cell = tableItems.cell
  20595. if (!table || !cell) return -1
  20596. var ut = getUETable(table)
  20597. if (ut.selectedTds.length) return -1
  20598. var cellInfo = ut.getCellInfo(cell),
  20599. downRowIndex = cellInfo.rowIndex + cellInfo.rowSpan
  20600. if (downRowIndex >= ut.rowsNum) return -1 // 如果处于最下边则不能向下合并
  20601. var downCellInfo = ut.indexTable[downRowIndex][cellInfo.colIndex],
  20602. downCell =
  20603. table.rows[downCellInfo.rowIndex].cells[downCellInfo.cellIndex]
  20604. if (!downCell || cell.tagName != downCell.tagName) return -1 // TH和TD不能相互合并
  20605. // 当且仅当两个Cell的开始列号和结束列号一致时能进行合并
  20606. return downCellInfo.colIndex == cellInfo.colIndex &&
  20607. downCellInfo.colSpan == cellInfo.colSpan
  20608. ? 0
  20609. : -1
  20610. },
  20611. execCommand: function () {
  20612. var rng = this.selection.getRange(),
  20613. bk = rng.createBookmark(true)
  20614. var cell = getTableItemsByRange(this).cell,
  20615. ut = getUETable(cell)
  20616. ut.mergeDown(cell)
  20617. rng.moveToBookmark(bk).select()
  20618. },
  20619. }
  20620. UE.commands['mergecells'] = {
  20621. queryCommandState: function () {
  20622. return getUETableBySelected(this) ? 0 : -1
  20623. },
  20624. execCommand: function () {
  20625. var ut = getUETableBySelected(this)
  20626. if (ut && ut.selectedTds.length) {
  20627. var cell = ut.selectedTds[0]
  20628. ut.mergeRange()
  20629. var rng = this.selection.getRange()
  20630. if (domUtils.isEmptyBlock(cell)) {
  20631. rng.setStart(cell, 0).collapse(true)
  20632. } else {
  20633. rng.selectNodeContents(cell)
  20634. }
  20635. rng.select()
  20636. }
  20637. },
  20638. }
  20639. UE.commands['insertrow'] = {
  20640. queryCommandState: function () {
  20641. var tableItems = getTableItemsByRange(this),
  20642. cell = tableItems.cell
  20643. return cell &&
  20644. (cell.tagName == 'TD' ||
  20645. (cell.tagName == 'TH' &&
  20646. tableItems.tr !== tableItems.table.rows[0])) &&
  20647. getUETable(tableItems.table).rowsNum < this.options.maxRowNum
  20648. ? 0
  20649. : -1
  20650. },
  20651. execCommand: function () {
  20652. var rng = this.selection.getRange(),
  20653. bk = rng.createBookmark(true)
  20654. var tableItems = getTableItemsByRange(this),
  20655. cell = tableItems.cell,
  20656. table = tableItems.table,
  20657. ut = getUETable(table),
  20658. cellInfo = ut.getCellInfo(cell)
  20659. //ut.insertRow(!ut.selectedTds.length ? cellInfo.rowIndex:ut.cellsRange.beginRowIndex,'');
  20660. if (!ut.selectedTds.length) {
  20661. ut.insertRow(cellInfo.rowIndex, cell)
  20662. } else {
  20663. var range = ut.cellsRange
  20664. for (
  20665. var i = 0, len = range.endRowIndex - range.beginRowIndex + 1;
  20666. i < len;
  20667. i++
  20668. ) {
  20669. ut.insertRow(range.beginRowIndex, cell)
  20670. }
  20671. }
  20672. rng.moveToBookmark(bk).select()
  20673. if (table.getAttribute('interlaced') === 'enabled')
  20674. this.fireEvent('interlacetable', table)
  20675. },
  20676. }
  20677. //后插入行
  20678. UE.commands['insertrownext'] = {
  20679. queryCommandState: function () {
  20680. var tableItems = getTableItemsByRange(this),
  20681. cell = tableItems.cell
  20682. return cell &&
  20683. cell.tagName == 'TD' &&
  20684. getUETable(tableItems.table).rowsNum < this.options.maxRowNum
  20685. ? 0
  20686. : -1
  20687. },
  20688. execCommand: function () {
  20689. var rng = this.selection.getRange(),
  20690. bk = rng.createBookmark(true)
  20691. var tableItems = getTableItemsByRange(this),
  20692. cell = tableItems.cell,
  20693. table = tableItems.table,
  20694. ut = getUETable(table),
  20695. cellInfo = ut.getCellInfo(cell)
  20696. //ut.insertRow(!ut.selectedTds.length? cellInfo.rowIndex + cellInfo.rowSpan : ut.cellsRange.endRowIndex + 1,'');
  20697. if (!ut.selectedTds.length) {
  20698. ut.insertRow(cellInfo.rowIndex + cellInfo.rowSpan, cell)
  20699. } else {
  20700. var range = ut.cellsRange
  20701. for (
  20702. var i = 0, len = range.endRowIndex - range.beginRowIndex + 1;
  20703. i < len;
  20704. i++
  20705. ) {
  20706. ut.insertRow(range.endRowIndex + 1, cell)
  20707. }
  20708. }
  20709. rng.moveToBookmark(bk).select()
  20710. if (table.getAttribute('interlaced') === 'enabled')
  20711. this.fireEvent('interlacetable', table)
  20712. },
  20713. }
  20714. UE.commands['deleterow'] = {
  20715. queryCommandState: function () {
  20716. var tableItems = getTableItemsByRange(this)
  20717. return tableItems.cell ? 0 : -1
  20718. },
  20719. execCommand: function () {
  20720. var cell = getTableItemsByRange(this).cell,
  20721. ut = getUETable(cell),
  20722. cellsRange = ut.cellsRange,
  20723. cellInfo = ut.getCellInfo(cell),
  20724. preCell = ut.getVSideCell(cell),
  20725. nextCell = ut.getVSideCell(cell, true),
  20726. rng = this.selection.getRange()
  20727. if (utils.isEmptyObject(cellsRange)) {
  20728. ut.deleteRow(cellInfo.rowIndex)
  20729. } else {
  20730. for (
  20731. var i = cellsRange.beginRowIndex;
  20732. i < cellsRange.endRowIndex + 1;
  20733. i++
  20734. ) {
  20735. ut.deleteRow(cellsRange.beginRowIndex)
  20736. }
  20737. }
  20738. var table = ut.table
  20739. if (!table.getElementsByTagName('td').length) {
  20740. var nextSibling = table.nextSibling
  20741. domUtils.remove(table)
  20742. if (nextSibling) {
  20743. rng.setStart(nextSibling, 0).setCursor(false, true)
  20744. }
  20745. } else {
  20746. if (
  20747. cellInfo.rowSpan == 1 ||
  20748. cellInfo.rowSpan ==
  20749. cellsRange.endRowIndex - cellsRange.beginRowIndex + 1
  20750. ) {
  20751. if (nextCell || preCell)
  20752. rng.selectNodeContents(nextCell || preCell).setCursor(false, true)
  20753. } else {
  20754. var newCell = ut.getCell(
  20755. cellInfo.rowIndex,
  20756. ut.indexTable[cellInfo.rowIndex][cellInfo.colIndex].cellIndex
  20757. )
  20758. if (newCell) rng.selectNodeContents(newCell).setCursor(false, true)
  20759. }
  20760. }
  20761. if (table.getAttribute('interlaced') === 'enabled')
  20762. this.fireEvent('interlacetable', table)
  20763. },
  20764. }
  20765. UE.commands['insertcol'] = {
  20766. queryCommandState: function (cmd) {
  20767. var tableItems = getTableItemsByRange(this),
  20768. cell = tableItems.cell
  20769. return cell &&
  20770. (cell.tagName == 'TD' ||
  20771. (cell.tagName == 'TH' && cell !== tableItems.tr.cells[0])) &&
  20772. getUETable(tableItems.table).colsNum < this.options.maxColNum
  20773. ? 0
  20774. : -1
  20775. },
  20776. execCommand: function (cmd) {
  20777. var rng = this.selection.getRange(),
  20778. bk = rng.createBookmark(true)
  20779. if (this.queryCommandState(cmd) == -1) return
  20780. var cell = getTableItemsByRange(this).cell,
  20781. ut = getUETable(cell),
  20782. cellInfo = ut.getCellInfo(cell)
  20783. //ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex:ut.cellsRange.beginColIndex);
  20784. if (!ut.selectedTds.length) {
  20785. ut.insertCol(cellInfo.colIndex, cell)
  20786. } else {
  20787. var range = ut.cellsRange
  20788. for (
  20789. var i = 0, len = range.endColIndex - range.beginColIndex + 1;
  20790. i < len;
  20791. i++
  20792. ) {
  20793. ut.insertCol(range.beginColIndex, cell)
  20794. }
  20795. }
  20796. rng.moveToBookmark(bk).select(true)
  20797. },
  20798. }
  20799. UE.commands['insertcolnext'] = {
  20800. queryCommandState: function () {
  20801. var tableItems = getTableItemsByRange(this),
  20802. cell = tableItems.cell
  20803. return cell &&
  20804. getUETable(tableItems.table).colsNum < this.options.maxColNum
  20805. ? 0
  20806. : -1
  20807. },
  20808. execCommand: function () {
  20809. var rng = this.selection.getRange(),
  20810. bk = rng.createBookmark(true)
  20811. var cell = getTableItemsByRange(this).cell,
  20812. ut = getUETable(cell),
  20813. cellInfo = ut.getCellInfo(cell)
  20814. //ut.insertCol(!ut.selectedTds.length ? cellInfo.colIndex + cellInfo.colSpan:ut.cellsRange.endColIndex +1);
  20815. if (!ut.selectedTds.length) {
  20816. ut.insertCol(cellInfo.colIndex + cellInfo.colSpan, cell)
  20817. } else {
  20818. var range = ut.cellsRange
  20819. for (
  20820. var i = 0, len = range.endColIndex - range.beginColIndex + 1;
  20821. i < len;
  20822. i++
  20823. ) {
  20824. ut.insertCol(range.endColIndex + 1, cell)
  20825. }
  20826. }
  20827. rng.moveToBookmark(bk).select()
  20828. },
  20829. }
  20830. UE.commands['deletecol'] = {
  20831. queryCommandState: function () {
  20832. var tableItems = getTableItemsByRange(this)
  20833. return tableItems.cell ? 0 : -1
  20834. },
  20835. execCommand: function () {
  20836. var cell = getTableItemsByRange(this).cell,
  20837. ut = getUETable(cell),
  20838. range = ut.cellsRange,
  20839. cellInfo = ut.getCellInfo(cell),
  20840. preCell = ut.getHSideCell(cell),
  20841. nextCell = ut.getHSideCell(cell, true)
  20842. if (utils.isEmptyObject(range)) {
  20843. ut.deleteCol(cellInfo.colIndex)
  20844. } else {
  20845. for (var i = range.beginColIndex; i < range.endColIndex + 1; i++) {
  20846. ut.deleteCol(range.beginColIndex)
  20847. }
  20848. }
  20849. var table = ut.table,
  20850. rng = this.selection.getRange()
  20851. if (!table.getElementsByTagName('td').length) {
  20852. var nextSibling = table.nextSibling
  20853. domUtils.remove(table)
  20854. if (nextSibling) {
  20855. rng.setStart(nextSibling, 0).setCursor(false, true)
  20856. }
  20857. } else {
  20858. if (domUtils.inDoc(cell, this.document)) {
  20859. rng.setStart(cell, 0).setCursor(false, true)
  20860. } else {
  20861. if (nextCell && domUtils.inDoc(nextCell, this.document)) {
  20862. rng.selectNodeContents(nextCell).setCursor(false, true)
  20863. } else {
  20864. if (preCell && domUtils.inDoc(preCell, this.document)) {
  20865. rng.selectNodeContents(preCell).setCursor(true, true)
  20866. }
  20867. }
  20868. }
  20869. }
  20870. },
  20871. }
  20872. UE.commands['splittocells'] = {
  20873. queryCommandState: function () {
  20874. var tableItems = getTableItemsByRange(this),
  20875. cell = tableItems.cell
  20876. if (!cell) return -1
  20877. var ut = getUETable(tableItems.table)
  20878. if (ut.selectedTds.length > 0) return -1
  20879. return cell && (cell.colSpan > 1 || cell.rowSpan > 1) ? 0 : -1
  20880. },
  20881. execCommand: function () {
  20882. var rng = this.selection.getRange(),
  20883. bk = rng.createBookmark(true)
  20884. var cell = getTableItemsByRange(this).cell,
  20885. ut = getUETable(cell)
  20886. ut.splitToCells(cell)
  20887. rng.moveToBookmark(bk).select()
  20888. },
  20889. }
  20890. UE.commands['splittorows'] = {
  20891. queryCommandState: function () {
  20892. var tableItems = getTableItemsByRange(this),
  20893. cell = tableItems.cell
  20894. if (!cell) return -1
  20895. var ut = getUETable(tableItems.table)
  20896. if (ut.selectedTds.length > 0) return -1
  20897. return cell && cell.rowSpan > 1 ? 0 : -1
  20898. },
  20899. execCommand: function () {
  20900. var rng = this.selection.getRange(),
  20901. bk = rng.createBookmark(true)
  20902. var cell = getTableItemsByRange(this).cell,
  20903. ut = getUETable(cell)
  20904. ut.splitToRows(cell)
  20905. rng.moveToBookmark(bk).select()
  20906. },
  20907. }
  20908. UE.commands['splittocols'] = {
  20909. queryCommandState: function () {
  20910. var tableItems = getTableItemsByRange(this),
  20911. cell = tableItems.cell
  20912. if (!cell) return -1
  20913. var ut = getUETable(tableItems.table)
  20914. if (ut.selectedTds.length > 0) return -1
  20915. return cell && cell.colSpan > 1 ? 0 : -1
  20916. },
  20917. execCommand: function () {
  20918. var rng = this.selection.getRange(),
  20919. bk = rng.createBookmark(true)
  20920. var cell = getTableItemsByRange(this).cell,
  20921. ut = getUETable(cell)
  20922. ut.splitToCols(cell)
  20923. rng.moveToBookmark(bk).select()
  20924. },
  20925. }
  20926. UE.commands['adaptbytext'] = UE.commands['adaptbywindow'] = {
  20927. queryCommandState: function () {
  20928. return getTableItemsByRange(this).table ? 0 : -1
  20929. },
  20930. execCommand: function (cmd) {
  20931. var tableItems = getTableItemsByRange(this),
  20932. table = tableItems.table
  20933. if (table) {
  20934. if (cmd == 'adaptbywindow') {
  20935. resetTdWidth(table, this)
  20936. } else {
  20937. var cells = domUtils.getElementsByTagName(table, 'td th')
  20938. utils.each(cells, function (cell) {
  20939. cell.removeAttribute('width')
  20940. })
  20941. table.removeAttribute('width')
  20942. }
  20943. }
  20944. },
  20945. }
  20946. //平均分配各列
  20947. UE.commands['averagedistributecol'] = {
  20948. queryCommandState: function () {
  20949. var ut = getUETableBySelected(this)
  20950. if (!ut) return -1
  20951. return ut.isFullRow() || ut.isFullCol() ? 0 : -1
  20952. },
  20953. execCommand: function (cmd) {
  20954. var me = this,
  20955. ut = getUETableBySelected(me)
  20956. function getAverageWidth() {
  20957. var tb = ut.table,
  20958. averageWidth,
  20959. sumWidth = 0,
  20960. colsNum = 0,
  20961. tbAttr = getDefaultValue(me, tb)
  20962. if (ut.isFullRow()) {
  20963. sumWidth = tb.offsetWidth
  20964. colsNum = ut.colsNum
  20965. } else {
  20966. var begin = ut.cellsRange.beginColIndex,
  20967. end = ut.cellsRange.endColIndex,
  20968. node
  20969. for (var i = begin; i <= end; ) {
  20970. node = ut.selectedTds[i]
  20971. sumWidth += node.offsetWidth
  20972. i += node.colSpan
  20973. colsNum += 1
  20974. }
  20975. }
  20976. averageWidth =
  20977. Math.ceil(sumWidth / colsNum) -
  20978. tbAttr.tdBorder * 2 -
  20979. tbAttr.tdPadding * 2
  20980. return averageWidth
  20981. }
  20982. function setAverageWidth(averageWidth) {
  20983. utils.each(
  20984. domUtils.getElementsByTagName(ut.table, 'th'),
  20985. function (node) {
  20986. node.setAttribute('width', '')
  20987. }
  20988. )
  20989. var cells = ut.isFullRow()
  20990. ? domUtils.getElementsByTagName(ut.table, 'td')
  20991. : ut.selectedTds
  20992. utils.each(cells, function (node) {
  20993. if (node.colSpan == 1) {
  20994. node.setAttribute('width', averageWidth)
  20995. }
  20996. })
  20997. }
  20998. if (ut && ut.selectedTds.length) {
  20999. setAverageWidth(getAverageWidth())
  21000. }
  21001. },
  21002. }
  21003. //平均分配各行
  21004. UE.commands['averagedistributerow'] = {
  21005. queryCommandState: function () {
  21006. var ut = getUETableBySelected(this)
  21007. if (!ut) return -1
  21008. if (ut.selectedTds && /th/gi.test(ut.selectedTds[0].tagName)) return -1
  21009. return ut.isFullRow() || ut.isFullCol() ? 0 : -1
  21010. },
  21011. execCommand: function (cmd) {
  21012. var me = this,
  21013. ut = getUETableBySelected(me)
  21014. function getAverageHeight() {
  21015. var averageHeight,
  21016. rowNum,
  21017. sumHeight = 0,
  21018. tb = ut.table,
  21019. tbAttr = getDefaultValue(me, tb),
  21020. tdpadding = parseInt(
  21021. domUtils.getComputedStyle(
  21022. tb.getElementsByTagName('td')[0],
  21023. 'padding-top'
  21024. )
  21025. )
  21026. if (ut.isFullCol()) {
  21027. var captionArr = domUtils.getElementsByTagName(tb, 'caption'),
  21028. thArr = domUtils.getElementsByTagName(tb, 'th'),
  21029. captionHeight,
  21030. thHeight
  21031. if (captionArr.length > 0) {
  21032. captionHeight = captionArr[0].offsetHeight
  21033. }
  21034. if (thArr.length > 0) {
  21035. thHeight = thArr[0].offsetHeight
  21036. }
  21037. sumHeight = tb.offsetHeight - (captionHeight || 0) - (thHeight || 0)
  21038. rowNum = thArr.length == 0 ? ut.rowsNum : ut.rowsNum - 1
  21039. } else {
  21040. var begin = ut.cellsRange.beginRowIndex,
  21041. end = ut.cellsRange.endRowIndex,
  21042. count = 0,
  21043. trs = domUtils.getElementsByTagName(tb, 'tr')
  21044. for (var i = begin; i <= end; i++) {
  21045. sumHeight += trs[i].offsetHeight
  21046. count += 1
  21047. }
  21048. rowNum = count
  21049. }
  21050. //ie8下是混杂模式
  21051. if (browser.ie && browser.version < 9) {
  21052. averageHeight = Math.ceil(sumHeight / rowNum)
  21053. } else {
  21054. averageHeight =
  21055. Math.ceil(sumHeight / rowNum) -
  21056. tbAttr.tdBorder * 2 -
  21057. tdpadding * 2
  21058. }
  21059. return averageHeight
  21060. }
  21061. function setAverageHeight(averageHeight) {
  21062. var cells = ut.isFullCol()
  21063. ? domUtils.getElementsByTagName(ut.table, 'td')
  21064. : ut.selectedTds
  21065. utils.each(cells, function (node) {
  21066. if (node.rowSpan == 1) {
  21067. node.setAttribute('height', averageHeight)
  21068. }
  21069. })
  21070. }
  21071. if (ut && ut.selectedTds.length) {
  21072. setAverageHeight(getAverageHeight())
  21073. }
  21074. },
  21075. }
  21076. //单元格对齐方式
  21077. UE.commands['cellalignment'] = {
  21078. queryCommandState: function () {
  21079. return getTableItemsByRange(this).table ? 0 : -1
  21080. },
  21081. execCommand: function (cmd, data) {
  21082. var me = this,
  21083. ut = getUETableBySelected(me)
  21084. if (!ut) {
  21085. var start = me.selection.getStart(),
  21086. cell =
  21087. start &&
  21088. domUtils.findParentByTagName(start, ['td', 'th', 'caption'], true)
  21089. if (!/caption/gi.test(cell.tagName)) {
  21090. domUtils.setAttributes(cell, data)
  21091. } else {
  21092. cell.style.textAlign = data.align
  21093. cell.style.verticalAlign = data.vAlign
  21094. }
  21095. me.selection.getRange().setCursor(true)
  21096. } else {
  21097. utils.each(ut.selectedTds, function (cell) {
  21098. domUtils.setAttributes(cell, data)
  21099. })
  21100. }
  21101. },
  21102. /**
  21103. * 查询当前点击的单元格的对齐状态, 如果当前已经选择了多个单元格, 则会返回所有单元格经过统一协调过后的状态
  21104. * @see UE.UETable.getTableCellAlignState
  21105. */
  21106. queryCommandValue: function (cmd) {
  21107. var activeMenuCell = getTableItemsByRange(this).cell
  21108. if (!activeMenuCell) {
  21109. activeMenuCell = getSelectedArr(this)[0]
  21110. }
  21111. if (!activeMenuCell) {
  21112. return null
  21113. } else {
  21114. //获取同时选中的其他单元格
  21115. var cells = UE.UETable.getUETable(activeMenuCell).selectedTds
  21116. !cells.length && (cells = activeMenuCell)
  21117. return UE.UETable.getTableCellAlignState(cells)
  21118. }
  21119. },
  21120. }
  21121. //表格对齐方式
  21122. UE.commands['tablealignment'] = {
  21123. queryCommandState: function () {
  21124. if (browser.ie && browser.version < 8) {
  21125. return -1
  21126. }
  21127. return getTableItemsByRange(this).table ? 0 : -1
  21128. },
  21129. execCommand: function (cmd, value) {
  21130. var me = this,
  21131. start = me.selection.getStart(),
  21132. table = start && domUtils.findParentByTagName(start, ['table'], true)
  21133. if (table) {
  21134. table.setAttribute('align', value)
  21135. }
  21136. },
  21137. }
  21138. //表格属性
  21139. UE.commands['edittable'] = {
  21140. queryCommandState: function () {
  21141. return getTableItemsByRange(this).table ? 0 : -1
  21142. },
  21143. execCommand: function (cmd, color) {
  21144. var rng = this.selection.getRange(),
  21145. table = domUtils.findParentByTagName(rng.startContainer, 'table')
  21146. if (table) {
  21147. var arr = domUtils
  21148. .getElementsByTagName(table, 'td')
  21149. .concat(
  21150. domUtils.getElementsByTagName(table, 'th'),
  21151. domUtils.getElementsByTagName(table, 'caption')
  21152. )
  21153. utils.each(arr, function (node) {
  21154. node.style.borderColor = color
  21155. })
  21156. }
  21157. },
  21158. }
  21159. //单元格属性
  21160. UE.commands['edittd'] = {
  21161. queryCommandState: function () {
  21162. return getTableItemsByRange(this).table ? 0 : -1
  21163. },
  21164. execCommand: function (cmd, bkColor) {
  21165. var me = this,
  21166. ut = getUETableBySelected(me)
  21167. if (!ut) {
  21168. var start = me.selection.getStart(),
  21169. cell =
  21170. start &&
  21171. domUtils.findParentByTagName(start, ['td', 'th', 'caption'], true)
  21172. if (cell) {
  21173. cell.style.backgroundColor = bkColor
  21174. }
  21175. } else {
  21176. utils.each(ut.selectedTds, function (cell) {
  21177. cell.style.backgroundColor = bkColor
  21178. })
  21179. }
  21180. },
  21181. }
  21182. UE.commands['settablebackground'] = {
  21183. queryCommandState: function () {
  21184. return getSelectedArr(this).length > 1 ? 0 : -1
  21185. },
  21186. execCommand: function (cmd, value) {
  21187. var cells, ut
  21188. cells = getSelectedArr(this)
  21189. ut = getUETable(cells[0])
  21190. ut.setBackground(cells, value)
  21191. },
  21192. }
  21193. UE.commands['cleartablebackground'] = {
  21194. queryCommandState: function () {
  21195. var cells = getSelectedArr(this)
  21196. if (!cells.length) return -1
  21197. for (var i = 0, cell; (cell = cells[i++]); ) {
  21198. if (cell.style.backgroundColor !== '') return 0
  21199. }
  21200. return -1
  21201. },
  21202. execCommand: function () {
  21203. var cells = getSelectedArr(this),
  21204. ut = getUETable(cells[0])
  21205. ut.removeBackground(cells)
  21206. },
  21207. }
  21208. UE.commands['interlacetable'] = UE.commands['uninterlacetable'] = {
  21209. queryCommandState: function (cmd) {
  21210. var table = getTableItemsByRange(this).table
  21211. if (!table) return -1
  21212. var interlaced = table.getAttribute('interlaced')
  21213. if (cmd == 'interlacetable') {
  21214. //TODO 待定
  21215. //是否需要待定,如果设置,则命令只能单次执行成功,但反射具备toggle效果;否则可以覆盖前次命令,但反射将不存在toggle效果
  21216. return interlaced === 'enabled' ? -1 : 0
  21217. } else {
  21218. return !interlaced || interlaced === 'disabled' ? -1 : 0
  21219. }
  21220. },
  21221. execCommand: function (cmd, classList) {
  21222. var table = getTableItemsByRange(this).table
  21223. if (cmd == 'interlacetable') {
  21224. table.setAttribute('interlaced', 'enabled')
  21225. this.fireEvent('interlacetable', table, classList)
  21226. } else {
  21227. table.setAttribute('interlaced', 'disabled')
  21228. this.fireEvent('uninterlacetable', table)
  21229. }
  21230. },
  21231. }
  21232. UE.commands['setbordervisible'] = {
  21233. queryCommandState: function (cmd) {
  21234. var table = getTableItemsByRange(this).table
  21235. if (!table) return -1
  21236. return 0
  21237. },
  21238. execCommand: function () {
  21239. var table = getTableItemsByRange(this).table
  21240. utils.each(domUtils.getElementsByTagName(table, 'td'), function (td) {
  21241. td.style.borderWidth = '1px'
  21242. td.style.borderStyle = 'solid'
  21243. })
  21244. },
  21245. }
  21246. function resetTdWidth(table, editor) {
  21247. var tds = domUtils.getElementsByTagName(table, 'td th')
  21248. utils.each(tds, function (td) {
  21249. td.removeAttribute('width')
  21250. })
  21251. table.setAttribute(
  21252. 'width',
  21253. getTableWidth(editor, true, getDefaultValue(editor, table))
  21254. )
  21255. var tdsWidths = []
  21256. setTimeout(function () {
  21257. utils.each(tds, function (td) {
  21258. td.colSpan == 1 && tdsWidths.push(td.offsetWidth)
  21259. })
  21260. utils.each(tds, function (td, i) {
  21261. td.colSpan == 1 && td.setAttribute('width', tdsWidths[i] + '')
  21262. })
  21263. }, 0)
  21264. }
  21265. function getTableWidth(editor, needIEHack, defaultValue) {
  21266. var body = editor.body
  21267. return (
  21268. body.offsetWidth -
  21269. (needIEHack
  21270. ? parseInt(domUtils.getComputedStyle(body, 'margin-left'), 10) * 2
  21271. : 0) -
  21272. defaultValue.tableBorder * 2 -
  21273. (editor.options.offsetWidth || 0)
  21274. )
  21275. }
  21276. function getSelectedArr(editor) {
  21277. var cell = getTableItemsByRange(editor).cell
  21278. if (cell) {
  21279. var ut = getUETable(cell)
  21280. return ut.selectedTds.length ? ut.selectedTds : [cell]
  21281. } else {
  21282. return []
  21283. }
  21284. }
  21285. })()
  21286. // plugins/table.action.js
  21287. /**
  21288. * Created with JetBrains PhpStorm.
  21289. * User: taoqili
  21290. * Date: 12-10-12
  21291. * Time: 上午10:05
  21292. * To change this template use File | Settings | File Templates.
  21293. */
  21294. UE.plugins['table'] = function () {
  21295. var me = this,
  21296. tabTimer = null,
  21297. //拖动计时器
  21298. tableDragTimer = null,
  21299. //双击计时器
  21300. tableResizeTimer = null,
  21301. //单元格最小宽度
  21302. cellMinWidth = 5,
  21303. isInResizeBuffer = false,
  21304. //单元格边框大小
  21305. cellBorderWidth = 5,
  21306. //鼠标偏移距离
  21307. offsetOfTableCell = 10,
  21308. //记录在有限时间内的点击状态, 共有3个取值, 0, 1, 2。 0代表未初始化, 1代表单击了1次,2代表2次
  21309. singleClickState = 0,
  21310. userActionStatus = null,
  21311. //双击允许的时间范围
  21312. dblclickTime = 360,
  21313. UT = UE.UETable,
  21314. getUETable = function (tdOrTable) {
  21315. return UT.getUETable(tdOrTable)
  21316. },
  21317. getUETableBySelected = function (editor) {
  21318. return UT.getUETableBySelected(editor)
  21319. },
  21320. getDefaultValue = function (editor, table) {
  21321. return UT.getDefaultValue(editor, table)
  21322. },
  21323. removeSelectedClass = function (cells) {
  21324. return UT.removeSelectedClass(cells)
  21325. }
  21326. function showError(e) {
  21327. // throw e;
  21328. }
  21329. me.ready(function () {
  21330. var me = this
  21331. var orgGetText = me.selection.getText
  21332. me.selection.getText = function () {
  21333. var table = getUETableBySelected(me)
  21334. if (table) {
  21335. var str = ''
  21336. utils.each(table.selectedTds, function (td) {
  21337. str += td[browser.ie ? 'innerText' : 'textContent']
  21338. })
  21339. return str
  21340. } else {
  21341. return orgGetText.call(me.selection)
  21342. }
  21343. }
  21344. })
  21345. //处理拖动及框选相关方法
  21346. var startTd = null, //鼠标按下时的锚点td
  21347. currentTd = null, //当前鼠标经过时的td
  21348. onDrag = '', //指示当前拖动状态,其值可为"","h","v" ,分别表示未拖动状态,横向拖动状态,纵向拖动状态,用于鼠标移动过程中的判断
  21349. onBorder = false, //检测鼠标按下时是否处在单元格边缘位置
  21350. dragButton = null,
  21351. dragOver = false,
  21352. dragLine = null, //模拟的拖动线
  21353. dragTd = null //发生拖动的目标td
  21354. var mousedown = false,
  21355. //todo 判断混乱模式
  21356. needIEHack = true
  21357. me.setOpt({
  21358. maxColNum: 20,
  21359. maxRowNum: 100,
  21360. defaultCols: 5,
  21361. defaultRows: 5,
  21362. tdvalign: 'top',
  21363. cursorpath: me.options.UEDITOR_HOME_URL + 'themes/default/images/cursor_',
  21364. tableDragable: false,
  21365. classList: [
  21366. 'ue-table-interlace-color-single',
  21367. 'ue-table-interlace-color-double',
  21368. ],
  21369. })
  21370. me.getUETable = getUETable
  21371. var commands = {
  21372. deletetable: 1,
  21373. inserttable: 1,
  21374. cellvalign: 1,
  21375. insertcaption: 1,
  21376. deletecaption: 1,
  21377. inserttitle: 1,
  21378. deletetitle: 1,
  21379. mergeright: 1,
  21380. mergedown: 1,
  21381. mergecells: 1,
  21382. insertrow: 1,
  21383. insertrownext: 1,
  21384. deleterow: 1,
  21385. insertcol: 1,
  21386. insertcolnext: 1,
  21387. deletecol: 1,
  21388. splittocells: 1,
  21389. splittorows: 1,
  21390. splittocols: 1,
  21391. adaptbytext: 1,
  21392. adaptbywindow: 1,
  21393. adaptbycustomer: 1,
  21394. insertparagraph: 1,
  21395. insertparagraphbeforetable: 1,
  21396. averagedistributecol: 1,
  21397. averagedistributerow: 1,
  21398. }
  21399. me.ready(function () {
  21400. utils.cssRule(
  21401. 'table',
  21402. //选中的td上的样式
  21403. '.selectTdClass{background-color:#edf5fa !important}' +
  21404. 'table.noBorderTable td,table.noBorderTable th,table.noBorderTable caption{border:1px dashed #ddd !important}' +
  21405. //插入的表格的默认样式
  21406. 'table{margin-bottom:10px;border-collapse:collapse;display:table;}' +
  21407. 'td,th{padding: 5px 10px;border: 1px solid #DDD;}' +
  21408. 'caption{border:1px dashed #DDD;border-bottom:0;padding:3px;text-align:center;}' +
  21409. 'th{border-top:1px solid #BBB;background-color:#F7F7F7;}' +
  21410. 'table tr.firstRow th{border-top-width:2px;}' +
  21411. '.ue-table-interlace-color-single{ background-color: #fcfcfc; } .ue-table-interlace-color-double{ background-color: #f7faff; }' +
  21412. 'td p{margin:0;padding:0;}',
  21413. me.document
  21414. )
  21415. var tableCopyList, isFullCol, isFullRow
  21416. //注册del/backspace事件
  21417. me.addListener('keydown', function (cmd, evt) {
  21418. var me = this
  21419. var keyCode = evt.keyCode || evt.which
  21420. if (keyCode == 8) {
  21421. var ut = getUETableBySelected(me)
  21422. if (ut && ut.selectedTds.length) {
  21423. if (ut.isFullCol()) {
  21424. me.execCommand('deletecol')
  21425. } else if (ut.isFullRow()) {
  21426. me.execCommand('deleterow')
  21427. } else {
  21428. me.fireEvent('delcells')
  21429. }
  21430. domUtils.preventDefault(evt)
  21431. }
  21432. var caption = domUtils.findParentByTagName(
  21433. me.selection.getStart(),
  21434. 'caption',
  21435. true
  21436. ),
  21437. range = me.selection.getRange()
  21438. if (range.collapsed && caption && isEmptyBlock(caption)) {
  21439. me.fireEvent('saveScene')
  21440. var table = caption.parentNode
  21441. domUtils.remove(caption)
  21442. if (table) {
  21443. range.setStart(table.rows[0].cells[0], 0).setCursor(false, true)
  21444. }
  21445. me.fireEvent('saveScene')
  21446. }
  21447. }
  21448. if (keyCode == 46) {
  21449. ut = getUETableBySelected(me)
  21450. if (ut) {
  21451. me.fireEvent('saveScene')
  21452. for (var i = 0, ci; (ci = ut.selectedTds[i++]); ) {
  21453. domUtils.fillNode(me.document, ci)
  21454. }
  21455. me.fireEvent('saveScene')
  21456. domUtils.preventDefault(evt)
  21457. }
  21458. }
  21459. if (keyCode == 13) {
  21460. var rng = me.selection.getRange(),
  21461. caption = domUtils.findParentByTagName(
  21462. rng.startContainer,
  21463. 'caption',
  21464. true
  21465. )
  21466. if (caption) {
  21467. var table = domUtils.findParentByTagName(caption, 'table')
  21468. if (!rng.collapsed) {
  21469. rng.deleteContents()
  21470. me.fireEvent('saveScene')
  21471. } else {
  21472. if (caption) {
  21473. rng.setStart(table.rows[0].cells[0], 0).setCursor(false, true)
  21474. }
  21475. }
  21476. domUtils.preventDefault(evt)
  21477. return
  21478. }
  21479. if (rng.collapsed) {
  21480. var table = domUtils.findParentByTagName(
  21481. rng.startContainer,
  21482. 'table'
  21483. )
  21484. if (table) {
  21485. var cell = table.rows[0].cells[0],
  21486. start = domUtils.findParentByTagName(
  21487. me.selection.getStart(),
  21488. ['td', 'th'],
  21489. true
  21490. ),
  21491. preNode = table.previousSibling
  21492. if (
  21493. cell === start &&
  21494. (!preNode ||
  21495. (preNode.nodeType == 1 && preNode.tagName == 'TABLE')) &&
  21496. domUtils.isStartInblock(rng)
  21497. ) {
  21498. var first = domUtils.findParent(
  21499. me.selection.getStart(),
  21500. function (n) {
  21501. return domUtils.isBlockElm(n)
  21502. },
  21503. true
  21504. )
  21505. if (
  21506. first &&
  21507. (/t(h|d)/i.test(first.tagName) || first === start.firstChild)
  21508. ) {
  21509. me.execCommand('insertparagraphbeforetable')
  21510. domUtils.preventDefault(evt)
  21511. }
  21512. }
  21513. }
  21514. }
  21515. }
  21516. if ((evt.ctrlKey || evt.metaKey) && evt.keyCode == '67') {
  21517. tableCopyList = null
  21518. var ut = getUETableBySelected(me)
  21519. if (ut) {
  21520. var tds = ut.selectedTds
  21521. isFullCol = ut.isFullCol()
  21522. isFullRow = ut.isFullRow()
  21523. tableCopyList = [[ut.cloneCell(tds[0], null, true)]]
  21524. for (var i = 1, ci; (ci = tds[i]); i++) {
  21525. if (ci.parentNode !== tds[i - 1].parentNode) {
  21526. tableCopyList.push([ut.cloneCell(ci, null, true)])
  21527. } else {
  21528. tableCopyList[tableCopyList.length - 1].push(
  21529. ut.cloneCell(ci, null, true)
  21530. )
  21531. }
  21532. }
  21533. }
  21534. }
  21535. })
  21536. me.addListener('tablehasdeleted', function () {
  21537. toggleDraggableState(this, false, '', null)
  21538. if (dragButton) domUtils.remove(dragButton)
  21539. })
  21540. me.addListener('beforepaste', function (cmd, html) {
  21541. var me = this
  21542. var rng = me.selection.getRange()
  21543. if (domUtils.findParentByTagName(rng.startContainer, 'caption', true)) {
  21544. var div = me.document.createElement('div')
  21545. div.innerHTML = html.html
  21546. //trace:3729
  21547. html.html = div[browser.ie9below ? 'innerText' : 'textContent']
  21548. return
  21549. }
  21550. var table = getUETableBySelected(me)
  21551. if (tableCopyList) {
  21552. me.fireEvent('saveScene')
  21553. var rng = me.selection.getRange()
  21554. var td = domUtils.findParentByTagName(
  21555. rng.startContainer,
  21556. ['td', 'th'],
  21557. true
  21558. ),
  21559. tmpNode,
  21560. preNode
  21561. if (td) {
  21562. var ut = getUETable(td)
  21563. if (isFullRow) {
  21564. var rowIndex = ut.getCellInfo(td).rowIndex
  21565. if (td.tagName == 'TH') {
  21566. rowIndex++
  21567. }
  21568. for (var i = 0, ci; (ci = tableCopyList[i++]); ) {
  21569. var tr = ut.insertRow(rowIndex++, 'td')
  21570. for (var j = 0, cj; (cj = ci[j]); j++) {
  21571. var cell = tr.cells[j]
  21572. if (!cell) {
  21573. cell = tr.insertCell(j)
  21574. }
  21575. cell.innerHTML = cj.innerHTML
  21576. cj.getAttribute('width') &&
  21577. cell.setAttribute('width', cj.getAttribute('width'))
  21578. cj.getAttribute('vAlign') &&
  21579. cell.setAttribute('vAlign', cj.getAttribute('vAlign'))
  21580. cj.getAttribute('align') &&
  21581. cell.setAttribute('align', cj.getAttribute('align'))
  21582. cj.style.cssText && (cell.style.cssText = cj.style.cssText)
  21583. }
  21584. for (var j = 0, cj; (cj = tr.cells[j]); j++) {
  21585. if (!ci[j]) break
  21586. cj.innerHTML = ci[j].innerHTML
  21587. ci[j].getAttribute('width') &&
  21588. cj.setAttribute('width', ci[j].getAttribute('width'))
  21589. ci[j].getAttribute('vAlign') &&
  21590. cj.setAttribute('vAlign', ci[j].getAttribute('vAlign'))
  21591. ci[j].getAttribute('align') &&
  21592. cj.setAttribute('align', ci[j].getAttribute('align'))
  21593. ci[j].style.cssText &&
  21594. (cj.style.cssText = ci[j].style.cssText)
  21595. }
  21596. }
  21597. } else {
  21598. if (isFullCol) {
  21599. cellInfo = ut.getCellInfo(td)
  21600. var maxColNum = 0
  21601. for (var j = 0, ci = tableCopyList[0], cj; (cj = ci[j++]); ) {
  21602. maxColNum += cj.colSpan || 1
  21603. }
  21604. me.__hasEnterExecCommand = true
  21605. for (i = 0; i < maxColNum; i++) {
  21606. me.execCommand('insertcol')
  21607. }
  21608. me.__hasEnterExecCommand = false
  21609. td = ut.table.rows[0].cells[cellInfo.cellIndex]
  21610. if (td.tagName == 'TH') {
  21611. td = ut.table.rows[1].cells[cellInfo.cellIndex]
  21612. }
  21613. }
  21614. for (var i = 0, ci; (ci = tableCopyList[i++]); ) {
  21615. tmpNode = td
  21616. for (var j = 0, cj; (cj = ci[j++]); ) {
  21617. if (td) {
  21618. td.innerHTML = cj.innerHTML
  21619. //todo 定制处理
  21620. cj.getAttribute('width') &&
  21621. td.setAttribute('width', cj.getAttribute('width'))
  21622. cj.getAttribute('vAlign') &&
  21623. td.setAttribute('vAlign', cj.getAttribute('vAlign'))
  21624. cj.getAttribute('align') &&
  21625. td.setAttribute('align', cj.getAttribute('align'))
  21626. cj.style.cssText && (td.style.cssText = cj.style.cssText)
  21627. preNode = td
  21628. td = td.nextSibling
  21629. } else {
  21630. var cloneTd = cj.cloneNode(true)
  21631. domUtils.removeAttributes(cloneTd, [
  21632. 'class',
  21633. 'rowSpan',
  21634. 'colSpan',
  21635. ])
  21636. preNode.parentNode.appendChild(cloneTd)
  21637. }
  21638. }
  21639. td = ut.getNextCell(tmpNode, true, true)
  21640. if (!tableCopyList[i]) break
  21641. if (!td) {
  21642. var cellInfo = ut.getCellInfo(tmpNode)
  21643. ut.table.insertRow(ut.table.rows.length)
  21644. ut.update()
  21645. td = ut.getVSideCell(tmpNode, true)
  21646. }
  21647. }
  21648. }
  21649. ut.update()
  21650. } else {
  21651. table = me.document.createElement('table')
  21652. for (var i = 0, ci; (ci = tableCopyList[i++]); ) {
  21653. var tr = table.insertRow(table.rows.length)
  21654. for (var j = 0, cj; (cj = ci[j++]); ) {
  21655. cloneTd = UT.cloneCell(cj, null, true)
  21656. domUtils.removeAttributes(cloneTd, ['class'])
  21657. tr.appendChild(cloneTd)
  21658. }
  21659. if (j == 2 && cloneTd.rowSpan > 1) {
  21660. cloneTd.rowSpan = 1
  21661. }
  21662. }
  21663. var defaultValue = getDefaultValue(me),
  21664. width =
  21665. me.body.offsetWidth -
  21666. (needIEHack
  21667. ? parseInt(
  21668. domUtils.getComputedStyle(me.body, 'margin-left'),
  21669. 10
  21670. ) * 2
  21671. : 0) -
  21672. defaultValue.tableBorder * 2 -
  21673. (me.options.offsetWidth || 0)
  21674. me.execCommand(
  21675. 'insertHTML',
  21676. '<table ' +
  21677. (isFullCol && isFullRow ? 'width="' + width + '"' : '') +
  21678. '>' +
  21679. table.innerHTML
  21680. .replace(/>\s*</g, '><')
  21681. .replace(/\bth\b/gi, 'td') +
  21682. '</table>'
  21683. )
  21684. }
  21685. me.fireEvent('contentchange')
  21686. me.fireEvent('saveScene')
  21687. html.html = ''
  21688. return true
  21689. } else {
  21690. var div = me.document.createElement('div'),
  21691. tables
  21692. div.innerHTML = html.html
  21693. tables = div.getElementsByTagName('table')
  21694. if (domUtils.findParentByTagName(me.selection.getStart(), 'table')) {
  21695. utils.each(tables, function (t) {
  21696. domUtils.remove(t)
  21697. })
  21698. if (
  21699. domUtils.findParentByTagName(
  21700. me.selection.getStart(),
  21701. 'caption',
  21702. true
  21703. )
  21704. ) {
  21705. div.innerHTML = div[browser.ie ? 'innerText' : 'textContent']
  21706. }
  21707. } else {
  21708. utils.each(tables, function (table) {
  21709. removeStyleSize(table, true)
  21710. domUtils.removeAttributes(table, ['style', 'border'])
  21711. utils.each(
  21712. domUtils.getElementsByTagName(table, 'td'),
  21713. function (td) {
  21714. if (isEmptyBlock(td)) {
  21715. domUtils.fillNode(me.document, td)
  21716. }
  21717. removeStyleSize(td, true)
  21718. // domUtils.removeAttributes(td, ['style'])
  21719. }
  21720. )
  21721. })
  21722. }
  21723. html.html = div.innerHTML
  21724. }
  21725. })
  21726. me.addListener('afterpaste', function () {
  21727. utils.each(
  21728. domUtils.getElementsByTagName(me.body, 'table'),
  21729. function (table) {
  21730. if (table.offsetWidth > me.body.offsetWidth) {
  21731. var defaultValue = getDefaultValue(me, table)
  21732. table.style.width =
  21733. me.body.offsetWidth -
  21734. (needIEHack
  21735. ? parseInt(
  21736. domUtils.getComputedStyle(me.body, 'margin-left'),
  21737. 10
  21738. ) * 2
  21739. : 0) -
  21740. defaultValue.tableBorder * 2 -
  21741. (me.options.offsetWidth || 0) +
  21742. 'px'
  21743. }
  21744. }
  21745. )
  21746. })
  21747. me.addListener('blur', function () {
  21748. tableCopyList = null
  21749. })
  21750. var timer
  21751. me.addListener('keydown', function () {
  21752. clearTimeout(timer)
  21753. timer = setTimeout(function () {
  21754. var rng = me.selection.getRange(),
  21755. cell = domUtils.findParentByTagName(
  21756. rng.startContainer,
  21757. ['th', 'td'],
  21758. true
  21759. )
  21760. if (cell) {
  21761. var table = cell.parentNode.parentNode.parentNode
  21762. if (table.offsetWidth > table.getAttribute('width')) {
  21763. cell.style.wordBreak = 'break-all'
  21764. }
  21765. }
  21766. }, 100)
  21767. })
  21768. me.addListener('selectionchange', function () {
  21769. toggleDraggableState(me, false, '', null)
  21770. })
  21771. //内容变化时触发索引更新
  21772. //todo 可否考虑标记检测,如果不涉及表格的变化就不进行索引重建和更新
  21773. me.addListener('contentchange', function () {
  21774. var me = this
  21775. //尽可能排除一些不需要更新的状况
  21776. hideDragLine(me)
  21777. if (getUETableBySelected(me)) return
  21778. var rng = me.selection.getRange()
  21779. var start = rng.startContainer
  21780. start = domUtils.findParentByTagName(start, ['td', 'th'], true)
  21781. utils.each(
  21782. domUtils.getElementsByTagName(me.document, 'table'),
  21783. function (table) {
  21784. if (me.fireEvent('excludetable', table) === true) return
  21785. table.ueTable = new UT(table)
  21786. //trace:3742
  21787. // utils.each(domUtils.getElementsByTagName(me.document, 'td'), function (td) {
  21788. //
  21789. // if (domUtils.isEmptyBlock(td) && td !== start) {
  21790. // domUtils.fillNode(me.document, td);
  21791. // if (browser.ie && browser.version == 6) {
  21792. // td.innerHTML = '&nbsp;'
  21793. // }
  21794. // }
  21795. // });
  21796. // utils.each(domUtils.getElementsByTagName(me.document, 'th'), function (th) {
  21797. // if (domUtils.isEmptyBlock(th) && th !== start) {
  21798. // domUtils.fillNode(me.document, th);
  21799. // if (browser.ie && browser.version == 6) {
  21800. // th.innerHTML = '&nbsp;'
  21801. // }
  21802. // }
  21803. // });
  21804. table.onmouseover = function () {
  21805. me.fireEvent('tablemouseover', table)
  21806. }
  21807. table.onmousemove = function () {
  21808. me.fireEvent('tablemousemove', table)
  21809. me.options.tableDragable && toggleDragButton(true, this, me)
  21810. utils.defer(function () {
  21811. me.fireEvent('contentchange', 50)
  21812. }, true)
  21813. }
  21814. table.onmouseout = function () {
  21815. me.fireEvent('tablemouseout', table)
  21816. toggleDraggableState(me, false, '', null)
  21817. hideDragLine(me)
  21818. }
  21819. table.onclick = function (evt) {
  21820. evt = me.window.event || evt
  21821. var target = getParentTdOrTh(evt.target || evt.srcElement)
  21822. if (!target) return
  21823. var ut = getUETable(target),
  21824. table = ut.table,
  21825. cellInfo = ut.getCellInfo(target),
  21826. cellsRange,
  21827. rng = me.selection.getRange()
  21828. // if ("topLeft" == inPosition(table, mouseCoords(evt))) {
  21829. // cellsRange = ut.getCellsRange(ut.table.rows[0].cells[0], ut.getLastCell());
  21830. // ut.setSelected(cellsRange);
  21831. // return;
  21832. // }
  21833. // if ("bottomRight" == inPosition(table, mouseCoords(evt))) {
  21834. //
  21835. // return;
  21836. // }
  21837. if (inTableSide(table, target, evt, true)) {
  21838. var endTdCol = ut.getCell(
  21839. ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].rowIndex,
  21840. ut.indexTable[ut.rowsNum - 1][cellInfo.colIndex].cellIndex
  21841. )
  21842. if (evt.shiftKey && ut.selectedTds.length) {
  21843. if (ut.selectedTds[0] !== endTdCol) {
  21844. cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdCol)
  21845. ut.setSelected(cellsRange)
  21846. } else {
  21847. rng && rng.selectNodeContents(endTdCol).select()
  21848. }
  21849. } else {
  21850. if (target !== endTdCol) {
  21851. cellsRange = ut.getCellsRange(target, endTdCol)
  21852. ut.setSelected(cellsRange)
  21853. } else {
  21854. rng && rng.selectNodeContents(endTdCol).select()
  21855. }
  21856. }
  21857. return
  21858. }
  21859. if (inTableSide(table, target, evt)) {
  21860. var endTdRow = ut.getCell(
  21861. ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].rowIndex,
  21862. ut.indexTable[cellInfo.rowIndex][ut.colsNum - 1].cellIndex
  21863. )
  21864. if (evt.shiftKey && ut.selectedTds.length) {
  21865. if (ut.selectedTds[0] !== endTdRow) {
  21866. cellsRange = ut.getCellsRange(ut.selectedTds[0], endTdRow)
  21867. ut.setSelected(cellsRange)
  21868. } else {
  21869. rng && rng.selectNodeContents(endTdRow).select()
  21870. }
  21871. } else {
  21872. if (target !== endTdRow) {
  21873. cellsRange = ut.getCellsRange(target, endTdRow)
  21874. ut.setSelected(cellsRange)
  21875. } else {
  21876. rng && rng.selectNodeContents(endTdRow).select()
  21877. }
  21878. }
  21879. }
  21880. }
  21881. }
  21882. )
  21883. switchBorderColor(me, true)
  21884. })
  21885. domUtils.on(me.document, 'mousemove', mouseMoveEvent)
  21886. domUtils.on(me.document, 'mouseout', function (evt) {
  21887. var target = evt.target || evt.srcElement
  21888. if (target.tagName == 'TABLE') {
  21889. toggleDraggableState(me, false, '', null)
  21890. }
  21891. })
  21892. /**
  21893. * 表格隔行变色
  21894. */
  21895. me.addListener('interlacetable', function (type, table, classList) {
  21896. if (!table) return
  21897. var me = this,
  21898. rows = table.rows,
  21899. len = rows.length,
  21900. getClass = function (list, index, repeat) {
  21901. return list[index]
  21902. ? list[index]
  21903. : repeat
  21904. ? list[index % list.length]
  21905. : ''
  21906. }
  21907. for (var i = 0; i < len; i++) {
  21908. rows[i].className = getClass(
  21909. classList || me.options.classList,
  21910. i,
  21911. true
  21912. )
  21913. }
  21914. })
  21915. me.addListener('uninterlacetable', function (type, table) {
  21916. if (!table) return
  21917. var me = this,
  21918. rows = table.rows,
  21919. classList = me.options.classList,
  21920. len = rows.length
  21921. for (var i = 0; i < len; i++) {
  21922. domUtils.removeClasses(rows[i], classList)
  21923. }
  21924. })
  21925. me.addListener('mousedown', mouseDownEvent)
  21926. me.addListener('mouseup', mouseUpEvent)
  21927. //拖动的时候触发mouseup
  21928. domUtils.on(me.body, 'dragstart', function (evt) {
  21929. mouseUpEvent.call(me, 'dragstart', evt)
  21930. })
  21931. me.addOutputRule(function (root) {
  21932. utils.each(root.getNodesByTagName('div'), function (n) {
  21933. if (n.getAttr('id') == 'ue_tableDragLine') {
  21934. n.parentNode.removeChild(n)
  21935. }
  21936. })
  21937. })
  21938. var currentRowIndex = 0
  21939. me.addListener('mousedown', function () {
  21940. currentRowIndex = 0
  21941. })
  21942. me.addListener('tabkeydown', function () {
  21943. var range = this.selection.getRange(),
  21944. common = range.getCommonAncestor(true, true),
  21945. table = domUtils.findParentByTagName(common, 'table')
  21946. if (table) {
  21947. if (domUtils.findParentByTagName(common, 'caption', true)) {
  21948. var cell = domUtils.getElementsByTagName(table, 'th td')
  21949. if (cell && cell.length) {
  21950. range.setStart(cell[0], 0).setCursor(false, true)
  21951. }
  21952. } else {
  21953. var cell = domUtils.findParentByTagName(common, ['td', 'th'], true),
  21954. ua = getUETable(cell)
  21955. currentRowIndex =
  21956. cell.rowSpan > 1 ? currentRowIndex : ua.getCellInfo(cell).rowIndex
  21957. var nextCell = ua.getTabNextCell(cell, currentRowIndex)
  21958. if (nextCell) {
  21959. if (isEmptyBlock(nextCell)) {
  21960. range.setStart(nextCell, 0).setCursor(false, true)
  21961. } else {
  21962. range.selectNodeContents(nextCell).select()
  21963. }
  21964. } else {
  21965. me.fireEvent('saveScene')
  21966. me.__hasEnterExecCommand = true
  21967. this.execCommand('insertrownext')
  21968. me.__hasEnterExecCommand = false
  21969. range = this.selection.getRange()
  21970. range
  21971. .setStart(table.rows[table.rows.length - 1].cells[0], 0)
  21972. .setCursor()
  21973. me.fireEvent('saveScene')
  21974. }
  21975. }
  21976. return true
  21977. }
  21978. })
  21979. browser.ie &&
  21980. me.addListener('selectionchange', function () {
  21981. toggleDraggableState(this, false, '', null)
  21982. })
  21983. me.addListener('keydown', function (type, evt) {
  21984. var me = this
  21985. //处理在表格的最后一个输入tab产生新的表格
  21986. var keyCode = evt.keyCode || evt.which
  21987. if (keyCode == 8 || keyCode == 46) {
  21988. return
  21989. }
  21990. var notCtrlKey =
  21991. !evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey
  21992. notCtrlKey &&
  21993. removeSelectedClass(domUtils.getElementsByTagName(me.body, 'td'))
  21994. var ut = getUETableBySelected(me)
  21995. if (!ut) return
  21996. notCtrlKey && ut.clearSelected()
  21997. })
  21998. me.addListener('beforegetcontent', function () {
  21999. switchBorderColor(this, false)
  22000. browser.ie &&
  22001. utils.each(
  22002. this.document.getElementsByTagName('caption'),
  22003. function (ci) {
  22004. if (domUtils.isEmptyNode(ci)) {
  22005. ci.innerHTML = '&nbsp;'
  22006. }
  22007. }
  22008. )
  22009. })
  22010. me.addListener('aftergetcontent', function () {
  22011. switchBorderColor(this, true)
  22012. })
  22013. me.addListener('getAllHtml', function () {
  22014. removeSelectedClass(me.document.getElementsByTagName('td'))
  22015. })
  22016. //修正全屏状态下插入的表格宽度在非全屏状态下撑开编辑器的情况
  22017. me.addListener('fullscreenchanged', function (type, fullscreen) {
  22018. if (!fullscreen) {
  22019. var ratio = this.body.offsetWidth / document.body.offsetWidth,
  22020. tables = domUtils.getElementsByTagName(this.body, 'table')
  22021. utils.each(tables, function (table) {
  22022. if (table.offsetWidth < me.body.offsetWidth) return false
  22023. var tds = domUtils.getElementsByTagName(table, 'td'),
  22024. backWidths = []
  22025. utils.each(tds, function (td) {
  22026. backWidths.push(td.offsetWidth)
  22027. })
  22028. for (var i = 0, td; (td = tds[i]); i++) {
  22029. td.setAttribute('width', Math.floor(backWidths[i] * ratio))
  22030. }
  22031. table.setAttribute(
  22032. 'width',
  22033. Math.floor(getTableWidth(me, needIEHack, getDefaultValue(me)))
  22034. )
  22035. })
  22036. }
  22037. })
  22038. //重写execCommand命令,用于处理框选时的处理
  22039. var oldExecCommand = me.execCommand
  22040. me.execCommand = function (cmd, datatat) {
  22041. var me = this,
  22042. args = arguments
  22043. cmd = cmd.toLowerCase()
  22044. var ut = getUETableBySelected(me),
  22045. tds,
  22046. range = new dom.Range(me.document),
  22047. cmdFun = me.commands[cmd] || UE.commands[cmd],
  22048. result
  22049. if (!cmdFun) return
  22050. if (
  22051. ut &&
  22052. !commands[cmd] &&
  22053. !cmdFun.notNeedUndo &&
  22054. !me.__hasEnterExecCommand
  22055. ) {
  22056. me.__hasEnterExecCommand = true
  22057. me.fireEvent('beforeexeccommand', cmd)
  22058. tds = ut.selectedTds
  22059. var lastState = -2,
  22060. lastValue = -2,
  22061. value,
  22062. state
  22063. for (var i = 0, td; (td = tds[i]); i++) {
  22064. if (isEmptyBlock(td)) {
  22065. range.setStart(td, 0).setCursor(false, true)
  22066. } else {
  22067. range.selectNode(td).select(true)
  22068. }
  22069. state = me.queryCommandState(cmd)
  22070. value = me.queryCommandValue(cmd)
  22071. if (state != -1) {
  22072. if (lastState !== state || lastValue !== value) {
  22073. me._ignoreContentChange = true
  22074. result = oldExecCommand.apply(me, arguments)
  22075. me._ignoreContentChange = false
  22076. }
  22077. lastState = me.queryCommandState(cmd)
  22078. lastValue = me.queryCommandValue(cmd)
  22079. if (domUtils.isEmptyBlock(td)) {
  22080. domUtils.fillNode(me.document, td)
  22081. }
  22082. }
  22083. }
  22084. range.setStart(tds[0], 0).shrinkBoundary(true).setCursor(false, true)
  22085. me.fireEvent('contentchange')
  22086. me.fireEvent('afterexeccommand', cmd)
  22087. me.__hasEnterExecCommand = false
  22088. me._selectionChange()
  22089. } else {
  22090. result = oldExecCommand.apply(me, arguments)
  22091. }
  22092. return result
  22093. }
  22094. })
  22095. /**
  22096. * 删除obj的宽高style,改成属性宽高
  22097. * @param obj
  22098. * @param replaceToProperty
  22099. */
  22100. function removeStyleSize(obj, replaceToProperty) {
  22101. removeStyle(obj, 'width', true)
  22102. removeStyle(obj, 'height', true)
  22103. }
  22104. function removeStyle(obj, styleName, replaceToProperty) {
  22105. if (obj.style[styleName]) {
  22106. replaceToProperty &&
  22107. obj.setAttribute(styleName, parseInt(obj.style[styleName], 10))
  22108. obj.style[styleName] = ''
  22109. }
  22110. }
  22111. function getParentTdOrTh(ele) {
  22112. if (ele.tagName == 'TD' || ele.tagName == 'TH') return ele
  22113. var td
  22114. if (
  22115. (td =
  22116. domUtils.findParentByTagName(ele, 'td', true) ||
  22117. domUtils.findParentByTagName(ele, 'th', true))
  22118. )
  22119. return td
  22120. return null
  22121. }
  22122. function isEmptyBlock(node) {
  22123. var reg = new RegExp(domUtils.fillChar, 'g')
  22124. if (
  22125. node[browser.ie ? 'innerText' : 'textContent']
  22126. .replace(/^\s*$/, '')
  22127. .replace(reg, '').length > 0
  22128. ) {
  22129. return 0
  22130. }
  22131. for (var n in dtd.$isNotEmpty) {
  22132. if (node.getElementsByTagName(n).length) {
  22133. return 0
  22134. }
  22135. }
  22136. return 1
  22137. }
  22138. function mouseCoords(evt) {
  22139. if (evt.pageX || evt.pageY) {
  22140. return { x: evt.pageX, y: evt.pageY }
  22141. }
  22142. return {
  22143. x:
  22144. evt.clientX +
  22145. me.document.body.scrollLeft -
  22146. me.document.body.clientLeft,
  22147. y:
  22148. evt.clientY + me.document.body.scrollTop - me.document.body.clientTop,
  22149. }
  22150. }
  22151. function mouseMoveEvent(evt) {
  22152. if (isEditorDisabled()) {
  22153. return
  22154. }
  22155. try {
  22156. //普通状态下鼠标移动
  22157. var target = getParentTdOrTh(evt.target || evt.srcElement),
  22158. pos
  22159. //区分用户的行为是拖动还是双击
  22160. if (isInResizeBuffer) {
  22161. me.body.style.webkitUserSelect = 'none'
  22162. if (
  22163. Math.abs(userActionStatus.x - evt.clientX) > offsetOfTableCell ||
  22164. Math.abs(userActionStatus.y - evt.clientY) > offsetOfTableCell
  22165. ) {
  22166. clearTableDragTimer()
  22167. isInResizeBuffer = false
  22168. singleClickState = 0
  22169. //drag action
  22170. tableBorderDrag(evt)
  22171. }
  22172. }
  22173. //修改单元格大小时的鼠标移动
  22174. if (onDrag && dragTd) {
  22175. singleClickState = 0
  22176. me.body.style.webkitUserSelect = 'none'
  22177. me.selection
  22178. .getNative()
  22179. [browser.ie9below ? 'empty' : 'removeAllRanges']()
  22180. pos = mouseCoords(evt)
  22181. toggleDraggableState(me, true, onDrag, pos, target)
  22182. if (onDrag == 'h') {
  22183. dragLine.style.left = getPermissionX(dragTd, evt) + 'px'
  22184. } else if (onDrag == 'v') {
  22185. dragLine.style.top = getPermissionY(dragTd, evt) + 'px'
  22186. }
  22187. return
  22188. }
  22189. //当鼠标处于table上时,修改移动过程中的光标状态
  22190. if (target) {
  22191. //针对使用table作为容器的组件不触发拖拽效果
  22192. if (me.fireEvent('excludetable', target) === true) return
  22193. pos = mouseCoords(evt)
  22194. var state = getRelation(target, pos),
  22195. table = domUtils.findParentByTagName(target, 'table', true)
  22196. if (inTableSide(table, target, evt, true)) {
  22197. if (me.fireEvent('excludetable', table) === true) return
  22198. me.body.style.cursor =
  22199. 'url(' + me.options.cursorpath + 'h.png),pointer'
  22200. } else if (inTableSide(table, target, evt)) {
  22201. if (me.fireEvent('excludetable', table) === true) return
  22202. me.body.style.cursor =
  22203. 'url(' + me.options.cursorpath + 'v.png),pointer'
  22204. } else {
  22205. me.body.style.cursor = 'text'
  22206. var curCell = target
  22207. if (/\d/.test(state)) {
  22208. state = state.replace(/\d/, '')
  22209. target = getUETable(target).getPreviewCell(target, state == 'v')
  22210. }
  22211. //位于第一行的顶部或者第一列的左边时不可拖动
  22212. toggleDraggableState(
  22213. me,
  22214. target ? !!state : false,
  22215. target ? state : '',
  22216. pos,
  22217. target
  22218. )
  22219. }
  22220. } else {
  22221. toggleDragButton(false, table, me)
  22222. }
  22223. } catch (e) {
  22224. showError(e)
  22225. }
  22226. }
  22227. var dragButtonTimer
  22228. function toggleDragButton(show, table, editor) {
  22229. if (!show) {
  22230. if (dragOver) return
  22231. dragButtonTimer = setTimeout(function () {
  22232. !dragOver &&
  22233. dragButton &&
  22234. dragButton.parentNode &&
  22235. dragButton.parentNode.removeChild(dragButton)
  22236. }, 2000)
  22237. } else {
  22238. createDragButton(table, editor)
  22239. }
  22240. }
  22241. function createDragButton(table, editor) {
  22242. var pos = domUtils.getXY(table),
  22243. doc = table.ownerDocument
  22244. if (dragButton && dragButton.parentNode) return dragButton
  22245. dragButton = doc.createElement('div')
  22246. dragButton.contentEditable = false
  22247. dragButton.innerHTML = ''
  22248. dragButton.style.cssText =
  22249. 'width:15px;height:15px;background-image:url(' +
  22250. editor.options.UEDITOR_HOME_URL +
  22251. 'dialogs/table/dragicon.png);position: absolute;cursor:move;top:' +
  22252. (pos.y - 15) +
  22253. 'px;left:' +
  22254. pos.x +
  22255. 'px;'
  22256. domUtils.unSelectable(dragButton)
  22257. dragButton.onmouseover = function (evt) {
  22258. dragOver = true
  22259. }
  22260. dragButton.onmouseout = function (evt) {
  22261. dragOver = false
  22262. }
  22263. domUtils.on(dragButton, 'click', function (type, evt) {
  22264. doClick(evt, this)
  22265. })
  22266. domUtils.on(dragButton, 'dblclick', function (type, evt) {
  22267. doDblClick(evt)
  22268. })
  22269. domUtils.on(dragButton, 'dragstart', function (type, evt) {
  22270. domUtils.preventDefault(evt)
  22271. })
  22272. var timer
  22273. function doClick(evt, button) {
  22274. // 部分浏览器下需要清理
  22275. clearTimeout(timer)
  22276. timer = setTimeout(function () {
  22277. editor.fireEvent('tableClicked', table, button)
  22278. }, 300)
  22279. }
  22280. function doDblClick(evt) {
  22281. clearTimeout(timer)
  22282. var ut = getUETable(table),
  22283. start = table.rows[0].cells[0],
  22284. end = ut.getLastCell(),
  22285. range = ut.getCellsRange(start, end)
  22286. editor.selection.getRange().setStart(start, 0).setCursor(false, true)
  22287. ut.setSelected(range)
  22288. }
  22289. doc.body.appendChild(dragButton)
  22290. }
  22291. // function inPosition(table, pos) {
  22292. // var tablePos = domUtils.getXY(table),
  22293. // width = table.offsetWidth,
  22294. // height = table.offsetHeight;
  22295. // if (pos.x - tablePos.x < 5 && pos.y - tablePos.y < 5) {
  22296. // return "topLeft";
  22297. // } else if (tablePos.x + width - pos.x < 5 && tablePos.y + height - pos.y < 5) {
  22298. // return "bottomRight";
  22299. // }
  22300. // }
  22301. function inTableSide(table, cell, evt, top) {
  22302. var pos = mouseCoords(evt),
  22303. state = getRelation(cell, pos)
  22304. if (top) {
  22305. var caption = table.getElementsByTagName('caption')[0],
  22306. capHeight = caption ? caption.offsetHeight : 0
  22307. return state == 'v1' && pos.y - domUtils.getXY(table).y - capHeight < 8
  22308. } else {
  22309. return state == 'h1' && pos.x - domUtils.getXY(table).x < 8
  22310. }
  22311. }
  22312. /**
  22313. * 获取拖动时允许的X轴坐标
  22314. * @param dragTd
  22315. * @param evt
  22316. */
  22317. function getPermissionX(dragTd, evt) {
  22318. var ut = getUETable(dragTd)
  22319. if (ut) {
  22320. var preTd = ut.getSameEndPosCells(dragTd, 'x')[0],
  22321. nextTd = ut.getSameStartPosXCells(dragTd)[0],
  22322. mouseX = mouseCoords(evt).x,
  22323. left =
  22324. (preTd ? domUtils.getXY(preTd).x : domUtils.getXY(ut.table).x) + 20,
  22325. right = nextTd
  22326. ? domUtils.getXY(nextTd).x + nextTd.offsetWidth - 20
  22327. : me.body.offsetWidth + 5 ||
  22328. parseInt(domUtils.getComputedStyle(me.body, 'width'), 10)
  22329. left += cellMinWidth
  22330. right -= cellMinWidth
  22331. return mouseX < left ? left : mouseX > right ? right : mouseX
  22332. }
  22333. }
  22334. /**
  22335. * 获取拖动时允许的Y轴坐标
  22336. */
  22337. function getPermissionY(dragTd, evt) {
  22338. try {
  22339. var top = domUtils.getXY(dragTd).y,
  22340. mousePosY = mouseCoords(evt).y
  22341. return mousePosY < top ? top : mousePosY
  22342. } catch (e) {
  22343. showError(e)
  22344. }
  22345. }
  22346. /**
  22347. * 移动状态切换
  22348. */
  22349. function toggleDraggableState(editor, draggable, dir, mousePos, cell) {
  22350. try {
  22351. editor.body.style.cursor =
  22352. dir == 'h' ? 'col-resize' : dir == 'v' ? 'row-resize' : 'text'
  22353. if (browser.ie) {
  22354. if (dir && !mousedown && !getUETableBySelected(editor)) {
  22355. getDragLine(editor, editor.document)
  22356. showDragLineAt(dir, cell)
  22357. } else {
  22358. hideDragLine(editor)
  22359. }
  22360. }
  22361. onBorder = draggable
  22362. } catch (e) {
  22363. showError(e)
  22364. }
  22365. }
  22366. /**
  22367. * 获取与UETable相关的resize line
  22368. * @param uetable UETable对象
  22369. */
  22370. function getResizeLineByUETable() {
  22371. var lineId = '_UETableResizeLine',
  22372. line = this.document.getElementById(lineId)
  22373. if (!line) {
  22374. line = this.document.createElement('div')
  22375. line.id = lineId
  22376. line.contnetEditable = false
  22377. line.setAttribute('unselectable', 'on')
  22378. var styles = {
  22379. width: 2 * cellBorderWidth + 1 + 'px',
  22380. position: 'absolute',
  22381. 'z-index': 100000,
  22382. cursor: 'col-resize',
  22383. background: 'red',
  22384. display: 'none',
  22385. }
  22386. //切换状态
  22387. line.onmouseout = function () {
  22388. this.style.display = 'none'
  22389. }
  22390. utils.extend(line.style, styles)
  22391. this.document.body.appendChild(line)
  22392. }
  22393. return line
  22394. }
  22395. /**
  22396. * 更新resize-line
  22397. */
  22398. function updateResizeLine(cell, uetable) {
  22399. var line = getResizeLineByUETable.call(this),
  22400. table = uetable.table,
  22401. styles = {
  22402. top: domUtils.getXY(table).y + 'px',
  22403. left:
  22404. domUtils.getXY(cell).x + cell.offsetWidth - cellBorderWidth + 'px',
  22405. display: 'block',
  22406. height: table.offsetHeight + 'px',
  22407. }
  22408. utils.extend(line.style, styles)
  22409. }
  22410. /**
  22411. * 显示resize-line
  22412. */
  22413. function showResizeLine(cell) {
  22414. var uetable = getUETable(cell)
  22415. updateResizeLine.call(this, cell, uetable)
  22416. }
  22417. /**
  22418. * 获取鼠标与当前单元格的相对位置
  22419. * @param ele
  22420. * @param mousePos
  22421. */
  22422. function getRelation(ele, mousePos) {
  22423. var elePos = domUtils.getXY(ele)
  22424. if (!elePos) {
  22425. return ''
  22426. }
  22427. if (elePos.x + ele.offsetWidth - mousePos.x < cellBorderWidth) {
  22428. return 'h'
  22429. }
  22430. if (mousePos.x - elePos.x < cellBorderWidth) {
  22431. return 'h1'
  22432. }
  22433. if (elePos.y + ele.offsetHeight - mousePos.y < cellBorderWidth) {
  22434. return 'v'
  22435. }
  22436. if (mousePos.y - elePos.y < cellBorderWidth) {
  22437. return 'v1'
  22438. }
  22439. return ''
  22440. }
  22441. function mouseDownEvent(type, evt) {
  22442. if (isEditorDisabled()) {
  22443. return
  22444. }
  22445. userActionStatus = {
  22446. x: evt.clientX,
  22447. y: evt.clientY,
  22448. }
  22449. //右键菜单单独处理
  22450. if (evt.button == 2) {
  22451. var ut = getUETableBySelected(me),
  22452. flag = false
  22453. if (ut) {
  22454. var td = getTargetTd(me, evt)
  22455. utils.each(ut.selectedTds, function (ti) {
  22456. if (ti === td) {
  22457. flag = true
  22458. }
  22459. })
  22460. if (!flag) {
  22461. removeSelectedClass(domUtils.getElementsByTagName(me.body, 'th td'))
  22462. ut.clearSelected()
  22463. } else {
  22464. td = ut.selectedTds[0]
  22465. setTimeout(function () {
  22466. me.selection.getRange().setStart(td, 0).setCursor(false, true)
  22467. }, 0)
  22468. }
  22469. }
  22470. } else {
  22471. tableClickHander(evt)
  22472. }
  22473. }
  22474. //清除表格的计时器
  22475. function clearTableTimer() {
  22476. tabTimer && clearTimeout(tabTimer)
  22477. tabTimer = null
  22478. }
  22479. //双击收缩
  22480. function tableDbclickHandler(evt) {
  22481. singleClickState = 0
  22482. evt = evt || me.window.event
  22483. var target = getParentTdOrTh(evt.target || evt.srcElement)
  22484. if (target) {
  22485. var h
  22486. if ((h = getRelation(target, mouseCoords(evt)))) {
  22487. hideDragLine(me)
  22488. if (h == 'h1') {
  22489. h = 'h'
  22490. if (
  22491. inTableSide(
  22492. domUtils.findParentByTagName(target, 'table'),
  22493. target,
  22494. evt
  22495. )
  22496. ) {
  22497. me.execCommand('adaptbywindow')
  22498. } else {
  22499. target = getUETable(target).getPreviewCell(target)
  22500. if (target) {
  22501. var rng = me.selection.getRange()
  22502. rng.selectNodeContents(target).setCursor(true, true)
  22503. }
  22504. }
  22505. }
  22506. if (h == 'h') {
  22507. var ut = getUETable(target),
  22508. table = ut.table,
  22509. cells = getCellsByMoveBorder(target, table, true)
  22510. cells = extractArray(cells, 'left')
  22511. ut.width = ut.offsetWidth
  22512. var oldWidth = [],
  22513. newWidth = []
  22514. utils.each(cells, function (cell) {
  22515. oldWidth.push(cell.offsetWidth)
  22516. })
  22517. utils.each(cells, function (cell) {
  22518. cell.removeAttribute('width')
  22519. })
  22520. window.setTimeout(function () {
  22521. //是否允许改变
  22522. var changeable = true
  22523. utils.each(cells, function (cell, index) {
  22524. var width = cell.offsetWidth
  22525. if (width > oldWidth[index]) {
  22526. changeable = false
  22527. return false
  22528. }
  22529. newWidth.push(width)
  22530. })
  22531. var change = changeable ? newWidth : oldWidth
  22532. utils.each(cells, function (cell, index) {
  22533. cell.width = change[index] - getTabcellSpace()
  22534. })
  22535. }, 0)
  22536. // minWidth -= cellMinWidth;
  22537. //
  22538. // table.removeAttribute("width");
  22539. // utils.each(cells, function (cell) {
  22540. // cell.style.width = "";
  22541. // cell.width -= minWidth;
  22542. // });
  22543. }
  22544. }
  22545. }
  22546. }
  22547. function tableClickHander(evt) {
  22548. removeSelectedClass(domUtils.getElementsByTagName(me.body, 'td th'))
  22549. //trace:3113
  22550. //选中单元格,点击table外部,不会清掉table上挂的ueTable,会引起getUETableBySelected方法返回值
  22551. utils.each(me.document.getElementsByTagName('table'), function (t) {
  22552. t.ueTable = null
  22553. })
  22554. startTd = getTargetTd(me, evt)
  22555. if (!startTd) return
  22556. var table = domUtils.findParentByTagName(startTd, 'table', true)
  22557. ut = getUETable(table)
  22558. ut && ut.clearSelected()
  22559. //判断当前鼠标状态
  22560. if (!onBorder) {
  22561. me.document.body.style.webkitUserSelect = ''
  22562. mousedown = true
  22563. me.addListener('mouseover', mouseOverEvent)
  22564. } else {
  22565. //边框上的动作处理
  22566. borderActionHandler(evt)
  22567. }
  22568. }
  22569. //处理表格边框上的动作, 这里做延时处理,避免两种动作互相影响
  22570. function borderActionHandler(evt) {
  22571. if (browser.ie) {
  22572. evt = reconstruct(evt)
  22573. }
  22574. clearTableDragTimer()
  22575. //是否正在等待resize的缓冲中
  22576. isInResizeBuffer = true
  22577. tableDragTimer = setTimeout(function () {
  22578. tableBorderDrag(evt)
  22579. }, dblclickTime)
  22580. }
  22581. function extractArray(originArr, key) {
  22582. var result = [],
  22583. tmp = null
  22584. for (var i = 0, len = originArr.length; i < len; i++) {
  22585. tmp = originArr[i][key]
  22586. if (tmp) {
  22587. result.push(tmp)
  22588. }
  22589. }
  22590. return result
  22591. }
  22592. function clearTableDragTimer() {
  22593. tableDragTimer && clearTimeout(tableDragTimer)
  22594. tableDragTimer = null
  22595. }
  22596. function reconstruct(obj) {
  22597. var attrs = [
  22598. 'pageX',
  22599. 'pageY',
  22600. 'clientX',
  22601. 'clientY',
  22602. 'srcElement',
  22603. 'target',
  22604. ],
  22605. newObj = {}
  22606. if (obj) {
  22607. for (var i = 0, key, val; (key = attrs[i]); i++) {
  22608. val = obj[key]
  22609. val && (newObj[key] = val)
  22610. }
  22611. }
  22612. return newObj
  22613. }
  22614. //边框拖动
  22615. function tableBorderDrag(evt) {
  22616. isInResizeBuffer = false
  22617. startTd = evt.target || evt.srcElement
  22618. if (!startTd) return
  22619. var state = getRelation(startTd, mouseCoords(evt))
  22620. if (/\d/.test(state)) {
  22621. state = state.replace(/\d/, '')
  22622. startTd = getUETable(startTd).getPreviewCell(startTd, state == 'v')
  22623. }
  22624. hideDragLine(me)
  22625. getDragLine(me, me.document)
  22626. me.fireEvent('saveScene')
  22627. showDragLineAt(state, startTd)
  22628. mousedown = true
  22629. //拖动开始
  22630. onDrag = state
  22631. dragTd = startTd
  22632. }
  22633. function mouseUpEvent(type, evt) {
  22634. if (isEditorDisabled()) {
  22635. return
  22636. }
  22637. clearTableDragTimer()
  22638. isInResizeBuffer = false
  22639. if (onBorder) {
  22640. singleClickState = ++singleClickState % 3
  22641. userActionStatus = {
  22642. x: evt.clientX,
  22643. y: evt.clientY,
  22644. }
  22645. tableResizeTimer = setTimeout(function () {
  22646. singleClickState > 0 && singleClickState--
  22647. }, dblclickTime)
  22648. if (singleClickState === 2) {
  22649. singleClickState = 0
  22650. tableDbclickHandler(evt)
  22651. return
  22652. }
  22653. }
  22654. if (evt.button == 2) return
  22655. var me = this
  22656. //清除表格上原生跨选问题
  22657. var range = me.selection.getRange(),
  22658. start = domUtils.findParentByTagName(
  22659. range.startContainer,
  22660. 'table',
  22661. true
  22662. ),
  22663. end = domUtils.findParentByTagName(range.endContainer, 'table', true)
  22664. if (start || end) {
  22665. if (start === end) {
  22666. start = domUtils.findParentByTagName(
  22667. range.startContainer,
  22668. ['td', 'th', 'caption'],
  22669. true
  22670. )
  22671. end = domUtils.findParentByTagName(
  22672. range.endContainer,
  22673. ['td', 'th', 'caption'],
  22674. true
  22675. )
  22676. if (start !== end) {
  22677. me.selection.clearRange()
  22678. }
  22679. } else {
  22680. me.selection.clearRange()
  22681. }
  22682. }
  22683. mousedown = false
  22684. me.document.body.style.webkitUserSelect = ''
  22685. //拖拽状态下的mouseUP
  22686. if (onDrag && dragTd) {
  22687. me.selection
  22688. .getNative()
  22689. [browser.ie9below ? 'empty' : 'removeAllRanges']()
  22690. singleClickState = 0
  22691. dragLine = me.document.getElementById('ue_tableDragLine')
  22692. // trace 3973
  22693. if (dragLine) {
  22694. var dragTdPos = domUtils.getXY(dragTd),
  22695. dragLinePos = domUtils.getXY(dragLine)
  22696. switch (onDrag) {
  22697. case 'h':
  22698. changeColWidth(dragTd, dragLinePos.x - dragTdPos.x)
  22699. break
  22700. case 'v':
  22701. changeRowHeight(
  22702. dragTd,
  22703. dragLinePos.y - dragTdPos.y - dragTd.offsetHeight
  22704. )
  22705. break
  22706. default:
  22707. }
  22708. onDrag = ''
  22709. dragTd = null
  22710. hideDragLine(me)
  22711. me.fireEvent('saveScene')
  22712. return
  22713. }
  22714. }
  22715. //正常状态下的mouseup
  22716. if (!startTd) {
  22717. var target = domUtils.findParentByTagName(
  22718. evt.target || evt.srcElement,
  22719. 'td',
  22720. true
  22721. )
  22722. if (!target)
  22723. target = domUtils.findParentByTagName(
  22724. evt.target || evt.srcElement,
  22725. 'th',
  22726. true
  22727. )
  22728. if (target && (target.tagName == 'TD' || target.tagName == 'TH')) {
  22729. if (me.fireEvent('excludetable', target) === true) return
  22730. range = new dom.Range(me.document)
  22731. range.setStart(target, 0).setCursor(false, true)
  22732. }
  22733. } else {
  22734. var ut = getUETable(startTd),
  22735. cell = ut ? ut.selectedTds[0] : null
  22736. if (cell) {
  22737. range = new dom.Range(me.document)
  22738. if (domUtils.isEmptyBlock(cell)) {
  22739. range.setStart(cell, 0).setCursor(false, true)
  22740. } else {
  22741. range
  22742. .selectNodeContents(cell)
  22743. .shrinkBoundary()
  22744. .setCursor(false, true)
  22745. }
  22746. } else {
  22747. range = me.selection.getRange().shrinkBoundary()
  22748. if (!range.collapsed) {
  22749. var start = domUtils.findParentByTagName(
  22750. range.startContainer,
  22751. ['td', 'th'],
  22752. true
  22753. ),
  22754. end = domUtils.findParentByTagName(
  22755. range.endContainer,
  22756. ['td', 'th'],
  22757. true
  22758. )
  22759. //在table里边的不能清除
  22760. if (
  22761. (start && !end) ||
  22762. (!start && end) ||
  22763. (start && end && start !== end)
  22764. ) {
  22765. range.setCursor(false, true)
  22766. }
  22767. }
  22768. }
  22769. startTd = null
  22770. me.removeListener('mouseover', mouseOverEvent)
  22771. }
  22772. me._selectionChange(250, evt)
  22773. }
  22774. function mouseOverEvent(type, evt) {
  22775. if (isEditorDisabled()) {
  22776. return
  22777. }
  22778. var me = this,
  22779. tar = evt.target || evt.srcElement
  22780. currentTd =
  22781. domUtils.findParentByTagName(tar, 'td', true) ||
  22782. domUtils.findParentByTagName(tar, 'th', true)
  22783. //需要判断两个TD是否位于同一个表格内
  22784. if (
  22785. startTd &&
  22786. currentTd &&
  22787. ((startTd.tagName == 'TD' && currentTd.tagName == 'TD') ||
  22788. (startTd.tagName == 'TH' && currentTd.tagName == 'TH')) &&
  22789. domUtils.findParentByTagName(startTd, 'table') ==
  22790. domUtils.findParentByTagName(currentTd, 'table')
  22791. ) {
  22792. var ut = getUETable(currentTd)
  22793. if (startTd != currentTd) {
  22794. me.document.body.style.webkitUserSelect = 'none'
  22795. me.selection
  22796. .getNative()
  22797. [browser.ie9below ? 'empty' : 'removeAllRanges']()
  22798. var range = ut.getCellsRange(startTd, currentTd)
  22799. ut.setSelected(range)
  22800. } else {
  22801. me.document.body.style.webkitUserSelect = ''
  22802. ut.clearSelected()
  22803. }
  22804. }
  22805. evt.preventDefault ? evt.preventDefault() : (evt.returnValue = false)
  22806. }
  22807. function setCellHeight(cell, height, backHeight) {
  22808. var lineHight = parseInt(
  22809. domUtils.getComputedStyle(cell, 'line-height'),
  22810. 10
  22811. ),
  22812. tmpHeight = backHeight + height
  22813. height = tmpHeight < lineHight ? lineHight : tmpHeight
  22814. if (cell.style.height) cell.style.height = ''
  22815. cell.rowSpan == 1
  22816. ? cell.setAttribute('height', height)
  22817. : cell.removeAttribute && cell.removeAttribute('height')
  22818. }
  22819. function getWidth(cell) {
  22820. if (!cell) return 0
  22821. return parseInt(domUtils.getComputedStyle(cell, 'width'), 10)
  22822. }
  22823. function changeColWidth(cell, changeValue) {
  22824. var ut = getUETable(cell)
  22825. if (ut) {
  22826. //根据当前移动的边框获取相关的单元格
  22827. var table = ut.table,
  22828. cells = getCellsByMoveBorder(cell, table)
  22829. table.style.width = ''
  22830. table.removeAttribute('width')
  22831. //修正改变量
  22832. changeValue = correctChangeValue(changeValue, cell, cells)
  22833. if (cell.nextSibling) {
  22834. var i = 0
  22835. utils.each(cells, function (cellGroup) {
  22836. cellGroup.left.width = +cellGroup.left.width + changeValue
  22837. cellGroup.right &&
  22838. (cellGroup.right.width = +cellGroup.right.width - changeValue)
  22839. })
  22840. } else {
  22841. utils.each(cells, function (cellGroup) {
  22842. cellGroup.left.width -= -changeValue
  22843. })
  22844. }
  22845. }
  22846. }
  22847. function isEditorDisabled() {
  22848. return me.body.contentEditable === 'false'
  22849. }
  22850. function changeRowHeight(td, changeValue) {
  22851. if (Math.abs(changeValue) < 10) return
  22852. var ut = getUETable(td)
  22853. if (ut) {
  22854. var cells = ut.getSameEndPosCells(td, 'y'),
  22855. //备份需要连带变化的td的原始高度,否则后期无法获取正确的值
  22856. backHeight = cells[0] ? cells[0].offsetHeight : 0
  22857. for (var i = 0, cell; (cell = cells[i++]); ) {
  22858. setCellHeight(cell, changeValue, backHeight)
  22859. }
  22860. }
  22861. }
  22862. /**
  22863. * 获取调整单元格大小的相关单元格
  22864. * @isContainMergeCell 返回的结果中是否包含发生合并后的单元格
  22865. */
  22866. function getCellsByMoveBorder(cell, table, isContainMergeCell) {
  22867. if (!table) {
  22868. table = domUtils.findParentByTagName(cell, 'table')
  22869. }
  22870. if (!table) {
  22871. return null
  22872. }
  22873. //获取到该单元格所在行的序列号
  22874. var index = domUtils.getNodeIndex(cell),
  22875. temp = cell,
  22876. rows = table.rows,
  22877. colIndex = 0
  22878. while (temp) {
  22879. //获取到当前单元格在未发生单元格合并时的序列
  22880. if (temp.nodeType === 1) {
  22881. colIndex += temp.colSpan || 1
  22882. }
  22883. temp = temp.previousSibling
  22884. }
  22885. temp = null
  22886. //记录想关的单元格
  22887. var borderCells = []
  22888. utils.each(rows, function (tabRow) {
  22889. var cells = tabRow.cells,
  22890. currIndex = 0
  22891. utils.each(cells, function (tabCell) {
  22892. currIndex += tabCell.colSpan || 1
  22893. if (currIndex === colIndex) {
  22894. borderCells.push({
  22895. left: tabCell,
  22896. right: tabCell.nextSibling || null,
  22897. })
  22898. return false
  22899. } else if (currIndex > colIndex) {
  22900. if (isContainMergeCell) {
  22901. borderCells.push({
  22902. left: tabCell,
  22903. })
  22904. }
  22905. return false
  22906. }
  22907. })
  22908. })
  22909. return borderCells
  22910. }
  22911. /**
  22912. * 通过给定的单元格集合获取最小的单元格width
  22913. */
  22914. function getMinWidthByTableCells(cells) {
  22915. var minWidth = Number.MAX_VALUE
  22916. for (var i = 0, curCell; (curCell = cells[i]); i++) {
  22917. minWidth = Math.min(
  22918. minWidth,
  22919. curCell.width || getTableCellWidth(curCell)
  22920. )
  22921. }
  22922. return minWidth
  22923. }
  22924. function correctChangeValue(changeValue, relatedCell, cells) {
  22925. //为单元格的paading预留空间
  22926. changeValue -= getTabcellSpace()
  22927. if (changeValue < 0) {
  22928. return 0
  22929. }
  22930. changeValue -= getTableCellWidth(relatedCell)
  22931. //确定方向
  22932. var direction = changeValue < 0 ? 'left' : 'right'
  22933. changeValue = Math.abs(changeValue)
  22934. //只关心非最后一个单元格就可以
  22935. utils.each(cells, function (cellGroup) {
  22936. var curCell = cellGroup[direction]
  22937. //为单元格保留最小空间
  22938. if (curCell) {
  22939. changeValue = Math.min(
  22940. changeValue,
  22941. getTableCellWidth(curCell) - cellMinWidth
  22942. )
  22943. }
  22944. })
  22945. //修正越界
  22946. changeValue = changeValue < 0 ? 0 : changeValue
  22947. return direction === 'left' ? -changeValue : changeValue
  22948. }
  22949. function getTableCellWidth(cell) {
  22950. var width = 0,
  22951. //偏移纠正量
  22952. offset = 0,
  22953. width = cell.offsetWidth - getTabcellSpace()
  22954. //最后一个节点纠正一下
  22955. if (!cell.nextSibling) {
  22956. width -= getTableCellOffset(cell)
  22957. }
  22958. width = width < 0 ? 0 : width
  22959. try {
  22960. cell.width = width
  22961. } catch (e) {}
  22962. return width
  22963. }
  22964. /**
  22965. * 获取单元格所在表格的最末单元格的偏移量
  22966. */
  22967. function getTableCellOffset(cell) {
  22968. tab = domUtils.findParentByTagName(cell, 'table', false)
  22969. if (tab.offsetVal === undefined) {
  22970. var prev = cell.previousSibling
  22971. if (prev) {
  22972. //最后一个单元格和前一个单元格的width diff结果 如果恰好为一个border width, 则条件成立
  22973. tab.offsetVal =
  22974. cell.offsetWidth - prev.offsetWidth === UT.borderWidth
  22975. ? UT.borderWidth
  22976. : 0
  22977. } else {
  22978. tab.offsetVal = 0
  22979. }
  22980. }
  22981. return tab.offsetVal
  22982. }
  22983. function getTabcellSpace() {
  22984. if (UT.tabcellSpace === undefined) {
  22985. var cell = null,
  22986. tab = me.document.createElement('table'),
  22987. tbody = me.document.createElement('tbody'),
  22988. trow = me.document.createElement('tr'),
  22989. tabcell = me.document.createElement('td'),
  22990. mirror = null
  22991. tabcell.style.cssText = 'border: 0;'
  22992. tabcell.width = 1
  22993. trow.appendChild(tabcell)
  22994. trow.appendChild((mirror = tabcell.cloneNode(false)))
  22995. tbody.appendChild(trow)
  22996. tab.appendChild(tbody)
  22997. tab.style.cssText = 'visibility: hidden;'
  22998. me.body.appendChild(tab)
  22999. UT.paddingSpace = tabcell.offsetWidth - 1
  23000. var tmpTabWidth = tab.offsetWidth
  23001. tabcell.style.cssText = ''
  23002. mirror.style.cssText = ''
  23003. UT.borderWidth = (tab.offsetWidth - tmpTabWidth) / 3
  23004. UT.tabcellSpace = UT.paddingSpace + UT.borderWidth
  23005. me.body.removeChild(tab)
  23006. }
  23007. getTabcellSpace = function () {
  23008. return UT.tabcellSpace
  23009. }
  23010. return UT.tabcellSpace
  23011. }
  23012. function getDragLine(editor, doc) {
  23013. if (mousedown) return
  23014. dragLine = editor.document.createElement('div')
  23015. domUtils.setAttributes(dragLine, {
  23016. id: 'ue_tableDragLine',
  23017. unselectable: 'on',
  23018. contenteditable: false,
  23019. onresizestart: 'return false',
  23020. ondragstart: 'return false',
  23021. onselectstart: 'return false',
  23022. style:
  23023. 'background-color:blue;position:absolute;padding:0;margin:0;background-image:none;border:0px none;opacity:0;filter:alpha(opacity=0)',
  23024. })
  23025. editor.body.appendChild(dragLine)
  23026. }
  23027. function hideDragLine(editor) {
  23028. if (mousedown) return
  23029. var line
  23030. while ((line = editor.document.getElementById('ue_tableDragLine'))) {
  23031. domUtils.remove(line)
  23032. }
  23033. }
  23034. /**
  23035. * 依据state(v|h)在cell位置显示横线
  23036. * @param state
  23037. * @param cell
  23038. */
  23039. function showDragLineAt(state, cell) {
  23040. if (!cell) return
  23041. var table = domUtils.findParentByTagName(cell, 'table'),
  23042. caption = table.getElementsByTagName('caption'),
  23043. width = table.offsetWidth,
  23044. height =
  23045. table.offsetHeight -
  23046. (caption.length > 0 ? caption[0].offsetHeight : 0),
  23047. tablePos = domUtils.getXY(table),
  23048. cellPos = domUtils.getXY(cell),
  23049. css
  23050. switch (state) {
  23051. case 'h':
  23052. css =
  23053. 'height:' +
  23054. height +
  23055. 'px;top:' +
  23056. (tablePos.y + (caption.length > 0 ? caption[0].offsetHeight : 0)) +
  23057. 'px;left:' +
  23058. (cellPos.x + cell.offsetWidth)
  23059. dragLine.style.cssText =
  23060. css +
  23061. 'px;position: absolute;display:block;background-color:blue;width:1px;border:0; color:blue;opacity:.3;filter:alpha(opacity=30)'
  23062. break
  23063. case 'v':
  23064. css =
  23065. 'width:' +
  23066. width +
  23067. 'px;left:' +
  23068. tablePos.x +
  23069. 'px;top:' +
  23070. (cellPos.y + cell.offsetHeight)
  23071. //必须加上border:0和color:blue,否则低版ie不支持背景色显示
  23072. dragLine.style.cssText =
  23073. css +
  23074. 'px;overflow:hidden;position: absolute;display:block;background-color:blue;height:1px;border:0;color:blue;opacity:.2;filter:alpha(opacity=20)'
  23075. break
  23076. default:
  23077. }
  23078. }
  23079. /**
  23080. * 当表格边框颜色为白色时设置为虚线,true为添加虚线
  23081. * @param editor
  23082. * @param flag
  23083. */
  23084. function switchBorderColor(editor, flag) {
  23085. var tableArr = domUtils.getElementsByTagName(editor.body, 'table'),
  23086. color
  23087. for (var i = 0, node; (node = tableArr[i++]); ) {
  23088. var td = domUtils.getElementsByTagName(node, 'td')
  23089. if (td[0]) {
  23090. if (flag) {
  23091. color = td[0].style.borderColor.replace(/\s/g, '')
  23092. if (/(#ffffff)|(rgb\(255,255,255\))/gi.test(color))
  23093. domUtils.addClass(node, 'noBorderTable')
  23094. } else {
  23095. domUtils.removeClasses(node, 'noBorderTable')
  23096. }
  23097. }
  23098. }
  23099. }
  23100. function getTableWidth(editor, needIEHack, defaultValue) {
  23101. var body = editor.body
  23102. return (
  23103. body.offsetWidth -
  23104. (needIEHack
  23105. ? parseInt(domUtils.getComputedStyle(body, 'margin-left'), 10) * 2
  23106. : 0) -
  23107. defaultValue.tableBorder * 2 -
  23108. (editor.options.offsetWidth || 0)
  23109. )
  23110. }
  23111. /**
  23112. * 获取当前拖动的单元格
  23113. */
  23114. function getTargetTd(editor, evt) {
  23115. var target = domUtils.findParentByTagName(
  23116. evt.target || evt.srcElement,
  23117. ['td', 'th'],
  23118. true
  23119. ),
  23120. dir = null
  23121. if (!target) {
  23122. return null
  23123. }
  23124. dir = getRelation(target, mouseCoords(evt))
  23125. //如果有前一个节点, 需要做一个修正, 否则可能会得到一个错误的td
  23126. if (!target) {
  23127. return null
  23128. }
  23129. if (dir === 'h1' && target.previousSibling) {
  23130. var position = domUtils.getXY(target),
  23131. cellWidth = target.offsetWidth
  23132. if (Math.abs(position.x + cellWidth - evt.clientX) > cellWidth / 3) {
  23133. target = target.previousSibling
  23134. }
  23135. } else if (dir === 'v1' && target.parentNode.previousSibling) {
  23136. var position = domUtils.getXY(target),
  23137. cellHeight = target.offsetHeight
  23138. if (Math.abs(position.y + cellHeight - evt.clientY) > cellHeight / 3) {
  23139. target = target.parentNode.previousSibling.firstChild
  23140. }
  23141. }
  23142. //排除了非td内部以及用于代码高亮部分的td
  23143. return target && !(editor.fireEvent('excludetable', target) === true)
  23144. ? target
  23145. : null
  23146. }
  23147. }
  23148. // plugins/table.sort.js
  23149. /**
  23150. * Created with JetBrains PhpStorm.
  23151. * User: Jinqn
  23152. * Date: 13-10-12
  23153. * Time: 上午10:20
  23154. * To change this template use File | Settings | File Templates.
  23155. */
  23156. UE.UETable.prototype.sortTable = function (sortByCellIndex, compareFn) {
  23157. var table = this.table,
  23158. rows = table.rows,
  23159. trArray = [],
  23160. flag = rows[0].cells[0].tagName === 'TH',
  23161. lastRowIndex = 0
  23162. if (this.selectedTds.length) {
  23163. var range = this.cellsRange,
  23164. len = range.endRowIndex + 1
  23165. for (var i = range.beginRowIndex; i < len; i++) {
  23166. trArray[i] = rows[i]
  23167. }
  23168. trArray.splice(0, range.beginRowIndex)
  23169. lastRowIndex =
  23170. range.endRowIndex + 1 === this.rowsNum ? 0 : range.endRowIndex + 1
  23171. } else {
  23172. for (var i = 0, len = rows.length; i < len; i++) {
  23173. trArray[i] = rows[i]
  23174. }
  23175. }
  23176. var Fn = {
  23177. reversecurrent: function (td1, td2) {
  23178. return 1
  23179. },
  23180. orderbyasc: function (td1, td2) {
  23181. var value1 = td1.innerText || td1.textContent,
  23182. value2 = td2.innerText || td2.textContent
  23183. return value1.localeCompare(value2)
  23184. },
  23185. reversebyasc: function (td1, td2) {
  23186. var value1 = td1.innerHTML,
  23187. value2 = td2.innerHTML
  23188. return value2.localeCompare(value1)
  23189. },
  23190. orderbynum: function (td1, td2) {
  23191. var value1 = td1[browser.ie ? 'innerText' : 'textContent'].match(/\d+/),
  23192. value2 = td2[browser.ie ? 'innerText' : 'textContent'].match(/\d+/)
  23193. if (value1) value1 = +value1[0]
  23194. if (value2) value2 = +value2[0]
  23195. return (value1 || 0) - (value2 || 0)
  23196. },
  23197. reversebynum: function (td1, td2) {
  23198. var value1 = td1[browser.ie ? 'innerText' : 'textContent'].match(/\d+/),
  23199. value2 = td2[browser.ie ? 'innerText' : 'textContent'].match(/\d+/)
  23200. if (value1) value1 = +value1[0]
  23201. if (value2) value2 = +value2[0]
  23202. return (value2 || 0) - (value1 || 0)
  23203. },
  23204. }
  23205. //对表格设置排序的标记data-sort-type
  23206. table.setAttribute(
  23207. 'data-sort-type',
  23208. compareFn && typeof compareFn === 'string' && Fn[compareFn]
  23209. ? compareFn
  23210. : ''
  23211. )
  23212. //th不参与排序
  23213. flag && trArray.splice(0, 1)
  23214. trArray = utils.sort(trArray, function (tr1, tr2) {
  23215. var result
  23216. if (compareFn && typeof compareFn === 'function') {
  23217. result = compareFn.call(
  23218. this,
  23219. tr1.cells[sortByCellIndex],
  23220. tr2.cells[sortByCellIndex]
  23221. )
  23222. } else if (compareFn && typeof compareFn === 'number') {
  23223. result = 1
  23224. } else if (compareFn && typeof compareFn === 'string' && Fn[compareFn]) {
  23225. result = Fn[compareFn].call(
  23226. this,
  23227. tr1.cells[sortByCellIndex],
  23228. tr2.cells[sortByCellIndex]
  23229. )
  23230. } else {
  23231. result = Fn['orderbyasc'].call(
  23232. this,
  23233. tr1.cells[sortByCellIndex],
  23234. tr2.cells[sortByCellIndex]
  23235. )
  23236. }
  23237. return result
  23238. })
  23239. var fragment = table.ownerDocument.createDocumentFragment()
  23240. for (var j = 0, len = trArray.length; j < len; j++) {
  23241. fragment.appendChild(trArray[j])
  23242. }
  23243. var tbody = table.getElementsByTagName('tbody')[0]
  23244. if (!lastRowIndex) {
  23245. tbody.appendChild(fragment)
  23246. } else {
  23247. tbody.insertBefore(
  23248. fragment,
  23249. rows[lastRowIndex - range.endRowIndex + range.beginRowIndex - 1]
  23250. )
  23251. }
  23252. }
  23253. UE.plugins['tablesort'] = function () {
  23254. var me = this,
  23255. UT = UE.UETable,
  23256. getUETable = function (tdOrTable) {
  23257. return UT.getUETable(tdOrTable)
  23258. },
  23259. getTableItemsByRange = function (editor) {
  23260. return UT.getTableItemsByRange(editor)
  23261. }
  23262. me.ready(function () {
  23263. //添加表格可排序的样式
  23264. utils.cssRule(
  23265. 'tablesort',
  23266. 'table.sortEnabled tr.firstRow th,table.sortEnabled tr.firstRow td{padding-right:20px;background-repeat: no-repeat;background-position: center right;' +
  23267. ' background-image:url(' +
  23268. me.options.themePath +
  23269. me.options.theme +
  23270. '/images/sortable.png);}',
  23271. me.document
  23272. )
  23273. //做单元格合并操作时,清除可排序标识
  23274. me.addListener('afterexeccommand', function (type, cmd) {
  23275. if (cmd == 'mergeright' || cmd == 'mergedown' || cmd == 'mergecells') {
  23276. this.execCommand('disablesort')
  23277. }
  23278. })
  23279. })
  23280. //表格排序
  23281. UE.commands['sorttable'] = {
  23282. queryCommandState: function () {
  23283. var me = this,
  23284. tableItems = getTableItemsByRange(me)
  23285. if (!tableItems.cell) return -1
  23286. var table = tableItems.table,
  23287. cells = table.getElementsByTagName('td')
  23288. for (var i = 0, cell; (cell = cells[i++]); ) {
  23289. if (cell.rowSpan != 1 || cell.colSpan != 1) return -1
  23290. }
  23291. return 0
  23292. },
  23293. execCommand: function (cmd, fn) {
  23294. var me = this,
  23295. range = me.selection.getRange(),
  23296. bk = range.createBookmark(true),
  23297. tableItems = getTableItemsByRange(me),
  23298. cell = tableItems.cell,
  23299. ut = getUETable(tableItems.table),
  23300. cellInfo = ut.getCellInfo(cell)
  23301. ut.sortTable(cellInfo.cellIndex, fn)
  23302. range.moveToBookmark(bk)
  23303. try {
  23304. range.select()
  23305. } catch (e) {}
  23306. },
  23307. }
  23308. //设置表格可排序,清除表格可排序
  23309. UE.commands['enablesort'] = UE.commands['disablesort'] = {
  23310. queryCommandState: function (cmd) {
  23311. var table = getTableItemsByRange(this).table
  23312. if (table && cmd == 'enablesort') {
  23313. var cells = domUtils.getElementsByTagName(table, 'th td')
  23314. for (var i = 0; i < cells.length; i++) {
  23315. if (
  23316. cells[i].getAttribute('colspan') > 1 ||
  23317. cells[i].getAttribute('rowspan') > 1
  23318. )
  23319. return -1
  23320. }
  23321. }
  23322. return !table
  23323. ? -1
  23324. : (cmd == 'enablesort') ^
  23325. (table.getAttribute('data-sort') != 'sortEnabled')
  23326. ? -1
  23327. : 0
  23328. },
  23329. execCommand: function (cmd) {
  23330. var table = getTableItemsByRange(this).table
  23331. table.setAttribute(
  23332. 'data-sort',
  23333. cmd == 'enablesort' ? 'sortEnabled' : 'sortDisabled'
  23334. )
  23335. cmd == 'enablesort'
  23336. ? domUtils.addClass(table, 'sortEnabled')
  23337. : domUtils.removeClasses(table, 'sortEnabled')
  23338. },
  23339. }
  23340. }
  23341. // plugins/contextmenu.js
  23342. ///import core
  23343. ///commands 右键菜单
  23344. ///commandsName ContextMenu
  23345. ///commandsTitle 右键菜单
  23346. /**
  23347. * 右键菜单
  23348. * @function
  23349. * @name baidu.editor.plugins.contextmenu
  23350. * @author zhanyi
  23351. */
  23352. UE.plugins['contextmenu'] = function () {
  23353. var me = this
  23354. me.setOpt('enableContextMenu', true)
  23355. if (me.getOpt('enableContextMenu') === false) {
  23356. return
  23357. }
  23358. var lang = me.getLang('contextMenu'),
  23359. menu,
  23360. items = me.options.contextMenu || [
  23361. { label: lang['selectall'], cmdName: 'selectall' },
  23362. {
  23363. label: lang.cleardoc,
  23364. cmdName: 'cleardoc',
  23365. exec: function () {
  23366. if (confirm(lang.confirmclear)) {
  23367. this.execCommand('cleardoc')
  23368. }
  23369. },
  23370. },
  23371. '-',
  23372. {
  23373. label: lang.unlink,
  23374. cmdName: 'unlink',
  23375. },
  23376. '-',
  23377. {
  23378. group: lang.paragraph,
  23379. icon: 'justifyjustify',
  23380. subMenu: [
  23381. {
  23382. label: lang.justifyleft,
  23383. cmdName: 'justify',
  23384. value: 'left',
  23385. },
  23386. {
  23387. label: lang.justifyright,
  23388. cmdName: 'justify',
  23389. value: 'right',
  23390. },
  23391. {
  23392. label: lang.justifycenter,
  23393. cmdName: 'justify',
  23394. value: 'center',
  23395. },
  23396. {
  23397. label: lang.justifyjustify,
  23398. cmdName: 'justify',
  23399. value: 'justify',
  23400. },
  23401. ],
  23402. },
  23403. '-',
  23404. {
  23405. group: lang.table,
  23406. icon: 'table',
  23407. subMenu: [
  23408. {
  23409. label: lang.inserttable,
  23410. cmdName: 'inserttable',
  23411. },
  23412. {
  23413. label: lang.deletetable,
  23414. cmdName: 'deletetable',
  23415. },
  23416. '-',
  23417. {
  23418. label: lang.deleterow,
  23419. cmdName: 'deleterow',
  23420. },
  23421. {
  23422. label: lang.deletecol,
  23423. cmdName: 'deletecol',
  23424. },
  23425. {
  23426. label: lang.insertcol,
  23427. cmdName: 'insertcol',
  23428. },
  23429. {
  23430. label: lang.insertcolnext,
  23431. cmdName: 'insertcolnext',
  23432. },
  23433. {
  23434. label: lang.insertrow,
  23435. cmdName: 'insertrow',
  23436. },
  23437. {
  23438. label: lang.insertrownext,
  23439. cmdName: 'insertrownext',
  23440. },
  23441. '-',
  23442. {
  23443. label: lang.insertcaption,
  23444. cmdName: 'insertcaption',
  23445. },
  23446. {
  23447. label: lang.deletecaption,
  23448. cmdName: 'deletecaption',
  23449. },
  23450. {
  23451. label: lang.inserttitle,
  23452. cmdName: 'inserttitle',
  23453. },
  23454. {
  23455. label: lang.deletetitle,
  23456. cmdName: 'deletetitle',
  23457. },
  23458. {
  23459. label: lang.inserttitlecol,
  23460. cmdName: 'inserttitlecol',
  23461. },
  23462. {
  23463. label: lang.deletetitlecol,
  23464. cmdName: 'deletetitlecol',
  23465. },
  23466. '-',
  23467. {
  23468. label: lang.mergecells,
  23469. cmdName: 'mergecells',
  23470. },
  23471. {
  23472. label: lang.mergeright,
  23473. cmdName: 'mergeright',
  23474. },
  23475. {
  23476. label: lang.mergedown,
  23477. cmdName: 'mergedown',
  23478. },
  23479. '-',
  23480. {
  23481. label: lang.splittorows,
  23482. cmdName: 'splittorows',
  23483. },
  23484. {
  23485. label: lang.splittocols,
  23486. cmdName: 'splittocols',
  23487. },
  23488. {
  23489. label: lang.splittocells,
  23490. cmdName: 'splittocells',
  23491. },
  23492. '-',
  23493. {
  23494. label: lang.averageDiseRow,
  23495. cmdName: 'averagedistributerow',
  23496. },
  23497. {
  23498. label: lang.averageDisCol,
  23499. cmdName: 'averagedistributecol',
  23500. },
  23501. '-',
  23502. {
  23503. label: lang.edittd,
  23504. cmdName: 'edittd',
  23505. exec: function () {
  23506. if (UE.ui['edittd']) {
  23507. new UE.ui['edittd'](this)
  23508. }
  23509. this.getDialog('edittd').open()
  23510. },
  23511. },
  23512. {
  23513. label: lang.edittable,
  23514. cmdName: 'edittable',
  23515. exec: function () {
  23516. if (UE.ui['edittable']) {
  23517. new UE.ui['edittable'](this)
  23518. }
  23519. this.getDialog('edittable').open()
  23520. },
  23521. },
  23522. {
  23523. label: lang.setbordervisible,
  23524. cmdName: 'setbordervisible',
  23525. },
  23526. ],
  23527. },
  23528. {
  23529. group: lang.tablesort,
  23530. icon: 'tablesort',
  23531. subMenu: [
  23532. {
  23533. label: lang.enablesort,
  23534. cmdName: 'enablesort',
  23535. },
  23536. {
  23537. label: lang.disablesort,
  23538. cmdName: 'disablesort',
  23539. },
  23540. '-',
  23541. {
  23542. label: lang.reversecurrent,
  23543. cmdName: 'sorttable',
  23544. value: 'reversecurrent',
  23545. },
  23546. {
  23547. label: lang.orderbyasc,
  23548. cmdName: 'sorttable',
  23549. value: 'orderbyasc',
  23550. },
  23551. {
  23552. label: lang.reversebyasc,
  23553. cmdName: 'sorttable',
  23554. value: 'reversebyasc',
  23555. },
  23556. {
  23557. label: lang.orderbynum,
  23558. cmdName: 'sorttable',
  23559. value: 'orderbynum',
  23560. },
  23561. {
  23562. label: lang.reversebynum,
  23563. cmdName: 'sorttable',
  23564. value: 'reversebynum',
  23565. },
  23566. ],
  23567. },
  23568. {
  23569. group: lang.borderbk,
  23570. icon: 'borderBack',
  23571. subMenu: [
  23572. {
  23573. label: lang.setcolor,
  23574. cmdName: 'interlacetable',
  23575. exec: function () {
  23576. this.execCommand('interlacetable')
  23577. },
  23578. },
  23579. {
  23580. label: lang.unsetcolor,
  23581. cmdName: 'uninterlacetable',
  23582. exec: function () {
  23583. this.execCommand('uninterlacetable')
  23584. },
  23585. },
  23586. {
  23587. label: lang.setbackground,
  23588. cmdName: 'settablebackground',
  23589. exec: function () {
  23590. this.execCommand('settablebackground', {
  23591. repeat: true,
  23592. colorList: ['#bbb', '#ccc'],
  23593. })
  23594. },
  23595. },
  23596. {
  23597. label: lang.unsetbackground,
  23598. cmdName: 'cleartablebackground',
  23599. exec: function () {
  23600. this.execCommand('cleartablebackground')
  23601. },
  23602. },
  23603. {
  23604. label: lang.redandblue,
  23605. cmdName: 'settablebackground',
  23606. exec: function () {
  23607. this.execCommand('settablebackground', {
  23608. repeat: true,
  23609. colorList: ['red', 'blue'],
  23610. })
  23611. },
  23612. },
  23613. {
  23614. label: lang.threecolorgradient,
  23615. cmdName: 'settablebackground',
  23616. exec: function () {
  23617. this.execCommand('settablebackground', {
  23618. repeat: true,
  23619. colorList: ['#aaa', '#bbb', '#ccc'],
  23620. })
  23621. },
  23622. },
  23623. ],
  23624. },
  23625. {
  23626. group: lang.aligntd,
  23627. icon: 'aligntd',
  23628. subMenu: [
  23629. {
  23630. cmdName: 'cellalignment',
  23631. value: { align: 'left', vAlign: 'top' },
  23632. },
  23633. {
  23634. cmdName: 'cellalignment',
  23635. value: { align: 'center', vAlign: 'top' },
  23636. },
  23637. {
  23638. cmdName: 'cellalignment',
  23639. value: { align: 'right', vAlign: 'top' },
  23640. },
  23641. {
  23642. cmdName: 'cellalignment',
  23643. value: { align: 'left', vAlign: 'middle' },
  23644. },
  23645. {
  23646. cmdName: 'cellalignment',
  23647. value: { align: 'center', vAlign: 'middle' },
  23648. },
  23649. {
  23650. cmdName: 'cellalignment',
  23651. value: { align: 'right', vAlign: 'middle' },
  23652. },
  23653. {
  23654. cmdName: 'cellalignment',
  23655. value: { align: 'left', vAlign: 'bottom' },
  23656. },
  23657. {
  23658. cmdName: 'cellalignment',
  23659. value: { align: 'center', vAlign: 'bottom' },
  23660. },
  23661. {
  23662. cmdName: 'cellalignment',
  23663. value: { align: 'right', vAlign: 'bottom' },
  23664. },
  23665. ],
  23666. },
  23667. {
  23668. group: lang.aligntable,
  23669. icon: 'aligntable',
  23670. subMenu: [
  23671. {
  23672. cmdName: 'tablealignment',
  23673. className: 'left',
  23674. label: lang.tableleft,
  23675. value: 'left',
  23676. },
  23677. {
  23678. cmdName: 'tablealignment',
  23679. className: 'center',
  23680. label: lang.tablecenter,
  23681. value: 'center',
  23682. },
  23683. {
  23684. cmdName: 'tablealignment',
  23685. className: 'right',
  23686. label: lang.tableright,
  23687. value: 'right',
  23688. },
  23689. ],
  23690. },
  23691. '-',
  23692. {
  23693. label: lang.insertparagraphbefore,
  23694. cmdName: 'insertparagraph',
  23695. value: true,
  23696. },
  23697. {
  23698. label: lang.insertparagraphafter,
  23699. cmdName: 'insertparagraph',
  23700. },
  23701. {
  23702. label: lang['copy'],
  23703. cmdName: 'copy',
  23704. },
  23705. {
  23706. label: lang['paste'],
  23707. cmdName: 'paste',
  23708. },
  23709. ]
  23710. if (!items.length) {
  23711. return
  23712. }
  23713. var uiUtils = UE.ui.uiUtils
  23714. me.addListener('contextmenu', function (type, evt) {
  23715. var offset = uiUtils.getViewportOffsetByEvent(evt)
  23716. me.fireEvent('beforeselectionchange')
  23717. if (menu) {
  23718. menu.destroy()
  23719. }
  23720. for (var i = 0, ti, contextItems = []; (ti = items[i]); i++) {
  23721. var last
  23722. ;(function (item) {
  23723. if (item == '-') {
  23724. if (
  23725. (last = contextItems[contextItems.length - 1]) &&
  23726. last !== '-'
  23727. ) {
  23728. contextItems.push('-')
  23729. }
  23730. } else if (item.hasOwnProperty('group')) {
  23731. for (var j = 0, cj, subMenu = []; (cj = item.subMenu[j]); j++) {
  23732. ;(function (subItem) {
  23733. if (subItem == '-') {
  23734. if ((last = subMenu[subMenu.length - 1]) && last !== '-') {
  23735. subMenu.push('-')
  23736. } else {
  23737. subMenu.splice(subMenu.length - 1)
  23738. }
  23739. } else {
  23740. if (
  23741. (me.commands[subItem.cmdName] ||
  23742. UE.commands[subItem.cmdName] ||
  23743. subItem.query) &&
  23744. (subItem.query
  23745. ? subItem.query()
  23746. : me.queryCommandState(subItem.cmdName)) > -1
  23747. ) {
  23748. subMenu.push({
  23749. label:
  23750. subItem.label ||
  23751. me.getLang(
  23752. 'contextMenu.' +
  23753. subItem.cmdName +
  23754. (subItem.value || '')
  23755. ) ||
  23756. '',
  23757. className:
  23758. 'edui-for-' +
  23759. subItem.cmdName +
  23760. (subItem.className
  23761. ? ' edui-for-' +
  23762. subItem.cmdName +
  23763. '-' +
  23764. subItem.className
  23765. : ''),
  23766. onclick: subItem.exec
  23767. ? function () {
  23768. subItem.exec.call(me)
  23769. }
  23770. : function () {
  23771. me.execCommand(subItem.cmdName, subItem.value)
  23772. },
  23773. })
  23774. }
  23775. }
  23776. })(cj)
  23777. }
  23778. if (subMenu.length) {
  23779. function getLabel() {
  23780. switch (item.icon) {
  23781. case 'table':
  23782. return me.getLang('contextMenu.table')
  23783. case 'justifyjustify':
  23784. return me.getLang('contextMenu.paragraph')
  23785. case 'aligntd':
  23786. return me.getLang('contextMenu.aligntd')
  23787. case 'aligntable':
  23788. return me.getLang('contextMenu.aligntable')
  23789. case 'tablesort':
  23790. return lang.tablesort
  23791. case 'borderBack':
  23792. return lang.borderbk
  23793. default:
  23794. return ''
  23795. }
  23796. }
  23797. contextItems.push({
  23798. //todo 修正成自动获取方式
  23799. label: getLabel(),
  23800. className: 'edui-for-' + item.icon,
  23801. subMenu: {
  23802. items: subMenu,
  23803. editor: me,
  23804. },
  23805. })
  23806. }
  23807. } else {
  23808. //有可能commmand没有加载右键不能出来,或者没有command也想能展示出来添加query方法
  23809. if (
  23810. (me.commands[item.cmdName] ||
  23811. UE.commands[item.cmdName] ||
  23812. item.query) &&
  23813. (item.query
  23814. ? item.query.call(me)
  23815. : me.queryCommandState(item.cmdName)) > -1
  23816. ) {
  23817. contextItems.push({
  23818. label: item.label || me.getLang('contextMenu.' + item.cmdName),
  23819. className:
  23820. 'edui-for-' +
  23821. (item.icon ? item.icon : item.cmdName + (item.value || '')),
  23822. onclick: item.exec
  23823. ? function () {
  23824. item.exec.call(me)
  23825. }
  23826. : function () {
  23827. me.execCommand(item.cmdName, item.value)
  23828. },
  23829. })
  23830. }
  23831. }
  23832. })(ti)
  23833. }
  23834. if (contextItems[contextItems.length - 1] == '-') {
  23835. contextItems.pop()
  23836. }
  23837. menu = new UE.ui.Menu({
  23838. items: contextItems,
  23839. className: 'edui-contextmenu',
  23840. editor: me,
  23841. })
  23842. menu.render()
  23843. menu.showAt(offset)
  23844. me.fireEvent('aftershowcontextmenu', menu)
  23845. domUtils.preventDefault(evt)
  23846. if (browser.ie) {
  23847. var ieRange
  23848. try {
  23849. ieRange = me.selection.getNative().createRange()
  23850. } catch (e) {
  23851. return
  23852. }
  23853. if (ieRange.item) {
  23854. var range = new dom.Range(me.document)
  23855. range.selectNode(ieRange.item(0)).select(true, true)
  23856. }
  23857. }
  23858. })
  23859. // 添加复制的flash按钮
  23860. me.addListener('aftershowcontextmenu', function (type, menu) {
  23861. if (me.zeroclipboard) {
  23862. var items = menu.items
  23863. for (var key in items) {
  23864. if (items[key].className == 'edui-for-copy') {
  23865. me.zeroclipboard.clip(items[key].getDom())
  23866. }
  23867. }
  23868. }
  23869. })
  23870. }
  23871. // plugins/shortcutmenu.js
  23872. ///import core
  23873. ///commands 弹出菜单
  23874. // commandsName popupmenu
  23875. ///commandsTitle 弹出菜单
  23876. /**
  23877. * 弹出菜单
  23878. * @function
  23879. * @name baidu.editor.plugins.popupmenu
  23880. * @author xuheng
  23881. */
  23882. UE.plugins['shortcutmenu'] = function () {
  23883. var me = this,
  23884. menu,
  23885. items = me.options.shortcutMenu || []
  23886. if (!items.length) {
  23887. return
  23888. }
  23889. me.addListener('contextmenu mouseup', function (type, e) {
  23890. var me = this,
  23891. customEvt = {
  23892. type: type,
  23893. target: e.target || e.srcElement,
  23894. screenX: e.screenX,
  23895. screenY: e.screenY,
  23896. clientX: e.clientX,
  23897. clientY: e.clientY,
  23898. }
  23899. setTimeout(function () {
  23900. var rng = me.selection.getRange()
  23901. if (rng.collapsed === false || type == 'contextmenu') {
  23902. if (!menu) {
  23903. menu = new baidu.editor.ui.ShortCutMenu({
  23904. editor: me,
  23905. items: items,
  23906. theme: me.options.theme,
  23907. className: 'edui-shortcutmenu',
  23908. })
  23909. menu.render()
  23910. me.fireEvent('afterrendershortcutmenu', menu)
  23911. }
  23912. menu.show(customEvt, !!UE.plugins['contextmenu'])
  23913. }
  23914. })
  23915. if (type == 'contextmenu') {
  23916. domUtils.preventDefault(e)
  23917. if (browser.ie9below) {
  23918. var ieRange
  23919. try {
  23920. ieRange = me.selection.getNative().createRange()
  23921. } catch (e) {
  23922. return
  23923. }
  23924. if (ieRange.item) {
  23925. var range = new dom.Range(me.document)
  23926. range.selectNode(ieRange.item(0)).select(true, true)
  23927. }
  23928. }
  23929. }
  23930. })
  23931. me.addListener('keydown', function (type) {
  23932. if (type == 'keydown') {
  23933. menu && !menu.isHidden && menu.hide()
  23934. }
  23935. })
  23936. }
  23937. // plugins/basestyle.js
  23938. /**
  23939. * B、I、sub、super命令支持
  23940. * @file
  23941. * @since 1.2.6.1
  23942. */
  23943. UE.plugins['basestyle'] = function () {
  23944. /**
  23945. * 字体加粗
  23946. * @command bold
  23947. * @param { String } cmd 命令字符串
  23948. * @remind 对已加粗的文本内容执行该命令, 将取消加粗
  23949. * @method execCommand
  23950. * @example
  23951. * ```javascript
  23952. * //editor是编辑器实例
  23953. * //对当前选中的文本内容执行加粗操作
  23954. * //第一次执行, 文本内容加粗
  23955. * editor.execCommand( 'bold' );
  23956. *
  23957. * //第二次执行, 文本内容取消加粗
  23958. * editor.execCommand( 'bold' );
  23959. * ```
  23960. */
  23961. /**
  23962. * 字体倾斜
  23963. * @command italic
  23964. * @method execCommand
  23965. * @param { String } cmd 命令字符串
  23966. * @remind 对已倾斜的文本内容执行该命令, 将取消倾斜
  23967. * @example
  23968. * ```javascript
  23969. * //editor是编辑器实例
  23970. * //对当前选中的文本内容执行斜体操作
  23971. * //第一次操作, 文本内容将变成斜体
  23972. * editor.execCommand( 'italic' );
  23973. *
  23974. * //再次对同一文本内容执行, 则文本内容将恢复正常
  23975. * editor.execCommand( 'italic' );
  23976. * ```
  23977. */
  23978. /**
  23979. * 下标文本,与“superscript”命令互斥
  23980. * @command subscript
  23981. * @method execCommand
  23982. * @remind 把选中的文本内容切换成下标文本, 如果当前选中的文本已经是下标, 则该操作会把文本内容还原成正常文本
  23983. * @param { String } cmd 命令字符串
  23984. * @example
  23985. * ```javascript
  23986. * //editor是编辑器实例
  23987. * //对当前选中的文本内容执行下标操作
  23988. * //第一次操作, 文本内容将变成下标文本
  23989. * editor.execCommand( 'subscript' );
  23990. *
  23991. * //再次对同一文本内容执行, 则文本内容将恢复正常
  23992. * editor.execCommand( 'subscript' );
  23993. * ```
  23994. */
  23995. /**
  23996. * 上标文本,与“subscript”命令互斥
  23997. * @command superscript
  23998. * @method execCommand
  23999. * @remind 把选中的文本内容切换成上标文本, 如果当前选中的文本已经是上标, 则该操作会把文本内容还原成正常文本
  24000. * @param { String } cmd 命令字符串
  24001. * @example
  24002. * ```javascript
  24003. * //editor是编辑器实例
  24004. * //对当前选中的文本内容执行上标操作
  24005. * //第一次操作, 文本内容将变成上标文本
  24006. * editor.execCommand( 'superscript' );
  24007. *
  24008. * //再次对同一文本内容执行, 则文本内容将恢复正常
  24009. * editor.execCommand( 'superscript' );
  24010. * ```
  24011. */
  24012. var basestyles = {
  24013. bold: ['strong', 'b'],
  24014. italic: ['em', 'i'],
  24015. subscript: ['sub'],
  24016. superscript: ['sup'],
  24017. },
  24018. getObj = function (editor, tagNames) {
  24019. return domUtils.filterNodeList(
  24020. editor.selection.getStartElementPath(),
  24021. tagNames
  24022. )
  24023. },
  24024. me = this
  24025. //添加快捷键
  24026. me.addshortcutkey({
  24027. Bold: 'ctrl+66', //^B
  24028. Italic: 'ctrl+73', //^I
  24029. Underline: 'ctrl+85', //^U
  24030. })
  24031. me.addInputRule(function (root) {
  24032. utils.each(root.getNodesByTagName('b i'), function (node) {
  24033. switch (node.tagName) {
  24034. case 'b':
  24035. node.tagName = 'strong'
  24036. break
  24037. case 'i':
  24038. node.tagName = 'em'
  24039. }
  24040. })
  24041. })
  24042. for (var style in basestyles) {
  24043. ;(function (cmd, tagNames) {
  24044. me.commands[cmd] = {
  24045. execCommand: function (cmdName) {
  24046. var range = me.selection.getRange(),
  24047. obj = getObj(this, tagNames)
  24048. if (range.collapsed) {
  24049. if (obj) {
  24050. var tmpText = me.document.createTextNode('')
  24051. range.insertNode(tmpText).removeInlineStyle(tagNames)
  24052. range.setStartBefore(tmpText)
  24053. domUtils.remove(tmpText)
  24054. } else {
  24055. var tmpNode = range.document.createElement(tagNames[0])
  24056. if (cmdName == 'superscript' || cmdName == 'subscript') {
  24057. tmpText = me.document.createTextNode('')
  24058. range
  24059. .insertNode(tmpText)
  24060. .removeInlineStyle(['sub', 'sup'])
  24061. .setStartBefore(tmpText)
  24062. .collapse(true)
  24063. }
  24064. range.insertNode(tmpNode).setStart(tmpNode, 0)
  24065. }
  24066. range.collapse(true)
  24067. } else {
  24068. if (cmdName == 'superscript' || cmdName == 'subscript') {
  24069. if (!obj || obj.tagName.toLowerCase() != cmdName) {
  24070. range.removeInlineStyle(['sub', 'sup'])
  24071. }
  24072. }
  24073. obj
  24074. ? range.removeInlineStyle(tagNames)
  24075. : range.applyInlineStyle(tagNames[0])
  24076. }
  24077. range.select()
  24078. },
  24079. queryCommandState: function () {
  24080. return getObj(this, tagNames) ? 1 : 0
  24081. },
  24082. }
  24083. })(style, basestyles[style])
  24084. }
  24085. }
  24086. // plugins/elementpath.js
  24087. /**
  24088. * 选取路径命令
  24089. * @file
  24090. */
  24091. UE.plugins['elementpath'] = function () {
  24092. var currentLevel,
  24093. tagNames,
  24094. me = this
  24095. me.setOpt('elementPathEnabled', true)
  24096. if (!me.options.elementPathEnabled) {
  24097. return
  24098. }
  24099. me.commands['elementpath'] = {
  24100. execCommand: function (cmdName, level) {
  24101. var start = tagNames[level],
  24102. range = me.selection.getRange()
  24103. currentLevel = level * 1
  24104. range.selectNode(start).select()
  24105. },
  24106. queryCommandValue: function () {
  24107. //产生一个副本,不能修改原来的startElementPath;
  24108. var parents = [].concat(this.selection.getStartElementPath()).reverse(),
  24109. names = []
  24110. tagNames = parents
  24111. for (var i = 0, ci; (ci = parents[i]); i++) {
  24112. if (ci.nodeType == 3) {
  24113. continue
  24114. }
  24115. var name = ci.tagName.toLowerCase()
  24116. if (name == 'img' && ci.getAttribute('anchorname')) {
  24117. name = 'anchor'
  24118. }
  24119. names[i] = name
  24120. if (currentLevel == i) {
  24121. currentLevel = -1
  24122. break
  24123. }
  24124. }
  24125. return names
  24126. },
  24127. }
  24128. }
  24129. // plugins/formatmatch.js
  24130. /**
  24131. * 格式刷,只格式inline的
  24132. * @file
  24133. * @since 1.2.6.1
  24134. */
  24135. /**
  24136. * 格式刷
  24137. * @command formatmatch
  24138. * @method execCommand
  24139. * @remind 该操作不能复制段落格式
  24140. * @param { String } cmd 命令字符串
  24141. * @example
  24142. * ```javascript
  24143. * //editor是编辑器实例
  24144. * //获取格式刷
  24145. * editor.execCommand( 'formatmatch' );
  24146. * ```
  24147. */
  24148. UE.plugins['formatmatch'] = function () {
  24149. var me = this,
  24150. list = [],
  24151. img,
  24152. flag = 0
  24153. me.addListener('reset', function () {
  24154. list = []
  24155. flag = 0
  24156. })
  24157. function addList(type, evt) {
  24158. if (browser.webkit) {
  24159. var target = evt.target.tagName == 'IMG' ? evt.target : null
  24160. }
  24161. function addFormat(range) {
  24162. if (text) {
  24163. range.selectNode(text)
  24164. }
  24165. return range.applyInlineStyle(list[list.length - 1].tagName, null, list)
  24166. }
  24167. me.undoManger && me.undoManger.save()
  24168. var range = me.selection.getRange(),
  24169. imgT = target || range.getClosedNode()
  24170. if (img && imgT && imgT.tagName == 'IMG') {
  24171. //trace:964
  24172. imgT.style.cssText +=
  24173. ';float:' +
  24174. (img.style.cssFloat || img.style.styleFloat || 'none') +
  24175. ';display:' +
  24176. (img.style.display || 'inline')
  24177. img = null
  24178. } else {
  24179. if (!img) {
  24180. var collapsed = range.collapsed
  24181. if (collapsed) {
  24182. var text = me.document.createTextNode('match')
  24183. range.insertNode(text).select()
  24184. }
  24185. me.__hasEnterExecCommand = true
  24186. //不能把block上的属性干掉
  24187. //trace:1553
  24188. var removeFormatAttributes = me.options.removeFormatAttributes
  24189. me.options.removeFormatAttributes = ''
  24190. me.execCommand('removeformat')
  24191. me.options.removeFormatAttributes = removeFormatAttributes
  24192. me.__hasEnterExecCommand = false
  24193. //trace:969
  24194. range = me.selection.getRange()
  24195. if (list.length) {
  24196. addFormat(range)
  24197. }
  24198. if (text) {
  24199. range.setStartBefore(text).collapse(true)
  24200. }
  24201. range.select()
  24202. text && domUtils.remove(text)
  24203. }
  24204. }
  24205. me.undoManger && me.undoManger.save()
  24206. me.removeListener('mouseup', addList)
  24207. flag = 0
  24208. }
  24209. me.commands['formatmatch'] = {
  24210. execCommand: function (cmdName) {
  24211. if (flag) {
  24212. flag = 0
  24213. list = []
  24214. me.removeListener('mouseup', addList)
  24215. return
  24216. }
  24217. var range = me.selection.getRange()
  24218. img = range.getClosedNode()
  24219. if (!img || img.tagName != 'IMG') {
  24220. range.collapse(true).shrinkBoundary()
  24221. var start = range.startContainer
  24222. list = domUtils.findParents(start, true, function (node) {
  24223. return !domUtils.isBlockElm(node) && node.nodeType == 1
  24224. })
  24225. //a不能加入格式刷, 并且克隆节点
  24226. for (var i = 0, ci; (ci = list[i]); i++) {
  24227. if (ci.tagName == 'A') {
  24228. list.splice(i, 1)
  24229. break
  24230. }
  24231. }
  24232. }
  24233. me.addListener('mouseup', addList)
  24234. flag = 1
  24235. },
  24236. queryCommandState: function () {
  24237. return flag
  24238. },
  24239. notNeedUndo: 1,
  24240. }
  24241. }
  24242. // plugins/searchreplace.js
  24243. ///import core
  24244. ///commands 查找替换
  24245. ///commandsName SearchReplace
  24246. ///commandsTitle 查询替换
  24247. ///commandsDialog dialogs\searchreplace
  24248. /**
  24249. * @description 查找替换
  24250. * @author zhanyi
  24251. */
  24252. UE.plugin.register('searchreplace', function () {
  24253. var me = this
  24254. var _blockElm = { table: 1, tbody: 1, tr: 1, ol: 1, ul: 1 }
  24255. function findTextInString(textContent, opt, currentIndex) {
  24256. var str = opt.searchStr
  24257. if (opt.dir == -1) {
  24258. textContent = textContent.split('').reverse().join('')
  24259. str = str.split('').reverse().join('')
  24260. currentIndex = textContent.length - currentIndex
  24261. }
  24262. var reg = new RegExp(str, 'g' + (opt.casesensitive ? '' : 'i')),
  24263. match
  24264. while ((match = reg.exec(textContent))) {
  24265. if (match.index >= currentIndex) {
  24266. return opt.dir == -1
  24267. ? textContent.length - match.index - opt.searchStr.length
  24268. : match.index
  24269. }
  24270. }
  24271. return -1
  24272. }
  24273. function findTextBlockElm(node, currentIndex, opt) {
  24274. var textContent,
  24275. index,
  24276. methodName =
  24277. opt.all || opt.dir == 1 ? 'getNextDomNode' : 'getPreDomNode'
  24278. if (domUtils.isBody(node)) {
  24279. node = node.firstChild
  24280. }
  24281. var first = 1
  24282. while (node) {
  24283. textContent =
  24284. node.nodeType == 3
  24285. ? node.nodeValue
  24286. : node[browser.ie ? 'innerText' : 'textContent']
  24287. index = findTextInString(textContent, opt, currentIndex)
  24288. first = 0
  24289. if (index != -1) {
  24290. return {
  24291. node: node,
  24292. index: index,
  24293. }
  24294. }
  24295. node = domUtils[methodName](node)
  24296. while (node && _blockElm[node.nodeName.toLowerCase()]) {
  24297. node = domUtils[methodName](node, true)
  24298. }
  24299. if (node) {
  24300. currentIndex =
  24301. opt.dir == -1
  24302. ? (node.nodeType == 3
  24303. ? node.nodeValue
  24304. : node[browser.ie ? 'innerText' : 'textContent']
  24305. ).length
  24306. : 0
  24307. }
  24308. }
  24309. }
  24310. function findNTextInBlockElm(node, index, str) {
  24311. var currentIndex = 0,
  24312. currentNode = node.firstChild,
  24313. currentNodeLength = 0,
  24314. result
  24315. while (currentNode) {
  24316. if (currentNode.nodeType == 3) {
  24317. currentNodeLength = currentNode.nodeValue.replace(
  24318. /(^[\t\r\n]+)|([\t\r\n]+$)/,
  24319. ''
  24320. ).length
  24321. currentIndex += currentNodeLength
  24322. if (currentIndex >= index) {
  24323. return {
  24324. node: currentNode,
  24325. index: currentNodeLength - (currentIndex - index),
  24326. }
  24327. }
  24328. } else if (!dtd.$empty[currentNode.tagName]) {
  24329. currentNodeLength = currentNode[
  24330. browser.ie ? 'innerText' : 'textContent'
  24331. ].replace(/(^[\t\r\n]+)|([\t\r\n]+$)/, '').length
  24332. currentIndex += currentNodeLength
  24333. if (currentIndex >= index) {
  24334. result = findNTextInBlockElm(
  24335. currentNode,
  24336. currentNodeLength - (currentIndex - index),
  24337. str
  24338. )
  24339. if (result) {
  24340. return result
  24341. }
  24342. }
  24343. }
  24344. currentNode = domUtils.getNextDomNode(currentNode)
  24345. }
  24346. }
  24347. function searchReplace(me, opt) {
  24348. var rng = me.selection.getRange(),
  24349. startBlockNode,
  24350. searchStr = opt.searchStr,
  24351. span = me.document.createElement('span')
  24352. span.innerHTML = '$$ueditor_searchreplace_key$$'
  24353. rng.shrinkBoundary(true)
  24354. //判断是不是第一次选中
  24355. if (!rng.collapsed) {
  24356. rng.select()
  24357. var rngText = me.selection.getText()
  24358. if (
  24359. new RegExp(
  24360. '^' + opt.searchStr + '$',
  24361. opt.casesensitive ? '' : 'i'
  24362. ).test(rngText)
  24363. ) {
  24364. if (opt.replaceStr != undefined) {
  24365. replaceText(rng, opt.replaceStr)
  24366. rng.select()
  24367. return true
  24368. } else {
  24369. rng.collapse(opt.dir == -1)
  24370. }
  24371. }
  24372. }
  24373. rng.insertNode(span)
  24374. rng.enlargeToBlockElm(true)
  24375. startBlockNode = rng.startContainer
  24376. var currentIndex = startBlockNode[
  24377. browser.ie ? 'innerText' : 'textContent'
  24378. ].indexOf('$$ueditor_searchreplace_key$$')
  24379. rng.setStartBefore(span)
  24380. domUtils.remove(span)
  24381. var result = findTextBlockElm(startBlockNode, currentIndex, opt)
  24382. if (result) {
  24383. var rngStart = findNTextInBlockElm(result.node, result.index, searchStr)
  24384. var rngEnd = findNTextInBlockElm(
  24385. result.node,
  24386. result.index + searchStr.length,
  24387. searchStr
  24388. )
  24389. rng
  24390. .setStart(rngStart.node, rngStart.index)
  24391. .setEnd(rngEnd.node, rngEnd.index)
  24392. if (opt.replaceStr !== undefined) {
  24393. replaceText(rng, opt.replaceStr)
  24394. }
  24395. rng.select()
  24396. return true
  24397. } else {
  24398. rng.setCursor()
  24399. }
  24400. }
  24401. function replaceText(rng, str) {
  24402. str = me.document.createTextNode(str)
  24403. rng.deleteContents().insertNode(str)
  24404. }
  24405. return {
  24406. commands: {
  24407. searchreplace: {
  24408. execCommand: function (cmdName, opt) {
  24409. utils.extend(
  24410. opt,
  24411. {
  24412. all: false,
  24413. casesensitive: false,
  24414. dir: 1,
  24415. },
  24416. true
  24417. )
  24418. var num = 0
  24419. if (opt.all) {
  24420. var rng = me.selection.getRange(),
  24421. first = me.body.firstChild
  24422. if (first && first.nodeType == 1) {
  24423. rng.setStart(first, 0)
  24424. rng.shrinkBoundary(true)
  24425. } else if (first.nodeType == 3) {
  24426. rng.setStartBefore(first)
  24427. }
  24428. rng.collapse(true).select(true)
  24429. if (opt.replaceStr !== undefined) {
  24430. me.fireEvent('saveScene')
  24431. }
  24432. while (searchReplace(this, opt)) {
  24433. num++
  24434. }
  24435. if (num) {
  24436. me.fireEvent('saveScene')
  24437. }
  24438. } else {
  24439. if (opt.replaceStr !== undefined) {
  24440. me.fireEvent('saveScene')
  24441. }
  24442. if (searchReplace(this, opt)) {
  24443. num++
  24444. }
  24445. if (num) {
  24446. me.fireEvent('saveScene')
  24447. }
  24448. }
  24449. return num
  24450. },
  24451. notNeedUndo: 1,
  24452. },
  24453. },
  24454. }
  24455. })
  24456. // plugins/customstyle.js
  24457. /**
  24458. * 自定义样式
  24459. * @file
  24460. * @since 1.2.6.1
  24461. */
  24462. /**
  24463. * 根据config配置文件里“customstyle”选项的值对匹配的标签执行样式替换。
  24464. * @command customstyle
  24465. * @method execCommand
  24466. * @param { String } cmd 命令字符串
  24467. * @example
  24468. * ```javascript
  24469. * editor.execCommand( 'customstyle' );
  24470. * ```
  24471. */
  24472. UE.plugins['customstyle'] = function () {
  24473. var me = this
  24474. me.setOpt({
  24475. customstyle: [
  24476. {
  24477. tag: 'h1',
  24478. name: 'tc',
  24479. style:
  24480. 'font-size:32px;font-weight:bold;border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:center;margin:0 0 20px 0;',
  24481. },
  24482. {
  24483. tag: 'h1',
  24484. name: 'tl',
  24485. style:
  24486. 'font-size:32px;font-weight:bold;border-bottom:#ccc 2px solid;padding:0 4px 0 0;text-align:left;margin:0 0 10px 0;',
  24487. },
  24488. {
  24489. tag: 'span',
  24490. name: 'im',
  24491. style:
  24492. 'font-size:16px;font-style:italic;font-weight:bold;line-height:18px;',
  24493. },
  24494. {
  24495. tag: 'span',
  24496. name: 'hi',
  24497. style:
  24498. 'font-size:16px;font-style:italic;font-weight:bold;color:rgb(51, 153, 204);line-height:18px;',
  24499. },
  24500. ],
  24501. })
  24502. me.commands['customstyle'] = {
  24503. execCommand: function (cmdName, obj) {
  24504. var me = this,
  24505. tagName = obj.tag,
  24506. node = domUtils.findParent(
  24507. me.selection.getStart(),
  24508. function (node) {
  24509. return node.getAttribute('label')
  24510. },
  24511. true
  24512. ),
  24513. range,
  24514. bk,
  24515. tmpObj = {}
  24516. for (var p in obj) {
  24517. if (obj[p] !== undefined) tmpObj[p] = obj[p]
  24518. }
  24519. delete tmpObj.tag
  24520. if (node && node.getAttribute('label') == obj.label) {
  24521. range = this.selection.getRange()
  24522. bk = range.createBookmark()
  24523. if (range.collapsed) {
  24524. //trace:1732 删掉自定义标签,要有p来回填站位
  24525. if (dtd.$block[node.tagName]) {
  24526. var fillNode = me.document.createElement('p')
  24527. domUtils.moveChild(node, fillNode)
  24528. node.parentNode.insertBefore(fillNode, node)
  24529. domUtils.remove(node)
  24530. } else {
  24531. domUtils.remove(node, true)
  24532. }
  24533. } else {
  24534. var common = domUtils.getCommonAncestor(bk.start, bk.end),
  24535. nodes = domUtils.getElementsByTagName(common, tagName)
  24536. if (new RegExp(tagName, 'i').test(common.tagName)) {
  24537. nodes.push(common)
  24538. }
  24539. for (var i = 0, ni; (ni = nodes[i++]); ) {
  24540. if (ni.getAttribute('label') == obj.label) {
  24541. var ps = domUtils.getPosition(ni, bk.start),
  24542. pe = domUtils.getPosition(ni, bk.end)
  24543. if (
  24544. (ps & domUtils.POSITION_FOLLOWING ||
  24545. ps & domUtils.POSITION_CONTAINS) &&
  24546. (pe & domUtils.POSITION_PRECEDING ||
  24547. pe & domUtils.POSITION_CONTAINS)
  24548. )
  24549. if (dtd.$block[tagName]) {
  24550. var fillNode = me.document.createElement('p')
  24551. domUtils.moveChild(ni, fillNode)
  24552. ni.parentNode.insertBefore(fillNode, ni)
  24553. }
  24554. domUtils.remove(ni, true)
  24555. }
  24556. }
  24557. node = domUtils.findParent(
  24558. common,
  24559. function (node) {
  24560. return node.getAttribute('label') == obj.label
  24561. },
  24562. true
  24563. )
  24564. if (node) {
  24565. domUtils.remove(node, true)
  24566. }
  24567. }
  24568. range.moveToBookmark(bk).select()
  24569. } else {
  24570. if (dtd.$block[tagName]) {
  24571. this.execCommand('paragraph', tagName, tmpObj, 'customstyle')
  24572. range = me.selection.getRange()
  24573. if (!range.collapsed) {
  24574. range.collapse()
  24575. node = domUtils.findParent(
  24576. me.selection.getStart(),
  24577. function (node) {
  24578. return node.getAttribute('label') == obj.label
  24579. },
  24580. true
  24581. )
  24582. var pNode = me.document.createElement('p')
  24583. domUtils.insertAfter(node, pNode)
  24584. domUtils.fillNode(me.document, pNode)
  24585. range.setStart(pNode, 0).setCursor()
  24586. }
  24587. } else {
  24588. range = me.selection.getRange()
  24589. if (range.collapsed) {
  24590. node = me.document.createElement(tagName)
  24591. domUtils.setAttributes(node, tmpObj)
  24592. range.insertNode(node).setStart(node, 0).setCursor()
  24593. return
  24594. }
  24595. bk = range.createBookmark()
  24596. range.applyInlineStyle(tagName, tmpObj).moveToBookmark(bk).select()
  24597. }
  24598. }
  24599. },
  24600. queryCommandValue: function () {
  24601. var parent = domUtils.filterNodeList(
  24602. this.selection.getStartElementPath(),
  24603. function (node) {
  24604. return node.getAttribute('label')
  24605. }
  24606. )
  24607. return parent ? parent.getAttribute('label') : ''
  24608. },
  24609. }
  24610. //当去掉customstyle是,如果是块元素,用p代替
  24611. me.addListener('keyup', function (type, evt) {
  24612. var keyCode = evt.keyCode || evt.which
  24613. if (keyCode == 32 || keyCode == 13) {
  24614. var range = me.selection.getRange()
  24615. if (range.collapsed) {
  24616. var node = domUtils.findParent(
  24617. me.selection.getStart(),
  24618. function (node) {
  24619. return node.getAttribute('label')
  24620. },
  24621. true
  24622. )
  24623. if (node && dtd.$block[node.tagName] && domUtils.isEmptyNode(node)) {
  24624. var p = me.document.createElement('p')
  24625. domUtils.insertAfter(node, p)
  24626. domUtils.fillNode(me.document, p)
  24627. domUtils.remove(node)
  24628. range.setStart(p, 0).setCursor()
  24629. }
  24630. }
  24631. }
  24632. })
  24633. }
  24634. // plugins/catchremoteimage.js
  24635. ///import core
  24636. ///commands 远程图片抓取
  24637. ///commandsName catchRemoteImage,catchremoteimageenable
  24638. ///commandsTitle 远程图片抓取
  24639. /**
  24640. * 远程图片抓取,当开启本插件时所有不符合本地域名的图片都将被抓取成为本地服务器上的图片
  24641. */
  24642. UE.plugins['catchremoteimage'] = function () {
  24643. var me = this,
  24644. ajax = UE.ajax
  24645. /* 设置默认值 */
  24646. if (me.options.catchRemoteImageEnable === false) return
  24647. me.setOpt({
  24648. catchRemoteImageEnable: false,
  24649. })
  24650. me.addListener('afterpaste', function () {
  24651. me.fireEvent('catchRemoteImage')
  24652. })
  24653. me.addListener('catchRemoteImage', function () {
  24654. var catcherLocalDomain = me.getOpt('catcherLocalDomain'),
  24655. catcherActionUrl = me.getActionUrl(me.getOpt('catcherActionName')),
  24656. catcherUrlPrefix = me.getOpt('catcherUrlPrefix'),
  24657. catcherFieldName = me.getOpt('catcherFieldName')
  24658. var remoteImages = [],
  24659. imgs = domUtils.getElementsByTagName(me.document, 'img'),
  24660. test = function (src, urls) {
  24661. if (src.indexOf(location.host) != -1 || /(^\.)|(^\/)/.test(src)) {
  24662. return true
  24663. }
  24664. if (urls) {
  24665. for (var j = 0, url; (url = urls[j++]); ) {
  24666. if (src.indexOf(url) !== -1) {
  24667. return true
  24668. }
  24669. }
  24670. }
  24671. return false
  24672. }
  24673. for (var i = 0, ci; (ci = imgs[i++]); ) {
  24674. if (ci.getAttribute('word_img')) {
  24675. continue
  24676. }
  24677. var src = ci.getAttribute('_src') || ci.src || ''
  24678. if (/^(https?|ftp):/i.test(src) && !test(src, catcherLocalDomain)) {
  24679. remoteImages.push(src)
  24680. }
  24681. }
  24682. if (remoteImages.length) {
  24683. catchremoteimage(remoteImages, {
  24684. //成功抓取
  24685. success: function (r) {
  24686. try {
  24687. var info =
  24688. r.state !== undefined ? r : eval('(' + r.responseText + ')')
  24689. } catch (e) {
  24690. return
  24691. }
  24692. /* 获取源路径和新路径 */
  24693. var i,
  24694. j,
  24695. ci,
  24696. cj,
  24697. oldSrc,
  24698. newSrc,
  24699. list = info.list
  24700. for (i = 0; (ci = imgs[i++]); ) {
  24701. oldSrc = ci.getAttribute('_src') || ci.src || ''
  24702. for (j = 0; (cj = list[j++]); ) {
  24703. if (oldSrc == cj.source && cj.state == 'SUCCESS') {
  24704. //抓取失败时不做替换处理
  24705. newSrc = catcherUrlPrefix + cj.url
  24706. domUtils.setAttributes(ci, {
  24707. src: newSrc,
  24708. _src: newSrc,
  24709. })
  24710. break
  24711. }
  24712. }
  24713. }
  24714. me.fireEvent('catchremotesuccess')
  24715. },
  24716. //回调失败,本次请求超时
  24717. error: function () {
  24718. me.fireEvent('catchremoteerror')
  24719. },
  24720. })
  24721. }
  24722. function catchremoteimage(imgs, callbacks) {
  24723. var params =
  24724. utils.serializeParam(me.queryCommandValue('serverparam')) || '',
  24725. url = utils.formatUrl(
  24726. catcherActionUrl +
  24727. (catcherActionUrl.indexOf('?') == -1 ? '?' : '&') +
  24728. params
  24729. ),
  24730. isJsonp = utils.isCrossDomainUrl(url),
  24731. opt = {
  24732. method: 'POST',
  24733. dataType: isJsonp ? 'jsonp' : '',
  24734. timeout: 60000, //单位:毫秒,回调请求超时设置。目标用户如果网速不是很快的话此处建议设置一个较大的数值
  24735. onsuccess: callbacks['success'],
  24736. onerror: callbacks['error'],
  24737. }
  24738. opt[catcherFieldName] = imgs
  24739. ajax.request(url, opt)
  24740. }
  24741. })
  24742. }
  24743. // plugins/snapscreen.js
  24744. /**
  24745. * 截屏插件,为UEditor提供插入支持
  24746. * @file
  24747. * @since 1.4.2
  24748. */
  24749. UE.plugin.register('snapscreen', function () {
  24750. var me = this
  24751. var snapplugin
  24752. function getLocation(url) {
  24753. var search,
  24754. a = document.createElement('a'),
  24755. params = utils.serializeParam(me.queryCommandValue('serverparam')) || ''
  24756. a.href = url
  24757. if (browser.ie) {
  24758. a.href = a.href
  24759. }
  24760. search = a.search
  24761. if (params) {
  24762. search = search + (search.indexOf('?') == -1 ? '?' : '&') + params
  24763. search = search.replace(/[&]+/gi, '&')
  24764. }
  24765. return {
  24766. port: a.port,
  24767. hostname: a.hostname,
  24768. path: a.pathname + search || +a.hash,
  24769. }
  24770. }
  24771. return {
  24772. commands: {
  24773. /**
  24774. * 字体背景颜色
  24775. * @command snapscreen
  24776. * @method execCommand
  24777. * @param { String } cmd 命令字符串
  24778. * @example
  24779. * ```javascript
  24780. * editor.execCommand('snapscreen');
  24781. * ```
  24782. */
  24783. snapscreen: {
  24784. execCommand: function (cmd) {
  24785. var url, local, res
  24786. var lang = me.getLang('snapScreen_plugin')
  24787. if (!snapplugin) {
  24788. var container = me.container
  24789. var doc = me.container.ownerDocument || me.container.document
  24790. snapplugin = doc.createElement('object')
  24791. try {
  24792. snapplugin.type = 'application/x-pluginbaidusnap'
  24793. } catch (e) {
  24794. return
  24795. }
  24796. snapplugin.style.cssText =
  24797. 'position:absolute;left:-9999px;width:0;height:0;'
  24798. snapplugin.setAttribute('width', '0')
  24799. snapplugin.setAttribute('height', '0')
  24800. container.appendChild(snapplugin)
  24801. }
  24802. function onSuccess(rs) {
  24803. try {
  24804. rs = eval('(' + rs + ')')
  24805. if (rs.state == 'SUCCESS') {
  24806. var opt = me.options
  24807. me.execCommand('insertimage', {
  24808. src: opt.snapscreenUrlPrefix + rs.url,
  24809. _src: opt.snapscreenUrlPrefix + rs.url,
  24810. alt: rs.title || '',
  24811. floatStyle: opt.snapscreenImgAlign,
  24812. })
  24813. } else {
  24814. alert(rs.state)
  24815. }
  24816. } catch (e) {
  24817. alert(lang.callBackErrorMsg)
  24818. }
  24819. }
  24820. url = me.getActionUrl(me.getOpt('snapscreenActionName'))
  24821. local = getLocation(url)
  24822. setTimeout(function () {
  24823. try {
  24824. res = snapplugin.saveSnapshot(
  24825. local.hostname,
  24826. local.path,
  24827. local.port
  24828. )
  24829. } catch (e) {
  24830. me.ui._dialogs['snapscreenDialog'].open()
  24831. return
  24832. }
  24833. onSuccess(res)
  24834. }, 50)
  24835. },
  24836. queryCommandState: function () {
  24837. return navigator.userAgent.indexOf('Windows', 0) != -1 ? 0 : -1
  24838. },
  24839. },
  24840. },
  24841. }
  24842. })
  24843. // plugins/insertparagraph.js
  24844. /**
  24845. * 插入段落
  24846. * @file
  24847. * @since 1.2.6.1
  24848. */
  24849. /**
  24850. * 插入段落
  24851. * @command insertparagraph
  24852. * @method execCommand
  24853. * @param { String } cmd 命令字符串
  24854. * @example
  24855. * ```javascript
  24856. * //editor是编辑器实例
  24857. * editor.execCommand( 'insertparagraph' );
  24858. * ```
  24859. */
  24860. UE.commands['insertparagraph'] = {
  24861. execCommand: function (cmdName, front) {
  24862. var me = this,
  24863. range = me.selection.getRange(),
  24864. start = range.startContainer,
  24865. tmpNode
  24866. while (start) {
  24867. if (domUtils.isBody(start)) {
  24868. break
  24869. }
  24870. tmpNode = start
  24871. start = start.parentNode
  24872. }
  24873. if (tmpNode) {
  24874. var p = me.document.createElement('p')
  24875. if (front) {
  24876. tmpNode.parentNode.insertBefore(p, tmpNode)
  24877. } else {
  24878. tmpNode.parentNode.insertBefore(p, tmpNode.nextSibling)
  24879. }
  24880. domUtils.fillNode(me.document, p)
  24881. range.setStart(p, 0).setCursor(false, true)
  24882. }
  24883. },
  24884. }
  24885. // plugins/webapp.js
  24886. /**
  24887. * 百度应用
  24888. * @file
  24889. * @since 1.2.6.1
  24890. */
  24891. /**
  24892. * 插入百度应用
  24893. * @command webapp
  24894. * @method execCommand
  24895. * @remind 需要百度APPKey
  24896. * @remind 百度应用主页: <a href="http://app.baidu.com/" target="_blank">http://app.baidu.com/</a>
  24897. * @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度,
  24898. * height=>应用容器高度,logo=>应用logo,url=>应用地址
  24899. * @example
  24900. * ```javascript
  24901. * //editor是编辑器实例
  24902. * //在编辑器里插入一个“植物大战僵尸”的APP
  24903. * editor.execCommand( 'webapp' , {
  24904. * title: '植物大战僵尸',
  24905. * width: 560,
  24906. * height: 465,
  24907. * logo: '应用展示的图片',
  24908. * url: '百度应用的地址'
  24909. * } );
  24910. * ```
  24911. */
  24912. //UE.plugins['webapp'] = function () {
  24913. // var me = this;
  24914. // function createInsertStr( obj, toIframe, addParagraph ) {
  24915. // return !toIframe ?
  24916. // (addParagraph ? '<p>' : '') + '<img title="'+obj.title+'" width="' + obj.width + '" height="' + obj.height + '"' +
  24917. // ' src="' + me.options.UEDITOR_HOME_URL + 'themes/default/images/spacer.gif" style="background:url(' + obj.logo+') no-repeat center center; border:1px solid gray;" class="edui-faked-webapp" _url="' + obj.url + '" />' +
  24918. // (addParagraph ? '</p>' : '')
  24919. // :
  24920. // '<iframe class="edui-faked-webapp" title="'+obj.title+'" width="' + obj.width + '" height="' + obj.height + '" scrolling="no" frameborder="0" src="' + obj.url + '" logo_url = '+obj.logo+'></iframe>';
  24921. // }
  24922. //
  24923. // function switchImgAndIframe( img2frame ) {
  24924. // var tmpdiv,
  24925. // nodes = domUtils.getElementsByTagName( me.document, !img2frame ? "iframe" : "img" );
  24926. // for ( var i = 0, node; node = nodes[i++]; ) {
  24927. // if ( node.className != "edui-faked-webapp" ){
  24928. // continue;
  24929. // }
  24930. // tmpdiv = me.document.createElement( "div" );
  24931. // tmpdiv.innerHTML = createInsertStr( img2frame ? {url:node.getAttribute( "_url" ), width:node.width, height:node.height,title:node.title,logo:node.style.backgroundImage.replace("url(","").replace(")","")} : {url:node.getAttribute( "src", 2 ),title:node.title, width:node.width, height:node.height,logo:node.getAttribute("logo_url")}, img2frame ? true : false,false );
  24932. // node.parentNode.replaceChild( tmpdiv.firstChild, node );
  24933. // }
  24934. // }
  24935. //
  24936. // me.addListener( "beforegetcontent", function () {
  24937. // switchImgAndIframe( true );
  24938. // } );
  24939. // me.addListener( 'aftersetcontent', function () {
  24940. // switchImgAndIframe( false );
  24941. // } );
  24942. // me.addListener( 'aftergetcontent', function ( cmdName ) {
  24943. // if ( cmdName == 'aftergetcontent' && me.queryCommandState( 'source' ) ){
  24944. // return;
  24945. // }
  24946. // switchImgAndIframe( false );
  24947. // } );
  24948. //
  24949. // me.commands['webapp'] = {
  24950. // execCommand:function ( cmd, obj ) {
  24951. // me.execCommand( "inserthtml", createInsertStr( obj, false,true ) );
  24952. // }
  24953. // };
  24954. //};
  24955. UE.plugin.register('webapp', function () {
  24956. var me = this
  24957. function createInsertStr(obj, toEmbed) {
  24958. return !toEmbed
  24959. ? '<img title="' +
  24960. obj.title +
  24961. '" width="' +
  24962. obj.width +
  24963. '" height="' +
  24964. obj.height +
  24965. '"' +
  24966. ' src="' +
  24967. me.options.UEDITOR_HOME_URL +
  24968. 'themes/default/images/spacer.gif" _logo_url="' +
  24969. obj.logo +
  24970. '" style="background:url(' +
  24971. obj.logo +
  24972. ') no-repeat center center; border:1px solid gray;" class="edui-faked-webapp" _url="' +
  24973. obj.url +
  24974. '" ' +
  24975. (obj.align && !obj.cssfloat ? 'align="' + obj.align + '"' : '') +
  24976. (obj.cssfloat ? 'style="float:' + obj.cssfloat + '"' : '') +
  24977. '/>'
  24978. : '<iframe class="edui-faked-webapp" title="' +
  24979. obj.title +
  24980. '" ' +
  24981. (obj.align && !obj.cssfloat ? 'align="' + obj.align + '"' : '') +
  24982. (obj.cssfloat ? 'style="float:' + obj.cssfloat + '"' : '') +
  24983. 'width="' +
  24984. obj.width +
  24985. '" height="' +
  24986. obj.height +
  24987. '" scrolling="no" frameborder="0" src="' +
  24988. obj.url +
  24989. '" logo_url = "' +
  24990. obj.logo +
  24991. '"></iframe>'
  24992. }
  24993. return {
  24994. outputRule: function (root) {
  24995. utils.each(root.getNodesByTagName('img'), function (node) {
  24996. var html
  24997. if (node.getAttr('class') == 'edui-faked-webapp') {
  24998. html = createInsertStr(
  24999. {
  25000. title: node.getAttr('title'),
  25001. width: node.getAttr('width'),
  25002. height: node.getAttr('height'),
  25003. align: node.getAttr('align'),
  25004. cssfloat: node.getStyle('float'),
  25005. url: node.getAttr('_url'),
  25006. logo: node.getAttr('_logo_url'),
  25007. },
  25008. true
  25009. )
  25010. var embed = UE.uNode.createElement(html)
  25011. node.parentNode.replaceChild(embed, node)
  25012. }
  25013. })
  25014. },
  25015. inputRule: function (root) {
  25016. utils.each(root.getNodesByTagName('iframe'), function (node) {
  25017. if (node.getAttr('class') == 'edui-faked-webapp') {
  25018. var img = UE.uNode.createElement(
  25019. createInsertStr({
  25020. title: node.getAttr('title'),
  25021. width: node.getAttr('width'),
  25022. height: node.getAttr('height'),
  25023. align: node.getAttr('align'),
  25024. cssfloat: node.getStyle('float'),
  25025. url: node.getAttr('src'),
  25026. logo: node.getAttr('logo_url'),
  25027. })
  25028. )
  25029. node.parentNode.replaceChild(img, node)
  25030. }
  25031. })
  25032. },
  25033. commands: {
  25034. /**
  25035. * 插入百度应用
  25036. * @command webapp
  25037. * @method execCommand
  25038. * @remind 需要百度APPKey
  25039. * @remind 百度应用主页: <a href="http://app.baidu.com/" target="_blank">http://app.baidu.com/</a>
  25040. * @param { Object } appOptions 应用所需的参数项, 支持的key有: title=>应用标题, width=>应用容器宽度,
  25041. * height=>应用容器高度,logo=>应用logo,url=>应用地址
  25042. * @example
  25043. * ```javascript
  25044. * //editor是编辑器实例
  25045. * //在编辑器里插入一个“植物大战僵尸”的APP
  25046. * editor.execCommand( 'webapp' , {
  25047. * title: '植物大战僵尸',
  25048. * width: 560,
  25049. * height: 465,
  25050. * logo: '应用展示的图片',
  25051. * url: '百度应用的地址'
  25052. * } );
  25053. * ```
  25054. */
  25055. webapp: {
  25056. execCommand: function (cmd, obj) {
  25057. var me = this,
  25058. str = createInsertStr(
  25059. utils.extend(obj, {
  25060. align: 'none',
  25061. }),
  25062. false
  25063. )
  25064. me.execCommand('inserthtml', str)
  25065. },
  25066. queryCommandState: function () {
  25067. var me = this,
  25068. img = me.selection.getRange().getClosedNode(),
  25069. flag = img && img.className == 'edui-faked-webapp'
  25070. return flag ? 1 : 0
  25071. },
  25072. },
  25073. },
  25074. }
  25075. })
  25076. // plugins/template.js
  25077. ///import core
  25078. ///import plugins\inserthtml.js
  25079. ///import plugins\cleardoc.js
  25080. ///commands 模板
  25081. ///commandsName template
  25082. ///commandsTitle 模板
  25083. ///commandsDialog dialogs\template
  25084. UE.plugins['template'] = function () {
  25085. UE.commands['template'] = {
  25086. execCommand: function (cmd, obj) {
  25087. obj.html && this.execCommand('inserthtml', obj.html)
  25088. },
  25089. }
  25090. this.addListener('click', function (type, evt) {
  25091. var el = evt.target || evt.srcElement,
  25092. range = this.selection.getRange()
  25093. var tnode = domUtils.findParent(
  25094. el,
  25095. function (node) {
  25096. if (node.className && domUtils.hasClass(node, 'ue_t')) {
  25097. return node
  25098. }
  25099. },
  25100. true
  25101. )
  25102. tnode && range.selectNode(tnode).shrinkBoundary().select()
  25103. })
  25104. this.addListener('keydown', function (type, evt) {
  25105. var range = this.selection.getRange()
  25106. if (!range.collapsed) {
  25107. if (!evt.ctrlKey && !evt.metaKey && !evt.shiftKey && !evt.altKey) {
  25108. var tnode = domUtils.findParent(
  25109. range.startContainer,
  25110. function (node) {
  25111. if (node.className && domUtils.hasClass(node, 'ue_t')) {
  25112. return node
  25113. }
  25114. },
  25115. true
  25116. )
  25117. if (tnode) {
  25118. domUtils.removeClasses(tnode, ['ue_t'])
  25119. }
  25120. }
  25121. }
  25122. })
  25123. }
  25124. // plugins/music.js
  25125. /**
  25126. * 插入音乐命令
  25127. * @file
  25128. */
  25129. UE.plugin.register('music', function () {
  25130. var me = this
  25131. function creatInsertStr(url, width, height, align, cssfloat, toEmbed) {
  25132. return !toEmbed
  25133. ? '<img ' +
  25134. (align && !cssfloat ? 'align="' + align + '"' : '') +
  25135. (cssfloat ? 'style="float:' + cssfloat + '"' : '') +
  25136. ' width="' +
  25137. width +
  25138. '" height="' +
  25139. height +
  25140. '" _url="' +
  25141. url +
  25142. '" class="edui-faked-music"' +
  25143. ' src="' +
  25144. me.options.langPath +
  25145. me.options.lang +
  25146. '/images/music.png" />'
  25147. : '<embed type="application/x-shockwave-flash" class="edui-faked-music" pluginspage="http://www.macromedia.com/go/getflashplayer"' +
  25148. ' src="' +
  25149. url +
  25150. '" width="' +
  25151. width +
  25152. '" height="' +
  25153. height +
  25154. '" ' +
  25155. (align && !cssfloat ? 'align="' + align + '"' : '') +
  25156. (cssfloat ? 'style="float:' + cssfloat + '"' : '') +
  25157. ' wmode="transparent" play="true" loop="false" menu="false" allowscriptaccess="never" allowfullscreen="true" >'
  25158. }
  25159. return {
  25160. outputRule: function (root) {
  25161. utils.each(root.getNodesByTagName('img'), function (node) {
  25162. var html
  25163. if (node.getAttr('class') == 'edui-faked-music') {
  25164. var cssfloat = node.getStyle('float')
  25165. var align = node.getAttr('align')
  25166. html = creatInsertStr(
  25167. node.getAttr('_url'),
  25168. node.getAttr('width'),
  25169. node.getAttr('height'),
  25170. align,
  25171. cssfloat,
  25172. true
  25173. )
  25174. var embed = UE.uNode.createElement(html)
  25175. node.parentNode.replaceChild(embed, node)
  25176. }
  25177. })
  25178. },
  25179. inputRule: function (root) {
  25180. utils.each(root.getNodesByTagName('embed'), function (node) {
  25181. if (node.getAttr('class') == 'edui-faked-music') {
  25182. var cssfloat = node.getStyle('float')
  25183. var align = node.getAttr('align')
  25184. html = creatInsertStr(
  25185. node.getAttr('src'),
  25186. node.getAttr('width'),
  25187. node.getAttr('height'),
  25188. align,
  25189. cssfloat,
  25190. false
  25191. )
  25192. var img = UE.uNode.createElement(html)
  25193. node.parentNode.replaceChild(img, node)
  25194. }
  25195. })
  25196. },
  25197. commands: {
  25198. /**
  25199. * 插入音乐
  25200. * @command music
  25201. * @method execCommand
  25202. * @param { Object } musicOptions 插入音乐的参数项, 支持的key有: url=>音乐地址;
  25203. * width=>音乐容器宽度;height=>音乐容器高度;align=>音乐文件的对齐方式, 可选值有: left, center, right, none
  25204. * @example
  25205. * ```javascript
  25206. * //editor是编辑器实例
  25207. * //在编辑器里插入一个“植物大战僵尸”的APP
  25208. * editor.execCommand( 'music' , {
  25209. * width: 400,
  25210. * height: 95,
  25211. * align: "center",
  25212. * url: "音乐地址"
  25213. * } );
  25214. * ```
  25215. */
  25216. music: {
  25217. execCommand: function (cmd, musicObj) {
  25218. var me = this,
  25219. str = creatInsertStr(
  25220. musicObj.url,
  25221. musicObj.width || 400,
  25222. musicObj.height || 95,
  25223. 'none',
  25224. false
  25225. )
  25226. me.execCommand('inserthtml', str)
  25227. },
  25228. queryCommandState: function () {
  25229. var me = this,
  25230. img = me.selection.getRange().getClosedNode(),
  25231. flag = img && img.className == 'edui-faked-music'
  25232. return flag ? 1 : 0
  25233. },
  25234. },
  25235. },
  25236. }
  25237. })
  25238. // plugins/autoupload.js
  25239. /**
  25240. * @description
  25241. * 1.拖放文件到编辑区域,自动上传并插入到选区
  25242. * 2.插入粘贴板的图片,自动上传并插入到选区
  25243. * @author Jinqn
  25244. * @date 2013-10-14
  25245. */
  25246. UE.plugin.register('autoupload', function () {
  25247. function sendAndInsertFile(file, editor) {
  25248. var me = editor
  25249. //模拟数据
  25250. var fieldName,
  25251. urlPrefix,
  25252. maxSize,
  25253. allowFiles,
  25254. actionUrl,
  25255. loadingHtml,
  25256. errorHandler,
  25257. successHandler,
  25258. filetype = /image\/\w+/i.test(file.type) ? 'image' : 'file',
  25259. loadingId = 'loading_' + (+new Date()).toString(36)
  25260. fieldName = me.getOpt(filetype + 'FieldName')
  25261. urlPrefix = me.getOpt(filetype + 'UrlPrefix')
  25262. maxSize = me.getOpt(filetype + 'MaxSize')
  25263. allowFiles = me.getOpt(filetype + 'AllowFiles')
  25264. actionUrl = me.getActionUrl(me.getOpt(filetype + 'ActionName'))
  25265. errorHandler = function (title) {
  25266. var loader = me.document.getElementById(loadingId)
  25267. loader && domUtils.remove(loader)
  25268. me.fireEvent('showmessage', {
  25269. id: loadingId,
  25270. content: title,
  25271. type: 'error',
  25272. timeout: 4000,
  25273. })
  25274. }
  25275. if (filetype == 'image') {
  25276. loadingHtml =
  25277. '<img class="loadingclass" id="' +
  25278. loadingId +
  25279. '" src="' +
  25280. me.options.themePath +
  25281. me.options.theme +
  25282. '/images/spacer.gif" title="' +
  25283. (me.getLang('autoupload.loading') || '') +
  25284. '" >'
  25285. successHandler = function (data) {
  25286. var link = urlPrefix + data.url,
  25287. loader = me.document.getElementById(loadingId)
  25288. if (loader) {
  25289. loader.setAttribute('src', link)
  25290. loader.setAttribute('_src', link)
  25291. loader.setAttribute('title', data.title || '')
  25292. loader.setAttribute('alt', data.original || '')
  25293. loader.removeAttribute('id')
  25294. domUtils.removeClasses(loader, 'loadingclass')
  25295. }
  25296. }
  25297. } else {
  25298. loadingHtml =
  25299. '<p>' +
  25300. '<img class="loadingclass" id="' +
  25301. loadingId +
  25302. '" src="' +
  25303. me.options.themePath +
  25304. me.options.theme +
  25305. '/images/spacer.gif" title="' +
  25306. (me.getLang('autoupload.loading') || '') +
  25307. '" >' +
  25308. '</p>'
  25309. successHandler = function (data) {
  25310. var link = urlPrefix + data.url,
  25311. loader = me.document.getElementById(loadingId)
  25312. var rng = me.selection.getRange(),
  25313. bk = rng.createBookmark()
  25314. rng.selectNode(loader).select()
  25315. me.execCommand('insertfile', { url: link })
  25316. rng.moveToBookmark(bk).select()
  25317. }
  25318. }
  25319. /* 插入loading的占位符 */
  25320. me.execCommand('inserthtml', loadingHtml)
  25321. /* 判断后端配置是否没有加载成功 */
  25322. if (!me.getOpt(filetype + 'ActionName')) {
  25323. console.log('此处baocuo')
  25324. errorHandler(me.getLang('autoupload.errorLoadConfig'))
  25325. return
  25326. }
  25327. /* 判断文件大小是否超出限制 */
  25328. if (file.size > maxSize) {
  25329. errorHandler(me.getLang('autoupload.exceedSizeError'))
  25330. return
  25331. }
  25332. /* 判断文件格式是否超出允许 */
  25333. var fileext = file.name
  25334. ? file.name.substr(file.name.lastIndexOf('.'))
  25335. : ''
  25336. if (
  25337. (fileext && filetype != 'image') ||
  25338. (allowFiles &&
  25339. (allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') ==
  25340. -1)
  25341. ) {
  25342. errorHandler(me.getLang('autoupload.exceedTypeError'))
  25343. return
  25344. }
  25345. /* 创建Ajax并提交 */
  25346. var xhr = new XMLHttpRequest(),
  25347. fd = new FormData(),
  25348. params =
  25349. utils.serializeParam(me.queryCommandValue('serverparam')) || '',
  25350. url = utils.formatUrl(
  25351. actionUrl + (actionUrl.indexOf('?') == -1 ? '?' : '&') + params
  25352. )
  25353. fd.append(
  25354. fieldName,
  25355. file,
  25356. file.name || 'blob.' + file.type.substr('image/'.length)
  25357. )
  25358. fd.append('type', 'ajax')
  25359. xhr.open('post', url, true)
  25360. xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
  25361. xhr.addEventListener('load', function (e) {
  25362. try {
  25363. var json = new Function('return ' + utils.trim(e.target.response))()
  25364. if (json.state == 'SUCCESS' && json.url) {
  25365. successHandler(json)
  25366. } else {
  25367. errorHandler(json.state)
  25368. }
  25369. } catch (er) {
  25370. errorHandler(me.getLang('autoupload.loadError'))
  25371. }
  25372. })
  25373. xhr.send(fd)
  25374. }
  25375. function getPasteImage(e) {
  25376. return e.clipboardData &&
  25377. e.clipboardData.items &&
  25378. e.clipboardData.items.length == 1 &&
  25379. /^image\//.test(e.clipboardData.items[0].type)
  25380. ? e.clipboardData.items
  25381. : null
  25382. }
  25383. function getDropImage(e) {
  25384. return e.dataTransfer && e.dataTransfer.files
  25385. ? e.dataTransfer.files
  25386. : null
  25387. }
  25388. return {
  25389. outputRule: function (root) {
  25390. utils.each(root.getNodesByTagName('img'), function (n) {
  25391. if (
  25392. /\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr('class'))
  25393. ) {
  25394. n.parentNode.removeChild(n)
  25395. }
  25396. })
  25397. utils.each(root.getNodesByTagName('p'), function (n) {
  25398. if (/\bloadpara\b/.test(n.getAttr('class'))) {
  25399. n.parentNode.removeChild(n)
  25400. }
  25401. })
  25402. },
  25403. bindEvents: {
  25404. //插入粘贴板的图片,拖放插入图片
  25405. ready: function (e) {
  25406. var me = this
  25407. if (window.FormData && window.FileReader) {
  25408. domUtils.on(me.body, 'paste drop', function (e) {
  25409. var hasImg = false,
  25410. items
  25411. //获取粘贴板文件列表或者拖放文件列表
  25412. items = e.type == 'paste' ? getPasteImage(e) : getDropImage(e)
  25413. if (items) {
  25414. var len = items.length,
  25415. file
  25416. while (len--) {
  25417. file = items[len]
  25418. if (file.getAsFile) file = file.getAsFile()
  25419. if (file && file.size > 0) {
  25420. sendAndInsertFile(file, me)
  25421. hasImg = true
  25422. }
  25423. }
  25424. hasImg && e.preventDefault()
  25425. }
  25426. })
  25427. //取消拖放图片时出现的文字光标位置提示
  25428. domUtils.on(me.body, 'dragover', function (e) {
  25429. if (e.dataTransfer.types[0] == 'Files') {
  25430. e.preventDefault()
  25431. }
  25432. })
  25433. //设置loading的样式
  25434. utils.cssRule(
  25435. 'loading',
  25436. ".loadingclass{display:inline-block;cursor:default;background: url('" +
  25437. this.options.themePath +
  25438. this.options.theme +
  25439. "/images/loading.gif') no-repeat center center transparent;border:1px solid #cccccc;margin-left:1px;height: 22px;width: 22px;}\n" +
  25440. ".loaderrorclass{display:inline-block;cursor:default;background: url('" +
  25441. this.options.themePath +
  25442. this.options.theme +
  25443. "/images/loaderror.png') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;" +
  25444. '}',
  25445. this.document
  25446. )
  25447. }
  25448. },
  25449. },
  25450. }
  25451. })
  25452. // plugins/autosave.js
  25453. UE.plugin.register('autosave', function () {
  25454. var me = this,
  25455. //无限循环保护
  25456. lastSaveTime = new Date(),
  25457. //最小保存间隔时间
  25458. MIN_TIME = 20,
  25459. //auto save key
  25460. saveKey = null
  25461. function save(editor) {
  25462. var saveData
  25463. if (new Date() - lastSaveTime < MIN_TIME) {
  25464. return
  25465. }
  25466. if (!editor.hasContents()) {
  25467. //这里不能调用命令来删除, 会造成事件死循环
  25468. saveKey && me.removePreferences(saveKey)
  25469. return
  25470. }
  25471. lastSaveTime = new Date()
  25472. editor._saveFlag = null
  25473. saveData = me.body.innerHTML
  25474. if (
  25475. editor.fireEvent('beforeautosave', {
  25476. content: saveData,
  25477. }) === false
  25478. ) {
  25479. return
  25480. }
  25481. me.setPreferences(saveKey, saveData)
  25482. editor.fireEvent('afterautosave', {
  25483. content: saveData,
  25484. })
  25485. }
  25486. return {
  25487. defaultOptions: {
  25488. //默认间隔时间
  25489. saveInterval: 500,
  25490. enableAutoSave: true, // HaoChuan9421
  25491. },
  25492. bindEvents: {
  25493. ready: function () {
  25494. var _suffix = '-drafts-data',
  25495. key = null
  25496. if (me.key) {
  25497. key = me.key + _suffix
  25498. } else {
  25499. key = (me.container.parentNode.id || 'ue-common') + _suffix
  25500. }
  25501. //页面地址+编辑器ID 保持唯一
  25502. saveKey =
  25503. (location.protocol + location.host + location.pathname).replace(
  25504. /[.:\/]/g,
  25505. '_'
  25506. ) + key
  25507. },
  25508. contentchange: function () {
  25509. // HaoChuan9421
  25510. if (!me.getOpt('enableAutoSave')) {
  25511. return
  25512. }
  25513. if (!saveKey) {
  25514. return
  25515. }
  25516. if (me._saveFlag) {
  25517. window.clearTimeout(me._saveFlag)
  25518. }
  25519. if (me.options.saveInterval > 0) {
  25520. me._saveFlag = window.setTimeout(function () {
  25521. save(me)
  25522. }, me.options.saveInterval)
  25523. } else {
  25524. save(me)
  25525. }
  25526. },
  25527. },
  25528. commands: {
  25529. clearlocaldata: {
  25530. execCommand: function (cmd, name) {
  25531. if (saveKey && me.getPreferences(saveKey)) {
  25532. me.removePreferences(saveKey)
  25533. }
  25534. },
  25535. notNeedUndo: true,
  25536. ignoreContentChange: true,
  25537. },
  25538. getlocaldata: {
  25539. execCommand: function (cmd, name) {
  25540. return saveKey ? me.getPreferences(saveKey) || '' : ''
  25541. },
  25542. notNeedUndo: true,
  25543. ignoreContentChange: true,
  25544. },
  25545. drafts: {
  25546. execCommand: function (cmd, name) {
  25547. if (saveKey) {
  25548. me.body.innerHTML =
  25549. me.getPreferences(saveKey) || '<p>' + domUtils.fillHtml + '</p>'
  25550. me.focus(true)
  25551. }
  25552. },
  25553. queryCommandState: function () {
  25554. return saveKey ? (me.getPreferences(saveKey) === null ? -1 : 0) : -1
  25555. },
  25556. notNeedUndo: true,
  25557. ignoreContentChange: true,
  25558. },
  25559. },
  25560. }
  25561. })
  25562. // plugins/charts.js
  25563. UE.plugin.register('charts', function () {
  25564. var me = this
  25565. return {
  25566. bindEvents: {
  25567. chartserror: function () {},
  25568. },
  25569. commands: {
  25570. charts: {
  25571. execCommand: function (cmd, data) {
  25572. var tableNode = domUtils.findParentByTagName(
  25573. this.selection.getRange().startContainer,
  25574. 'table',
  25575. true
  25576. ),
  25577. flagText = [],
  25578. config = {}
  25579. if (!tableNode) {
  25580. return false
  25581. }
  25582. if (!validData(tableNode)) {
  25583. me.fireEvent('chartserror')
  25584. return false
  25585. }
  25586. config.title = data.title || ''
  25587. config.subTitle = data.subTitle || ''
  25588. config.xTitle = data.xTitle || ''
  25589. config.yTitle = data.yTitle || ''
  25590. config.suffix = data.suffix || ''
  25591. config.tip = data.tip || ''
  25592. //数据对齐方式
  25593. config.dataFormat = data.tableDataFormat || ''
  25594. //图表类型
  25595. config.chartType = data.chartType || 0
  25596. for (var key in config) {
  25597. if (!config.hasOwnProperty(key)) {
  25598. continue
  25599. }
  25600. flagText.push(key + ':' + config[key])
  25601. }
  25602. tableNode.setAttribute('data-chart', flagText.join(';'))
  25603. domUtils.addClass(tableNode, 'edui-charts-table')
  25604. },
  25605. queryCommandState: function (cmd, name) {
  25606. var tableNode = domUtils.findParentByTagName(
  25607. this.selection.getRange().startContainer,
  25608. 'table',
  25609. true
  25610. )
  25611. return tableNode && validData(tableNode) ? 0 : -1
  25612. },
  25613. },
  25614. },
  25615. inputRule: function (root) {
  25616. utils.each(root.getNodesByTagName('table'), function (tableNode) {
  25617. if (tableNode.getAttr('data-chart') !== undefined) {
  25618. tableNode.setAttr('style')
  25619. }
  25620. })
  25621. },
  25622. outputRule: function (root) {
  25623. utils.each(root.getNodesByTagName('table'), function (tableNode) {
  25624. if (tableNode.getAttr('data-chart') !== undefined) {
  25625. tableNode.setAttr('style', 'display: none;')
  25626. }
  25627. })
  25628. },
  25629. }
  25630. function validData(table) {
  25631. var firstRows = null,
  25632. cellCount = 0
  25633. //行数不够
  25634. if (table.rows.length < 2) {
  25635. return false
  25636. }
  25637. //列数不够
  25638. if (table.rows[0].cells.length < 2) {
  25639. return false
  25640. }
  25641. //第一行所有cell必须是th
  25642. firstRows = table.rows[0].cells
  25643. cellCount = firstRows.length
  25644. for (var i = 0, cell; (cell = firstRows[i]); i++) {
  25645. if (cell.tagName.toLowerCase() !== 'th') {
  25646. return false
  25647. }
  25648. }
  25649. for (var i = 1, row; (row = table.rows[i]); i++) {
  25650. //每行单元格数不匹配, 返回false
  25651. if (row.cells.length != cellCount) {
  25652. return false
  25653. }
  25654. //第一列不是th也返回false
  25655. if (row.cells[0].tagName.toLowerCase() !== 'th') {
  25656. return false
  25657. }
  25658. for (var j = 1, cell; (cell = row.cells[j]); j++) {
  25659. var value = utils.trim(cell.innerText || cell.textContent || '')
  25660. value = value
  25661. .replace(new RegExp(UE.dom.domUtils.fillChar, 'g'), '')
  25662. .replace(/^\s+|\s+$/g, '')
  25663. //必须是数字
  25664. if (!/^\d*\.?\d+$/.test(value)) {
  25665. return false
  25666. }
  25667. }
  25668. }
  25669. return true
  25670. }
  25671. })
  25672. // plugins/section.js
  25673. /**
  25674. * 目录大纲支持插件
  25675. * @file
  25676. * @since 1.3.0
  25677. */
  25678. UE.plugin.register('section', function () {
  25679. /* 目录节点对象 */
  25680. function Section(option) {
  25681. this.tag = ''
  25682. ;(this.level = -1), (this.dom = null)
  25683. this.nextSection = null
  25684. this.previousSection = null
  25685. this.parentSection = null
  25686. this.startAddress = []
  25687. this.endAddress = []
  25688. this.children = []
  25689. }
  25690. function getSection(option) {
  25691. var section = new Section()
  25692. return utils.extend(section, option)
  25693. }
  25694. function getNodeFromAddress(startAddress, root) {
  25695. var current = root
  25696. for (var i = 0; i < startAddress.length; i++) {
  25697. if (!current.childNodes) return null
  25698. current = current.childNodes[startAddress[i]]
  25699. }
  25700. return current
  25701. }
  25702. var me = this
  25703. return {
  25704. bindMultiEvents: {
  25705. type: 'aftersetcontent afterscencerestore',
  25706. handler: function () {
  25707. me.fireEvent('updateSections')
  25708. },
  25709. },
  25710. bindEvents: {
  25711. /* 初始化、拖拽、粘贴、执行setcontent之后 */
  25712. ready: function () {
  25713. me.fireEvent('updateSections')
  25714. domUtils.on(me.body, 'drop paste', function () {
  25715. me.fireEvent('updateSections')
  25716. })
  25717. },
  25718. /* 执行paragraph命令之后 */
  25719. afterexeccommand: function (type, cmd) {
  25720. if (cmd == 'paragraph') {
  25721. me.fireEvent('updateSections')
  25722. }
  25723. },
  25724. /* 部分键盘操作,触发updateSections事件 */
  25725. keyup: function (type, e) {
  25726. var me = this,
  25727. range = me.selection.getRange()
  25728. if (range.collapsed != true) {
  25729. me.fireEvent('updateSections')
  25730. } else {
  25731. var keyCode = e.keyCode || e.which
  25732. if (keyCode == 13 || keyCode == 8 || keyCode == 46) {
  25733. me.fireEvent('updateSections')
  25734. }
  25735. }
  25736. },
  25737. },
  25738. commands: {
  25739. getsections: {
  25740. execCommand: function (cmd, levels) {
  25741. var levelFn = levels || ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']
  25742. for (var i = 0; i < levelFn.length; i++) {
  25743. if (typeof levelFn[i] == 'string') {
  25744. levelFn[i] = (function (fn) {
  25745. return function (node) {
  25746. return node.tagName == fn.toUpperCase()
  25747. }
  25748. })(levelFn[i])
  25749. } else if (typeof levelFn[i] != 'function') {
  25750. levelFn[i] = function (node) {
  25751. return null
  25752. }
  25753. }
  25754. }
  25755. function getSectionLevel(node) {
  25756. for (var i = 0; i < levelFn.length; i++) {
  25757. if (levelFn[i](node)) return i
  25758. }
  25759. return -1
  25760. }
  25761. var me = this,
  25762. Directory = getSection({ level: -1, title: 'root' }),
  25763. previous = Directory
  25764. function traversal(node, Directory) {
  25765. var level,
  25766. tmpSection = null,
  25767. parent,
  25768. child,
  25769. children = node.childNodes
  25770. for (var i = 0, len = children.length; i < len; i++) {
  25771. child = children[i]
  25772. level = getSectionLevel(child)
  25773. if (level >= 0) {
  25774. var address = me.selection
  25775. .getRange()
  25776. .selectNode(child)
  25777. .createAddress(true).startAddress,
  25778. current = getSection({
  25779. tag: child.tagName,
  25780. title: child.innerText || child.textContent || '',
  25781. level: level,
  25782. dom: child,
  25783. startAddress: utils.clone(address, []),
  25784. endAddress: utils.clone(address, []),
  25785. children: [],
  25786. })
  25787. previous.nextSection = current
  25788. current.previousSection = previous
  25789. parent = previous
  25790. while (level <= parent.level) {
  25791. parent = parent.parentSection
  25792. }
  25793. current.parentSection = parent
  25794. parent.children.push(current)
  25795. tmpSection = previous = current
  25796. } else {
  25797. child.nodeType === 1 && traversal(child, Directory)
  25798. tmpSection &&
  25799. tmpSection.endAddress[tmpSection.endAddress.length - 1]++
  25800. }
  25801. }
  25802. }
  25803. traversal(me.body, Directory)
  25804. return Directory
  25805. },
  25806. notNeedUndo: true,
  25807. },
  25808. movesection: {
  25809. execCommand: function (cmd, sourceSection, targetSection, isAfter) {
  25810. var me = this,
  25811. targetAddress,
  25812. target
  25813. if (!sourceSection || !targetSection || targetSection.level == -1)
  25814. return
  25815. targetAddress = isAfter
  25816. ? targetSection.endAddress
  25817. : targetSection.startAddress
  25818. target = getNodeFromAddress(targetAddress, me.body)
  25819. /* 判断目标地址是否被源章节包含 */
  25820. if (
  25821. !targetAddress ||
  25822. !target ||
  25823. isContainsAddress(
  25824. sourceSection.startAddress,
  25825. sourceSection.endAddress,
  25826. targetAddress
  25827. )
  25828. )
  25829. return
  25830. var startNode = getNodeFromAddress(
  25831. sourceSection.startAddress,
  25832. me.body
  25833. ),
  25834. endNode = getNodeFromAddress(sourceSection.endAddress, me.body),
  25835. current,
  25836. nextNode
  25837. if (isAfter) {
  25838. current = endNode
  25839. while (
  25840. current &&
  25841. !(
  25842. domUtils.getPosition(startNode, current) &
  25843. domUtils.POSITION_FOLLOWING
  25844. )
  25845. ) {
  25846. nextNode = current.previousSibling
  25847. domUtils.insertAfter(target, current)
  25848. if (current == startNode) break
  25849. current = nextNode
  25850. }
  25851. } else {
  25852. current = startNode
  25853. while (
  25854. current &&
  25855. !(
  25856. domUtils.getPosition(current, endNode) &
  25857. domUtils.POSITION_FOLLOWING
  25858. )
  25859. ) {
  25860. nextNode = current.nextSibling
  25861. target.parentNode.insertBefore(current, target)
  25862. if (current == endNode) break
  25863. current = nextNode
  25864. }
  25865. }
  25866. me.fireEvent('updateSections')
  25867. /* 获取地址的包含关系 */
  25868. function isContainsAddress(
  25869. startAddress,
  25870. endAddress,
  25871. addressTarget
  25872. ) {
  25873. var isAfterStartAddress = false,
  25874. isBeforeEndAddress = false
  25875. for (var i = 0; i < startAddress.length; i++) {
  25876. if (i >= addressTarget.length) break
  25877. if (addressTarget[i] > startAddress[i]) {
  25878. isAfterStartAddress = true
  25879. break
  25880. } else if (addressTarget[i] < startAddress[i]) {
  25881. break
  25882. }
  25883. }
  25884. for (var i = 0; i < endAddress.length; i++) {
  25885. if (i >= addressTarget.length) break
  25886. if (addressTarget[i] < startAddress[i]) {
  25887. isBeforeEndAddress = true
  25888. break
  25889. } else if (addressTarget[i] > startAddress[i]) {
  25890. break
  25891. }
  25892. }
  25893. return isAfterStartAddress && isBeforeEndAddress
  25894. }
  25895. },
  25896. },
  25897. deletesection: {
  25898. execCommand: function (cmd, section, keepChildren) {
  25899. var me = this
  25900. if (!section) return
  25901. function getNodeFromAddress(startAddress) {
  25902. var current = me.body
  25903. for (var i = 0; i < startAddress.length; i++) {
  25904. if (!current.childNodes) return null
  25905. current = current.childNodes[startAddress[i]]
  25906. }
  25907. return current
  25908. }
  25909. var startNode = getNodeFromAddress(section.startAddress),
  25910. endNode = getNodeFromAddress(section.endAddress),
  25911. current = startNode,
  25912. nextNode
  25913. if (!keepChildren) {
  25914. while (
  25915. current &&
  25916. domUtils.inDoc(endNode, me.document) &&
  25917. !(
  25918. domUtils.getPosition(current, endNode) &
  25919. domUtils.POSITION_FOLLOWING
  25920. )
  25921. ) {
  25922. nextNode = current.nextSibling
  25923. domUtils.remove(current)
  25924. current = nextNode
  25925. }
  25926. } else {
  25927. domUtils.remove(current)
  25928. }
  25929. me.fireEvent('updateSections')
  25930. },
  25931. },
  25932. selectsection: {
  25933. execCommand: function (cmd, section) {
  25934. if (!section && !section.dom) return false
  25935. var me = this,
  25936. range = me.selection.getRange(),
  25937. address = {
  25938. startAddress: utils.clone(section.startAddress, []),
  25939. endAddress: utils.clone(section.endAddress, []),
  25940. }
  25941. address.endAddress[address.endAddress.length - 1]++
  25942. range.moveToAddress(address).select().scrollToView()
  25943. return true
  25944. },
  25945. notNeedUndo: true,
  25946. },
  25947. scrolltosection: {
  25948. execCommand: function (cmd, section) {
  25949. if (!section && !section.dom) return false
  25950. var me = this,
  25951. range = me.selection.getRange(),
  25952. address = {
  25953. startAddress: section.startAddress,
  25954. endAddress: section.endAddress,
  25955. }
  25956. address.endAddress[address.endAddress.length - 1]++
  25957. range.moveToAddress(address).scrollToView()
  25958. return true
  25959. },
  25960. notNeedUndo: true,
  25961. },
  25962. },
  25963. }
  25964. })
  25965. // plugins/simpleupload.js
  25966. /**
  25967. * @description
  25968. * 简单上传:点击按钮,直接选择文件上传。
  25969. * 原 UEditor 作者使用了 form 表单 + iframe 的方式上传
  25970. * 但由于同源策略的限制,父页面无法访问跨域的 iframe 内容
  25971. * 导致无法获取接口返回的数据,使得单图上传无法在跨域的情况下使用
  25972. * 这里改为普通的XHR上传,兼容到IE10+
  25973. * @author HaoChuan9421 <hc199421@gmail.com>
  25974. * @date 2018-12-20
  25975. */
  25976. UE.plugin.register('simpleupload', function () {
  25977. var me = this,
  25978. containerBtn,
  25979. timestrap = (+new Date()).toString(36)
  25980. function initUploadBtn() {
  25981. var w = containerBtn.offsetWidth || 20,
  25982. h = containerBtn.offsetHeight || 20,
  25983. btnStyle =
  25984. 'display:block;width:' +
  25985. w +
  25986. 'px;height:' +
  25987. h +
  25988. 'px;overflow:hidden;border:0;margin:0;padding:0;position:absolute;top:0;left:0;filter:alpha(opacity=0);-moz-opacity:0;-khtml-opacity: 0;opacity: 0;cursor:pointer;'
  25989. var form = document.createElement('form')
  25990. var input = document.createElement('input')
  25991. form.id = 'edui_form_' + timestrap
  25992. form.enctype = 'multipart/form-data'
  25993. form.style = btnStyle
  25994. input.id = 'edui_input_' + timestrap
  25995. input.type = 'file'
  25996. input.accept = 'image/*'
  25997. input.name = me.options.imageFieldName
  25998. input.style = btnStyle
  25999. form.appendChild(input)
  26000. containerBtn.appendChild(form)
  26001. input.addEventListener('change', function (event) {
  26002. if (!input.value) return
  26003. var loadingId = 'loading_' + (+new Date()).toString(36)
  26004. var imageActionUrl = me.getActionUrl(me.getOpt('imageActionName'))
  26005. var params =
  26006. utils.serializeParam(me.queryCommandValue('serverparam')) || ''
  26007. var action = utils.formatUrl(
  26008. imageActionUrl +
  26009. (imageActionUrl.indexOf('?') == -1 ? '?' : '&') +
  26010. params
  26011. )
  26012. var allowFiles = me.getOpt('imageAllowFiles')
  26013. me.focus()
  26014. me.execCommand(
  26015. 'inserthtml',
  26016. '<img class="loadingclass" id="' +
  26017. loadingId +
  26018. '" src="' +
  26019. me.options.themePath +
  26020. me.options.theme +
  26021. '/images/spacer.gif" title="' +
  26022. (me.getLang('simpleupload.loading') || '') +
  26023. '" >'
  26024. )
  26025. function showErrorLoader(title) {
  26026. if (loadingId) {
  26027. var loader = me.document.getElementById(loadingId)
  26028. loader && domUtils.remove(loader)
  26029. me.fireEvent('showmessage', {
  26030. id: loadingId,
  26031. content: title,
  26032. type: 'error',
  26033. timeout: 4000,
  26034. })
  26035. }
  26036. }
  26037. /* 判断后端配置是否没有加载成功 */
  26038. if (!me.getOpt('imageActionName')) {
  26039. console.log('此处baocuo1111111111111111111')
  26040. showErrorLoader(me.getLang('autoupload.errorLoadConfig'))
  26041. return
  26042. }
  26043. // 判断文件格式是否错误
  26044. var filename = input.value,
  26045. fileext = filename ? filename.substr(filename.lastIndexOf('.')) : ''
  26046. if (
  26047. !fileext ||
  26048. (allowFiles &&
  26049. (allowFiles.join('') + '.').indexOf(fileext.toLowerCase() + '.') ==
  26050. -1)
  26051. ) {
  26052. showErrorLoader(me.getLang('simpleupload.exceedTypeError'))
  26053. return
  26054. }
  26055. var xhr = new XMLHttpRequest()
  26056. xhr.open('post', action, true)
  26057. if (
  26058. me.options.headers &&
  26059. Object.prototype.toString.apply(me.options.headers) ===
  26060. '[object Object]'
  26061. ) {
  26062. for (var key in me.options.headers) {
  26063. xhr.setRequestHeader(key, me.options.headers[key])
  26064. }
  26065. }
  26066. xhr.onload = function () {
  26067. if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
  26068. var res = JSON.parse(xhr.responseText)
  26069. var link = me.options.imageUrlPrefix + res.url
  26070. if (res.state == 'SUCCESS' && res.url) {
  26071. loader = me.document.getElementById(loadingId)
  26072. loader.setAttribute('src', link)
  26073. loader.setAttribute('_src', link)
  26074. loader.setAttribute('title', res.title || '')
  26075. loader.setAttribute('alt', res.original || '')
  26076. loader.removeAttribute('id')
  26077. domUtils.removeClasses(loader, 'loadingclass')
  26078. me.fireEvent('contentchange')
  26079. } else {
  26080. showErrorLoader(res.state)
  26081. }
  26082. } else {
  26083. showErrorLoader(me.getLang('simpleupload.loadError'))
  26084. }
  26085. }
  26086. xhr.onerror = function () {
  26087. showErrorLoader(me.getLang('simpleupload.loadError'))
  26088. }
  26089. xhr.send(new FormData(form))
  26090. form.reset()
  26091. })
  26092. }
  26093. return {
  26094. bindEvents: {
  26095. ready: function () {
  26096. //设置loading的样式
  26097. utils.cssRule(
  26098. 'loading',
  26099. ".loadingclass{display:inline-block;cursor:default;background: url('" +
  26100. this.options.themePath +
  26101. this.options.theme +
  26102. "/images/loading.gif') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;}\n" +
  26103. ".loaderrorclass{display:inline-block;cursor:default;background: url('" +
  26104. this.options.themePath +
  26105. this.options.theme +
  26106. "/images/loaderror.png') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;" +
  26107. '}',
  26108. this.document
  26109. )
  26110. },
  26111. /* 初始化简单上传按钮 */
  26112. simpleuploadbtnready: function (type, container) {
  26113. containerBtn = container
  26114. me.afterConfigReady(initUploadBtn)
  26115. },
  26116. },
  26117. outputRule: function (root) {
  26118. utils.each(root.getNodesByTagName('img'), function (n) {
  26119. if (
  26120. /\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr('class'))
  26121. ) {
  26122. n.parentNode.removeChild(n)
  26123. }
  26124. })
  26125. },
  26126. }
  26127. })
  26128. // plugins/serverparam.js
  26129. /**
  26130. * 服务器提交的额外参数列表设置插件
  26131. * @file
  26132. * @since 1.2.6.1
  26133. */
  26134. UE.plugin.register('serverparam', function () {
  26135. var me = this,
  26136. serverParam = {}
  26137. return {
  26138. commands: {
  26139. /**
  26140. * 修改服务器提交的额外参数列表,清除所有项
  26141. * @command serverparam
  26142. * @method execCommand
  26143. * @param { String } cmd 命令字符串
  26144. * @example
  26145. * ```javascript
  26146. * editor.execCommand('serverparam');
  26147. * editor.queryCommandValue('serverparam'); //返回空
  26148. * ```
  26149. */
  26150. /**
  26151. * 修改服务器提交的额外参数列表,删除指定项
  26152. * @command serverparam
  26153. * @method execCommand
  26154. * @param { String } cmd 命令字符串
  26155. * @param { String } key 要清除的属性
  26156. * @example
  26157. * ```javascript
  26158. * editor.execCommand('serverparam', 'name'); //删除属性name
  26159. * ```
  26160. */
  26161. /**
  26162. * 修改服务器提交的额外参数列表,使用键值添加项
  26163. * @command serverparam
  26164. * @method execCommand
  26165. * @param { String } cmd 命令字符串
  26166. * @param { String } key 要添加的属性
  26167. * @param { String } value 要添加属性的值
  26168. * @example
  26169. * ```javascript
  26170. * editor.execCommand('serverparam', 'name', 'hello');
  26171. * editor.queryCommandValue('serverparam'); //返回对象 {'name': 'hello'}
  26172. * ```
  26173. */
  26174. /**
  26175. * 修改服务器提交的额外参数列表,传入键值对对象添加多项
  26176. * @command serverparam
  26177. * @method execCommand
  26178. * @param { String } cmd 命令字符串
  26179. * @param { Object } key 传入的键值对对象
  26180. * @example
  26181. * ```javascript
  26182. * editor.execCommand('serverparam', {'name': 'hello'});
  26183. * editor.queryCommandValue('serverparam'); //返回对象 {'name': 'hello'}
  26184. * ```
  26185. */
  26186. /**
  26187. * 修改服务器提交的额外参数列表,使用自定义函数添加多项
  26188. * @command serverparam
  26189. * @method execCommand
  26190. * @param { String } cmd 命令字符串
  26191. * @param { Function } key 自定义获取参数的函数
  26192. * @example
  26193. * ```javascript
  26194. * editor.execCommand('serverparam', function(editor){
  26195. * return {'key': 'value'};
  26196. * });
  26197. * editor.queryCommandValue('serverparam'); //返回对象 {'key': 'value'}
  26198. * ```
  26199. */
  26200. /**
  26201. * 获取服务器提交的额外参数列表
  26202. * @command serverparam
  26203. * @method queryCommandValue
  26204. * @param { String } cmd 命令字符串
  26205. * @example
  26206. * ```javascript
  26207. * editor.queryCommandValue( 'serverparam' ); //返回对象 {'key': 'value'}
  26208. * ```
  26209. */
  26210. serverparam: {
  26211. execCommand: function (cmd, key, value) {
  26212. if (key === undefined || key === null) {
  26213. //不传参数,清空列表
  26214. serverParam = {}
  26215. } else if (utils.isString(key)) {
  26216. //传入键值
  26217. if (value === undefined || value === null) {
  26218. delete serverParam[key]
  26219. } else {
  26220. serverParam[key] = value
  26221. }
  26222. } else if (utils.isObject(key)) {
  26223. //传入对象,覆盖列表项
  26224. utils.extend(serverParam, key, true)
  26225. } else if (utils.isFunction(key)) {
  26226. //传入函数,添加列表项
  26227. utils.extend(serverParam, key(), true)
  26228. }
  26229. },
  26230. queryCommandValue: function () {
  26231. return serverParam || {}
  26232. },
  26233. },
  26234. },
  26235. }
  26236. })
  26237. // plugins/insertfile.js
  26238. /**
  26239. * 插入附件
  26240. */
  26241. UE.plugin.register('insertfile', function () {
  26242. var me = this
  26243. function getFileIcon(url) {
  26244. var ext = url.substr(url.lastIndexOf('.') + 1).toLowerCase(),
  26245. maps = {
  26246. rar: 'icon_rar.gif',
  26247. zip: 'icon_rar.gif',
  26248. tar: 'icon_rar.gif',
  26249. gz: 'icon_rar.gif',
  26250. bz2: 'icon_rar.gif',
  26251. doc: 'icon_doc.gif',
  26252. docx: 'icon_doc.gif',
  26253. pdf: 'icon_pdf.gif',
  26254. mp3: 'icon_mp3.gif',
  26255. xls: 'icon_xls.gif',
  26256. chm: 'icon_chm.gif',
  26257. ppt: 'icon_ppt.gif',
  26258. pptx: 'icon_ppt.gif',
  26259. avi: 'icon_mv.gif',
  26260. rmvb: 'icon_mv.gif',
  26261. wmv: 'icon_mv.gif',
  26262. flv: 'icon_mv.gif',
  26263. swf: 'icon_mv.gif',
  26264. rm: 'icon_mv.gif',
  26265. exe: 'icon_exe.gif',
  26266. psd: 'icon_psd.gif',
  26267. txt: 'icon_txt.gif',
  26268. jpg: 'icon_jpg.gif',
  26269. png: 'icon_jpg.gif',
  26270. jpeg: 'icon_jpg.gif',
  26271. gif: 'icon_jpg.gif',
  26272. ico: 'icon_jpg.gif',
  26273. bmp: 'icon_jpg.gif',
  26274. }
  26275. return maps[ext] ? maps[ext] : maps['txt']
  26276. }
  26277. return {
  26278. commands: {
  26279. insertfile: {
  26280. execCommand: function (command, filelist) {
  26281. filelist = utils.isArray(filelist) ? filelist : [filelist]
  26282. var i,
  26283. item,
  26284. icon,
  26285. title,
  26286. html = '',
  26287. URL = me.getOpt('UEDITOR_HOME_URL'),
  26288. iconDir =
  26289. URL +
  26290. (URL.substr(URL.length - 1) == '/' ? '' : '/') +
  26291. 'dialogs/attachment/fileTypeImages/'
  26292. for (i = 0; i < filelist.length; i++) {
  26293. item = filelist[i]
  26294. icon = iconDir + getFileIcon(item.url)
  26295. title =
  26296. item.title || item.url.substr(item.url.lastIndexOf('/') + 1)
  26297. html +=
  26298. '<p style="line-height: 16px;">' +
  26299. '<img style="vertical-align: middle; margin-right: 2px;" src="' +
  26300. icon +
  26301. '" _src="' +
  26302. icon +
  26303. '" />' +
  26304. '<a style="font-size:12px; color:#0066cc;" href="' +
  26305. item.url +
  26306. '" title="' +
  26307. title +
  26308. '">' +
  26309. title +
  26310. '</a>' +
  26311. '</p>'
  26312. }
  26313. me.execCommand('insertHtml', html)
  26314. },
  26315. },
  26316. },
  26317. }
  26318. })
  26319. /**
  26320. * 插入word
  26321. */
  26322. UE.plugin.register('wordupload', function () {
  26323. var me = this,
  26324. isLoaded = false,
  26325. containerBtn
  26326. function initUploadBtn() {
  26327. console.log(me.options, 'me.options')
  26328. var w = containerBtn.offsetWidth || 20,
  26329. h = containerBtn.offsetHeight || 20,
  26330. btnIframe = document.createElement('iframe'),
  26331. btnStyle =
  26332. 'display:block;width:' +
  26333. w +
  26334. 'px;height:' +
  26335. h +
  26336. 'px;overflow:hidden;border:0;margin:0;padding:0;position:absolute;top:0;left:0;filter:alpha(opacity=0);-moz-opacity:0;-khtml-opacity: 0;opacity: 0;cursor:pointer;'
  26337. domUtils.on(btnIframe, 'load', function () {
  26338. var timestrap = (+new Date()).toString(36),
  26339. wrapper,
  26340. btnIframeDoc,
  26341. btnIframeBody
  26342. btnIframeDoc =
  26343. btnIframe.contentDocument || btnIframe.contentWindow.document
  26344. btnIframeBody = btnIframeDoc.body
  26345. wrapper = btnIframeDoc.createElement('div')
  26346. wrapper.innerHTML =
  26347. '<form id="edui_form_' +
  26348. timestrap +
  26349. '" target="edui_iframe_' +
  26350. timestrap +
  26351. '" method="POST" enctype="multipart/form-data" action="' +
  26352. me.getOpt('serverUrl') +
  26353. '" ' +
  26354. 'style="' +
  26355. btnStyle +
  26356. '">' +
  26357. '<input id="edui_input_' +
  26358. // application/msword
  26359. timestrap +
  26360. '" type="file" accept=".doc,.docx" name="' +
  26361. me.options.wordFieldName +
  26362. '" ' +
  26363. 'style="' +
  26364. btnStyle +
  26365. '">' +
  26366. '</form>' +
  26367. '<iframe id="edui_iframe_' +
  26368. timestrap +
  26369. '" name="edui_iframe_' +
  26370. timestrap +
  26371. '" style="display:none;width:0;height:0;border:0;margin:0;padding:0;position:absolute;"></iframe>'
  26372. wrapper.className = 'edui-' + me.options.theme
  26373. wrapper.id = me.ui.id + '_iframeupload'
  26374. btnIframeBody.style.cssText = btnStyle
  26375. btnIframeBody.style.width = w + 'px'
  26376. btnIframeBody.style.height = h + 'px'
  26377. btnIframeBody.appendChild(wrapper)
  26378. if (btnIframeBody.parentNode) {
  26379. btnIframeBody.parentNode.style.width = w + 'px'
  26380. btnIframeBody.parentNode.style.height = w + 'px'
  26381. }
  26382. var form = btnIframeDoc.getElementById('edui_form_' + timestrap)
  26383. var input = btnIframeDoc.getElementById('edui_input_' + timestrap)
  26384. var iframe = btnIframeDoc.getElementById('edui_iframe_' + timestrap)
  26385. domUtils.on(input, 'change', function () {
  26386. if (!input.value) return
  26387. var loadingId = 'loading_' + (+new Date()).toString(36)
  26388. var allowFiles = me.getOpt('wordAllowFiles')
  26389. me.focus()
  26390. me.execCommand(
  26391. 'inserthtml',
  26392. '<img class="loadingclass" id="' +
  26393. loadingId +
  26394. '" src="' +
  26395. me.options.themePath +
  26396. me.options.theme +
  26397. '/images/spacer.gif" title="' +
  26398. (me.getLang('wordupload.loading') || '') +
  26399. '" >'
  26400. )
  26401. function callback() {
  26402. try {
  26403. // 获取到内容
  26404. var body = (
  26405. iframe.contentDocument || iframe.contentWindow.document
  26406. ).body
  26407. // 获取加载中图片并关闭
  26408. var loader = me.document.getElementById(loadingId)
  26409. loader.removeAttribute('id')
  26410. domUtils.removeClasses(loader, 'loadingclass')
  26411. // 向编辑器赋值
  26412. me.setContent(body.innerHTML, false)
  26413. // me.execCommand('insertHtml', body.innerHTML);
  26414. } catch (er) {
  26415. showErrorLoader &&
  26416. showErrorLoader(me.getLang('wordupload.loadError'))
  26417. }
  26418. form.reset()
  26419. domUtils.un(iframe, 'load', callback)
  26420. }
  26421. function showErrorLoader(title) {
  26422. if (loadingId) {
  26423. var loader = me.document.getElementById(loadingId)
  26424. loader && domUtils.remove(loader)
  26425. me.fireEvent('showmessage', {
  26426. id: loadingId,
  26427. content: title,
  26428. type: 'error',
  26429. timeout: 4000,
  26430. })
  26431. }
  26432. }
  26433. /* 判断后端配置是否没有加载成功 */
  26434. if (!me.getOpt('wordActionName')) {
  26435. errorHandler(me.getLang('autoupload.errorLoadConfig'))
  26436. return
  26437. }
  26438. // 判断文件格式是否错误
  26439. var filename = input.value,
  26440. fileext = filename ? filename.substr(filename.lastIndexOf('.')) : ''
  26441. if (
  26442. !fileext ||
  26443. (allowFiles &&
  26444. (allowFiles.join('') + '.').indexOf(
  26445. fileext.toLowerCase() + '.'
  26446. ) == -1)
  26447. ) {
  26448. showErrorLoader(me.getLang('wordupload.exceedTypeError'))
  26449. return
  26450. }
  26451. domUtils.on(iframe, 'load', callback)
  26452. // 上传操作
  26453. // form.action = utils.formatUrl(imageActionUrl + (imageActionUrl.indexOf('?') == -1 ? '?':'&') + params);
  26454. // 替换请求地址为框架后台地址
  26455. form.action = '/admin.php?m=fwordToHtml&a=index'
  26456. //form.action ='/daili/ueditor/controller.php'
  26457. form.method = 'post'
  26458. form.submit()
  26459. })
  26460. var stateTimer
  26461. me.addListener('selectionchange', function () {
  26462. clearTimeout(stateTimer)
  26463. stateTimer = setTimeout(function () {
  26464. var state = me.queryCommandState('wordupload')
  26465. if (state == -1) {
  26466. input.disabled = 'disabled'
  26467. } else {
  26468. input.disabled = false
  26469. }
  26470. }, 400)
  26471. })
  26472. isLoaded = true
  26473. })
  26474. btnIframe.style.cssText = btnStyle
  26475. containerBtn.appendChild(btnIframe)
  26476. }
  26477. return {
  26478. bindEvents: {
  26479. ready: function () {
  26480. //设置loading的样式
  26481. utils.cssRule(
  26482. 'loading',
  26483. ".loadingclass{display:inline-block;cursor:default;background: url('" +
  26484. this.options.themePath +
  26485. this.options.theme +
  26486. "/images/loading.gif') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;}\n" +
  26487. ".loaderrorclass{display:inline-block;cursor:default;background: url('" +
  26488. this.options.themePath +
  26489. this.options.theme +
  26490. "/images/loaderror.png') no-repeat center center transparent;border:1px solid #cccccc;margin-right:1px;height: 22px;width: 22px;" +
  26491. '}',
  26492. this.document
  26493. )
  26494. },
  26495. /* 初始化word上传按钮 */
  26496. worduploadbtnready: function (type, container) {
  26497. containerBtn = container
  26498. me.afterConfigReady(initUploadBtn)
  26499. },
  26500. },
  26501. outputRule: function (root) {
  26502. utils.each(root.getNodesByTagName('img'), function (n) {
  26503. if (
  26504. /\b(loaderrorclass)|(bloaderrorclass)\b/.test(n.getAttr('class'))
  26505. ) {
  26506. n.parentNode.removeChild(n)
  26507. }
  26508. })
  26509. },
  26510. commands: {
  26511. wordupload: {
  26512. queryCommandState: function () {
  26513. return isLoaded ? 0 : -1
  26514. },
  26515. },
  26516. },
  26517. }
  26518. })
  26519. // plugins/xssFilter.js
  26520. /**
  26521. * @file xssFilter.js
  26522. * @desc xss过滤器
  26523. * @author robbenmu
  26524. */
  26525. UE.plugins.xssFilter = function () {
  26526. var config = UEDITOR_CONFIG
  26527. var whitList = config.whitList
  26528. function filter(node) {
  26529. var tagName = node.tagName
  26530. var attrs = node.attrs
  26531. if (!whitList.hasOwnProperty(tagName)) {
  26532. node.parentNode.removeChild(node)
  26533. return false
  26534. }
  26535. UE.utils.each(attrs, function (val, key) {
  26536. if (whitList[tagName].indexOf(key) === -1) {
  26537. node.setAttr(key)
  26538. }
  26539. })
  26540. }
  26541. // 添加inserthtml\paste等操作用的过滤规则
  26542. if (whitList && config.xssFilterRules) {
  26543. this.options.filterRules = (function () {
  26544. var result = {}
  26545. UE.utils.each(whitList, function (val, key) {
  26546. result[key] = function (node) {
  26547. return filter(node)
  26548. }
  26549. })
  26550. return result
  26551. })()
  26552. }
  26553. var tagList = []
  26554. UE.utils.each(whitList, function (val, key) {
  26555. tagList.push(key)
  26556. })
  26557. // 添加input过滤规则
  26558. //
  26559. if (whitList && config.inputXssFilter) {
  26560. this.addInputRule(function (root) {
  26561. root.traversal(function (node) {
  26562. if (node.type !== 'element') {
  26563. return false
  26564. }
  26565. filter(node)
  26566. })
  26567. })
  26568. }
  26569. // 添加output过滤规则
  26570. //
  26571. if (whitList && config.outputXssFilter) {
  26572. this.addOutputRule(function (root) {
  26573. root.traversal(function (node) {
  26574. if (node.type !== 'element') {
  26575. return false
  26576. }
  26577. filter(node)
  26578. })
  26579. })
  26580. }
  26581. }
  26582. // ui/ui.js
  26583. var baidu = baidu || {}
  26584. baidu.editor = baidu.editor || {}
  26585. UE.ui = baidu.editor.ui = {}
  26586. // ui/uiutils.js
  26587. ;(function () {
  26588. var browser = baidu.editor.browser,
  26589. domUtils = baidu.editor.dom.domUtils
  26590. var magic = '$EDITORUI'
  26591. var root = (window[magic] = {})
  26592. var uidMagic = 'ID' + magic
  26593. var uidCount = 0
  26594. var uiUtils = (baidu.editor.ui.uiUtils = {
  26595. uid: function (obj) {
  26596. return obj ? obj[uidMagic] || (obj[uidMagic] = ++uidCount) : ++uidCount
  26597. },
  26598. hook: function (fn, callback) {
  26599. var dg
  26600. if (fn && fn._callbacks) {
  26601. dg = fn
  26602. } else {
  26603. dg = function () {
  26604. var q
  26605. if (fn) {
  26606. q = fn.apply(this, arguments)
  26607. }
  26608. var callbacks = dg._callbacks
  26609. var k = callbacks.length
  26610. while (k--) {
  26611. var r = callbacks[k].apply(this, arguments)
  26612. if (q === undefined) {
  26613. q = r
  26614. }
  26615. }
  26616. return q
  26617. }
  26618. dg._callbacks = []
  26619. }
  26620. dg._callbacks.push(callback)
  26621. return dg
  26622. },
  26623. createElementByHtml: function (html) {
  26624. var el = document.createElement('div')
  26625. el.innerHTML = html
  26626. el = el.firstChild
  26627. el.parentNode.removeChild(el)
  26628. return el
  26629. },
  26630. getViewportElement: function () {
  26631. return browser.ie && browser.quirks
  26632. ? document.body
  26633. : document.documentElement
  26634. },
  26635. getClientRect: function (element) {
  26636. var bcr
  26637. //trace IE6下在控制编辑器显隐时可能会报错,catch一下
  26638. try {
  26639. bcr = element.getBoundingClientRect()
  26640. } catch (e) {
  26641. bcr = { left: 0, top: 0, height: 0, width: 0 }
  26642. }
  26643. var rect = {
  26644. left: Math.round(bcr.left),
  26645. top: Math.round(bcr.top),
  26646. height: Math.round(bcr.bottom - bcr.top),
  26647. width: Math.round(bcr.right - bcr.left),
  26648. }
  26649. var doc
  26650. while (
  26651. (doc = element.ownerDocument) !== document &&
  26652. (element = domUtils.getWindow(doc).frameElement)
  26653. ) {
  26654. bcr = element.getBoundingClientRect()
  26655. rect.left += bcr.left
  26656. rect.top += bcr.top
  26657. }
  26658. rect.bottom = rect.top + rect.height
  26659. rect.right = rect.left + rect.width
  26660. return rect
  26661. },
  26662. getViewportRect: function () {
  26663. var viewportEl = uiUtils.getViewportElement()
  26664. var width = (window.innerWidth || viewportEl.clientWidth) | 0
  26665. var height = (window.innerHeight || viewportEl.clientHeight) | 0
  26666. return {
  26667. left: 0,
  26668. top: 0,
  26669. height: height,
  26670. width: width,
  26671. bottom: height,
  26672. right: width,
  26673. }
  26674. },
  26675. setViewportOffset: function (element, offset) {
  26676. var rect
  26677. var fixedLayer = uiUtils.getFixedLayer()
  26678. if (element.parentNode === fixedLayer) {
  26679. element.style.left = offset.left + 'px'
  26680. element.style.top = offset.top + 'px'
  26681. } else {
  26682. domUtils.setViewportOffset(element, offset)
  26683. }
  26684. },
  26685. getEventOffset: function (evt) {
  26686. var el = evt.target || evt.srcElement
  26687. var rect = uiUtils.getClientRect(el)
  26688. var offset = uiUtils.getViewportOffsetByEvent(evt)
  26689. return {
  26690. left: offset.left - rect.left,
  26691. top: offset.top - rect.top,
  26692. }
  26693. },
  26694. getViewportOffsetByEvent: function (evt) {
  26695. var el = evt.target || evt.srcElement
  26696. var frameEl = domUtils.getWindow(el).frameElement
  26697. var offset = {
  26698. left: evt.clientX,
  26699. top: evt.clientY,
  26700. }
  26701. if (frameEl && el.ownerDocument !== document) {
  26702. var rect = uiUtils.getClientRect(frameEl)
  26703. offset.left += rect.left
  26704. offset.top += rect.top
  26705. }
  26706. return offset
  26707. },
  26708. setGlobal: function (id, obj) {
  26709. root[id] = obj
  26710. return magic + '["' + id + '"]'
  26711. },
  26712. unsetGlobal: function (id) {
  26713. delete root[id]
  26714. },
  26715. copyAttributes: function (tgt, src) {
  26716. var attributes = src.attributes
  26717. var k = attributes.length
  26718. while (k--) {
  26719. var attrNode = attributes[k]
  26720. if (
  26721. attrNode.nodeName != 'style' &&
  26722. attrNode.nodeName != 'class' &&
  26723. (!browser.ie || attrNode.specified)
  26724. ) {
  26725. tgt.setAttribute(attrNode.nodeName, attrNode.nodeValue)
  26726. }
  26727. }
  26728. if (src.className) {
  26729. domUtils.addClass(tgt, src.className)
  26730. }
  26731. if (src.style.cssText) {
  26732. tgt.style.cssText += ';' + src.style.cssText
  26733. }
  26734. },
  26735. removeStyle: function (el, styleName) {
  26736. if (el.style.removeProperty) {
  26737. el.style.removeProperty(styleName)
  26738. } else if (el.style.removeAttribute) {
  26739. el.style.removeAttribute(styleName)
  26740. } else throw ''
  26741. },
  26742. contains: function (elA, elB) {
  26743. return (
  26744. elA &&
  26745. elB &&
  26746. (elA === elB
  26747. ? false
  26748. : elA.contains
  26749. ? elA.contains(elB)
  26750. : elA.compareDocumentPosition(elB) & 16)
  26751. )
  26752. },
  26753. startDrag: function (evt, callbacks, doc) {
  26754. var doc = doc || document
  26755. var startX = evt.clientX
  26756. var startY = evt.clientY
  26757. function handleMouseMove(evt) {
  26758. var x = evt.clientX - startX
  26759. var y = evt.clientY - startY
  26760. callbacks.ondragmove(x, y, evt)
  26761. if (evt.stopPropagation) {
  26762. evt.stopPropagation()
  26763. } else {
  26764. evt.cancelBubble = true
  26765. }
  26766. }
  26767. if (doc.addEventListener) {
  26768. function handleMouseUp(evt) {
  26769. doc.removeEventListener('mousemove', handleMouseMove, true)
  26770. doc.removeEventListener('mouseup', handleMouseUp, true)
  26771. window.removeEventListener('mouseup', handleMouseUp, true)
  26772. callbacks.ondragstop()
  26773. }
  26774. doc.addEventListener('mousemove', handleMouseMove, true)
  26775. doc.addEventListener('mouseup', handleMouseUp, true)
  26776. window.addEventListener('mouseup', handleMouseUp, true)
  26777. evt.preventDefault()
  26778. } else {
  26779. var elm = evt.srcElement
  26780. elm.setCapture()
  26781. function releaseCaptrue() {
  26782. elm.releaseCapture()
  26783. elm.detachEvent('onmousemove', handleMouseMove)
  26784. elm.detachEvent('onmouseup', releaseCaptrue)
  26785. elm.detachEvent('onlosecaptrue', releaseCaptrue)
  26786. callbacks.ondragstop()
  26787. }
  26788. elm.attachEvent('onmousemove', handleMouseMove)
  26789. elm.attachEvent('onmouseup', releaseCaptrue)
  26790. elm.attachEvent('onlosecaptrue', releaseCaptrue)
  26791. evt.returnValue = false
  26792. }
  26793. callbacks.ondragstart()
  26794. },
  26795. getFixedLayer: function () {
  26796. var layer = document.getElementById('edui_fixedlayer')
  26797. if (layer == null) {
  26798. layer = document.createElement('div')
  26799. layer.id = 'edui_fixedlayer'
  26800. document.body.appendChild(layer)
  26801. if (browser.ie && browser.version <= 8) {
  26802. layer.style.position = 'absolute'
  26803. bindFixedLayer()
  26804. setTimeout(updateFixedOffset)
  26805. } else {
  26806. layer.style.position = 'fixed'
  26807. }
  26808. layer.style.left = '0'
  26809. layer.style.top = '0'
  26810. layer.style.width = '0'
  26811. layer.style.height = '0'
  26812. }
  26813. return layer
  26814. },
  26815. makeUnselectable: function (element) {
  26816. if (browser.opera || (browser.ie && browser.version < 9)) {
  26817. element.unselectable = 'on'
  26818. if (element.hasChildNodes()) {
  26819. for (var i = 0; i < element.childNodes.length; i++) {
  26820. if (element.childNodes[i].nodeType == 1) {
  26821. uiUtils.makeUnselectable(element.childNodes[i])
  26822. }
  26823. }
  26824. }
  26825. } else {
  26826. if (element.style.MozUserSelect !== undefined) {
  26827. element.style.MozUserSelect = 'none'
  26828. } else if (element.style.WebkitUserSelect !== undefined) {
  26829. element.style.WebkitUserSelect = 'none'
  26830. } else if (element.style.KhtmlUserSelect !== undefined) {
  26831. element.style.KhtmlUserSelect = 'none'
  26832. }
  26833. }
  26834. },
  26835. })
  26836. function updateFixedOffset() {
  26837. var layer = document.getElementById('edui_fixedlayer')
  26838. uiUtils.setViewportOffset(layer, {
  26839. left: 0,
  26840. top: 0,
  26841. })
  26842. // layer.style.display = 'none';
  26843. // layer.style.display = 'block';
  26844. //#trace: 1354
  26845. // setTimeout(updateFixedOffset);
  26846. }
  26847. function bindFixedLayer(adjOffset) {
  26848. domUtils.on(window, 'scroll', updateFixedOffset)
  26849. domUtils.on(
  26850. window,
  26851. 'resize',
  26852. baidu.editor.utils.defer(updateFixedOffset, 0, true)
  26853. )
  26854. }
  26855. })()
  26856. // ui/uibase.js
  26857. ;(function () {
  26858. var utils = baidu.editor.utils,
  26859. uiUtils = baidu.editor.ui.uiUtils,
  26860. EventBase = baidu.editor.EventBase,
  26861. UIBase = (baidu.editor.ui.UIBase = function () {})
  26862. UIBase.prototype = {
  26863. className: '',
  26864. uiName: '',
  26865. initOptions: function (options) {
  26866. var me = this
  26867. for (var k in options) {
  26868. me[k] = options[k]
  26869. }
  26870. this.id = this.id || 'edui' + uiUtils.uid()
  26871. },
  26872. initUIBase: function () {
  26873. this._globalKey = utils.unhtml(uiUtils.setGlobal(this.id, this))
  26874. },
  26875. render: function (holder) {
  26876. var html = this.renderHtml()
  26877. var el = uiUtils.createElementByHtml(html)
  26878. //by xuheng 给每个node添加class
  26879. var list = domUtils.getElementsByTagName(el, '*')
  26880. var theme = 'edui-' + (this.theme || this.editor.options.theme)
  26881. var layer = document.getElementById('edui_fixedlayer')
  26882. for (var i = 0, node; (node = list[i++]); ) {
  26883. domUtils.addClass(node, theme)
  26884. }
  26885. domUtils.addClass(el, theme)
  26886. if (layer) {
  26887. layer.className = ''
  26888. domUtils.addClass(layer, theme)
  26889. }
  26890. var seatEl = this.getDom()
  26891. if (seatEl != null) {
  26892. seatEl.parentNode.replaceChild(el, seatEl)
  26893. uiUtils.copyAttributes(el, seatEl)
  26894. } else {
  26895. if (typeof holder == 'string') {
  26896. holder = document.getElementById(holder)
  26897. }
  26898. holder = holder || uiUtils.getFixedLayer()
  26899. domUtils.addClass(holder, theme)
  26900. holder.appendChild(el)
  26901. }
  26902. this.postRender()
  26903. },
  26904. getDom: function (name) {
  26905. if (!name) {
  26906. return document.getElementById(this.id)
  26907. } else {
  26908. return document.getElementById(this.id + '_' + name)
  26909. }
  26910. },
  26911. postRender: function () {
  26912. this.fireEvent('postrender')
  26913. },
  26914. getHtmlTpl: function () {
  26915. return ''
  26916. },
  26917. formatHtml: function (tpl) {
  26918. var prefix = 'edui-' + this.uiName
  26919. return tpl
  26920. .replace(/##/g, this.id)
  26921. .replace(/%%-/g, this.uiName ? prefix + '-' : '')
  26922. .replace(/%%/g, (this.uiName ? prefix : '') + ' ' + this.className)
  26923. .replace(/\$\$/g, this._globalKey)
  26924. },
  26925. renderHtml: function () {
  26926. return this.formatHtml(this.getHtmlTpl())
  26927. },
  26928. dispose: function () {
  26929. var box = this.getDom()
  26930. if (box) baidu.editor.dom.domUtils.remove(box)
  26931. uiUtils.unsetGlobal(this.id)
  26932. },
  26933. }
  26934. utils.inherits(UIBase, EventBase)
  26935. })()
  26936. // ui/separator.js
  26937. ;(function () {
  26938. var utils = baidu.editor.utils,
  26939. UIBase = baidu.editor.ui.UIBase,
  26940. Separator = (baidu.editor.ui.Separator = function (options) {
  26941. this.initOptions(options)
  26942. this.initSeparator()
  26943. })
  26944. Separator.prototype = {
  26945. uiName: 'separator',
  26946. initSeparator: function () {
  26947. this.initUIBase()
  26948. },
  26949. getHtmlTpl: function () {
  26950. return '<div id="##" class="edui-box %%"></div>'
  26951. },
  26952. }
  26953. utils.inherits(Separator, UIBase)
  26954. })()
  26955. // ui/mask.js
  26956. ///import core
  26957. ///import uicore
  26958. ;(function () {
  26959. var utils = baidu.editor.utils,
  26960. domUtils = baidu.editor.dom.domUtils,
  26961. UIBase = baidu.editor.ui.UIBase,
  26962. uiUtils = baidu.editor.ui.uiUtils
  26963. var Mask = (baidu.editor.ui.Mask = function (options) {
  26964. this.initOptions(options)
  26965. this.initUIBase()
  26966. })
  26967. Mask.prototype = {
  26968. getHtmlTpl: function () {
  26969. return '<div id="##" class="edui-mask %%" onclick="return $$._onClick(event, this);" onmousedown="return $$._onMouseDown(event, this);"></div>'
  26970. },
  26971. postRender: function () {
  26972. var me = this
  26973. domUtils.on(window, 'resize', function () {
  26974. setTimeout(function () {
  26975. if (!me.isHidden()) {
  26976. me._fill()
  26977. }
  26978. })
  26979. })
  26980. },
  26981. show: function (zIndex) {
  26982. this._fill()
  26983. this.getDom().style.display = ''
  26984. this.getDom().style.zIndex = zIndex
  26985. },
  26986. hide: function () {
  26987. this.getDom().style.display = 'none'
  26988. this.getDom().style.zIndex = ''
  26989. },
  26990. isHidden: function () {
  26991. return this.getDom().style.display == 'none'
  26992. },
  26993. _onMouseDown: function () {
  26994. return false
  26995. },
  26996. _onClick: function (e, target) {
  26997. this.fireEvent('click', e, target)
  26998. },
  26999. _fill: function () {
  27000. var el = this.getDom()
  27001. var vpRect = uiUtils.getViewportRect()
  27002. el.style.width = vpRect.width + 'px'
  27003. el.style.height = vpRect.height + 'px'
  27004. },
  27005. }
  27006. utils.inherits(Mask, UIBase)
  27007. })()
  27008. // ui/popup.js
  27009. ///import core
  27010. ///import uicore
  27011. ;(function () {
  27012. var utils = baidu.editor.utils,
  27013. uiUtils = baidu.editor.ui.uiUtils,
  27014. domUtils = baidu.editor.dom.domUtils,
  27015. UIBase = baidu.editor.ui.UIBase,
  27016. Popup = (baidu.editor.ui.Popup = function (options) {
  27017. this.initOptions(options)
  27018. this.initPopup()
  27019. })
  27020. var allPopups = []
  27021. function closeAllPopup(evt, el) {
  27022. for (var i = 0; i < allPopups.length; i++) {
  27023. var pop = allPopups[i]
  27024. if (!pop.isHidden()) {
  27025. if (pop.queryAutoHide(el) !== false) {
  27026. if (
  27027. evt &&
  27028. /scroll/gi.test(evt.type) &&
  27029. pop.className == 'edui-wordpastepop'
  27030. )
  27031. return
  27032. pop.hide()
  27033. }
  27034. }
  27035. }
  27036. if (allPopups.length) pop.editor.fireEvent('afterhidepop')
  27037. }
  27038. Popup.postHide = closeAllPopup
  27039. var ANCHOR_CLASSES = [
  27040. 'edui-anchor-topleft',
  27041. 'edui-anchor-topright',
  27042. 'edui-anchor-bottomleft',
  27043. 'edui-anchor-bottomright',
  27044. ]
  27045. Popup.prototype = {
  27046. SHADOW_RADIUS: 5,
  27047. content: null,
  27048. _hidden: false,
  27049. autoRender: true,
  27050. canSideLeft: true,
  27051. canSideUp: true,
  27052. initPopup: function () {
  27053. this.initUIBase()
  27054. allPopups.push(this)
  27055. },
  27056. getHtmlTpl: function () {
  27057. return (
  27058. '<div id="##" class="edui-popup %%" onmousedown="return false;">' +
  27059. ' <div id="##_body" class="edui-popup-body">' +
  27060. ' <iframe style="position:absolute;z-index:-1;left:0;top:0;background-color: transparent;" frameborder="0" width="100%" height="100%" src="about:blank"></iframe>' +
  27061. ' <div class="edui-shadow"></div>' +
  27062. ' <div id="##_content" class="edui-popup-content">' +
  27063. this.getContentHtmlTpl() +
  27064. ' </div>' +
  27065. ' </div>' +
  27066. '</div>'
  27067. )
  27068. },
  27069. getContentHtmlTpl: function () {
  27070. if (this.content) {
  27071. if (typeof this.content == 'string') {
  27072. return this.content
  27073. }
  27074. return this.content.renderHtml()
  27075. } else {
  27076. return ''
  27077. }
  27078. },
  27079. _UIBase_postRender: UIBase.prototype.postRender,
  27080. postRender: function () {
  27081. if (this.content instanceof UIBase) {
  27082. this.content.postRender()
  27083. }
  27084. //捕获鼠标滚轮
  27085. if (this.captureWheel && !this.captured) {
  27086. this.captured = true
  27087. var winHeight =
  27088. (document.documentElement.clientHeight ||
  27089. document.body.clientHeight) - 80,
  27090. _height = this.getDom().offsetHeight,
  27091. _top = uiUtils.getClientRect(this.combox.getDom()).top,
  27092. content = this.getDom('content'),
  27093. ifr = this.getDom('body').getElementsByTagName('iframe'),
  27094. me = this
  27095. ifr.length && (ifr = ifr[0])
  27096. while (_top + _height > winHeight) {
  27097. _height -= 30
  27098. }
  27099. content.style.height = _height + 'px'
  27100. //同步更改iframe高度
  27101. ifr && (ifr.style.height = _height + 'px')
  27102. //阻止在combox上的鼠标滚轮事件, 防止用户的正常操作被误解
  27103. if (window.XMLHttpRequest) {
  27104. domUtils.on(
  27105. content,
  27106. 'onmousewheel' in document.body ? 'mousewheel' : 'DOMMouseScroll',
  27107. function (e) {
  27108. if (e.preventDefault) {
  27109. e.preventDefault()
  27110. } else {
  27111. e.returnValue = false
  27112. }
  27113. if (e.wheelDelta) {
  27114. content.scrollTop -= (e.wheelDelta / 120) * 60
  27115. } else {
  27116. content.scrollTop -= (e.detail / -3) * 60
  27117. }
  27118. }
  27119. )
  27120. } else {
  27121. //ie6
  27122. domUtils.on(this.getDom(), 'mousewheel', function (e) {
  27123. e.returnValue = false
  27124. me.getDom('content').scrollTop -= (e.wheelDelta / 120) * 60
  27125. })
  27126. }
  27127. }
  27128. this.fireEvent('postRenderAfter')
  27129. this.hide(true)
  27130. this._UIBase_postRender()
  27131. },
  27132. _doAutoRender: function () {
  27133. if (!this.getDom() && this.autoRender) {
  27134. this.render()
  27135. }
  27136. },
  27137. mesureSize: function () {
  27138. var box = this.getDom('content')
  27139. return uiUtils.getClientRect(box)
  27140. },
  27141. fitSize: function () {
  27142. if (this.captureWheel && this.sized) {
  27143. return this.__size
  27144. }
  27145. this.sized = true
  27146. var popBodyEl = this.getDom('body')
  27147. popBodyEl.style.width = ''
  27148. popBodyEl.style.height = ''
  27149. var size = this.mesureSize()
  27150. if (this.captureWheel) {
  27151. popBodyEl.style.width = -(-20 - size.width) + 'px'
  27152. var height = parseInt(this.getDom('content').style.height, 10)
  27153. !window.isNaN(height) && (size.height = height)
  27154. } else {
  27155. popBodyEl.style.width = size.width + 'px'
  27156. }
  27157. popBodyEl.style.height = size.height + 'px'
  27158. this.__size = size
  27159. this.captureWheel && (this.getDom('content').style.overflow = 'auto')
  27160. return size
  27161. },
  27162. showAnchor: function (element, hoz) {
  27163. this.showAnchorRect(uiUtils.getClientRect(element), hoz)
  27164. },
  27165. showAnchorRect: function (rect, hoz, adj) {
  27166. this._doAutoRender()
  27167. var vpRect = uiUtils.getViewportRect()
  27168. this.getDom().style.visibility = 'hidden'
  27169. this._show()
  27170. var popSize = this.fitSize()
  27171. var sideLeft, sideUp, left, top
  27172. if (hoz) {
  27173. sideLeft =
  27174. this.canSideLeft &&
  27175. rect.right + popSize.width > vpRect.right &&
  27176. rect.left > popSize.width
  27177. sideUp =
  27178. this.canSideUp &&
  27179. rect.top + popSize.height > vpRect.bottom &&
  27180. rect.bottom > popSize.height
  27181. left = sideLeft ? rect.left - popSize.width : rect.right
  27182. top = sideUp ? rect.bottom - popSize.height : rect.top
  27183. } else {
  27184. sideLeft =
  27185. this.canSideLeft &&
  27186. rect.right + popSize.width > vpRect.right &&
  27187. rect.left > popSize.width
  27188. sideUp =
  27189. this.canSideUp &&
  27190. rect.top + popSize.height > vpRect.bottom &&
  27191. rect.bottom > popSize.height
  27192. left = sideLeft ? rect.right - popSize.width : rect.left
  27193. top = sideUp ? rect.top - popSize.height : rect.bottom
  27194. }
  27195. var popEl = this.getDom()
  27196. uiUtils.setViewportOffset(popEl, {
  27197. left: left,
  27198. top: top,
  27199. })
  27200. domUtils.removeClasses(popEl, ANCHOR_CLASSES)
  27201. popEl.className +=
  27202. ' ' + ANCHOR_CLASSES[(sideUp ? 1 : 0) * 2 + (sideLeft ? 1 : 0)]
  27203. if (this.editor) {
  27204. popEl.style.zIndex = this.editor.container.style.zIndex * 1 + 10
  27205. baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex =
  27206. popEl.style.zIndex - 1
  27207. }
  27208. this.getDom().style.visibility = 'visible'
  27209. },
  27210. showAt: function (offset) {
  27211. var left = offset.left
  27212. var top = offset.top
  27213. var rect = {
  27214. left: left,
  27215. top: top,
  27216. right: left,
  27217. bottom: top,
  27218. height: 0,
  27219. width: 0,
  27220. }
  27221. this.showAnchorRect(rect, false, true)
  27222. },
  27223. _show: function () {
  27224. if (this._hidden) {
  27225. var box = this.getDom()
  27226. box.style.display = ''
  27227. this._hidden = false
  27228. // if (box.setActive) {
  27229. // box.setActive();
  27230. // }
  27231. this.fireEvent('show')
  27232. }
  27233. },
  27234. isHidden: function () {
  27235. return this._hidden
  27236. },
  27237. show: function () {
  27238. this._doAutoRender()
  27239. this._show()
  27240. },
  27241. hide: function (notNofity) {
  27242. if (!this._hidden && this.getDom()) {
  27243. this.getDom().style.display = 'none'
  27244. this._hidden = true
  27245. if (!notNofity) {
  27246. this.fireEvent('hide')
  27247. }
  27248. }
  27249. },
  27250. queryAutoHide: function (el) {
  27251. return !el || !uiUtils.contains(this.getDom(), el)
  27252. },
  27253. }
  27254. utils.inherits(Popup, UIBase)
  27255. domUtils.on(document, 'mousedown', function (evt) {
  27256. var el = evt.target || evt.srcElement
  27257. closeAllPopup(evt, el)
  27258. })
  27259. domUtils.on(window, 'scroll', function (evt, el) {
  27260. closeAllPopup(evt, el)
  27261. })
  27262. })()
  27263. // ui/colorpicker.js
  27264. ///import core
  27265. ///import uicore
  27266. ;(function () {
  27267. var utils = baidu.editor.utils,
  27268. UIBase = baidu.editor.ui.UIBase,
  27269. ColorPicker = (baidu.editor.ui.ColorPicker = function (options) {
  27270. this.initOptions(options)
  27271. this.noColorText = this.noColorText || this.editor.getLang('clearColor')
  27272. this.initUIBase()
  27273. })
  27274. ColorPicker.prototype = {
  27275. getHtmlTpl: function () {
  27276. return genColorPicker(this.noColorText, this.editor)
  27277. },
  27278. _onTableClick: function (evt) {
  27279. var tgt = evt.target || evt.srcElement
  27280. var color = tgt.getAttribute('data-color')
  27281. if (color) {
  27282. this.fireEvent('pickcolor', color)
  27283. }
  27284. },
  27285. _onTableOver: function (evt) {
  27286. var tgt = evt.target || evt.srcElement
  27287. var color = tgt.getAttribute('data-color')
  27288. if (color) {
  27289. this.getDom('preview').style.backgroundColor = color
  27290. }
  27291. },
  27292. _onTableOut: function () {
  27293. this.getDom('preview').style.backgroundColor = ''
  27294. },
  27295. _onPickNoColor: function () {
  27296. this.fireEvent('picknocolor')
  27297. },
  27298. }
  27299. utils.inherits(ColorPicker, UIBase)
  27300. var COLORS = (
  27301. 'ffffff,000000,eeece1,1f497d,4f81bd,c0504d,9bbb59,8064a2,4bacc6,f79646,' +
  27302. 'f2f2f2,7f7f7f,ddd9c3,c6d9f0,dbe5f1,f2dcdb,ebf1dd,e5e0ec,dbeef3,fdeada,' +
  27303. 'd8d8d8,595959,c4bd97,8db3e2,b8cce4,e5b9b7,d7e3bc,ccc1d9,b7dde8,fbd5b5,' +
  27304. 'bfbfbf,3f3f3f,938953,548dd4,95b3d7,d99694,c3d69b,b2a2c7,92cddc,fac08f,' +
  27305. 'a5a5a5,262626,494429,17365d,366092,953734,76923c,5f497a,31859b,e36c09,' +
  27306. '7f7f7f,0c0c0c,1d1b10,0f243e,244061,632423,4f6128,3f3151,205867,974806,' +
  27307. 'c00000,ff0000,ffc000,ffff00,92d050,00b050,00b0f0,0070c0,002060,7030a0,'
  27308. ).split(',')
  27309. function genColorPicker(noColorText, editor) {
  27310. var html =
  27311. '<div id="##" class="edui-colorpicker %%">' +
  27312. '<div class="edui-colorpicker-topbar edui-clearfix">' +
  27313. '<div unselectable="on" id="##_preview" class="edui-colorpicker-preview"></div>' +
  27314. '<div unselectable="on" class="edui-colorpicker-nocolor" onclick="$$._onPickNoColor(event, this);">' +
  27315. noColorText +
  27316. '</div>' +
  27317. '</div>' +
  27318. '<table class="edui-box" style="border-collapse: collapse;" onmouseover="$$._onTableOver(event, this);" onmouseout="$$._onTableOut(event, this);" onclick="return $$._onTableClick(event, this);" cellspacing="0" cellpadding="0">' +
  27319. '<tr style="border-bottom: 1px solid #ddd;font-size: 13px;line-height: 25px;color:#39C;padding-top: 2px"><td colspan="10">' +
  27320. editor.getLang('themeColor') +
  27321. '</td> </tr>' +
  27322. '<tr class="edui-colorpicker-tablefirstrow" >'
  27323. for (var i = 0; i < COLORS.length; i++) {
  27324. if (i && i % 10 === 0) {
  27325. html +=
  27326. '</tr>' +
  27327. (i == 60
  27328. ? '<tr style="border-bottom: 1px solid #ddd;font-size: 13px;line-height: 25px;color:#39C;"><td colspan="10">' +
  27329. editor.getLang('standardColor') +
  27330. '</td></tr>'
  27331. : '') +
  27332. '<tr' +
  27333. (i == 60 ? ' class="edui-colorpicker-tablefirstrow"' : '') +
  27334. '>'
  27335. }
  27336. html +=
  27337. i < 70
  27338. ? '<td style="padding: 0 2px;"><a hidefocus title="' +
  27339. COLORS[i] +
  27340. '" onclick="return false;" href="javascript:" unselectable="on" class="edui-box edui-colorpicker-colorcell"' +
  27341. ' data-color="#' +
  27342. COLORS[i] +
  27343. '"' +
  27344. ' style="background-color:#' +
  27345. COLORS[i] +
  27346. ';border:solid #ccc;' +
  27347. (i < 10 || i >= 60
  27348. ? 'border-width:1px;'
  27349. : i >= 10 && i < 20
  27350. ? 'border-width:1px 1px 0 1px;'
  27351. : 'border-width:0 1px 0 1px;') +
  27352. '"' +
  27353. '></a></td>'
  27354. : ''
  27355. }
  27356. html += '</tr></table></div>'
  27357. return html
  27358. }
  27359. })()
  27360. // ui/tablepicker.js
  27361. ///import core
  27362. ///import uicore
  27363. ;(function () {
  27364. var utils = baidu.editor.utils,
  27365. uiUtils = baidu.editor.ui.uiUtils,
  27366. UIBase = baidu.editor.ui.UIBase
  27367. var TablePicker = (baidu.editor.ui.TablePicker = function (options) {
  27368. this.initOptions(options)
  27369. this.initTablePicker()
  27370. })
  27371. TablePicker.prototype = {
  27372. defaultNumRows: 10,
  27373. defaultNumCols: 10,
  27374. maxNumRows: 20,
  27375. maxNumCols: 20,
  27376. numRows: 10,
  27377. numCols: 10,
  27378. lengthOfCellSide: 22,
  27379. initTablePicker: function () {
  27380. this.initUIBase()
  27381. },
  27382. getHtmlTpl: function () {
  27383. var me = this
  27384. return (
  27385. '<div id="##" class="edui-tablepicker %%">' +
  27386. '<div class="edui-tablepicker-body">' +
  27387. '<div class="edui-infoarea">' +
  27388. '<span id="##_label" class="edui-label"></span>' +
  27389. '</div>' +
  27390. '<div class="edui-pickarea"' +
  27391. ' onmousemove="$$._onMouseMove(event, this);"' +
  27392. ' onmouseover="$$._onMouseOver(event, this);"' +
  27393. ' onmouseout="$$._onMouseOut(event, this);"' +
  27394. ' onclick="$$._onClick(event, this);"' +
  27395. '>' +
  27396. '<div id="##_overlay" class="edui-overlay"></div>' +
  27397. '</div>' +
  27398. '</div>' +
  27399. '</div>'
  27400. )
  27401. },
  27402. _UIBase_render: UIBase.prototype.render,
  27403. render: function (holder) {
  27404. this._UIBase_render(holder)
  27405. this.getDom('label').innerHTML =
  27406. '0' +
  27407. this.editor.getLang('t_row') +
  27408. ' x 0' +
  27409. this.editor.getLang('t_col')
  27410. },
  27411. _track: function (numCols, numRows) {
  27412. var style = this.getDom('overlay').style
  27413. var sideLen = this.lengthOfCellSide
  27414. style.width = numCols * sideLen + 'px'
  27415. style.height = numRows * sideLen + 'px'
  27416. var label = this.getDom('label')
  27417. label.innerHTML =
  27418. numCols +
  27419. this.editor.getLang('t_col') +
  27420. ' x ' +
  27421. numRows +
  27422. this.editor.getLang('t_row')
  27423. this.numCols = numCols
  27424. this.numRows = numRows
  27425. },
  27426. _onMouseOver: function (evt, el) {
  27427. var rel = evt.relatedTarget || evt.fromElement
  27428. if (!uiUtils.contains(el, rel) && el !== rel) {
  27429. this.getDom('label').innerHTML =
  27430. '0' +
  27431. this.editor.getLang('t_col') +
  27432. ' x 0' +
  27433. this.editor.getLang('t_row')
  27434. this.getDom('overlay').style.visibility = ''
  27435. }
  27436. },
  27437. _onMouseOut: function (evt, el) {
  27438. var rel = evt.relatedTarget || evt.toElement
  27439. if (!uiUtils.contains(el, rel) && el !== rel) {
  27440. this.getDom('label').innerHTML =
  27441. '0' +
  27442. this.editor.getLang('t_col') +
  27443. ' x 0' +
  27444. this.editor.getLang('t_row')
  27445. this.getDom('overlay').style.visibility = 'hidden'
  27446. }
  27447. },
  27448. _onMouseMove: function (evt, el) {
  27449. var style = this.getDom('overlay').style
  27450. var offset = uiUtils.getEventOffset(evt)
  27451. var sideLen = this.lengthOfCellSide
  27452. var numCols = Math.ceil(offset.left / sideLen)
  27453. var numRows = Math.ceil(offset.top / sideLen)
  27454. this._track(numCols, numRows)
  27455. },
  27456. _onClick: function () {
  27457. this.fireEvent('picktable', this.numCols, this.numRows)
  27458. },
  27459. }
  27460. utils.inherits(TablePicker, UIBase)
  27461. })()
  27462. // ui/stateful.js
  27463. ;(function () {
  27464. var browser = baidu.editor.browser,
  27465. domUtils = baidu.editor.dom.domUtils,
  27466. uiUtils = baidu.editor.ui.uiUtils
  27467. var TPL_STATEFUL =
  27468. 'onmousedown="$$.Stateful_onMouseDown(event, this);"' +
  27469. ' onmouseup="$$.Stateful_onMouseUp(event, this);"' +
  27470. (browser.ie
  27471. ? ' onmouseenter="$$.Stateful_onMouseEnter(event, this);"' +
  27472. ' onmouseleave="$$.Stateful_onMouseLeave(event, this);"'
  27473. : ' onmouseover="$$.Stateful_onMouseOver(event, this);"' +
  27474. ' onmouseout="$$.Stateful_onMouseOut(event, this);"')
  27475. baidu.editor.ui.Stateful = {
  27476. alwalysHoverable: false,
  27477. target: null, //目标元素和this指向dom不一样
  27478. Stateful_init: function () {
  27479. this._Stateful_dGetHtmlTpl = this.getHtmlTpl
  27480. this.getHtmlTpl = this.Stateful_getHtmlTpl
  27481. },
  27482. Stateful_getHtmlTpl: function () {
  27483. var tpl = this._Stateful_dGetHtmlTpl()
  27484. // 使用function避免$转义
  27485. return tpl.replace(/stateful/g, function () {
  27486. return TPL_STATEFUL
  27487. })
  27488. },
  27489. Stateful_onMouseEnter: function (evt, el) {
  27490. this.target = el
  27491. if (!this.isDisabled() || this.alwalysHoverable) {
  27492. this.addState('hover')
  27493. this.fireEvent('over')
  27494. }
  27495. },
  27496. Stateful_onMouseLeave: function (evt, el) {
  27497. if (!this.isDisabled() || this.alwalysHoverable) {
  27498. this.removeState('hover')
  27499. this.removeState('active')
  27500. this.fireEvent('out')
  27501. }
  27502. },
  27503. Stateful_onMouseOver: function (evt, el) {
  27504. var rel = evt.relatedTarget
  27505. if (!uiUtils.contains(el, rel) && el !== rel) {
  27506. this.Stateful_onMouseEnter(evt, el)
  27507. }
  27508. },
  27509. Stateful_onMouseOut: function (evt, el) {
  27510. var rel = evt.relatedTarget
  27511. if (!uiUtils.contains(el, rel) && el !== rel) {
  27512. this.Stateful_onMouseLeave(evt, el)
  27513. }
  27514. },
  27515. Stateful_onMouseDown: function (evt, el) {
  27516. if (!this.isDisabled()) {
  27517. this.addState('active')
  27518. }
  27519. },
  27520. Stateful_onMouseUp: function (evt, el) {
  27521. if (!this.isDisabled()) {
  27522. this.removeState('active')
  27523. }
  27524. },
  27525. Stateful_postRender: function () {
  27526. if (this.disabled && !this.hasState('disabled')) {
  27527. this.addState('disabled')
  27528. }
  27529. },
  27530. hasState: function (state) {
  27531. return domUtils.hasClass(this.getStateDom(), 'edui-state-' + state)
  27532. },
  27533. addState: function (state) {
  27534. if (!this.hasState(state)) {
  27535. this.getStateDom().className += ' edui-state-' + state
  27536. }
  27537. },
  27538. removeState: function (state) {
  27539. if (this.hasState(state)) {
  27540. domUtils.removeClasses(this.getStateDom(), ['edui-state-' + state])
  27541. }
  27542. },
  27543. getStateDom: function () {
  27544. return this.getDom('state')
  27545. },
  27546. isChecked: function () {
  27547. return this.hasState('checked')
  27548. },
  27549. setChecked: function (checked) {
  27550. if (!this.isDisabled() && checked) {
  27551. this.addState('checked')
  27552. } else {
  27553. this.removeState('checked')
  27554. }
  27555. },
  27556. isDisabled: function () {
  27557. return this.hasState('disabled')
  27558. },
  27559. setDisabled: function (disabled) {
  27560. if (disabled) {
  27561. this.removeState('hover')
  27562. this.removeState('checked')
  27563. this.removeState('active')
  27564. this.addState('disabled')
  27565. } else {
  27566. this.removeState('disabled')
  27567. }
  27568. },
  27569. }
  27570. })()
  27571. // ui/button.js
  27572. ///import core
  27573. ///import uicore
  27574. ///import ui/stateful.js
  27575. ;(function () {
  27576. var utils = baidu.editor.utils,
  27577. UIBase = baidu.editor.ui.UIBase,
  27578. Stateful = baidu.editor.ui.Stateful,
  27579. Button = (baidu.editor.ui.Button = function (options) {
  27580. if (options.name) {
  27581. var btnName = options.name
  27582. var cssRules = options.cssRules
  27583. if (!options.className) {
  27584. options.className = 'edui-for-' + btnName
  27585. }
  27586. options.cssRules =
  27587. '.edui-default .edui-for-' +
  27588. btnName +
  27589. ' .edui-icon {' +
  27590. cssRules +
  27591. '}'
  27592. }
  27593. this.initOptions(options)
  27594. this.initButton()
  27595. })
  27596. Button.prototype = {
  27597. uiName: 'button',
  27598. label: '',
  27599. title: '',
  27600. showIcon: true,
  27601. showText: true,
  27602. cssRules: '',
  27603. initButton: function () {
  27604. this.initUIBase()
  27605. this.Stateful_init()
  27606. if (this.cssRules) {
  27607. utils.cssRule('edui-customize-' + this.name + '-style', this.cssRules)
  27608. }
  27609. },
  27610. getHtmlTpl: function () {
  27611. return (
  27612. '<div id="##" class="edui-box %%">' +
  27613. '<div id="##_state" stateful>' +
  27614. '<div class="%%-wrap"><div id="##_body" unselectable="on" ' +
  27615. (this.title ? 'title="' + this.title + '"' : '') +
  27616. ' class="%%-body" onmousedown="return $$._onMouseDown(event, this);" onclick="return $$._onClick(event, this);">' +
  27617. (this.showIcon ? '<div class="edui-box edui-icon"></div>' : '') +
  27618. (this.showText
  27619. ? '<div class="edui-box edui-label">' + this.label + '</div>'
  27620. : '') +
  27621. '</div>' +
  27622. '</div>' +
  27623. '</div></div>'
  27624. )
  27625. },
  27626. postRender: function () {
  27627. this.Stateful_postRender()
  27628. this.setDisabled(this.disabled)
  27629. },
  27630. _onMouseDown: function (e) {
  27631. var target = e.target || e.srcElement,
  27632. tagName = target && target.tagName && target.tagName.toLowerCase()
  27633. if (tagName == 'input' || tagName == 'object' || tagName == 'object') {
  27634. return false
  27635. }
  27636. },
  27637. _onClick: function () {
  27638. if (!this.isDisabled()) {
  27639. this.fireEvent('click')
  27640. }
  27641. },
  27642. setTitle: function (text) {
  27643. var label = this.getDom('label')
  27644. label.innerHTML = text
  27645. },
  27646. }
  27647. utils.inherits(Button, UIBase)
  27648. utils.extend(Button.prototype, Stateful)
  27649. })()
  27650. // ui/splitbutton.js
  27651. ///import core
  27652. ///import uicore
  27653. ///import ui/stateful.js
  27654. ;(function () {
  27655. var utils = baidu.editor.utils,
  27656. uiUtils = baidu.editor.ui.uiUtils,
  27657. domUtils = baidu.editor.dom.domUtils,
  27658. UIBase = baidu.editor.ui.UIBase,
  27659. Stateful = baidu.editor.ui.Stateful,
  27660. SplitButton = (baidu.editor.ui.SplitButton = function (options) {
  27661. this.initOptions(options)
  27662. this.initSplitButton()
  27663. })
  27664. SplitButton.prototype = {
  27665. popup: null,
  27666. uiName: 'splitbutton',
  27667. title: '',
  27668. initSplitButton: function () {
  27669. this.initUIBase()
  27670. this.Stateful_init()
  27671. var me = this
  27672. if (this.popup != null) {
  27673. var popup = this.popup
  27674. this.popup = null
  27675. this.setPopup(popup)
  27676. }
  27677. },
  27678. _UIBase_postRender: UIBase.prototype.postRender,
  27679. postRender: function () {
  27680. this.Stateful_postRender()
  27681. this._UIBase_postRender()
  27682. },
  27683. setPopup: function (popup) {
  27684. if (this.popup === popup) return
  27685. if (this.popup != null) {
  27686. this.popup.dispose()
  27687. }
  27688. popup.addListener('show', utils.bind(this._onPopupShow, this))
  27689. popup.addListener('hide', utils.bind(this._onPopupHide, this))
  27690. popup.addListener(
  27691. 'postrender',
  27692. utils.bind(function () {
  27693. popup
  27694. .getDom('body')
  27695. .appendChild(
  27696. uiUtils.createElementByHtml(
  27697. '<div id="' +
  27698. this.popup.id +
  27699. '_bordereraser" class="edui-bordereraser edui-background" style="width:' +
  27700. (uiUtils.getClientRect(this.getDom()).width + 20) +
  27701. 'px"></div>'
  27702. )
  27703. )
  27704. popup.getDom().className += ' ' + this.className
  27705. }, this)
  27706. )
  27707. this.popup = popup
  27708. },
  27709. _onPopupShow: function () {
  27710. this.addState('opened')
  27711. },
  27712. _onPopupHide: function () {
  27713. this.removeState('opened')
  27714. },
  27715. getHtmlTpl: function () {
  27716. return (
  27717. '<div id="##" class="edui-box %%">' +
  27718. '<div ' +
  27719. (this.title ? 'title="' + this.title + '"' : '') +
  27720. ' id="##_state" stateful><div class="%%-body">' +
  27721. '<div id="##_button_body" class="edui-box edui-button-body" onclick="$$._onButtonClick(event, this);">' +
  27722. '<div class="edui-box edui-icon"></div>' +
  27723. '</div>' +
  27724. '<div class="edui-box edui-splitborder"></div>' +
  27725. '<div class="edui-box edui-arrow" onclick="$$._onArrowClick();"></div>' +
  27726. '</div></div></div>'
  27727. )
  27728. },
  27729. showPopup: function () {
  27730. // 当popup往上弹出的时候,做特殊处理
  27731. var rect = uiUtils.getClientRect(this.getDom())
  27732. rect.top -= this.popup.SHADOW_RADIUS
  27733. rect.height += this.popup.SHADOW_RADIUS
  27734. this.popup.showAnchorRect(rect)
  27735. },
  27736. _onArrowClick: function (event, el) {
  27737. if (!this.isDisabled()) {
  27738. this.showPopup()
  27739. }
  27740. },
  27741. _onButtonClick: function () {
  27742. if (!this.isDisabled()) {
  27743. this.fireEvent('buttonclick')
  27744. }
  27745. },
  27746. }
  27747. utils.inherits(SplitButton, UIBase)
  27748. utils.extend(SplitButton.prototype, Stateful, true)
  27749. })()
  27750. // ui/colorbutton.js
  27751. ///import core
  27752. ///import uicore
  27753. ///import ui/colorpicker.js
  27754. ///import ui/popup.js
  27755. ///import ui/splitbutton.js
  27756. ;(function () {
  27757. var utils = baidu.editor.utils,
  27758. uiUtils = baidu.editor.ui.uiUtils,
  27759. ColorPicker = baidu.editor.ui.ColorPicker,
  27760. Popup = baidu.editor.ui.Popup,
  27761. SplitButton = baidu.editor.ui.SplitButton,
  27762. ColorButton = (baidu.editor.ui.ColorButton = function (options) {
  27763. this.initOptions(options)
  27764. this.initColorButton()
  27765. })
  27766. ColorButton.prototype = {
  27767. initColorButton: function () {
  27768. var me = this
  27769. this.popup = new Popup({
  27770. content: new ColorPicker({
  27771. noColorText: me.editor.getLang('clearColor'),
  27772. editor: me.editor,
  27773. onpickcolor: function (t, color) {
  27774. me._onPickColor(color)
  27775. },
  27776. onpicknocolor: function (t, color) {
  27777. me._onPickNoColor(color)
  27778. },
  27779. }),
  27780. editor: me.editor,
  27781. })
  27782. this.initSplitButton()
  27783. },
  27784. _SplitButton_postRender: SplitButton.prototype.postRender,
  27785. postRender: function () {
  27786. this._SplitButton_postRender()
  27787. this.getDom('button_body').appendChild(
  27788. uiUtils.createElementByHtml(
  27789. '<div id="' + this.id + '_colorlump" class="edui-colorlump"></div>'
  27790. )
  27791. )
  27792. this.getDom().className += ' edui-colorbutton'
  27793. },
  27794. setColor: function (color) {
  27795. this.getDom('colorlump').style.backgroundColor = color
  27796. this.color = color
  27797. },
  27798. _onPickColor: function (color) {
  27799. if (this.fireEvent('pickcolor', color) !== false) {
  27800. this.setColor(color)
  27801. this.popup.hide()
  27802. }
  27803. },
  27804. _onPickNoColor: function (color) {
  27805. if (this.fireEvent('picknocolor') !== false) {
  27806. this.popup.hide()
  27807. }
  27808. },
  27809. }
  27810. utils.inherits(ColorButton, SplitButton)
  27811. })()
  27812. // ui/tablebutton.js
  27813. ///import core
  27814. ///import uicore
  27815. ///import ui/popup.js
  27816. ///import ui/tablepicker.js
  27817. ///import ui/splitbutton.js
  27818. ;(function () {
  27819. var utils = baidu.editor.utils,
  27820. Popup = baidu.editor.ui.Popup,
  27821. TablePicker = baidu.editor.ui.TablePicker,
  27822. SplitButton = baidu.editor.ui.SplitButton,
  27823. TableButton = (baidu.editor.ui.TableButton = function (options) {
  27824. this.initOptions(options)
  27825. this.initTableButton()
  27826. })
  27827. TableButton.prototype = {
  27828. initTableButton: function () {
  27829. var me = this
  27830. this.popup = new Popup({
  27831. content: new TablePicker({
  27832. editor: me.editor,
  27833. onpicktable: function (t, numCols, numRows) {
  27834. me._onPickTable(numCols, numRows)
  27835. },
  27836. }),
  27837. editor: me.editor,
  27838. })
  27839. this.initSplitButton()
  27840. },
  27841. _onPickTable: function (numCols, numRows) {
  27842. if (this.fireEvent('picktable', numCols, numRows) !== false) {
  27843. this.popup.hide()
  27844. }
  27845. },
  27846. }
  27847. utils.inherits(TableButton, SplitButton)
  27848. })()
  27849. // ui/autotypesetpicker.js
  27850. ///import core
  27851. ///import uicore
  27852. ;(function () {
  27853. var utils = baidu.editor.utils,
  27854. UIBase = baidu.editor.ui.UIBase
  27855. var AutoTypeSetPicker = (baidu.editor.ui.AutoTypeSetPicker = function (
  27856. options
  27857. ) {
  27858. this.initOptions(options)
  27859. this.initAutoTypeSetPicker()
  27860. })
  27861. AutoTypeSetPicker.prototype = {
  27862. initAutoTypeSetPicker: function () {
  27863. this.initUIBase()
  27864. },
  27865. getHtmlTpl: function () {
  27866. var me = this.editor,
  27867. opt = me.options.autotypeset,
  27868. lang = me.getLang('autoTypeSet')
  27869. var textAlignInputName = 'textAlignValue' + me.uid,
  27870. imageBlockInputName = 'imageBlockLineValue' + me.uid,
  27871. symbolConverInputName = 'symbolConverValue' + me.uid
  27872. return (
  27873. '<div id="##" class="edui-autotypesetpicker %%">' +
  27874. '<div class="edui-autotypesetpicker-body">' +
  27875. '<table >' +
  27876. '<tr><td nowrap><input type="checkbox" name="mergeEmptyline" ' +
  27877. (opt['mergeEmptyline'] ? 'checked' : '') +
  27878. '>' +
  27879. lang.mergeLine +
  27880. '</td><td colspan="2"><input type="checkbox" name="removeEmptyline" ' +
  27881. (opt['removeEmptyline'] ? 'checked' : '') +
  27882. '>' +
  27883. lang.delLine +
  27884. '</td></tr>' +
  27885. '<tr><td nowrap><input type="checkbox" name="removeClass" ' +
  27886. (opt['removeClass'] ? 'checked' : '') +
  27887. '>' +
  27888. lang.removeFormat +
  27889. '</td><td colspan="2"><input type="checkbox" name="indent" ' +
  27890. (opt['indent'] ? 'checked' : '') +
  27891. '>' +
  27892. lang.indent +
  27893. '</td></tr>' +
  27894. '<tr>' +
  27895. '<td nowrap><input type="checkbox" name="textAlign" ' +
  27896. (opt['textAlign'] ? 'checked' : '') +
  27897. '>' +
  27898. lang.alignment +
  27899. '</td>' +
  27900. '<td colspan="2" id="' +
  27901. textAlignInputName +
  27902. '">' +
  27903. '<input type="radio" name="' +
  27904. textAlignInputName +
  27905. '" value="left" ' +
  27906. (opt['textAlign'] && opt['textAlign'] == 'left' ? 'checked' : '') +
  27907. '>' +
  27908. me.getLang('justifyleft') +
  27909. '<input type="radio" name="' +
  27910. textAlignInputName +
  27911. '" value="center" ' +
  27912. (opt['textAlign'] && opt['textAlign'] == 'center' ? 'checked' : '') +
  27913. '>' +
  27914. me.getLang('justifycenter') +
  27915. '<input type="radio" name="' +
  27916. textAlignInputName +
  27917. '" value="right" ' +
  27918. (opt['textAlign'] && opt['textAlign'] == 'right' ? 'checked' : '') +
  27919. '>' +
  27920. me.getLang('justifyright') +
  27921. '</td>' +
  27922. '</tr>' +
  27923. '<tr>' +
  27924. '<td nowrap><input type="checkbox" name="imageBlockLine" ' +
  27925. (opt['imageBlockLine'] ? 'checked' : '') +
  27926. '>' +
  27927. lang.imageFloat +
  27928. '</td>' +
  27929. '<td nowrap id="' +
  27930. imageBlockInputName +
  27931. '">' +
  27932. '<input type="radio" name="' +
  27933. imageBlockInputName +
  27934. '" value="none" ' +
  27935. (opt['imageBlockLine'] && opt['imageBlockLine'] == 'none'
  27936. ? 'checked'
  27937. : '') +
  27938. '>' +
  27939. me.getLang('default') +
  27940. '<input type="radio" name="' +
  27941. imageBlockInputName +
  27942. '" value="left" ' +
  27943. (opt['imageBlockLine'] && opt['imageBlockLine'] == 'left'
  27944. ? 'checked'
  27945. : '') +
  27946. '>' +
  27947. me.getLang('justifyleft') +
  27948. '<input type="radio" name="' +
  27949. imageBlockInputName +
  27950. '" value="center" ' +
  27951. (opt['imageBlockLine'] && opt['imageBlockLine'] == 'center'
  27952. ? 'checked'
  27953. : '') +
  27954. '>' +
  27955. me.getLang('justifycenter') +
  27956. '<input type="radio" name="' +
  27957. imageBlockInputName +
  27958. '" value="right" ' +
  27959. (opt['imageBlockLine'] && opt['imageBlockLine'] == 'right'
  27960. ? 'checked'
  27961. : '') +
  27962. '>' +
  27963. me.getLang('justifyright') +
  27964. '</td>' +
  27965. '</tr>' +
  27966. '<tr><td nowrap><input type="checkbox" name="clearFontSize" ' +
  27967. (opt['clearFontSize'] ? 'checked' : '') +
  27968. '>' +
  27969. lang.removeFontsize +
  27970. '</td><td colspan="2"><input type="checkbox" name="clearFontFamily" ' +
  27971. (opt['clearFontFamily'] ? 'checked' : '') +
  27972. '>' +
  27973. lang.removeFontFamily +
  27974. '</td></tr>' +
  27975. '<tr><td nowrap colspan="3"><input type="checkbox" name="removeEmptyNode" ' +
  27976. (opt['removeEmptyNode'] ? 'checked' : '') +
  27977. '>' +
  27978. lang.removeHtml +
  27979. '</td></tr>' +
  27980. '<tr><td nowrap colspan="3"><input type="checkbox" name="pasteFilter" ' +
  27981. (opt['pasteFilter'] ? 'checked' : '') +
  27982. '>' +
  27983. lang.pasteFilter +
  27984. '</td></tr>' +
  27985. '<tr>' +
  27986. '<td nowrap><input type="checkbox" name="symbolConver" ' +
  27987. (opt['bdc2sb'] || opt['tobdc'] ? 'checked' : '') +
  27988. '>' +
  27989. lang.symbol +
  27990. '</td>' +
  27991. '<td id="' +
  27992. symbolConverInputName +
  27993. '">' +
  27994. '<input type="radio" name="bdc" value="bdc2sb" ' +
  27995. (opt['bdc2sb'] ? 'checked' : '') +
  27996. '>' +
  27997. lang.bdc2sb +
  27998. '<input type="radio" name="bdc" value="tobdc" ' +
  27999. (opt['tobdc'] ? 'checked' : '') +
  28000. '>' +
  28001. lang.tobdc +
  28002. '' +
  28003. '</td>' +
  28004. '<td nowrap align="right"><button >' +
  28005. lang.run +
  28006. '</button></td>' +
  28007. '</tr>' +
  28008. '</table>' +
  28009. '</div>' +
  28010. '</div>'
  28011. )
  28012. },
  28013. _UIBase_render: UIBase.prototype.render,
  28014. }
  28015. utils.inherits(AutoTypeSetPicker, UIBase)
  28016. })()
  28017. // ui/autotypesetbutton.js
  28018. ///import core
  28019. ///import uicore
  28020. ///import ui/popup.js
  28021. ///import ui/autotypesetpicker.js
  28022. ///import ui/splitbutton.js
  28023. ;(function () {
  28024. var utils = baidu.editor.utils,
  28025. Popup = baidu.editor.ui.Popup,
  28026. AutoTypeSetPicker = baidu.editor.ui.AutoTypeSetPicker,
  28027. SplitButton = baidu.editor.ui.SplitButton,
  28028. AutoTypeSetButton = (baidu.editor.ui.AutoTypeSetButton = function (
  28029. options
  28030. ) {
  28031. this.initOptions(options)
  28032. this.initAutoTypeSetButton()
  28033. })
  28034. function getPara(me) {
  28035. var opt = {},
  28036. cont = me.getDom(),
  28037. editorId = me.editor.uid,
  28038. inputType = null,
  28039. attrName = null,
  28040. ipts = domUtils.getElementsByTagName(cont, 'input')
  28041. for (var i = ipts.length - 1, ipt; (ipt = ipts[i--]); ) {
  28042. inputType = ipt.getAttribute('type')
  28043. if (inputType == 'checkbox') {
  28044. attrName = ipt.getAttribute('name')
  28045. opt[attrName] && delete opt[attrName]
  28046. if (ipt.checked) {
  28047. var attrValue = document.getElementById(
  28048. attrName + 'Value' + editorId
  28049. )
  28050. if (attrValue) {
  28051. if (/input/gi.test(attrValue.tagName)) {
  28052. opt[attrName] = attrValue.value
  28053. } else {
  28054. var iptChilds = attrValue.getElementsByTagName('input')
  28055. for (
  28056. var j = iptChilds.length - 1, iptchild;
  28057. (iptchild = iptChilds[j--]);
  28058. ) {
  28059. if (iptchild.checked) {
  28060. opt[attrName] = iptchild.value
  28061. break
  28062. }
  28063. }
  28064. }
  28065. } else {
  28066. opt[attrName] = true
  28067. }
  28068. } else {
  28069. opt[attrName] = false
  28070. }
  28071. } else {
  28072. opt[ipt.getAttribute('value')] = ipt.checked
  28073. }
  28074. }
  28075. var selects = domUtils.getElementsByTagName(cont, 'select')
  28076. for (var i = 0, si; (si = selects[i++]); ) {
  28077. var attr = si.getAttribute('name')
  28078. opt[attr] = opt[attr] ? si.value : ''
  28079. }
  28080. utils.extend(me.editor.options.autotypeset, opt)
  28081. me.editor.setPreferences('autotypeset', opt)
  28082. }
  28083. AutoTypeSetButton.prototype = {
  28084. initAutoTypeSetButton: function () {
  28085. var me = this
  28086. this.popup = new Popup({
  28087. //传入配置参数
  28088. content: new AutoTypeSetPicker({ editor: me.editor }),
  28089. editor: me.editor,
  28090. hide: function () {
  28091. if (!this._hidden && this.getDom()) {
  28092. getPara(this)
  28093. this.getDom().style.display = 'none'
  28094. this._hidden = true
  28095. this.fireEvent('hide')
  28096. }
  28097. },
  28098. })
  28099. var flag = 0
  28100. this.popup.addListener('postRenderAfter', function () {
  28101. var popupUI = this
  28102. if (flag) return
  28103. var cont = this.getDom(),
  28104. btn = cont.getElementsByTagName('button')[0]
  28105. btn.onclick = function () {
  28106. getPara(popupUI)
  28107. me.editor.execCommand('autotypeset')
  28108. popupUI.hide()
  28109. }
  28110. domUtils.on(cont, 'click', function (e) {
  28111. var target = e.target || e.srcElement,
  28112. editorId = me.editor.uid
  28113. if (target && target.tagName == 'INPUT') {
  28114. // 点击图片浮动的checkbox,去除对应的radio
  28115. if (
  28116. target.name == 'imageBlockLine' ||
  28117. target.name == 'textAlign' ||
  28118. target.name == 'symbolConver'
  28119. ) {
  28120. var checked = target.checked,
  28121. radioTd = document.getElementById(
  28122. target.name + 'Value' + editorId
  28123. ),
  28124. radios = radioTd.getElementsByTagName('input'),
  28125. defalutSelect = {
  28126. imageBlockLine: 'none',
  28127. textAlign: 'left',
  28128. symbolConver: 'tobdc',
  28129. }
  28130. for (var i = 0; i < radios.length; i++) {
  28131. if (checked) {
  28132. if (radios[i].value == defalutSelect[target.name]) {
  28133. radios[i].checked = 'checked'
  28134. }
  28135. } else {
  28136. radios[i].checked = false
  28137. }
  28138. }
  28139. }
  28140. // 点击radio,选中对应的checkbox
  28141. if (
  28142. target.name == 'imageBlockLineValue' + editorId ||
  28143. target.name == 'textAlignValue' + editorId ||
  28144. target.name == 'bdc'
  28145. ) {
  28146. var checkboxs =
  28147. target.parentNode.previousSibling.getElementsByTagName(
  28148. 'input'
  28149. )
  28150. checkboxs && (checkboxs[0].checked = true)
  28151. }
  28152. getPara(popupUI)
  28153. }
  28154. })
  28155. flag = 1
  28156. })
  28157. this.initSplitButton()
  28158. },
  28159. }
  28160. utils.inherits(AutoTypeSetButton, SplitButton)
  28161. })()
  28162. // ui/cellalignpicker.js
  28163. ///import core
  28164. ///import uicore
  28165. ;(function () {
  28166. var utils = baidu.editor.utils,
  28167. Popup = baidu.editor.ui.Popup,
  28168. Stateful = baidu.editor.ui.Stateful,
  28169. UIBase = baidu.editor.ui.UIBase
  28170. /**
  28171. * 该参数将新增一个参数: selected, 参数类型为一个Object, 形如{ 'align': 'center', 'valign': 'top' }, 表示单元格的初始
  28172. * 对齐状态为: 竖直居上,水平居中; 其中 align的取值为:'center', 'left', 'right'; valign的取值为: 'top', 'middle', 'bottom'
  28173. * @update 2013/4/2 hancong03@baidu.com
  28174. */
  28175. var CellAlignPicker = (baidu.editor.ui.CellAlignPicker = function (
  28176. options
  28177. ) {
  28178. this.initOptions(options)
  28179. this.initSelected()
  28180. this.initCellAlignPicker()
  28181. })
  28182. CellAlignPicker.prototype = {
  28183. //初始化选中状态, 该方法将根据传递进来的参数获取到应该选中的对齐方式图标的索引
  28184. initSelected: function () {
  28185. var status = {
  28186. valign: {
  28187. top: 0,
  28188. middle: 1,
  28189. bottom: 2,
  28190. },
  28191. align: {
  28192. left: 0,
  28193. center: 1,
  28194. right: 2,
  28195. },
  28196. count: 3,
  28197. },
  28198. result = -1
  28199. if (this.selected) {
  28200. this.selectedIndex =
  28201. status.valign[this.selected.valign] * status.count +
  28202. status.align[this.selected.align]
  28203. }
  28204. },
  28205. initCellAlignPicker: function () {
  28206. this.initUIBase()
  28207. this.Stateful_init()
  28208. },
  28209. getHtmlTpl: function () {
  28210. var alignType = ['left', 'center', 'right'],
  28211. COUNT = 9,
  28212. tempClassName = null,
  28213. tempIndex = -1,
  28214. tmpl = []
  28215. for (var i = 0; i < COUNT; i++) {
  28216. tempClassName =
  28217. this.selectedIndex === i ? ' class="edui-cellalign-selected" ' : ''
  28218. tempIndex = i % 3
  28219. tempIndex === 0 && tmpl.push('<tr>')
  28220. tmpl.push(
  28221. '<td index="' +
  28222. i +
  28223. '" ' +
  28224. tempClassName +
  28225. ' stateful><div class="edui-icon edui-' +
  28226. alignType[tempIndex] +
  28227. '"></div></td>'
  28228. )
  28229. tempIndex === 2 && tmpl.push('</tr>')
  28230. }
  28231. return (
  28232. '<div id="##" class="edui-cellalignpicker %%">' +
  28233. '<div class="edui-cellalignpicker-body">' +
  28234. '<table onclick="$$._onClick(event);">' +
  28235. tmpl.join('') +
  28236. '</table>' +
  28237. '</div>' +
  28238. '</div>'
  28239. )
  28240. },
  28241. getStateDom: function () {
  28242. return this.target
  28243. },
  28244. _onClick: function (evt) {
  28245. var target = evt.target || evt.srcElement
  28246. if (/icon/.test(target.className)) {
  28247. this.items[target.parentNode.getAttribute('index')].onclick()
  28248. Popup.postHide(evt)
  28249. }
  28250. },
  28251. _UIBase_render: UIBase.prototype.render,
  28252. }
  28253. utils.inherits(CellAlignPicker, UIBase)
  28254. utils.extend(CellAlignPicker.prototype, Stateful, true)
  28255. })()
  28256. // ui/pastepicker.js
  28257. ///import core
  28258. ///import uicore
  28259. ;(function () {
  28260. var utils = baidu.editor.utils,
  28261. Stateful = baidu.editor.ui.Stateful,
  28262. uiUtils = baidu.editor.ui.uiUtils,
  28263. UIBase = baidu.editor.ui.UIBase
  28264. var PastePicker = (baidu.editor.ui.PastePicker = function (options) {
  28265. this.initOptions(options)
  28266. this.initPastePicker()
  28267. })
  28268. PastePicker.prototype = {
  28269. initPastePicker: function () {
  28270. this.initUIBase()
  28271. this.Stateful_init()
  28272. },
  28273. getHtmlTpl: function () {
  28274. return (
  28275. '<div class="edui-pasteicon" onclick="$$._onClick(this)"></div>' +
  28276. '<div class="edui-pastecontainer">' +
  28277. '<div class="edui-title">' +
  28278. this.editor.getLang('pasteOpt') +
  28279. '</div>' +
  28280. '<div class="edui-button">' +
  28281. '<div title="' +
  28282. this.editor.getLang('pasteSourceFormat') +
  28283. '" onclick="$$.format(false)" stateful>' +
  28284. '<div class="edui-richtxticon"></div></div>' +
  28285. '<div title="' +
  28286. this.editor.getLang('tagFormat') +
  28287. '" onclick="$$.format(2)" stateful>' +
  28288. '<div class="edui-tagicon"></div></div>' +
  28289. '<div title="' +
  28290. this.editor.getLang('pasteTextFormat') +
  28291. '" onclick="$$.format(true)" stateful>' +
  28292. '<div class="edui-plaintxticon"></div></div>' +
  28293. '</div>' +
  28294. '</div>' +
  28295. '</div>'
  28296. )
  28297. },
  28298. getStateDom: function () {
  28299. return this.target
  28300. },
  28301. format: function (param) {
  28302. this.editor.ui._isTransfer = true
  28303. this.editor.fireEvent('pasteTransfer', param)
  28304. },
  28305. _onClick: function (cur) {
  28306. var node = domUtils.getNextDomNode(cur),
  28307. screenHt = uiUtils.getViewportRect().height,
  28308. subPop = uiUtils.getClientRect(node)
  28309. if (subPop.top + subPop.height > screenHt)
  28310. node.style.top = -subPop.height - cur.offsetHeight + 'px'
  28311. else node.style.top = ''
  28312. if (/hidden/gi.test(domUtils.getComputedStyle(node, 'visibility'))) {
  28313. node.style.visibility = 'visible'
  28314. domUtils.addClass(cur, 'edui-state-opened')
  28315. } else {
  28316. node.style.visibility = 'hidden'
  28317. domUtils.removeClasses(cur, 'edui-state-opened')
  28318. }
  28319. },
  28320. _UIBase_render: UIBase.prototype.render,
  28321. }
  28322. utils.inherits(PastePicker, UIBase)
  28323. utils.extend(PastePicker.prototype, Stateful, true)
  28324. })()
  28325. // ui/toolbar.js
  28326. ;(function () {
  28327. var utils = baidu.editor.utils,
  28328. uiUtils = baidu.editor.ui.uiUtils,
  28329. UIBase = baidu.editor.ui.UIBase,
  28330. Toolbar = (baidu.editor.ui.Toolbar = function (options) {
  28331. this.initOptions(options)
  28332. this.initToolbar()
  28333. })
  28334. Toolbar.prototype = {
  28335. items: null,
  28336. initToolbar: function () {
  28337. this.items = this.items || []
  28338. this.initUIBase()
  28339. },
  28340. add: function (item, index) {
  28341. if (index === undefined) {
  28342. this.items.push(item)
  28343. } else {
  28344. this.items.splice(index, 0, item)
  28345. }
  28346. },
  28347. getHtmlTpl: function () {
  28348. var buff = []
  28349. for (var i = 0; i < this.items.length; i++) {
  28350. buff[i] = this.items[i].renderHtml()
  28351. }
  28352. return (
  28353. '<div id="##" class="edui-toolbar %%" onselectstart="return false;" onmousedown="return $$._onMouseDown(event, this);">' +
  28354. buff.join('') +
  28355. '</div>'
  28356. )
  28357. },
  28358. postRender: function () {
  28359. var box = this.getDom()
  28360. for (var i = 0; i < this.items.length; i++) {
  28361. this.items[i].postRender()
  28362. }
  28363. uiUtils.makeUnselectable(box)
  28364. },
  28365. _onMouseDown: function (e) {
  28366. var target = e.target || e.srcElement,
  28367. tagName = target && target.tagName && target.tagName.toLowerCase()
  28368. if (tagName == 'input' || tagName == 'object' || tagName == 'object') {
  28369. return false
  28370. }
  28371. },
  28372. }
  28373. utils.inherits(Toolbar, UIBase)
  28374. })()
  28375. // ui/menu.js
  28376. ///import core
  28377. ///import uicore
  28378. ///import ui\popup.js
  28379. ///import ui\stateful.js
  28380. ;(function () {
  28381. var utils = baidu.editor.utils,
  28382. domUtils = baidu.editor.dom.domUtils,
  28383. uiUtils = baidu.editor.ui.uiUtils,
  28384. UIBase = baidu.editor.ui.UIBase,
  28385. Popup = baidu.editor.ui.Popup,
  28386. Stateful = baidu.editor.ui.Stateful,
  28387. CellAlignPicker = baidu.editor.ui.CellAlignPicker,
  28388. Menu = (baidu.editor.ui.Menu = function (options) {
  28389. this.initOptions(options)
  28390. this.initMenu()
  28391. })
  28392. var menuSeparator = {
  28393. renderHtml: function () {
  28394. return '<div class="edui-menuitem edui-menuseparator"><div class="edui-menuseparator-inner"></div></div>'
  28395. },
  28396. postRender: function () {},
  28397. queryAutoHide: function () {
  28398. return true
  28399. },
  28400. }
  28401. Menu.prototype = {
  28402. items: null,
  28403. uiName: 'menu',
  28404. initMenu: function () {
  28405. this.items = this.items || []
  28406. this.initPopup()
  28407. this.initItems()
  28408. },
  28409. initItems: function () {
  28410. for (var i = 0; i < this.items.length; i++) {
  28411. var item = this.items[i]
  28412. if (item == '-') {
  28413. this.items[i] = this.getSeparator()
  28414. } else if (!(item instanceof MenuItem)) {
  28415. item.editor = this.editor
  28416. item.theme = this.editor.options.theme
  28417. this.items[i] = this.createItem(item)
  28418. }
  28419. }
  28420. },
  28421. getSeparator: function () {
  28422. return menuSeparator
  28423. },
  28424. createItem: function (item) {
  28425. //新增一个参数menu, 该参数存储了menuItem所对应的menu引用
  28426. item.menu = this
  28427. return new MenuItem(item)
  28428. },
  28429. _Popup_getContentHtmlTpl: Popup.prototype.getContentHtmlTpl,
  28430. getContentHtmlTpl: function () {
  28431. if (this.items.length == 0) {
  28432. return this._Popup_getContentHtmlTpl()
  28433. }
  28434. var buff = []
  28435. for (var i = 0; i < this.items.length; i++) {
  28436. var item = this.items[i]
  28437. buff[i] = item.renderHtml()
  28438. }
  28439. return '<div class="%%-body">' + buff.join('') + '</div>'
  28440. },
  28441. _Popup_postRender: Popup.prototype.postRender,
  28442. postRender: function () {
  28443. var me = this
  28444. for (var i = 0; i < this.items.length; i++) {
  28445. var item = this.items[i]
  28446. item.ownerMenu = this
  28447. item.postRender()
  28448. }
  28449. domUtils.on(this.getDom(), 'mouseover', function (evt) {
  28450. evt = evt || event
  28451. var rel = evt.relatedTarget || evt.fromElement
  28452. var el = me.getDom()
  28453. if (!uiUtils.contains(el, rel) && el !== rel) {
  28454. me.fireEvent('over')
  28455. }
  28456. })
  28457. this._Popup_postRender()
  28458. },
  28459. queryAutoHide: function (el) {
  28460. if (el) {
  28461. if (uiUtils.contains(this.getDom(), el)) {
  28462. return false
  28463. }
  28464. for (var i = 0; i < this.items.length; i++) {
  28465. var item = this.items[i]
  28466. if (item.queryAutoHide(el) === false) {
  28467. return false
  28468. }
  28469. }
  28470. }
  28471. },
  28472. clearItems: function () {
  28473. for (var i = 0; i < this.items.length; i++) {
  28474. var item = this.items[i]
  28475. clearTimeout(item._showingTimer)
  28476. clearTimeout(item._closingTimer)
  28477. if (item.subMenu) {
  28478. item.subMenu.destroy()
  28479. }
  28480. }
  28481. this.items = []
  28482. },
  28483. destroy: function () {
  28484. if (this.getDom()) {
  28485. domUtils.remove(this.getDom())
  28486. }
  28487. this.clearItems()
  28488. },
  28489. dispose: function () {
  28490. this.destroy()
  28491. },
  28492. }
  28493. utils.inherits(Menu, Popup)
  28494. /**
  28495. * @update 2013/04/03 hancong03 新增一个参数menu, 该参数存储了menuItem所对应的menu引用
  28496. * @type {Function}
  28497. */
  28498. var MenuItem = (baidu.editor.ui.MenuItem = function (options) {
  28499. this.initOptions(options)
  28500. this.initUIBase()
  28501. this.Stateful_init()
  28502. if (this.subMenu && !(this.subMenu instanceof Menu)) {
  28503. if (options.className && options.className.indexOf('aligntd') != -1) {
  28504. var me = this
  28505. //获取单元格对齐初始状态
  28506. this.subMenu.selected = this.editor.queryCommandValue('cellalignment')
  28507. this.subMenu = new Popup({
  28508. content: new CellAlignPicker(this.subMenu),
  28509. parentMenu: me,
  28510. editor: me.editor,
  28511. destroy: function () {
  28512. if (this.getDom()) {
  28513. domUtils.remove(this.getDom())
  28514. }
  28515. },
  28516. })
  28517. this.subMenu.addListener('postRenderAfter', function () {
  28518. domUtils.on(this.getDom(), 'mouseover', function () {
  28519. me.addState('opened')
  28520. })
  28521. })
  28522. } else {
  28523. this.subMenu = new Menu(this.subMenu)
  28524. }
  28525. }
  28526. })
  28527. MenuItem.prototype = {
  28528. label: '',
  28529. subMenu: null,
  28530. ownerMenu: null,
  28531. uiName: 'menuitem',
  28532. alwalysHoverable: true,
  28533. getHtmlTpl: function () {
  28534. return (
  28535. '<div id="##" class="%%" stateful onclick="$$._onClick(event, this);">' +
  28536. '<div class="%%-body">' +
  28537. this.renderLabelHtml() +
  28538. '</div>' +
  28539. '</div>'
  28540. )
  28541. },
  28542. postRender: function () {
  28543. var me = this
  28544. this.addListener('over', function () {
  28545. me.ownerMenu.fireEvent('submenuover', me)
  28546. if (me.subMenu) {
  28547. me.delayShowSubMenu()
  28548. }
  28549. })
  28550. if (this.subMenu) {
  28551. this.getDom().className += ' edui-hassubmenu'
  28552. this.subMenu.render()
  28553. this.addListener('out', function () {
  28554. me.delayHideSubMenu()
  28555. })
  28556. this.subMenu.addListener('over', function () {
  28557. clearTimeout(me._closingTimer)
  28558. me._closingTimer = null
  28559. me.addState('opened')
  28560. })
  28561. this.ownerMenu.addListener('hide', function () {
  28562. me.hideSubMenu()
  28563. })
  28564. this.ownerMenu.addListener('submenuover', function (t, subMenu) {
  28565. if (subMenu !== me) {
  28566. me.delayHideSubMenu()
  28567. }
  28568. })
  28569. this.subMenu._bakQueryAutoHide = this.subMenu.queryAutoHide
  28570. this.subMenu.queryAutoHide = function (el) {
  28571. if (el && uiUtils.contains(me.getDom(), el)) {
  28572. return false
  28573. }
  28574. return this._bakQueryAutoHide(el)
  28575. }
  28576. }
  28577. this.getDom().style.tabIndex = '-1'
  28578. uiUtils.makeUnselectable(this.getDom())
  28579. this.Stateful_postRender()
  28580. },
  28581. delayShowSubMenu: function () {
  28582. var me = this
  28583. if (!me.isDisabled()) {
  28584. me.addState('opened')
  28585. clearTimeout(me._showingTimer)
  28586. clearTimeout(me._closingTimer)
  28587. me._closingTimer = null
  28588. me._showingTimer = setTimeout(function () {
  28589. me.showSubMenu()
  28590. }, 250)
  28591. }
  28592. },
  28593. delayHideSubMenu: function () {
  28594. var me = this
  28595. if (!me.isDisabled()) {
  28596. me.removeState('opened')
  28597. clearTimeout(me._showingTimer)
  28598. if (!me._closingTimer) {
  28599. me._closingTimer = setTimeout(function () {
  28600. if (!me.hasState('opened')) {
  28601. me.hideSubMenu()
  28602. }
  28603. me._closingTimer = null
  28604. }, 400)
  28605. }
  28606. }
  28607. },
  28608. renderLabelHtml: function () {
  28609. return (
  28610. '<div class="edui-arrow"></div>' +
  28611. '<div class="edui-box edui-icon"></div>' +
  28612. '<div class="edui-box edui-label %%-label">' +
  28613. (this.label || '') +
  28614. '</div>'
  28615. )
  28616. },
  28617. getStateDom: function () {
  28618. return this.getDom()
  28619. },
  28620. queryAutoHide: function (el) {
  28621. if (this.subMenu && this.hasState('opened')) {
  28622. return this.subMenu.queryAutoHide(el)
  28623. }
  28624. },
  28625. _onClick: function (event, this_) {
  28626. if (this.hasState('disabled')) return
  28627. if (this.fireEvent('click', event, this_) !== false) {
  28628. if (this.subMenu) {
  28629. this.showSubMenu()
  28630. } else {
  28631. Popup.postHide(event)
  28632. }
  28633. }
  28634. },
  28635. showSubMenu: function () {
  28636. var rect = uiUtils.getClientRect(this.getDom())
  28637. rect.right -= 5
  28638. rect.left += 2
  28639. rect.width -= 7
  28640. rect.top -= 4
  28641. rect.bottom += 4
  28642. rect.height += 8
  28643. this.subMenu.showAnchorRect(rect, true, true)
  28644. },
  28645. hideSubMenu: function () {
  28646. this.subMenu.hide()
  28647. },
  28648. }
  28649. utils.inherits(MenuItem, UIBase)
  28650. utils.extend(MenuItem.prototype, Stateful, true)
  28651. })()
  28652. // ui/combox.js
  28653. ///import core
  28654. ///import uicore
  28655. ///import ui/menu.js
  28656. ///import ui/splitbutton.js
  28657. ;(function () {
  28658. // todo: menu和item提成通用list
  28659. var utils = baidu.editor.utils,
  28660. uiUtils = baidu.editor.ui.uiUtils,
  28661. Menu = baidu.editor.ui.Menu,
  28662. SplitButton = baidu.editor.ui.SplitButton,
  28663. Combox = (baidu.editor.ui.Combox = function (options) {
  28664. this.initOptions(options)
  28665. this.initCombox()
  28666. })
  28667. Combox.prototype = {
  28668. uiName: 'combox',
  28669. onbuttonclick: function () {
  28670. this.showPopup()
  28671. },
  28672. initCombox: function () {
  28673. var me = this
  28674. this.items = this.items || []
  28675. for (var i = 0; i < this.items.length; i++) {
  28676. var item = this.items[i]
  28677. item.uiName = 'listitem'
  28678. item.index = i
  28679. item.onclick = function () {
  28680. me.selectByIndex(this.index)
  28681. }
  28682. }
  28683. this.popup = new Menu({
  28684. items: this.items,
  28685. uiName: 'list',
  28686. editor: this.editor,
  28687. captureWheel: true,
  28688. combox: this,
  28689. })
  28690. this.initSplitButton()
  28691. },
  28692. _SplitButton_postRender: SplitButton.prototype.postRender,
  28693. postRender: function () {
  28694. this._SplitButton_postRender()
  28695. this.setLabel(this.label || '')
  28696. this.setValue(this.initValue || '')
  28697. },
  28698. showPopup: function () {
  28699. var rect = uiUtils.getClientRect(this.getDom())
  28700. rect.top += 1
  28701. rect.bottom -= 1
  28702. rect.height -= 2
  28703. this.popup.showAnchorRect(rect)
  28704. },
  28705. getValue: function () {
  28706. return this.value
  28707. },
  28708. setValue: function (value) {
  28709. var index = this.indexByValue(value)
  28710. if (index != -1) {
  28711. this.selectedIndex = index
  28712. this.setLabel(this.items[index].label)
  28713. this.value = this.items[index].value
  28714. } else {
  28715. this.selectedIndex = -1
  28716. this.setLabel(this.getLabelForUnknowValue(value))
  28717. this.value = value
  28718. }
  28719. },
  28720. setLabel: function (label) {
  28721. this.getDom('button_body').innerHTML = label
  28722. this.label = label
  28723. },
  28724. getLabelForUnknowValue: function (value) {
  28725. return value
  28726. },
  28727. indexByValue: function (value) {
  28728. for (var i = 0; i < this.items.length; i++) {
  28729. if (value == this.items[i].value) {
  28730. return i
  28731. }
  28732. }
  28733. return -1
  28734. },
  28735. getItem: function (index) {
  28736. return this.items[index]
  28737. },
  28738. selectByIndex: function (index) {
  28739. if (
  28740. index < this.items.length &&
  28741. this.fireEvent('select', index) !== false
  28742. ) {
  28743. this.selectedIndex = index
  28744. this.value = this.items[index].value
  28745. this.setLabel(this.items[index].label)
  28746. }
  28747. },
  28748. }
  28749. utils.inherits(Combox, SplitButton)
  28750. })()
  28751. // ui/dialog.js
  28752. ///import core
  28753. ///import uicore
  28754. ///import ui/mask.js
  28755. ///import ui/button.js
  28756. ;(function () {
  28757. var utils = baidu.editor.utils,
  28758. domUtils = baidu.editor.dom.domUtils,
  28759. uiUtils = baidu.editor.ui.uiUtils,
  28760. Mask = baidu.editor.ui.Mask,
  28761. UIBase = baidu.editor.ui.UIBase,
  28762. Button = baidu.editor.ui.Button,
  28763. Dialog = (baidu.editor.ui.Dialog = function (options) {
  28764. if (options.name) {
  28765. var name = options.name
  28766. var cssRules = options.cssRules
  28767. if (!options.className) {
  28768. options.className = 'edui-for-' + name
  28769. }
  28770. if (cssRules) {
  28771. options.cssRules =
  28772. '.edui-default .edui-for-' +
  28773. name +
  28774. ' .edui-dialog-content {' +
  28775. cssRules +
  28776. '}'
  28777. }
  28778. }
  28779. this.initOptions(
  28780. utils.extend(
  28781. {
  28782. autoReset: true,
  28783. draggable: true,
  28784. onok: function () {},
  28785. oncancel: function () {},
  28786. onclose: function (t, ok) {
  28787. return ok ? this.onok() : this.oncancel()
  28788. },
  28789. //是否控制dialog中的scroll事件, 默认为不阻止
  28790. holdScroll: false,
  28791. },
  28792. options
  28793. )
  28794. )
  28795. this.initDialog()
  28796. })
  28797. var modalMask
  28798. var dragMask
  28799. var activeDialog
  28800. Dialog.prototype = {
  28801. draggable: false,
  28802. uiName: 'dialog',
  28803. initDialog: function () {
  28804. var me = this,
  28805. theme = this.editor.options.theme
  28806. if (this.cssRules) {
  28807. utils.cssRule('edui-customize-' + this.name + '-style', this.cssRules)
  28808. }
  28809. this.initUIBase()
  28810. this.modalMask =
  28811. modalMask ||
  28812. (modalMask = new Mask({
  28813. className: 'edui-dialog-modalmask',
  28814. theme: theme,
  28815. onclick: function () {
  28816. activeDialog && activeDialog.close(false)
  28817. },
  28818. }))
  28819. this.dragMask =
  28820. dragMask ||
  28821. (dragMask = new Mask({
  28822. className: 'edui-dialog-dragmask',
  28823. theme: theme,
  28824. }))
  28825. this.closeButton = new Button({
  28826. className: 'edui-dialog-closebutton',
  28827. title: me.closeDialog,
  28828. theme: theme,
  28829. onclick: function () {
  28830. me.close(false)
  28831. },
  28832. })
  28833. this.fullscreen && this.initResizeEvent()
  28834. if (this.buttons) {
  28835. for (var i = 0; i < this.buttons.length; i++) {
  28836. if (!(this.buttons[i] instanceof Button)) {
  28837. this.buttons[i] = new Button(
  28838. utils.extend(
  28839. this.buttons[i],
  28840. {
  28841. editor: this.editor,
  28842. },
  28843. true
  28844. )
  28845. )
  28846. }
  28847. }
  28848. }
  28849. },
  28850. initResizeEvent: function () {
  28851. var me = this
  28852. domUtils.on(window, 'resize', function () {
  28853. if (me._hidden || me._hidden === undefined) {
  28854. return
  28855. }
  28856. if (me.__resizeTimer) {
  28857. window.clearTimeout(me.__resizeTimer)
  28858. }
  28859. me.__resizeTimer = window.setTimeout(function () {
  28860. me.__resizeTimer = null
  28861. var dialogWrapNode = me.getDom(),
  28862. contentNode = me.getDom('content'),
  28863. wrapRect = UE.ui.uiUtils.getClientRect(dialogWrapNode),
  28864. contentRect = UE.ui.uiUtils.getClientRect(contentNode),
  28865. vpRect = uiUtils.getViewportRect()
  28866. contentNode.style.width =
  28867. vpRect.width - wrapRect.width + contentRect.width + 'px'
  28868. contentNode.style.height =
  28869. vpRect.height - wrapRect.height + contentRect.height + 'px'
  28870. dialogWrapNode.style.width = vpRect.width + 'px'
  28871. dialogWrapNode.style.height = vpRect.height + 'px'
  28872. me.fireEvent('resize')
  28873. }, 100)
  28874. })
  28875. },
  28876. fitSize: function () {
  28877. var popBodyEl = this.getDom('body')
  28878. // if (!(baidu.editor.browser.ie && baidu.editor.browser.version == 7)) {
  28879. // uiUtils.removeStyle(popBodyEl, 'width');
  28880. // uiUtils.removeStyle(popBodyEl, 'height');
  28881. // }
  28882. var size = this.mesureSize()
  28883. popBodyEl.style.width = size.width + 'px'
  28884. popBodyEl.style.height = size.height + 'px'
  28885. return size
  28886. },
  28887. safeSetOffset: function (offset) {
  28888. var me = this
  28889. var el = me.getDom()
  28890. var vpRect = uiUtils.getViewportRect()
  28891. var rect = uiUtils.getClientRect(el)
  28892. var left = offset.left
  28893. if (left + rect.width > vpRect.right) {
  28894. left = vpRect.right - rect.width
  28895. }
  28896. var top = offset.top
  28897. if (top + rect.height > vpRect.bottom) {
  28898. top = vpRect.bottom - rect.height
  28899. }
  28900. el.style.left = Math.max(left, 0) + 'px'
  28901. el.style.top = Math.max(top, 0) + 'px'
  28902. },
  28903. showAtCenter: function () {
  28904. var vpRect = uiUtils.getViewportRect()
  28905. if (!this.fullscreen) {
  28906. this.getDom().style.display = ''
  28907. var popSize = this.fitSize()
  28908. var titleHeight = this.getDom('titlebar').offsetHeight | 0
  28909. var left = vpRect.width / 2 - popSize.width / 2
  28910. var top =
  28911. vpRect.height / 2 - (popSize.height - titleHeight) / 2 - titleHeight
  28912. var popEl = this.getDom()
  28913. this.safeSetOffset({
  28914. left: Math.max(left | 0, 0),
  28915. top: Math.max(top | 0, 0),
  28916. })
  28917. if (!domUtils.hasClass(popEl, 'edui-state-centered')) {
  28918. popEl.className += ' edui-state-centered'
  28919. }
  28920. } else {
  28921. var dialogWrapNode = this.getDom(),
  28922. contentNode = this.getDom('content')
  28923. dialogWrapNode.style.display = 'block'
  28924. var wrapRect = UE.ui.uiUtils.getClientRect(dialogWrapNode),
  28925. contentRect = UE.ui.uiUtils.getClientRect(contentNode)
  28926. dialogWrapNode.style.left = '-100000px'
  28927. contentNode.style.width =
  28928. vpRect.width - wrapRect.width + contentRect.width + 'px'
  28929. contentNode.style.height =
  28930. vpRect.height - wrapRect.height + contentRect.height + 'px'
  28931. dialogWrapNode.style.width = vpRect.width + 'px'
  28932. dialogWrapNode.style.height = vpRect.height + 'px'
  28933. dialogWrapNode.style.left = 0
  28934. //保存环境的overflow值
  28935. this._originalContext = {
  28936. html: {
  28937. overflowX: document.documentElement.style.overflowX,
  28938. overflowY: document.documentElement.style.overflowY,
  28939. },
  28940. body: {
  28941. overflowX: document.body.style.overflowX,
  28942. overflowY: document.body.style.overflowY,
  28943. },
  28944. }
  28945. document.documentElement.style.overflowX = 'hidden'
  28946. document.documentElement.style.overflowY = 'hidden'
  28947. document.body.style.overflowX = 'hidden'
  28948. document.body.style.overflowY = 'hidden'
  28949. }
  28950. this._show()
  28951. },
  28952. getContentHtml: function () {
  28953. var contentHtml = ''
  28954. if (typeof this.content == 'string') {
  28955. contentHtml = this.content
  28956. } else if (this.iframeUrl) {
  28957. contentHtml =
  28958. '<span id="' +
  28959. this.id +
  28960. '_contmask" class="dialogcontmask"></span><iframe id="' +
  28961. this.id +
  28962. '_iframe" class="%%-iframe" height="100%" width="100%" frameborder="0" src="' +
  28963. this.iframeUrl +
  28964. '"></iframe>'
  28965. }
  28966. return contentHtml
  28967. },
  28968. getHtmlTpl: function () {
  28969. var footHtml = ''
  28970. if (this.buttons) {
  28971. var buff = []
  28972. for (var i = 0; i < this.buttons.length; i++) {
  28973. buff[i] = this.buttons[i].renderHtml()
  28974. }
  28975. footHtml =
  28976. '<div class="%%-foot">' +
  28977. '<div id="##_buttons" class="%%-buttons">' +
  28978. buff.join('') +
  28979. '</div>' +
  28980. '</div>'
  28981. }
  28982. return (
  28983. '<div id="##" class="%%"><div ' +
  28984. (!this.fullscreen
  28985. ? 'class="%%"'
  28986. : 'class="%%-wrap edui-dialog-fullscreen-flag"') +
  28987. '><div id="##_body" class="%%-body">' +
  28988. '<div class="%%-shadow"></div>' +
  28989. '<div id="##_titlebar" class="%%-titlebar">' +
  28990. '<div class="%%-draghandle" onmousedown="$$._onTitlebarMouseDown(event, this);">' +
  28991. '<span class="%%-caption">' +
  28992. (this.title || '') +
  28993. '</span>' +
  28994. '</div>' +
  28995. this.closeButton.renderHtml() +
  28996. '</div>' +
  28997. '<div id="##_content" class="%%-content">' +
  28998. (this.autoReset ? '' : this.getContentHtml()) +
  28999. '</div>' +
  29000. footHtml +
  29001. '</div></div></div>'
  29002. )
  29003. },
  29004. postRender: function () {
  29005. // todo: 保持居中/记住上次关闭位置选项
  29006. if (!this.modalMask.getDom()) {
  29007. this.modalMask.render()
  29008. this.modalMask.hide()
  29009. }
  29010. if (!this.dragMask.getDom()) {
  29011. this.dragMask.render()
  29012. this.dragMask.hide()
  29013. }
  29014. var me = this
  29015. this.addListener('show', function () {
  29016. me.modalMask.show(this.getDom().style.zIndex - 2)
  29017. })
  29018. this.addListener('hide', function () {
  29019. me.modalMask.hide()
  29020. })
  29021. if (this.buttons) {
  29022. for (var i = 0; i < this.buttons.length; i++) {
  29023. this.buttons[i].postRender()
  29024. }
  29025. }
  29026. domUtils.on(window, 'resize', function () {
  29027. setTimeout(function () {
  29028. if (!me.isHidden()) {
  29029. me.safeSetOffset(uiUtils.getClientRect(me.getDom()))
  29030. }
  29031. })
  29032. })
  29033. //hold住scroll事件,防止dialog的滚动影响页面
  29034. // if( this.holdScroll ) {
  29035. //
  29036. // if( !me.iframeUrl ) {
  29037. // domUtils.on( document.getElementById( me.id + "_iframe"), !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
  29038. // domUtils.preventDefault(e);
  29039. // } );
  29040. // } else {
  29041. // me.addListener('dialogafterreset', function(){
  29042. // window.setTimeout(function(){
  29043. // var iframeWindow = document.getElementById( me.id + "_iframe").contentWindow;
  29044. //
  29045. // if( browser.ie ) {
  29046. //
  29047. // var timer = window.setInterval(function(){
  29048. //
  29049. // if( iframeWindow.document && iframeWindow.document.body ) {
  29050. // window.clearInterval( timer );
  29051. // timer = null;
  29052. // domUtils.on( iframeWindow.document.body, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
  29053. // domUtils.preventDefault(e);
  29054. // } );
  29055. // }
  29056. //
  29057. // }, 100);
  29058. //
  29059. // } else {
  29060. // domUtils.on( iframeWindow, !browser.gecko ? "mousewheel" : "DOMMouseScroll", function(e){
  29061. // domUtils.preventDefault(e);
  29062. // } );
  29063. // }
  29064. //
  29065. // }, 1);
  29066. // });
  29067. // }
  29068. //
  29069. // }
  29070. this._hide()
  29071. },
  29072. mesureSize: function () {
  29073. var body = this.getDom('body')
  29074. var width = uiUtils.getClientRect(this.getDom('content')).width
  29075. var dialogBodyStyle = body.style
  29076. dialogBodyStyle.width = width
  29077. return uiUtils.getClientRect(body)
  29078. },
  29079. _onTitlebarMouseDown: function (evt, el) {
  29080. if (this.draggable) {
  29081. var rect
  29082. var vpRect = uiUtils.getViewportRect()
  29083. var me = this
  29084. uiUtils.startDrag(evt, {
  29085. ondragstart: function () {
  29086. rect = uiUtils.getClientRect(me.getDom())
  29087. me.getDom('contmask').style.visibility = 'visible'
  29088. me.dragMask.show(me.getDom().style.zIndex - 1)
  29089. },
  29090. ondragmove: function (x, y) {
  29091. var left = rect.left + x
  29092. var top = rect.top + y
  29093. me.safeSetOffset({
  29094. left: left,
  29095. top: top,
  29096. })
  29097. },
  29098. ondragstop: function () {
  29099. me.getDom('contmask').style.visibility = 'hidden'
  29100. domUtils.removeClasses(me.getDom(), ['edui-state-centered'])
  29101. me.dragMask.hide()
  29102. },
  29103. })
  29104. }
  29105. },
  29106. reset: function () {
  29107. this.getDom('content').innerHTML = this.getContentHtml()
  29108. this.fireEvent('dialogafterreset')
  29109. },
  29110. _show: function () {
  29111. if (this._hidden) {
  29112. this.getDom().style.display = ''
  29113. //要高过编辑器的zindxe
  29114. this.editor.container.style.zIndex &&
  29115. (this.getDom().style.zIndex =
  29116. this.editor.container.style.zIndex * 1 + 10)
  29117. this._hidden = false
  29118. this.fireEvent('show')
  29119. baidu.editor.ui.uiUtils.getFixedLayer().style.zIndex =
  29120. this.getDom().style.zIndex - 4
  29121. }
  29122. },
  29123. isHidden: function () {
  29124. return this._hidden
  29125. },
  29126. _hide: function () {
  29127. if (!this._hidden) {
  29128. var wrapNode = this.getDom()
  29129. wrapNode.style.display = 'none'
  29130. wrapNode.style.zIndex = ''
  29131. wrapNode.style.width = ''
  29132. wrapNode.style.height = ''
  29133. this._hidden = true
  29134. this.fireEvent('hide')
  29135. }
  29136. },
  29137. open: function () {
  29138. if (this.autoReset) {
  29139. //有可能还没有渲染
  29140. try {
  29141. this.reset()
  29142. } catch (e) {
  29143. this.render()
  29144. this.open()
  29145. }
  29146. }
  29147. this.showAtCenter()
  29148. if (this.iframeUrl) {
  29149. try {
  29150. this.getDom('iframe').focus()
  29151. } catch (ex) {}
  29152. }
  29153. activeDialog = this
  29154. },
  29155. _onCloseButtonClick: function (evt, el) {
  29156. this.close(false)
  29157. },
  29158. close: function (ok) {
  29159. if (this.fireEvent('close', ok) !== false) {
  29160. //还原环境
  29161. if (this.fullscreen) {
  29162. document.documentElement.style.overflowX =
  29163. this._originalContext.html.overflowX
  29164. document.documentElement.style.overflowY =
  29165. this._originalContext.html.overflowY
  29166. document.body.style.overflowX = this._originalContext.body.overflowX
  29167. document.body.style.overflowY = this._originalContext.body.overflowY
  29168. delete this._originalContext
  29169. }
  29170. this._hide()
  29171. //销毁content
  29172. var content = this.getDom('content')
  29173. var iframe = this.getDom('iframe')
  29174. if (content && iframe) {
  29175. var doc = iframe.contentDocument || iframe.contentWindow.document
  29176. doc && (doc.body.innerHTML = '')
  29177. domUtils.remove(content)
  29178. }
  29179. }
  29180. },
  29181. }
  29182. utils.inherits(Dialog, UIBase)
  29183. })()
  29184. // ui/menubutton.js
  29185. ///import core
  29186. ///import uicore
  29187. ///import ui/menu.js
  29188. ///import ui/splitbutton.js
  29189. ;(function () {
  29190. var utils = baidu.editor.utils,
  29191. Menu = baidu.editor.ui.Menu,
  29192. SplitButton = baidu.editor.ui.SplitButton,
  29193. MenuButton = (baidu.editor.ui.MenuButton = function (options) {
  29194. this.initOptions(options)
  29195. this.initMenuButton()
  29196. })
  29197. MenuButton.prototype = {
  29198. initMenuButton: function () {
  29199. var me = this
  29200. this.uiName = 'menubutton'
  29201. this.popup = new Menu({
  29202. items: me.items,
  29203. className: me.className,
  29204. editor: me.editor,
  29205. })
  29206. this.popup.addListener('show', function () {
  29207. var list = this
  29208. for (var i = 0; i < list.items.length; i++) {
  29209. list.items[i].removeState('checked')
  29210. if (list.items[i].value == me._value) {
  29211. list.items[i].addState('checked')
  29212. this.value = me._value
  29213. }
  29214. }
  29215. })
  29216. this.initSplitButton()
  29217. },
  29218. setValue: function (value) {
  29219. this._value = value
  29220. },
  29221. }
  29222. utils.inherits(MenuButton, SplitButton)
  29223. })()
  29224. // ui/multiMenu.js
  29225. ///import core
  29226. ///import uicore
  29227. ///commands 表情
  29228. ;(function () {
  29229. var utils = baidu.editor.utils,
  29230. Popup = baidu.editor.ui.Popup,
  29231. SplitButton = baidu.editor.ui.SplitButton,
  29232. MultiMenuPop = (baidu.editor.ui.MultiMenuPop = function (options) {
  29233. this.initOptions(options)
  29234. this.initMultiMenu()
  29235. })
  29236. MultiMenuPop.prototype = {
  29237. initMultiMenu: function () {
  29238. var me = this
  29239. this.popup = new Popup({
  29240. content: '',
  29241. editor: me.editor,
  29242. iframe_rendered: false,
  29243. onshow: function () {
  29244. if (!this.iframe_rendered) {
  29245. this.iframe_rendered = true
  29246. this.getDom('content').innerHTML =
  29247. '<iframe id="' +
  29248. me.id +
  29249. '_iframe" src="' +
  29250. me.iframeUrl +
  29251. '" frameborder="0"></iframe>'
  29252. me.editor.container.style.zIndex &&
  29253. (this.getDom().style.zIndex =
  29254. me.editor.container.style.zIndex * 1 + 1)
  29255. }
  29256. },
  29257. // canSideUp:false,
  29258. // canSideLeft:false
  29259. })
  29260. this.onbuttonclick = function () {
  29261. this.showPopup()
  29262. }
  29263. this.initSplitButton()
  29264. },
  29265. }
  29266. utils.inherits(MultiMenuPop, SplitButton)
  29267. })()
  29268. // ui/shortcutmenu.js
  29269. ;(function () {
  29270. var UI = baidu.editor.ui,
  29271. UIBase = UI.UIBase,
  29272. uiUtils = UI.uiUtils,
  29273. utils = baidu.editor.utils,
  29274. domUtils = baidu.editor.dom.domUtils
  29275. var allMenus = [], //存储所有快捷菜单
  29276. timeID,
  29277. isSubMenuShow = false //是否有子pop显示
  29278. var ShortCutMenu = (UI.ShortCutMenu = function (options) {
  29279. this.initOptions(options)
  29280. this.initShortCutMenu()
  29281. })
  29282. ShortCutMenu.postHide = hideAllMenu
  29283. ShortCutMenu.prototype = {
  29284. isHidden: true,
  29285. SPACE: 5,
  29286. initShortCutMenu: function () {
  29287. this.items = this.items || []
  29288. this.initUIBase()
  29289. this.initItems()
  29290. this.initEvent()
  29291. allMenus.push(this)
  29292. },
  29293. initEvent: function () {
  29294. var me = this,
  29295. doc = me.editor.document
  29296. domUtils.on(doc, 'mousemove', function (e) {
  29297. if (me.isHidden === false) {
  29298. //有pop显示就不隐藏快捷菜单
  29299. if (me.getSubMenuMark() || me.eventType == 'contextmenu') return
  29300. var flag = true,
  29301. el = me.getDom(),
  29302. wt = el.offsetWidth,
  29303. ht = el.offsetHeight,
  29304. distanceX = wt / 2 + me.SPACE, //距离中心X标准
  29305. distanceY = ht / 2, //距离中心Y标准
  29306. x = Math.abs(e.screenX - me.left), //离中心距离横坐标
  29307. y = Math.abs(e.screenY - me.top) //离中心距离纵坐标
  29308. clearTimeout(timeID)
  29309. timeID = setTimeout(function () {
  29310. if (y > 0 && y < distanceY) {
  29311. me.setOpacity(el, '1')
  29312. } else if (y > distanceY && y < distanceY + 70) {
  29313. me.setOpacity(el, '0.5')
  29314. flag = false
  29315. } else if (y > distanceY + 70 && y < distanceY + 140) {
  29316. me.hide()
  29317. }
  29318. if (flag && x > 0 && x < distanceX) {
  29319. me.setOpacity(el, '1')
  29320. } else if (x > distanceX && x < distanceX + 70) {
  29321. me.setOpacity(el, '0.5')
  29322. } else if (x > distanceX + 70 && x < distanceX + 140) {
  29323. me.hide()
  29324. }
  29325. })
  29326. }
  29327. })
  29328. //ie\ff下 mouseout不准
  29329. if (browser.chrome) {
  29330. domUtils.on(doc, 'mouseout', function (e) {
  29331. var relatedTgt = e.relatedTarget || e.toElement
  29332. if (relatedTgt == null || relatedTgt.tagName == 'HTML') {
  29333. me.hide()
  29334. }
  29335. })
  29336. }
  29337. me.editor.addListener('afterhidepop', function () {
  29338. if (!me.isHidden) {
  29339. isSubMenuShow = true
  29340. }
  29341. })
  29342. },
  29343. initItems: function () {
  29344. if (utils.isArray(this.items)) {
  29345. for (var i = 0, len = this.items.length; i < len; i++) {
  29346. var item = this.items[i].toLowerCase()
  29347. if (UI[item]) {
  29348. this.items[i] = new UI[item](this.editor)
  29349. this.items[i].className += ' edui-shortcutsubmenu '
  29350. }
  29351. }
  29352. }
  29353. },
  29354. setOpacity: function (el, value) {
  29355. if (browser.ie && browser.version < 9) {
  29356. el.style.filter = 'alpha(opacity = ' + parseFloat(value) * 100 + ');'
  29357. } else {
  29358. el.style.opacity = value
  29359. }
  29360. },
  29361. getSubMenuMark: function () {
  29362. isSubMenuShow = false
  29363. var layerEle = uiUtils.getFixedLayer()
  29364. var list = domUtils.getElementsByTagName(
  29365. layerEle,
  29366. 'div',
  29367. function (node) {
  29368. return domUtils.hasClass(node, 'edui-shortcutsubmenu edui-popup')
  29369. }
  29370. )
  29371. for (var i = 0, node; (node = list[i++]); ) {
  29372. if (node.style.display != 'none') {
  29373. isSubMenuShow = true
  29374. }
  29375. }
  29376. return isSubMenuShow
  29377. },
  29378. show: function (e, hasContextmenu) {
  29379. var me = this,
  29380. offset = {},
  29381. el = this.getDom(),
  29382. fixedlayer = uiUtils.getFixedLayer()
  29383. function setPos(offset) {
  29384. if (offset.left < 0) {
  29385. offset.left = 0
  29386. }
  29387. if (offset.top < 0) {
  29388. offset.top = 0
  29389. }
  29390. el.style.cssText =
  29391. 'position:absolute;left:' +
  29392. offset.left +
  29393. 'px;top:' +
  29394. offset.top +
  29395. 'px;'
  29396. }
  29397. function setPosByCxtMenu(menu) {
  29398. if (!menu.tagName) {
  29399. menu = menu.getDom()
  29400. }
  29401. offset.left = parseInt(menu.style.left)
  29402. offset.top = parseInt(menu.style.top)
  29403. offset.top -= el.offsetHeight + 15
  29404. setPos(offset)
  29405. }
  29406. me.eventType = e.type
  29407. el.style.cssText = 'display:block;left:-9999px'
  29408. if (e.type == 'contextmenu' && hasContextmenu) {
  29409. var menu = domUtils.getElementsByTagName(
  29410. fixedlayer,
  29411. 'div',
  29412. 'edui-contextmenu'
  29413. )[0]
  29414. if (menu) {
  29415. setPosByCxtMenu(menu)
  29416. } else {
  29417. me.editor.addListener(
  29418. 'aftershowcontextmenu',
  29419. function (type, menu) {
  29420. setPosByCxtMenu(menu)
  29421. }
  29422. )
  29423. }
  29424. } else {
  29425. offset = uiUtils.getViewportOffsetByEvent(e)
  29426. offset.top -= el.offsetHeight + me.SPACE
  29427. offset.left += me.SPACE + 20
  29428. setPos(offset)
  29429. me.setOpacity(el, 0.2)
  29430. }
  29431. me.isHidden = false
  29432. me.left = e.screenX + el.offsetWidth / 2 - me.SPACE
  29433. me.top = e.screenY - el.offsetHeight / 2 - me.SPACE
  29434. if (me.editor) {
  29435. el.style.zIndex = me.editor.container.style.zIndex * 1 + 10
  29436. fixedlayer.style.zIndex = el.style.zIndex - 1
  29437. }
  29438. },
  29439. hide: function () {
  29440. if (this.getDom()) {
  29441. this.getDom().style.display = 'none'
  29442. }
  29443. this.isHidden = true
  29444. },
  29445. postRender: function () {
  29446. if (utils.isArray(this.items)) {
  29447. for (var i = 0, item; (item = this.items[i++]); ) {
  29448. item.postRender()
  29449. }
  29450. }
  29451. },
  29452. getHtmlTpl: function () {
  29453. var buff
  29454. if (utils.isArray(this.items)) {
  29455. buff = []
  29456. for (var i = 0; i < this.items.length; i++) {
  29457. buff[i] = this.items[i].renderHtml()
  29458. }
  29459. buff = buff.join('')
  29460. } else {
  29461. buff = this.items
  29462. }
  29463. return (
  29464. '<div id="##" class="%% edui-toolbar" data-src="shortcutmenu" onmousedown="return false;" onselectstart="return false;" >' +
  29465. buff +
  29466. '</div>'
  29467. )
  29468. },
  29469. }
  29470. utils.inherits(ShortCutMenu, UIBase)
  29471. function hideAllMenu(e) {
  29472. var tgt = e.target || e.srcElement,
  29473. cur = domUtils.findParent(
  29474. tgt,
  29475. function (node) {
  29476. return (
  29477. domUtils.hasClass(node, 'edui-shortcutmenu') ||
  29478. domUtils.hasClass(node, 'edui-popup')
  29479. )
  29480. },
  29481. true
  29482. )
  29483. if (!cur) {
  29484. for (var i = 0, menu; (menu = allMenus[i++]); ) {
  29485. menu.hide()
  29486. }
  29487. }
  29488. }
  29489. domUtils.on(document, 'mousedown', function (e) {
  29490. hideAllMenu(e)
  29491. })
  29492. domUtils.on(window, 'scroll', function (e) {
  29493. hideAllMenu(e)
  29494. })
  29495. })()
  29496. // ui/breakline.js
  29497. ;(function () {
  29498. var utils = baidu.editor.utils,
  29499. UIBase = baidu.editor.ui.UIBase,
  29500. Breakline = (baidu.editor.ui.Breakline = function (options) {
  29501. this.initOptions(options)
  29502. this.initSeparator()
  29503. })
  29504. Breakline.prototype = {
  29505. uiName: 'Breakline',
  29506. initSeparator: function () {
  29507. this.initUIBase()
  29508. },
  29509. getHtmlTpl: function () {
  29510. return '<br/>'
  29511. },
  29512. }
  29513. utils.inherits(Breakline, UIBase)
  29514. })()
  29515. // ui/message.js
  29516. ///import core
  29517. ///import uicore
  29518. ;(function () {
  29519. var utils = baidu.editor.utils,
  29520. domUtils = baidu.editor.dom.domUtils,
  29521. UIBase = baidu.editor.ui.UIBase,
  29522. Message = (baidu.editor.ui.Message = function (options) {
  29523. this.initOptions(options)
  29524. this.initMessage()
  29525. })
  29526. Message.prototype = {
  29527. initMessage: function () {
  29528. this.initUIBase()
  29529. },
  29530. getHtmlTpl: function () {
  29531. return (
  29532. '<div id="##" class="edui-message %%">' +
  29533. ' <div id="##_closer" class="edui-message-closer">×</div>' +
  29534. ' <div id="##_body" class="edui-message-body edui-message-type-info">' +
  29535. ' <iframe style="position:absolute;z-index:-1;left:0;top:0;background-color: transparent;" frameborder="0" width="100%" height="100%" src="about:blank"></iframe>' +
  29536. ' <div class="edui-shadow"></div>' +
  29537. ' <div id="##_content" class="edui-message-content">' +
  29538. ' </div>' +
  29539. ' </div>' +
  29540. '</div>'
  29541. )
  29542. },
  29543. reset: function (opt) {
  29544. var me = this
  29545. if (!opt.keepshow) {
  29546. clearTimeout(this.timer)
  29547. me.timer = setTimeout(function () {
  29548. me.hide()
  29549. }, opt.timeout || 4000)
  29550. }
  29551. opt.content !== undefined && me.setContent(opt.content)
  29552. opt.type !== undefined && me.setType(opt.type)
  29553. me.show()
  29554. },
  29555. postRender: function () {
  29556. var me = this,
  29557. closer = this.getDom('closer')
  29558. closer &&
  29559. domUtils.on(closer, 'click', function () {
  29560. me.hide()
  29561. })
  29562. },
  29563. setContent: function (content) {
  29564. this.getDom('content').innerHTML = content
  29565. },
  29566. setType: function (type) {
  29567. type = type || 'info'
  29568. var body = this.getDom('body')
  29569. body.className = body.className.replace(
  29570. /edui-message-type-[\w-]+/,
  29571. 'edui-message-type-' + type
  29572. )
  29573. },
  29574. getContent: function () {
  29575. return this.getDom('content').innerHTML
  29576. },
  29577. getType: function () {
  29578. var arr = this.getDom('body').match(/edui-message-type-([\w-]+)/)
  29579. return arr ? arr[1] : ''
  29580. },
  29581. show: function () {
  29582. this.getDom().style.display = 'block'
  29583. },
  29584. hide: function () {
  29585. var dom = this.getDom()
  29586. if (dom) {
  29587. dom.style.display = 'none'
  29588. dom.parentNode && dom.parentNode.removeChild(dom)
  29589. }
  29590. },
  29591. }
  29592. utils.inherits(Message, UIBase)
  29593. })()
  29594. // adapter/editorui.js
  29595. //ui跟编辑器的适配層
  29596. //那个按钮弹出是dialog,是下拉筐等都是在这个js中配置
  29597. //自己写的ui也要在这里配置,放到baidu.editor.ui下边,当编辑器实例化的时候会根据ueditor.config中的toolbars找到相应的进行实例化
  29598. ;(function () {
  29599. var utils = baidu.editor.utils
  29600. var editorui = baidu.editor.ui
  29601. var _Dialog = editorui.Dialog
  29602. editorui.buttons = {}
  29603. editorui.Dialog = function (options) {
  29604. var dialog = new _Dialog(options)
  29605. dialog.addListener('hide', function () {
  29606. if (dialog.editor) {
  29607. var editor = dialog.editor
  29608. try {
  29609. if (browser.gecko) {
  29610. var y = editor.window.scrollY,
  29611. x = editor.window.scrollX
  29612. editor.body.focus()
  29613. editor.window.scrollTo(x, y)
  29614. } else {
  29615. editor.focus()
  29616. }
  29617. } catch (ex) {}
  29618. }
  29619. })
  29620. return dialog
  29621. }
  29622. var iframeUrlMap = {
  29623. anchor: '~/dialogs/anchor/anchor.html',
  29624. insertimage: '~/dialogs/image/image.html',
  29625. link: '~/dialogs/link/link.html',
  29626. spechars: '~/dialogs/spechars/spechars.html',
  29627. searchreplace: '~/dialogs/searchreplace/searchreplace.html',
  29628. map: '~/dialogs/map/map.html',
  29629. gmap: '~/dialogs/gmap/gmap.html',
  29630. insertvideo: '~/dialogs/video/video.html',
  29631. help: '~/dialogs/help/help.html',
  29632. preview: '~/dialogs/preview/preview.html',
  29633. emotion: '~/dialogs/emotion/emotion.html',
  29634. wordimage: '~/dialogs/wordimage/wordimage.html',
  29635. attachment: '~/dialogs/attachment/attachment.html',
  29636. insertframe: '~/dialogs/insertframe/insertframe.html',
  29637. edittip: '~/dialogs/table/edittip.html',
  29638. edittable: '~/dialogs/table/edittable.html',
  29639. edittd: '~/dialogs/table/edittd.html',
  29640. webapp: '~/dialogs/webapp/webapp.html',
  29641. snapscreen: '~/dialogs/snapscreen/snapscreen.html',
  29642. scrawl: '~/dialogs/scrawl/scrawl.html',
  29643. music: '~/dialogs/music/music.html',
  29644. template: '~/dialogs/template/template.html',
  29645. background: '~/dialogs/background/background.html',
  29646. charts: '~/dialogs/charts/charts.html',
  29647. }
  29648. //为工具栏添加按钮,以下都是统一的按钮触发命令,所以写在一起
  29649. var btnCmds = [
  29650. 'undo',
  29651. 'redo',
  29652. 'formatmatch',
  29653. 'bold',
  29654. 'italic',
  29655. 'underline',
  29656. 'fontborder',
  29657. 'touppercase',
  29658. 'tolowercase',
  29659. 'strikethrough',
  29660. 'subscript',
  29661. 'superscript',
  29662. 'source',
  29663. 'indent',
  29664. 'outdent',
  29665. 'blockquote',
  29666. 'pasteplain',
  29667. 'pagebreak',
  29668. 'selectall',
  29669. 'print',
  29670. 'horizontal',
  29671. 'removeformat',
  29672. 'time',
  29673. 'date',
  29674. 'unlink',
  29675. 'insertparagraphbeforetable',
  29676. 'insertrow',
  29677. 'insertcol',
  29678. 'mergeright',
  29679. 'mergedown',
  29680. 'deleterow',
  29681. 'deletecol',
  29682. 'splittorows',
  29683. 'splittocols',
  29684. 'splittocells',
  29685. 'mergecells',
  29686. 'deletetable',
  29687. 'drafts',
  29688. 'wordupload',
  29689. ]
  29690. for (var i = 0, ci; (ci = btnCmds[i++]); ) {
  29691. ci = ci.toLowerCase()
  29692. editorui[ci] = (function (cmd) {
  29693. return function (editor) {
  29694. var ui = new editorui.Button({
  29695. className: 'edui-for-' + cmd,
  29696. title:
  29697. editor.options.labelMap[cmd] ||
  29698. editor.getLang('labelMap.' + cmd) ||
  29699. '',
  29700. onclick: function () {
  29701. editor.execCommand(cmd)
  29702. },
  29703. theme: editor.options.theme,
  29704. showText: false,
  29705. })
  29706. editorui.buttons[cmd] = ui
  29707. editor.addListener(
  29708. 'selectionchange',
  29709. function (type, causeByUi, uiReady) {
  29710. var state = editor.queryCommandState(cmd)
  29711. if (state == -1) {
  29712. ui.setDisabled(true)
  29713. ui.setChecked(false)
  29714. } else {
  29715. if (!uiReady) {
  29716. ui.setDisabled(false)
  29717. ui.setChecked(state)
  29718. }
  29719. }
  29720. }
  29721. )
  29722. return ui
  29723. }
  29724. })(ci)
  29725. }
  29726. //清除文档
  29727. editorui.cleardoc = function (editor) {
  29728. var ui = new editorui.Button({
  29729. className: 'edui-for-cleardoc',
  29730. title:
  29731. editor.options.labelMap.cleardoc ||
  29732. editor.getLang('labelMap.cleardoc') ||
  29733. '',
  29734. theme: editor.options.theme,
  29735. onclick: function () {
  29736. if (confirm(editor.getLang('confirmClear'))) {
  29737. editor.execCommand('cleardoc')
  29738. }
  29739. },
  29740. })
  29741. editorui.buttons['cleardoc'] = ui
  29742. editor.addListener('selectionchange', function () {
  29743. ui.setDisabled(editor.queryCommandState('cleardoc') == -1)
  29744. })
  29745. return ui
  29746. }
  29747. //排版,图片排版,文字方向
  29748. var typeset = {
  29749. justify: ['left', 'right', 'center', 'justify'],
  29750. imagefloat: ['none', 'left', 'center', 'right'],
  29751. directionality: ['ltr', 'rtl'],
  29752. }
  29753. for (var p in typeset) {
  29754. ;(function (cmd, val) {
  29755. for (var i = 0, ci; (ci = val[i++]); ) {
  29756. ;(function (cmd2) {
  29757. editorui[cmd.replace('float', '') + cmd2] = function (editor) {
  29758. var ui = new editorui.Button({
  29759. className: 'edui-for-' + cmd.replace('float', '') + cmd2,
  29760. title:
  29761. editor.options.labelMap[cmd.replace('float', '') + cmd2] ||
  29762. editor.getLang(
  29763. 'labelMap.' + cmd.replace('float', '') + cmd2
  29764. ) ||
  29765. '',
  29766. theme: editor.options.theme,
  29767. onclick: function () {
  29768. editor.execCommand(cmd, cmd2)
  29769. },
  29770. })
  29771. editorui.buttons[cmd] = ui
  29772. editor.addListener(
  29773. 'selectionchange',
  29774. function (type, causeByUi, uiReady) {
  29775. ui.setDisabled(editor.queryCommandState(cmd) == -1)
  29776. ui.setChecked(
  29777. editor.queryCommandValue(cmd) == cmd2 && !uiReady
  29778. )
  29779. }
  29780. )
  29781. return ui
  29782. }
  29783. })(ci)
  29784. }
  29785. })(p, typeset[p])
  29786. }
  29787. //字体颜色和背景颜色
  29788. for (var i = 0, ci; (ci = ['backcolor', 'forecolor'][i++]); ) {
  29789. editorui[ci] = (function (cmd) {
  29790. return function (editor) {
  29791. var ui = new editorui.ColorButton({
  29792. className: 'edui-for-' + cmd,
  29793. color: 'default',
  29794. title:
  29795. editor.options.labelMap[cmd] ||
  29796. editor.getLang('labelMap.' + cmd) ||
  29797. '',
  29798. editor: editor,
  29799. onpickcolor: function (t, color) {
  29800. editor.execCommand(cmd, color)
  29801. },
  29802. onpicknocolor: function () {
  29803. editor.execCommand(cmd, 'default')
  29804. this.setColor('transparent')
  29805. this.color = 'default'
  29806. },
  29807. onbuttonclick: function () {
  29808. editor.execCommand(cmd, this.color)
  29809. },
  29810. })
  29811. editorui.buttons[cmd] = ui
  29812. editor.addListener('selectionchange', function () {
  29813. ui.setDisabled(editor.queryCommandState(cmd) == -1)
  29814. })
  29815. return ui
  29816. }
  29817. })(ci)
  29818. }
  29819. var dialogBtns = {
  29820. noOk: ['searchreplace', 'help', 'spechars', 'webapp', 'preview'],
  29821. ok: [
  29822. 'attachment',
  29823. 'anchor',
  29824. 'link',
  29825. 'insertimage',
  29826. 'map',
  29827. 'gmap',
  29828. 'insertframe',
  29829. 'wordimage',
  29830. 'insertvideo',
  29831. 'insertframe',
  29832. 'edittip',
  29833. 'edittable',
  29834. 'edittd',
  29835. 'scrawl',
  29836. 'template',
  29837. 'music',
  29838. 'background',
  29839. 'charts',
  29840. ],
  29841. }
  29842. for (var p in dialogBtns) {
  29843. ;(function (type, vals) {
  29844. for (var i = 0, ci; (ci = vals[i++]); ) {
  29845. //todo opera下存在问题
  29846. if (browser.opera && ci === 'searchreplace') {
  29847. continue
  29848. }
  29849. ;(function (cmd) {
  29850. editorui[cmd] = function (editor, iframeUrl, title) {
  29851. iframeUrl =
  29852. iframeUrl ||
  29853. (editor.options.iframeUrlMap || {})[cmd] ||
  29854. iframeUrlMap[cmd]
  29855. title =
  29856. editor.options.labelMap[cmd] ||
  29857. editor.getLang('labelMap.' + cmd) ||
  29858. ''
  29859. var dialog
  29860. //没有iframeUrl不创建dialog
  29861. if (iframeUrl) {
  29862. dialog = new editorui.Dialog(
  29863. utils.extend(
  29864. {
  29865. iframeUrl: editor.ui.mapUrl(iframeUrl),
  29866. editor: editor,
  29867. className: 'edui-for-' + cmd,
  29868. title: title,
  29869. holdScroll: cmd === 'insertimage',
  29870. fullscreen: /charts|preview/.test(cmd),
  29871. closeDialog: editor.getLang('closeDialog'),
  29872. },
  29873. type == 'ok'
  29874. ? {
  29875. buttons: [
  29876. {
  29877. className: 'edui-okbutton',
  29878. label: editor.getLang('ok'),
  29879. editor: editor,
  29880. onclick: function () {
  29881. dialog.close(true)
  29882. },
  29883. },
  29884. {
  29885. className: 'edui-cancelbutton',
  29886. label: editor.getLang('cancel'),
  29887. editor: editor,
  29888. onclick: function () {
  29889. dialog.close(false)
  29890. },
  29891. },
  29892. ],
  29893. }
  29894. : {}
  29895. )
  29896. )
  29897. editor.ui._dialogs[cmd + 'Dialog'] = dialog
  29898. }
  29899. var ui = new editorui.Button({
  29900. className: 'edui-for-' + cmd,
  29901. title: title,
  29902. onclick: function () {
  29903. if (dialog) {
  29904. switch (cmd) {
  29905. case 'wordimage':
  29906. var images = editor.execCommand('wordimage')
  29907. if (images && images.length) {
  29908. dialog.render()
  29909. dialog.open()
  29910. }
  29911. break
  29912. case 'scrawl':
  29913. if (editor.queryCommandState('scrawl') != -1) {
  29914. dialog.render()
  29915. dialog.open()
  29916. }
  29917. break
  29918. default:
  29919. dialog.render()
  29920. dialog.open()
  29921. }
  29922. }
  29923. },
  29924. theme: editor.options.theme,
  29925. disabled:
  29926. (cmd == 'scrawl' &&
  29927. editor.queryCommandState('scrawl') == -1) ||
  29928. cmd == 'charts',
  29929. })
  29930. editorui.buttons[cmd] = ui
  29931. editor.addListener('selectionchange', function () {
  29932. //只存在于右键菜单而无工具栏按钮的ui不需要检测状态
  29933. var unNeedCheckState = { edittable: 1 }
  29934. if (cmd in unNeedCheckState) return
  29935. var state = editor.queryCommandState(cmd)
  29936. if (ui.getDom()) {
  29937. ui.setDisabled(state == -1)
  29938. ui.setChecked(state)
  29939. }
  29940. })
  29941. return ui
  29942. }
  29943. })(ci.toLowerCase())
  29944. }
  29945. })(p, dialogBtns[p])
  29946. }
  29947. editorui.snapscreen = function (editor, iframeUrl, title) {
  29948. title =
  29949. editor.options.labelMap['snapscreen'] ||
  29950. editor.getLang('labelMap.snapscreen') ||
  29951. ''
  29952. var ui = new editorui.Button({
  29953. className: 'edui-for-snapscreen',
  29954. title: title,
  29955. onclick: function () {
  29956. editor.execCommand('snapscreen')
  29957. },
  29958. theme: editor.options.theme,
  29959. })
  29960. editorui.buttons['snapscreen'] = ui
  29961. iframeUrl =
  29962. iframeUrl ||
  29963. (editor.options.iframeUrlMap || {})['snapscreen'] ||
  29964. iframeUrlMap['snapscreen']
  29965. if (iframeUrl) {
  29966. var dialog = new editorui.Dialog({
  29967. iframeUrl: editor.ui.mapUrl(iframeUrl),
  29968. editor: editor,
  29969. className: 'edui-for-snapscreen',
  29970. title: title,
  29971. buttons: [
  29972. {
  29973. className: 'edui-okbutton',
  29974. label: editor.getLang('ok'),
  29975. editor: editor,
  29976. onclick: function () {
  29977. dialog.close(true)
  29978. },
  29979. },
  29980. {
  29981. className: 'edui-cancelbutton',
  29982. label: editor.getLang('cancel'),
  29983. editor: editor,
  29984. onclick: function () {
  29985. dialog.close(false)
  29986. },
  29987. },
  29988. ],
  29989. })
  29990. dialog.render()
  29991. editor.ui._dialogs['snapscreenDialog'] = dialog
  29992. }
  29993. editor.addListener('selectionchange', function () {
  29994. ui.setDisabled(editor.queryCommandState('snapscreen') == -1)
  29995. })
  29996. return ui
  29997. }
  29998. editorui.insertcode = function (editor, list, title) {
  29999. list = editor.options['insertcode'] || []
  30000. title =
  30001. editor.options.labelMap['insertcode'] ||
  30002. editor.getLang('labelMap.insertcode') ||
  30003. ''
  30004. // if (!list.length) return;
  30005. var items = []
  30006. utils.each(list, function (key, val) {
  30007. items.push({
  30008. label: key,
  30009. value: val,
  30010. theme: editor.options.theme,
  30011. renderLabelHtml: function () {
  30012. return (
  30013. '<div class="edui-label %%-label" >' +
  30014. (this.label || '') +
  30015. '</div>'
  30016. )
  30017. },
  30018. })
  30019. })
  30020. var ui = new editorui.Combox({
  30021. editor: editor,
  30022. items: items,
  30023. onselect: function (t, index) {
  30024. editor.execCommand('insertcode', this.items[index].value)
  30025. },
  30026. onbuttonclick: function () {
  30027. this.showPopup()
  30028. },
  30029. title: title,
  30030. initValue: title,
  30031. className: 'edui-for-insertcode',
  30032. indexByValue: function (value) {
  30033. if (value) {
  30034. for (var i = 0, ci; (ci = this.items[i]); i++) {
  30035. if (ci.value.indexOf(value) != -1) return i
  30036. }
  30037. }
  30038. return -1
  30039. },
  30040. })
  30041. editorui.buttons['insertcode'] = ui
  30042. editor.addListener(
  30043. 'selectionchange',
  30044. function (type, causeByUi, uiReady) {
  30045. if (!uiReady) {
  30046. var state = editor.queryCommandState('insertcode')
  30047. if (state == -1) {
  30048. ui.setDisabled(true)
  30049. } else {
  30050. ui.setDisabled(false)
  30051. var value = editor.queryCommandValue('insertcode')
  30052. if (!value) {
  30053. ui.setValue(title)
  30054. return
  30055. }
  30056. //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
  30057. value && (value = value.replace(/['"]/g, '').split(',')[0])
  30058. ui.setValue(value)
  30059. }
  30060. }
  30061. }
  30062. )
  30063. return ui
  30064. }
  30065. editorui.fontfamily = function (editor, list, title) {
  30066. list = editor.options['fontfamily'] || []
  30067. title =
  30068. editor.options.labelMap['fontfamily'] ||
  30069. editor.getLang('labelMap.fontfamily') ||
  30070. ''
  30071. if (!list.length) return
  30072. for (var i = 0, ci, items = []; (ci = list[i]); i++) {
  30073. var langLabel = editor.getLang('fontfamily')[ci.name] || ''
  30074. ;(function (key, val) {
  30075. items.push({
  30076. label: key,
  30077. value: val,
  30078. theme: editor.options.theme,
  30079. renderLabelHtml: function () {
  30080. return (
  30081. '<div class="edui-label %%-label" style="font-family:' +
  30082. utils.unhtml(this.value) +
  30083. '">' +
  30084. (this.label || '') +
  30085. '</div>'
  30086. )
  30087. },
  30088. })
  30089. })(ci.label || langLabel, ci.val)
  30090. }
  30091. var ui = new editorui.Combox({
  30092. editor: editor,
  30093. items: items,
  30094. onselect: function (t, index) {
  30095. editor.execCommand('FontFamily', this.items[index].value)
  30096. },
  30097. onbuttonclick: function () {
  30098. this.showPopup()
  30099. },
  30100. title: title,
  30101. initValue: title,
  30102. className: 'edui-for-fontfamily',
  30103. indexByValue: function (value) {
  30104. if (value) {
  30105. for (var i = 0, ci; (ci = this.items[i]); i++) {
  30106. if (ci.value.indexOf(value) != -1) return i
  30107. }
  30108. }
  30109. return -1
  30110. },
  30111. })
  30112. editorui.buttons['fontfamily'] = ui
  30113. editor.addListener(
  30114. 'selectionchange',
  30115. function (type, causeByUi, uiReady) {
  30116. if (!uiReady) {
  30117. var state = editor.queryCommandState('FontFamily')
  30118. if (state == -1) {
  30119. ui.setDisabled(true)
  30120. } else {
  30121. ui.setDisabled(false)
  30122. var value = editor.queryCommandValue('FontFamily')
  30123. //trace:1871 ie下从源码模式切换回来时,字体会带单引号,而且会有逗号
  30124. value && (value = value.replace(/['"]/g, '').split(',')[0])
  30125. ui.setValue(value)
  30126. }
  30127. }
  30128. }
  30129. )
  30130. return ui
  30131. }
  30132. editorui.fontsize = function (editor, list, title) {
  30133. title =
  30134. editor.options.labelMap['fontsize'] ||
  30135. editor.getLang('labelMap.fontsize') ||
  30136. ''
  30137. list = list || editor.options['fontsize'] || []
  30138. if (!list.length) return
  30139. var items = []
  30140. for (var i = 0; i < list.length; i++) {
  30141. var size = list[i] + 'px'
  30142. items.push({
  30143. label: size,
  30144. value: size,
  30145. theme: editor.options.theme,
  30146. renderLabelHtml: function () {
  30147. return (
  30148. '<div class="edui-label %%-label" style="line-height:1;font-size:' +
  30149. this.value +
  30150. '">' +
  30151. (this.label || '') +
  30152. '</div>'
  30153. )
  30154. },
  30155. })
  30156. }
  30157. var ui = new editorui.Combox({
  30158. editor: editor,
  30159. items: items,
  30160. title: title,
  30161. initValue: title,
  30162. onselect: function (t, index) {
  30163. editor.execCommand('FontSize', this.items[index].value)
  30164. },
  30165. onbuttonclick: function () {
  30166. this.showPopup()
  30167. },
  30168. className: 'edui-for-fontsize',
  30169. })
  30170. editorui.buttons['fontsize'] = ui
  30171. editor.addListener(
  30172. 'selectionchange',
  30173. function (type, causeByUi, uiReady) {
  30174. if (!uiReady) {
  30175. var state = editor.queryCommandState('FontSize')
  30176. if (state == -1) {
  30177. ui.setDisabled(true)
  30178. } else {
  30179. ui.setDisabled(false)
  30180. ui.setValue(editor.queryCommandValue('FontSize'))
  30181. }
  30182. }
  30183. }
  30184. )
  30185. return ui
  30186. }
  30187. editorui.paragraph = function (editor, list, title) {
  30188. title =
  30189. editor.options.labelMap['paragraph'] ||
  30190. editor.getLang('labelMap.paragraph') ||
  30191. ''
  30192. list = editor.options['paragraph'] || []
  30193. if (utils.isEmptyObject(list)) return
  30194. var items = []
  30195. for (var i in list) {
  30196. items.push({
  30197. value: i,
  30198. label: list[i] || editor.getLang('paragraph')[i],
  30199. theme: editor.options.theme,
  30200. renderLabelHtml: function () {
  30201. return (
  30202. '<div class="edui-label %%-label"><span class="edui-for-' +
  30203. this.value +
  30204. '">' +
  30205. (this.label || '') +
  30206. '</span></div>'
  30207. )
  30208. },
  30209. })
  30210. }
  30211. var ui = new editorui.Combox({
  30212. editor: editor,
  30213. items: items,
  30214. title: title,
  30215. initValue: title,
  30216. className: 'edui-for-paragraph',
  30217. onselect: function (t, index) {
  30218. editor.execCommand('Paragraph', this.items[index].value)
  30219. },
  30220. onbuttonclick: function () {
  30221. this.showPopup()
  30222. },
  30223. })
  30224. editorui.buttons['paragraph'] = ui
  30225. editor.addListener(
  30226. 'selectionchange',
  30227. function (type, causeByUi, uiReady) {
  30228. if (!uiReady) {
  30229. var state = editor.queryCommandState('Paragraph')
  30230. if (state == -1) {
  30231. ui.setDisabled(true)
  30232. } else {
  30233. ui.setDisabled(false)
  30234. var value = editor.queryCommandValue('Paragraph')
  30235. var index = ui.indexByValue(value)
  30236. if (index != -1) {
  30237. ui.setValue(value)
  30238. } else {
  30239. ui.setValue(ui.initValue)
  30240. }
  30241. }
  30242. }
  30243. }
  30244. )
  30245. return ui
  30246. }
  30247. //自定义标题
  30248. editorui.customstyle = function (editor) {
  30249. var list = editor.options['customstyle'] || [],
  30250. title =
  30251. editor.options.labelMap['customstyle'] ||
  30252. editor.getLang('labelMap.customstyle') ||
  30253. ''
  30254. if (!list.length) return
  30255. var langCs = editor.getLang('customstyle')
  30256. for (var i = 0, items = [], t; (t = list[i++]); ) {
  30257. ;(function (t) {
  30258. var ck = {}
  30259. ck.label = t.label ? t.label : langCs[t.name]
  30260. ck.style = t.style
  30261. ck.className = t.className
  30262. ck.tag = t.tag
  30263. items.push({
  30264. label: ck.label,
  30265. value: ck,
  30266. theme: editor.options.theme,
  30267. renderLabelHtml: function () {
  30268. return (
  30269. '<div class="edui-label %%-label">' +
  30270. '<' +
  30271. ck.tag +
  30272. ' ' +
  30273. (ck.className ? ' class="' + ck.className + '"' : '') +
  30274. (ck.style ? ' style="' + ck.style + '"' : '') +
  30275. '>' +
  30276. ck.label +
  30277. '</' +
  30278. ck.tag +
  30279. '>' +
  30280. '</div>'
  30281. )
  30282. },
  30283. })
  30284. })(t)
  30285. }
  30286. var ui = new editorui.Combox({
  30287. editor: editor,
  30288. items: items,
  30289. title: title,
  30290. initValue: title,
  30291. className: 'edui-for-customstyle',
  30292. onselect: function (t, index) {
  30293. editor.execCommand('customstyle', this.items[index].value)
  30294. },
  30295. onbuttonclick: function () {
  30296. this.showPopup()
  30297. },
  30298. indexByValue: function (value) {
  30299. for (var i = 0, ti; (ti = this.items[i++]); ) {
  30300. if (ti.label == value) {
  30301. return i - 1
  30302. }
  30303. }
  30304. return -1
  30305. },
  30306. })
  30307. editorui.buttons['customstyle'] = ui
  30308. editor.addListener(
  30309. 'selectionchange',
  30310. function (type, causeByUi, uiReady) {
  30311. if (!uiReady) {
  30312. var state = editor.queryCommandState('customstyle')
  30313. if (state == -1) {
  30314. ui.setDisabled(true)
  30315. } else {
  30316. ui.setDisabled(false)
  30317. var value = editor.queryCommandValue('customstyle')
  30318. var index = ui.indexByValue(value)
  30319. if (index != -1) {
  30320. ui.setValue(value)
  30321. } else {
  30322. ui.setValue(ui.initValue)
  30323. }
  30324. }
  30325. }
  30326. }
  30327. )
  30328. return ui
  30329. }
  30330. editorui.inserttable = function (editor, iframeUrl, title) {
  30331. title =
  30332. editor.options.labelMap['inserttable'] ||
  30333. editor.getLang('labelMap.inserttable') ||
  30334. ''
  30335. var ui = new editorui.TableButton({
  30336. editor: editor,
  30337. title: title,
  30338. className: 'edui-for-inserttable',
  30339. onpicktable: function (t, numCols, numRows) {
  30340. editor.execCommand('InsertTable', {
  30341. numRows: numRows,
  30342. numCols: numCols,
  30343. border: 1,
  30344. })
  30345. },
  30346. onbuttonclick: function () {
  30347. this.showPopup()
  30348. },
  30349. })
  30350. editorui.buttons['inserttable'] = ui
  30351. editor.addListener('selectionchange', function () {
  30352. ui.setDisabled(editor.queryCommandState('inserttable') == -1)
  30353. })
  30354. return ui
  30355. }
  30356. editorui.lineheight = function (editor) {
  30357. var val = editor.options.lineheight || []
  30358. if (!val.length) return
  30359. for (var i = 0, ci, items = []; (ci = val[i++]); ) {
  30360. items.push({
  30361. //todo:写死了
  30362. label: ci,
  30363. value: ci,
  30364. theme: editor.options.theme,
  30365. onclick: function () {
  30366. editor.execCommand('lineheight', this.value)
  30367. },
  30368. })
  30369. }
  30370. var ui = new editorui.MenuButton({
  30371. editor: editor,
  30372. className: 'edui-for-lineheight',
  30373. title:
  30374. editor.options.labelMap['lineheight'] ||
  30375. editor.getLang('labelMap.lineheight') ||
  30376. '',
  30377. items: items,
  30378. onbuttonclick: function () {
  30379. var value = editor.queryCommandValue('LineHeight') || this.value
  30380. editor.execCommand('LineHeight', value)
  30381. },
  30382. })
  30383. editorui.buttons['lineheight'] = ui
  30384. editor.addListener('selectionchange', function () {
  30385. var state = editor.queryCommandState('LineHeight')
  30386. if (state == -1) {
  30387. ui.setDisabled(true)
  30388. } else {
  30389. ui.setDisabled(false)
  30390. var value = editor.queryCommandValue('LineHeight')
  30391. value && ui.setValue((value + '').replace(/cm/, ''))
  30392. ui.setChecked(state)
  30393. }
  30394. })
  30395. return ui
  30396. }
  30397. var rowspacings = ['top', 'bottom']
  30398. for (var r = 0, ri; (ri = rowspacings[r++]); ) {
  30399. ;(function (cmd) {
  30400. editorui['rowspacing' + cmd] = function (editor) {
  30401. var val = editor.options['rowspacing' + cmd] || []
  30402. if (!val.length) return null
  30403. for (var i = 0, ci, items = []; (ci = val[i++]); ) {
  30404. items.push({
  30405. label: ci,
  30406. value: ci,
  30407. theme: editor.options.theme,
  30408. onclick: function () {
  30409. editor.execCommand('rowspacing', this.value, cmd)
  30410. },
  30411. })
  30412. }
  30413. var ui = new editorui.MenuButton({
  30414. editor: editor,
  30415. className: 'edui-for-rowspacing' + cmd,
  30416. title:
  30417. editor.options.labelMap['rowspacing' + cmd] ||
  30418. editor.getLang('labelMap.rowspacing' + cmd) ||
  30419. '',
  30420. items: items,
  30421. onbuttonclick: function () {
  30422. var value =
  30423. editor.queryCommandValue('rowspacing', cmd) || this.value
  30424. editor.execCommand('rowspacing', value, cmd)
  30425. },
  30426. })
  30427. editorui.buttons[cmd] = ui
  30428. editor.addListener('selectionchange', function () {
  30429. var state = editor.queryCommandState('rowspacing', cmd)
  30430. if (state == -1) {
  30431. ui.setDisabled(true)
  30432. } else {
  30433. ui.setDisabled(false)
  30434. var value = editor.queryCommandValue('rowspacing', cmd)
  30435. value && ui.setValue((value + '').replace(/%/, ''))
  30436. ui.setChecked(state)
  30437. }
  30438. })
  30439. return ui
  30440. }
  30441. })(ri)
  30442. }
  30443. //有序,无序列表
  30444. var lists = ['insertorderedlist', 'insertunorderedlist']
  30445. for (var l = 0, cl; (cl = lists[l++]); ) {
  30446. ;(function (cmd) {
  30447. editorui[cmd] = function (editor) {
  30448. var vals = editor.options[cmd],
  30449. _onMenuClick = function () {
  30450. editor.execCommand(cmd, this.value)
  30451. },
  30452. items = []
  30453. for (var i in vals) {
  30454. items.push({
  30455. label: vals[i] || editor.getLang()[cmd][i] || '',
  30456. value: i,
  30457. theme: editor.options.theme,
  30458. onclick: _onMenuClick,
  30459. })
  30460. }
  30461. var ui = new editorui.MenuButton({
  30462. editor: editor,
  30463. className: 'edui-for-' + cmd,
  30464. title: editor.getLang('labelMap.' + cmd) || '',
  30465. items: items,
  30466. onbuttonclick: function () {
  30467. var value = editor.queryCommandValue(cmd) || this.value
  30468. editor.execCommand(cmd, value)
  30469. },
  30470. })
  30471. editorui.buttons[cmd] = ui
  30472. editor.addListener('selectionchange', function () {
  30473. var state = editor.queryCommandState(cmd)
  30474. if (state == -1) {
  30475. ui.setDisabled(true)
  30476. } else {
  30477. ui.setDisabled(false)
  30478. var value = editor.queryCommandValue(cmd)
  30479. ui.setValue(value)
  30480. ui.setChecked(state)
  30481. }
  30482. })
  30483. return ui
  30484. }
  30485. })(cl)
  30486. }
  30487. editorui.fullscreen = function (editor, title) {
  30488. title =
  30489. editor.options.labelMap['fullscreen'] ||
  30490. editor.getLang('labelMap.fullscreen') ||
  30491. ''
  30492. var ui = new editorui.Button({
  30493. className: 'edui-for-fullscreen',
  30494. title: title,
  30495. theme: editor.options.theme,
  30496. onclick: function () {
  30497. if (editor.ui) {
  30498. editor.ui.setFullScreen(!editor.ui.isFullScreen())
  30499. }
  30500. this.setChecked(editor.ui.isFullScreen())
  30501. },
  30502. })
  30503. editorui.buttons['fullscreen'] = ui
  30504. editor.addListener('selectionchange', function () {
  30505. var state = editor.queryCommandState('fullscreen')
  30506. ui.setDisabled(state == -1)
  30507. ui.setChecked(editor.ui.isFullScreen())
  30508. })
  30509. return ui
  30510. }
  30511. // 表情
  30512. editorui['emotion'] = function (editor, iframeUrl) {
  30513. var cmd = 'emotion'
  30514. var ui = new editorui.MultiMenuPop({
  30515. title:
  30516. editor.options.labelMap[cmd] ||
  30517. editor.getLang('labelMap.' + cmd + '') ||
  30518. '',
  30519. editor: editor,
  30520. className: 'edui-for-' + cmd,
  30521. iframeUrl: editor.ui.mapUrl(
  30522. iframeUrl ||
  30523. (editor.options.iframeUrlMap || {})[cmd] ||
  30524. iframeUrlMap[cmd]
  30525. ),
  30526. })
  30527. editorui.buttons[cmd] = ui
  30528. editor.addListener('selectionchange', function () {
  30529. ui.setDisabled(editor.queryCommandState(cmd) == -1)
  30530. })
  30531. return ui
  30532. }
  30533. editorui.autotypeset = function (editor) {
  30534. var ui = new editorui.AutoTypeSetButton({
  30535. editor: editor,
  30536. title:
  30537. editor.options.labelMap['autotypeset'] ||
  30538. editor.getLang('labelMap.autotypeset') ||
  30539. '',
  30540. className: 'edui-for-autotypeset',
  30541. onbuttonclick: function () {
  30542. editor.execCommand('autotypeset')
  30543. },
  30544. })
  30545. editorui.buttons['autotypeset'] = ui
  30546. editor.addListener('selectionchange', function () {
  30547. ui.setDisabled(editor.queryCommandState('autotypeset') == -1)
  30548. })
  30549. return ui
  30550. }
  30551. /* 简单上传插件 */
  30552. editorui['simpleupload'] = function (editor) {
  30553. var name = 'simpleupload',
  30554. ui = new editorui.Button({
  30555. className: 'edui-for-' + name,
  30556. title:
  30557. editor.options.labelMap[name] ||
  30558. editor.getLang('labelMap.' + name) ||
  30559. '',
  30560. onclick: function () {},
  30561. theme: editor.options.theme,
  30562. showText: false,
  30563. })
  30564. editorui.buttons[name] = ui
  30565. editor.addListener('ready', function () {
  30566. var b = ui.getDom('body'),
  30567. iconSpan = b.children[0]
  30568. editor.fireEvent('simpleuploadbtnready', iconSpan)
  30569. })
  30570. editor.addListener(
  30571. 'selectionchange',
  30572. function (type, causeByUi, uiReady) {
  30573. var state = editor.queryCommandState(name)
  30574. if (state == -1) {
  30575. ui.setDisabled(true)
  30576. ui.setChecked(false)
  30577. } else {
  30578. if (!uiReady) {
  30579. ui.setDisabled(false)
  30580. ui.setChecked(state)
  30581. }
  30582. }
  30583. }
  30584. )
  30585. return ui
  30586. }
  30587. /* word上传 */
  30588. editorui['wordupload'] = function (editor) {
  30589. var name = 'wordupload',
  30590. ui = new editorui.Button({
  30591. className: 'edui-for-' + name,
  30592. title:
  30593. editor.options.labelMap[name] ||
  30594. editor.getLang('labelMap.' + name) ||
  30595. '',
  30596. onclick: function () {},
  30597. theme: editor.options.theme,
  30598. showText: false,
  30599. })
  30600. editorui.buttons[name] = ui
  30601. editor.addListener('ready', function () {
  30602. var b = ui.getDom('body'),
  30603. iconSpan = b.children[0]
  30604. editor.fireEvent('worduploadbtnready', iconSpan)
  30605. })
  30606. editor.addListener(
  30607. 'selectionchange',
  30608. function (type, causeByUi, uiReady) {
  30609. var state = editor.queryCommandState(name)
  30610. if (state == -1) {
  30611. ui.setDisabled(true)
  30612. ui.setChecked(false)
  30613. } else {
  30614. if (!uiReady) {
  30615. ui.setDisabled(false)
  30616. ui.setChecked(state)
  30617. }
  30618. }
  30619. }
  30620. )
  30621. return ui
  30622. }
  30623. })()
  30624. // adapter/editor.js
  30625. ///import core
  30626. ///commands 全屏
  30627. ///commandsName FullScreen
  30628. ///commandsTitle 全屏
  30629. ;(function () {
  30630. var utils = baidu.editor.utils,
  30631. uiUtils = baidu.editor.ui.uiUtils,
  30632. UIBase = baidu.editor.ui.UIBase,
  30633. domUtils = baidu.editor.dom.domUtils
  30634. var nodeStack = []
  30635. function EditorUI(options) {
  30636. this.initOptions(options)
  30637. this.initEditorUI()
  30638. }
  30639. EditorUI.prototype = {
  30640. uiName: 'editor',
  30641. initEditorUI: function () {
  30642. this.editor.ui = this
  30643. this._dialogs = {}
  30644. this.initUIBase()
  30645. this._initToolbars()
  30646. var editor = this.editor,
  30647. me = this
  30648. editor.addListener('ready', function () {
  30649. //提供getDialog方法
  30650. editor.getDialog = function (name) {
  30651. return editor.ui._dialogs[name + 'Dialog']
  30652. }
  30653. domUtils.on(editor.window, 'scroll', function (evt) {
  30654. baidu.editor.ui.Popup.postHide(evt)
  30655. })
  30656. //提供编辑器实时宽高(全屏时宽高不变化)
  30657. editor.ui._actualFrameWidth = editor.options.initialFrameWidth
  30658. UE.browser.ie &&
  30659. UE.browser.version === 6 &&
  30660. editor.container.ownerDocument.execCommand(
  30661. 'BackgroundImageCache',
  30662. false,
  30663. true
  30664. )
  30665. //display bottom-bar label based on config
  30666. if (editor.options.elementPathEnabled) {
  30667. editor.ui.getDom('elementpath').innerHTML =
  30668. '<div class="edui-editor-breadcrumb">' +
  30669. editor.getLang('elementPathTip') +
  30670. ':</div>'
  30671. }
  30672. if (editor.options.wordCount) {
  30673. function countFn() {
  30674. setCount(editor, me)
  30675. domUtils.un(editor.document, 'click', arguments.callee)
  30676. }
  30677. domUtils.on(editor.document, 'click', countFn)
  30678. editor.ui.getDom('wordcount').innerHTML =
  30679. editor.getLang('wordCountTip')
  30680. }
  30681. editor.ui._scale()
  30682. if (editor.options.scaleEnabled) {
  30683. if (editor.autoHeightEnabled) {
  30684. editor.disableAutoHeight()
  30685. }
  30686. me.enableScale()
  30687. } else {
  30688. me.disableScale()
  30689. }
  30690. if (
  30691. !editor.options.elementPathEnabled &&
  30692. !editor.options.wordCount &&
  30693. !editor.options.scaleEnabled
  30694. ) {
  30695. editor.ui.getDom('elementpath').style.display = 'none'
  30696. editor.ui.getDom('wordcount').style.display = 'none'
  30697. editor.ui.getDom('scale').style.display = 'none'
  30698. }
  30699. if (!editor.selection.isFocus()) return
  30700. editor.fireEvent('selectionchange', false, true)
  30701. })
  30702. editor.addListener('mousedown', function (t, evt) {
  30703. var el = evt.target || evt.srcElement
  30704. baidu.editor.ui.Popup.postHide(evt, el)
  30705. baidu.editor.ui.ShortCutMenu.postHide(evt)
  30706. })
  30707. editor.addListener('delcells', function () {
  30708. if (UE.ui['edittip']) {
  30709. new UE.ui['edittip'](editor)
  30710. }
  30711. editor.getDialog('edittip').open()
  30712. })
  30713. var pastePop,
  30714. isPaste = false,
  30715. timer
  30716. editor.addListener('afterpaste', function () {
  30717. if (editor.queryCommandState('pasteplain')) return
  30718. if (baidu.editor.ui.PastePicker) {
  30719. pastePop = new baidu.editor.ui.Popup({
  30720. content: new baidu.editor.ui.PastePicker({ editor: editor }),
  30721. editor: editor,
  30722. className: 'edui-wordpastepop',
  30723. })
  30724. pastePop.render()
  30725. }
  30726. isPaste = true
  30727. })
  30728. editor.addListener('afterinserthtml', function () {
  30729. clearTimeout(timer)
  30730. timer = setTimeout(function () {
  30731. if (pastePop && (isPaste || editor.ui._isTransfer)) {
  30732. if (pastePop.isHidden()) {
  30733. var span = domUtils.createElement(editor.document, 'span', {
  30734. style: 'line-height:0px;',
  30735. innerHTML: '\ufeff',
  30736. }),
  30737. range = editor.selection.getRange()
  30738. range.insertNode(span)
  30739. var tmp = getDomNode(span, 'firstChild', 'previousSibling')
  30740. tmp &&
  30741. pastePop.showAnchor(tmp.nodeType == 3 ? tmp.parentNode : tmp)
  30742. domUtils.remove(span)
  30743. } else {
  30744. pastePop.show()
  30745. }
  30746. delete editor.ui._isTransfer
  30747. isPaste = false
  30748. }
  30749. }, 200)
  30750. })
  30751. editor.addListener('contextmenu', function (t, evt) {
  30752. baidu.editor.ui.Popup.postHide(evt)
  30753. })
  30754. editor.addListener('keydown', function (t, evt) {
  30755. if (pastePop) pastePop.dispose(evt)
  30756. var keyCode = evt.keyCode || evt.which
  30757. if (evt.altKey && keyCode == 90) {
  30758. UE.ui.buttons['fullscreen'].onclick()
  30759. }
  30760. })
  30761. editor.addListener('wordcount', function (type) {
  30762. setCount(this, me)
  30763. })
  30764. function setCount(editor, ui) {
  30765. editor.setOpt({
  30766. wordCount: true,
  30767. maximumWords: 10000,
  30768. wordCountMsg:
  30769. editor.options.wordCountMsg || editor.getLang('wordCountMsg'),
  30770. wordOverFlowMsg:
  30771. editor.options.wordOverFlowMsg ||
  30772. editor.getLang('wordOverFlowMsg'),
  30773. })
  30774. var opt = editor.options,
  30775. max = opt.maximumWords,
  30776. msg = opt.wordCountMsg,
  30777. errMsg = opt.wordOverFlowMsg,
  30778. countDom = ui.getDom('wordcount')
  30779. if (!opt.wordCount) {
  30780. return
  30781. }
  30782. var count = editor.getContentLength(true)
  30783. if (count > max) {
  30784. countDom.innerHTML = errMsg
  30785. editor.fireEvent('wordcountoverflow')
  30786. } else {
  30787. countDom.innerHTML = msg
  30788. .replace('{#leave}', max - count)
  30789. .replace('{#count}', count)
  30790. }
  30791. }
  30792. editor.addListener('selectionchange', function () {
  30793. if (editor.options.elementPathEnabled) {
  30794. me[
  30795. (editor.queryCommandState('elementpath') == -1 ? 'dis' : 'en') +
  30796. 'ableElementPath'
  30797. ]()
  30798. }
  30799. if (editor.options.scaleEnabled) {
  30800. me[
  30801. (editor.queryCommandState('scale') == -1 ? 'dis' : 'en') +
  30802. 'ableScale'
  30803. ]()
  30804. }
  30805. })
  30806. var popup = new baidu.editor.ui.Popup({
  30807. editor: editor,
  30808. content: '',
  30809. className: 'edui-bubble',
  30810. _onEditButtonClick: function () {
  30811. this.hide()
  30812. editor.ui._dialogs.linkDialog.open()
  30813. },
  30814. _onImgEditButtonClick: function (name) {
  30815. this.hide()
  30816. editor.ui._dialogs[name] && editor.ui._dialogs[name].open()
  30817. },
  30818. _onImgSetFloat: function (value) {
  30819. this.hide()
  30820. editor.execCommand('imagefloat', value)
  30821. },
  30822. _setIframeAlign: function (value) {
  30823. var frame = popup.anchorEl
  30824. var newFrame = frame.cloneNode(true)
  30825. switch (value) {
  30826. case -2:
  30827. newFrame.setAttribute('align', '')
  30828. break
  30829. case -1:
  30830. newFrame.setAttribute('align', 'left')
  30831. break
  30832. case 1:
  30833. newFrame.setAttribute('align', 'right')
  30834. break
  30835. }
  30836. frame.parentNode.insertBefore(newFrame, frame)
  30837. domUtils.remove(frame)
  30838. popup.anchorEl = newFrame
  30839. popup.showAnchor(popup.anchorEl)
  30840. },
  30841. _updateIframe: function () {
  30842. var frame = (editor._iframe = popup.anchorEl)
  30843. if (domUtils.hasClass(frame, 'ueditor_baidumap')) {
  30844. editor.selection.getRange().selectNode(frame).select()
  30845. editor.ui._dialogs.mapDialog.open()
  30846. popup.hide()
  30847. } else {
  30848. editor.ui._dialogs.insertframeDialog.open()
  30849. popup.hide()
  30850. }
  30851. },
  30852. _onRemoveButtonClick: function (cmdName) {
  30853. editor.execCommand(cmdName)
  30854. this.hide()
  30855. },
  30856. queryAutoHide: function (el) {
  30857. if (el && el.ownerDocument == editor.document) {
  30858. if (
  30859. el.tagName.toLowerCase() == 'img' ||
  30860. domUtils.findParentByTagName(el, 'a', true)
  30861. ) {
  30862. return el !== popup.anchorEl
  30863. }
  30864. }
  30865. return baidu.editor.ui.Popup.prototype.queryAutoHide.call(this, el)
  30866. },
  30867. })
  30868. popup.render()
  30869. if (editor.options.imagePopup) {
  30870. editor.addListener('mouseover', function (t, evt) {
  30871. evt = evt || window.event
  30872. var el = evt.target || evt.srcElement
  30873. if (
  30874. editor.ui._dialogs.insertframeDialog &&
  30875. /iframe/gi.test(el.tagName)
  30876. ) {
  30877. var html = popup.formatHtml(
  30878. '<nobr>' +
  30879. editor.getLang('property') +
  30880. ': <span onclick=$$._setIframeAlign(-2) class="edui-clickable">' +
  30881. editor.getLang('default') +
  30882. '</span>&nbsp;&nbsp;<span onclick=$$._setIframeAlign(-1) class="edui-clickable">' +
  30883. editor.getLang('justifyleft') +
  30884. '</span>&nbsp;&nbsp;<span onclick=$$._setIframeAlign(1) class="edui-clickable">' +
  30885. editor.getLang('justifyright') +
  30886. '</span>&nbsp;&nbsp;' +
  30887. ' <span onclick="$$._updateIframe( this);" class="edui-clickable">' +
  30888. editor.getLang('modify') +
  30889. '</span></nobr>'
  30890. )
  30891. if (html) {
  30892. popup.getDom('content').innerHTML = html
  30893. popup.anchorEl = el
  30894. popup.showAnchor(popup.anchorEl)
  30895. } else {
  30896. popup.hide()
  30897. }
  30898. }
  30899. })
  30900. editor.addListener('selectionchange', function (t, causeByUi) {
  30901. if (!causeByUi) return
  30902. var html = '',
  30903. str = '',
  30904. img = editor.selection.getRange().getClosedNode(),
  30905. dialogs = editor.ui._dialogs
  30906. if (img && img.tagName == 'IMG') {
  30907. var dialogName = 'insertimageDialog'
  30908. if (
  30909. img.className.indexOf('edui-faked-video') != -1 ||
  30910. img.className.indexOf('edui-upload-video') != -1
  30911. ) {
  30912. dialogName = 'insertvideoDialog'
  30913. }
  30914. if (img.className.indexOf('edui-faked-webapp') != -1) {
  30915. dialogName = 'webappDialog'
  30916. }
  30917. if (img.src.indexOf('http://api.map.baidu.com') != -1) {
  30918. dialogName = 'mapDialog'
  30919. }
  30920. if (img.className.indexOf('edui-faked-music') != -1) {
  30921. dialogName = 'musicDialog'
  30922. }
  30923. if (
  30924. img.src.indexOf('http://maps.google.com/maps/api/staticmap') !=
  30925. -1
  30926. ) {
  30927. dialogName = 'gmapDialog'
  30928. }
  30929. if (img.getAttribute('anchorname')) {
  30930. dialogName = 'anchorDialog'
  30931. html = popup.formatHtml(
  30932. '<nobr>' +
  30933. editor.getLang('property') +
  30934. ': <span onclick=$$._onImgEditButtonClick("anchorDialog") class="edui-clickable">' +
  30935. editor.getLang('modify') +
  30936. '</span>&nbsp;&nbsp;' +
  30937. '<span onclick=$$._onRemoveButtonClick(\'anchor\') class="edui-clickable">' +
  30938. editor.getLang('delete') +
  30939. '</span></nobr>'
  30940. )
  30941. }
  30942. if (img.getAttribute('word_img')) {
  30943. //todo 放到dialog去做查询
  30944. editor.word_img = [img.getAttribute('word_img')]
  30945. dialogName = 'wordimageDialog'
  30946. }
  30947. if (
  30948. domUtils.hasClass(img, 'loadingclass') ||
  30949. domUtils.hasClass(img, 'loaderrorclass')
  30950. ) {
  30951. dialogName = ''
  30952. }
  30953. if (!dialogs[dialogName]) {
  30954. return
  30955. }
  30956. str =
  30957. '<nobr>' +
  30958. editor.getLang('property') +
  30959. ': ' +
  30960. '<span onclick=$$._onImgSetFloat("none") class="edui-clickable">' +
  30961. editor.getLang('default') +
  30962. '</span>&nbsp;&nbsp;' +
  30963. '<span onclick=$$._onImgSetFloat("left") class="edui-clickable">' +
  30964. editor.getLang('justifyleft') +
  30965. '</span>&nbsp;&nbsp;' +
  30966. '<span onclick=$$._onImgSetFloat("right") class="edui-clickable">' +
  30967. editor.getLang('justifyright') +
  30968. '</span>&nbsp;&nbsp;' +
  30969. '<span onclick=$$._onImgSetFloat("center") class="edui-clickable">' +
  30970. editor.getLang('justifycenter') +
  30971. '</span>&nbsp;&nbsp;' +
  30972. '<span onclick="$$._onImgEditButtonClick(\'' +
  30973. dialogName +
  30974. '\');" class="edui-clickable">' +
  30975. editor.getLang('modify') +
  30976. '</span></nobr>'
  30977. !html && (html = popup.formatHtml(str))
  30978. }
  30979. if (editor.ui._dialogs.linkDialog) {
  30980. var link = editor.queryCommandValue('link')
  30981. var url
  30982. if (
  30983. link &&
  30984. (url =
  30985. link.getAttribute('_href') || link.getAttribute('href', 2))
  30986. ) {
  30987. var txt = url
  30988. if (url.length > 30) {
  30989. txt = url.substring(0, 20) + '...'
  30990. }
  30991. if (html) {
  30992. html += '<div style="height:5px;"></div>'
  30993. }
  30994. html += popup.formatHtml(
  30995. '<nobr>' +
  30996. editor.getLang('anthorMsg') +
  30997. ': <a target="_blank" href="' +
  30998. url +
  30999. '" title="' +
  31000. url +
  31001. '" >' +
  31002. txt +
  31003. '</a>' +
  31004. ' <span class="edui-clickable" onclick="$$._onEditButtonClick();">' +
  31005. editor.getLang('modify') +
  31006. '</span>' +
  31007. ' <span class="edui-clickable" onclick="$$._onRemoveButtonClick(\'unlink\');"> ' +
  31008. editor.getLang('clear') +
  31009. '</span></nobr>'
  31010. )
  31011. popup.showAnchor(link)
  31012. }
  31013. }
  31014. if (html) {
  31015. popup.getDom('content').innerHTML = html
  31016. popup.anchorEl = img || link
  31017. popup.showAnchor(popup.anchorEl)
  31018. } else {
  31019. popup.hide()
  31020. }
  31021. })
  31022. }
  31023. },
  31024. _initToolbars: function () {
  31025. var editor = this.editor
  31026. var toolbars = this.toolbars || []
  31027. var toolbarUis = []
  31028. for (var i = 0; i < toolbars.length; i++) {
  31029. var toolbar = toolbars[i]
  31030. var toolbarUi = new baidu.editor.ui.Toolbar({
  31031. theme: editor.options.theme,
  31032. })
  31033. for (var j = 0; j < toolbar.length; j++) {
  31034. var toolbarItem = toolbar[j]
  31035. var toolbarItemUi = null
  31036. if (typeof toolbarItem == 'string') {
  31037. toolbarItem = toolbarItem.toLowerCase()
  31038. if (toolbarItem == '|') {
  31039. toolbarItem = 'Separator'
  31040. }
  31041. if (toolbarItem == '||') {
  31042. toolbarItem = 'Breakline'
  31043. }
  31044. if (baidu.editor.ui[toolbarItem]) {
  31045. toolbarItemUi = new baidu.editor.ui[toolbarItem](editor)
  31046. }
  31047. //fullscreen这里单独处理一下,放到首行去
  31048. if (toolbarItem == 'fullscreen') {
  31049. if (toolbarUis && toolbarUis[0]) {
  31050. toolbarUis[0].items.splice(0, 0, toolbarItemUi)
  31051. } else {
  31052. toolbarItemUi && toolbarUi.items.splice(0, 0, toolbarItemUi)
  31053. }
  31054. continue
  31055. }
  31056. } else {
  31057. toolbarItemUi = toolbarItem
  31058. }
  31059. if (toolbarItemUi && toolbarItemUi.id) {
  31060. toolbarUi.add(toolbarItemUi)
  31061. }
  31062. }
  31063. toolbarUis[i] = toolbarUi
  31064. }
  31065. //接受外部定制的UI(修复因 utils.each 无法准确的循环出对象的全部元素而导致的自定义 UI 不符合预期的 BUG by HaoChuan9421)
  31066. // utils.each(UE._customizeUI,function(obj,key){
  31067. // var itemUI,index;
  31068. // if(obj.id && obj.id != editor.key){
  31069. // return false;
  31070. // }
  31071. // itemUI = obj.execFn.call(editor,editor,key);
  31072. // if(itemUI){
  31073. // index = obj.index;
  31074. // if(index === undefined){
  31075. // index = toolbarUi.items.length;
  31076. // }
  31077. // toolbarUi.add(itemUI,index)
  31078. // }
  31079. // });
  31080. for (var key in UE._customizeUI) {
  31081. var obj = UE._customizeUI[key]
  31082. var itemUI, index
  31083. if (!obj.id || obj.id == editor.key) {
  31084. itemUI = obj.execFn.call(editor, editor, key)
  31085. if (itemUI) {
  31086. index = obj.index
  31087. if (index === undefined) {
  31088. index = toolbarUi.items.length
  31089. }
  31090. toolbarUi.add(itemUI, index)
  31091. }
  31092. }
  31093. }
  31094. this.toolbars = toolbarUis
  31095. },
  31096. getHtmlTpl: function () {
  31097. return (
  31098. '<div id="##" class="%%">' +
  31099. '<div id="##_toolbarbox" class="%%-toolbarbox">' +
  31100. (this.toolbars.length
  31101. ? '<div id="##_toolbarboxouter" class="%%-toolbarboxouter"><div class="%%-toolbarboxinner">' +
  31102. this.renderToolbarBoxHtml() +
  31103. '</div></div>'
  31104. : '') +
  31105. '<div id="##_toolbarmsg" class="%%-toolbarmsg" style="display:none;">' +
  31106. '<div id = "##_upload_dialog" class="%%-toolbarmsg-upload" onclick="$$.showWordImageDialog();">' +
  31107. this.editor.getLang('clickToUpload') +
  31108. '</div>' +
  31109. '<div class="%%-toolbarmsg-close" onclick="$$.hideToolbarMsg();">x</div>' +
  31110. '<div id="##_toolbarmsg_label" class="%%-toolbarmsg-label"></div>' +
  31111. '<div style="height:0;overflow:hidden;clear:both;"></div>' +
  31112. '</div>' +
  31113. '<div id="##_message_holder" class="%%-messageholder"></div>' +
  31114. '</div>' +
  31115. '<div id="##_iframeholder" class="%%-iframeholder">' +
  31116. '</div>' +
  31117. //modify wdcount by matao
  31118. '<div id="##_bottombar" class="%%-bottomContainer"><table><tr>' +
  31119. '<td id="##_elementpath" class="%%-bottombar"></td>' +
  31120. '<td id="##_wordcount" class="%%-wordcount"></td>' +
  31121. '<td id="##_scale" class="%%-scale"><div class="%%-icon"></div></td>' +
  31122. '</tr></table></div>' +
  31123. '<div id="##_scalelayer"></div>' +
  31124. '</div>'
  31125. )
  31126. },
  31127. showWordImageDialog: function () {
  31128. this._dialogs['wordimageDialog'].open()
  31129. },
  31130. renderToolbarBoxHtml: function () {
  31131. var buff = []
  31132. for (var i = 0; i < this.toolbars.length; i++) {
  31133. buff.push(this.toolbars[i].renderHtml())
  31134. }
  31135. return buff.join('')
  31136. },
  31137. setFullScreen: function (fullscreen) {
  31138. var editor = this.editor,
  31139. container = editor.container.parentNode.parentNode
  31140. if (this._fullscreen != fullscreen) {
  31141. this._fullscreen = fullscreen
  31142. this.editor.fireEvent('beforefullscreenchange', fullscreen)
  31143. if (baidu.editor.browser.gecko) {
  31144. var bk = editor.selection.getRange().createBookmark()
  31145. }
  31146. if (fullscreen) {
  31147. while (container.tagName != 'BODY') {
  31148. var position = baidu.editor.dom.domUtils.getComputedStyle(
  31149. container,
  31150. 'position'
  31151. )
  31152. nodeStack.push(position)
  31153. container.style.position = 'static'
  31154. container = container.parentNode
  31155. }
  31156. this._bakHtmlOverflow = document.documentElement.style.overflow
  31157. this._bakBodyOverflow = document.body.style.overflow
  31158. this._bakAutoHeight = this.editor.autoHeightEnabled
  31159. this._bakScrollTop = Math.max(
  31160. document.documentElement.scrollTop,
  31161. document.body.scrollTop
  31162. )
  31163. this._bakEditorContaninerWidth =
  31164. editor.iframe.parentNode.offsetWidth
  31165. if (this._bakAutoHeight) {
  31166. //当全屏时不能执行自动长高
  31167. editor.autoHeightEnabled = false
  31168. this.editor.disableAutoHeight()
  31169. }
  31170. document.documentElement.style.overflow = 'hidden'
  31171. //修复,滚动条不收起的问题
  31172. window.scrollTo(0, window.scrollY)
  31173. this._bakCssText = this.getDom().style.cssText
  31174. this._bakCssText1 = this.getDom('iframeholder').style.cssText
  31175. editor.iframe.parentNode.style.width = ''
  31176. this._updateFullScreen()
  31177. } else {
  31178. while (container.tagName != 'BODY') {
  31179. container.style.position = nodeStack.shift()
  31180. container = container.parentNode
  31181. }
  31182. this.getDom().style.cssText = this._bakCssText
  31183. this.getDom('iframeholder').style.cssText = this._bakCssText1
  31184. if (this._bakAutoHeight) {
  31185. editor.autoHeightEnabled = true
  31186. this.editor.enableAutoHeight()
  31187. }
  31188. document.documentElement.style.overflow = this._bakHtmlOverflow
  31189. document.body.style.overflow = this._bakBodyOverflow
  31190. editor.iframe.parentNode.style.width =
  31191. this._bakEditorContaninerWidth + 'px'
  31192. window.scrollTo(0, this._bakScrollTop)
  31193. }
  31194. if (browser.gecko && editor.body.contentEditable === 'true') {
  31195. var input = document.createElement('input')
  31196. document.body.appendChild(input)
  31197. editor.body.contentEditable = false
  31198. setTimeout(function () {
  31199. input.focus()
  31200. setTimeout(function () {
  31201. editor.body.contentEditable = true
  31202. editor.fireEvent('fullscreenchanged', fullscreen)
  31203. editor.selection.getRange().moveToBookmark(bk).select(true)
  31204. baidu.editor.dom.domUtils.remove(input)
  31205. fullscreen && window.scroll(0, 0)
  31206. }, 0)
  31207. }, 0)
  31208. }
  31209. if (editor.body.contentEditable === 'true') {
  31210. this.editor.fireEvent('fullscreenchanged', fullscreen)
  31211. this.triggerLayout()
  31212. }
  31213. }
  31214. },
  31215. _updateFullScreen: function () {
  31216. if (this._fullscreen) {
  31217. var vpRect = uiUtils.getViewportRect()
  31218. this.getDom().style.cssText =
  31219. 'border:0;position:absolute;left:0;top:' +
  31220. (this.editor.options.topOffset || 0) +
  31221. 'px;width:' +
  31222. vpRect.width +
  31223. 'px;height:' +
  31224. vpRect.height +
  31225. 'px;z-index:' +
  31226. (this.getDom().style.zIndex * 1 + 100)
  31227. uiUtils.setViewportOffset(this.getDom(), {
  31228. left: 0,
  31229. top: this.editor.options.topOffset || 0,
  31230. })
  31231. this.editor.setHeight(
  31232. vpRect.height -
  31233. this.getDom('toolbarbox').offsetHeight -
  31234. this.getDom('bottombar').offsetHeight -
  31235. (this.editor.options.topOffset || 0),
  31236. true
  31237. )
  31238. //不手动调一下,会导致全屏失效
  31239. if (browser.gecko) {
  31240. try {
  31241. window.onresize()
  31242. } catch (e) {}
  31243. }
  31244. }
  31245. },
  31246. _updateElementPath: function () {
  31247. var bottom = this.getDom('elementpath'),
  31248. list
  31249. if (
  31250. this.elementPathEnabled &&
  31251. (list = this.editor.queryCommandValue('elementpath'))
  31252. ) {
  31253. var buff = []
  31254. for (var i = 0, ci; (ci = list[i]); i++) {
  31255. buff[i] = this.formatHtml(
  31256. '<span unselectable="on" onclick="$$.editor.execCommand(&quot;elementpath&quot;, &quot;' +
  31257. i +
  31258. '&quot;);">' +
  31259. ci +
  31260. '</span>'
  31261. )
  31262. }
  31263. bottom.innerHTML =
  31264. '<div class="edui-editor-breadcrumb" onmousedown="return false;">' +
  31265. this.editor.getLang('elementPathTip') +
  31266. ': ' +
  31267. buff.join(' &gt; ') +
  31268. '</div>'
  31269. } else {
  31270. bottom.style.display = 'none'
  31271. }
  31272. },
  31273. disableElementPath: function () {
  31274. var bottom = this.getDom('elementpath')
  31275. bottom.innerHTML = ''
  31276. bottom.style.display = 'none'
  31277. this.elementPathEnabled = false
  31278. },
  31279. enableElementPath: function () {
  31280. var bottom = this.getDom('elementpath')
  31281. bottom.style.display = ''
  31282. this.elementPathEnabled = true
  31283. this._updateElementPath()
  31284. },
  31285. _scale: function () {
  31286. var doc = document,
  31287. editor = this.editor,
  31288. editorHolder = editor.container,
  31289. editorDocument = editor.document,
  31290. toolbarBox = this.getDom('toolbarbox'),
  31291. bottombar = this.getDom('bottombar'),
  31292. scale = this.getDom('scale'),
  31293. scalelayer = this.getDom('scalelayer')
  31294. var isMouseMove = false,
  31295. position = null,
  31296. minEditorHeight = 0,
  31297. minEditorWidth = editor.options.minFrameWidth,
  31298. pageX = 0,
  31299. pageY = 0,
  31300. scaleWidth = 0,
  31301. scaleHeight = 0
  31302. function down() {
  31303. position = domUtils.getXY(editorHolder)
  31304. if (!minEditorHeight) {
  31305. minEditorHeight =
  31306. editor.options.minFrameHeight +
  31307. toolbarBox.offsetHeight +
  31308. bottombar.offsetHeight
  31309. }
  31310. scalelayer.style.cssText =
  31311. 'position:absolute;left:0;display:;top:0;background-color:#41ABFF;opacity:0.4;filter: Alpha(opacity=40);width:' +
  31312. editorHolder.offsetWidth +
  31313. 'px;height:' +
  31314. editorHolder.offsetHeight +
  31315. 'px;z-index:' +
  31316. (editor.options.zIndex + 1)
  31317. domUtils.on(doc, 'mousemove', move)
  31318. domUtils.on(editorDocument, 'mouseup', up)
  31319. domUtils.on(doc, 'mouseup', up)
  31320. }
  31321. var me = this
  31322. //by xuheng 全屏时关掉缩放
  31323. this.editor.addListener('fullscreenchanged', function (e, fullScreen) {
  31324. if (fullScreen) {
  31325. me.disableScale()
  31326. } else {
  31327. if (me.editor.options.scaleEnabled) {
  31328. me.enableScale()
  31329. var tmpNode = me.editor.document.createElement('span')
  31330. me.editor.body.appendChild(tmpNode)
  31331. me.editor.body.style.height =
  31332. Math.max(
  31333. domUtils.getXY(tmpNode).y,
  31334. me.editor.iframe.offsetHeight - 20
  31335. ) + 'px'
  31336. domUtils.remove(tmpNode)
  31337. }
  31338. }
  31339. })
  31340. function move(event) {
  31341. clearSelection()
  31342. var e = event || window.event
  31343. pageX = e.pageX || doc.documentElement.scrollLeft + e.clientX
  31344. pageY = e.pageY || doc.documentElement.scrollTop + e.clientY
  31345. scaleWidth = pageX - position.x
  31346. scaleHeight = pageY - position.y
  31347. if (scaleWidth >= minEditorWidth) {
  31348. isMouseMove = true
  31349. scalelayer.style.width = scaleWidth + 'px'
  31350. }
  31351. if (scaleHeight >= minEditorHeight) {
  31352. isMouseMove = true
  31353. scalelayer.style.height = scaleHeight + 'px'
  31354. }
  31355. }
  31356. function up() {
  31357. if (isMouseMove) {
  31358. isMouseMove = false
  31359. editor.ui._actualFrameWidth = scalelayer.offsetWidth - 2
  31360. editorHolder.style.width = editor.ui._actualFrameWidth + 'px'
  31361. editor.setHeight(
  31362. scalelayer.offsetHeight -
  31363. bottombar.offsetHeight -
  31364. toolbarBox.offsetHeight -
  31365. 2,
  31366. true
  31367. )
  31368. }
  31369. if (scalelayer) {
  31370. scalelayer.style.display = 'none'
  31371. }
  31372. clearSelection()
  31373. domUtils.un(doc, 'mousemove', move)
  31374. domUtils.un(editorDocument, 'mouseup', up)
  31375. domUtils.un(doc, 'mouseup', up)
  31376. }
  31377. function clearSelection() {
  31378. if (browser.ie) doc.selection.clear()
  31379. else window.getSelection().removeAllRanges()
  31380. }
  31381. this.enableScale = function () {
  31382. //trace:2868
  31383. if (editor.queryCommandState('source') == 1) return
  31384. scale.style.display = ''
  31385. this.scaleEnabled = true
  31386. domUtils.on(scale, 'mousedown', down)
  31387. }
  31388. this.disableScale = function () {
  31389. scale.style.display = 'none'
  31390. this.scaleEnabled = false
  31391. domUtils.un(scale, 'mousedown', down)
  31392. }
  31393. },
  31394. isFullScreen: function () {
  31395. return this._fullscreen
  31396. },
  31397. postRender: function () {
  31398. UIBase.prototype.postRender.call(this)
  31399. for (var i = 0; i < this.toolbars.length; i++) {
  31400. this.toolbars[i].postRender()
  31401. }
  31402. var me = this
  31403. var timerId,
  31404. domUtils = baidu.editor.dom.domUtils,
  31405. updateFullScreenTime = function () {
  31406. clearTimeout(timerId)
  31407. timerId = setTimeout(function () {
  31408. me._updateFullScreen()
  31409. })
  31410. }
  31411. domUtils.on(window, 'resize', updateFullScreenTime)
  31412. me.addListener('destroy', function () {
  31413. domUtils.un(window, 'resize', updateFullScreenTime)
  31414. clearTimeout(timerId)
  31415. })
  31416. },
  31417. showToolbarMsg: function (msg, flag) {
  31418. this.getDom('toolbarmsg_label').innerHTML = msg
  31419. this.getDom('toolbarmsg').style.display = ''
  31420. //
  31421. if (!flag) {
  31422. var w = this.getDom('upload_dialog')
  31423. w.style.display = 'none'
  31424. }
  31425. },
  31426. hideToolbarMsg: function () {
  31427. this.getDom('toolbarmsg').style.display = 'none'
  31428. },
  31429. mapUrl: function (url) {
  31430. return url
  31431. ? url.replace('~/', this.editor.options.UEDITOR_HOME_URL || '')
  31432. : ''
  31433. },
  31434. triggerLayout: function () {
  31435. var dom = this.getDom()
  31436. if (dom.style.zoom == '1') {
  31437. dom.style.zoom = '100%'
  31438. } else {
  31439. dom.style.zoom = '1'
  31440. }
  31441. },
  31442. }
  31443. utils.inherits(EditorUI, baidu.editor.ui.UIBase)
  31444. var instances = {}
  31445. UE.ui.Editor = function (options) {
  31446. var editor = new UE.Editor(options)
  31447. editor.options.editor = editor
  31448. utils.loadFile(document, {
  31449. href:
  31450. editor.options.themePath + editor.options.theme + '/css/ueditor.css',
  31451. tag: 'link',
  31452. type: 'text/css',
  31453. rel: 'stylesheet',
  31454. })
  31455. var oldRender = editor.render
  31456. editor.render = function (holder) {
  31457. if (holder.constructor === String) {
  31458. editor.key = holder
  31459. instances[holder] = editor
  31460. }
  31461. utils.domReady(function () {
  31462. editor.langIsReady
  31463. ? renderUI()
  31464. : editor.addListener('langReady', renderUI)
  31465. function renderUI() {
  31466. editor.setOpt({
  31467. labelMap: editor.options.labelMap || editor.getLang('labelMap'),
  31468. })
  31469. new EditorUI(editor.options)
  31470. if (holder) {
  31471. if (holder.constructor === String) {
  31472. holder = document.getElementById(holder)
  31473. }
  31474. holder &&
  31475. holder.getAttribute('name') &&
  31476. (editor.options.textarea = holder.getAttribute('name'))
  31477. if (holder && /script|textarea/gi.test(holder.tagName)) {
  31478. var newDiv = document.createElement('div')
  31479. holder.parentNode.insertBefore(newDiv, holder)
  31480. var cont = holder.value || holder.innerHTML
  31481. editor.options.initialContent = /^[\t\r\n ]*$/.test(cont)
  31482. ? editor.options.initialContent
  31483. : cont
  31484. .replace(/>[\n\r\t]+([ ]{4})+/g, '>')
  31485. .replace(/[\n\r\t]+([ ]{4})+</g, '<')
  31486. .replace(/>[\n\r\t]+</g, '><')
  31487. holder.className && (newDiv.className = holder.className)
  31488. holder.style.cssText &&
  31489. (newDiv.style.cssText = holder.style.cssText)
  31490. if (/textarea/i.test(holder.tagName)) {
  31491. editor.textarea = holder
  31492. editor.textarea.style.display = 'none'
  31493. } else {
  31494. holder.parentNode.removeChild(holder)
  31495. }
  31496. if (holder.id) {
  31497. newDiv.id = holder.id
  31498. domUtils.removeAttributes(holder, 'id')
  31499. }
  31500. holder = newDiv
  31501. holder.innerHTML = ''
  31502. }
  31503. }
  31504. domUtils.addClass(holder, 'edui-' + editor.options.theme)
  31505. editor.ui.render(holder)
  31506. var opt = editor.options
  31507. //给实例添加一个编辑器的容器引用
  31508. editor.container = editor.ui.getDom()
  31509. var parents = domUtils.findParents(holder, true)
  31510. var displays = []
  31511. for (var i = 0, ci; (ci = parents[i]); i++) {
  31512. displays[i] = ci.style.display
  31513. ci.style.display = 'block'
  31514. }
  31515. if (opt.initialFrameWidth) {
  31516. opt.minFrameWidth = opt.initialFrameWidth
  31517. } else {
  31518. opt.minFrameWidth = opt.initialFrameWidth = holder.offsetWidth
  31519. var styleWidth = holder.style.width
  31520. if (/%$/.test(styleWidth)) {
  31521. opt.initialFrameWidth = styleWidth
  31522. }
  31523. }
  31524. if (opt.initialFrameHeight) {
  31525. opt.minFrameHeight = opt.initialFrameHeight
  31526. } else {
  31527. opt.initialFrameHeight = opt.minFrameHeight = holder.offsetHeight
  31528. }
  31529. for (var i = 0, ci; (ci = parents[i]); i++) {
  31530. ci.style.display = displays[i]
  31531. }
  31532. //编辑器最外容器设置了高度,会导致,编辑器不占位
  31533. //todo 先去掉,没有找到原因
  31534. if (holder.style.height) {
  31535. holder.style.height = ''
  31536. }
  31537. editor.container.style.width =
  31538. opt.initialFrameWidth +
  31539. (/%$/.test(opt.initialFrameWidth) ? '' : 'px')
  31540. editor.container.style.zIndex = opt.zIndex
  31541. oldRender.call(editor, editor.ui.getDom('iframeholder'))
  31542. editor.fireEvent('afteruiready')
  31543. }
  31544. })
  31545. }
  31546. return editor
  31547. }
  31548. /**
  31549. * @file
  31550. * @name UE
  31551. * @short UE
  31552. * @desc UEditor的顶部命名空间
  31553. */
  31554. /**
  31555. * @name getEditor
  31556. * @since 1.2.4+
  31557. * @grammar UE.getEditor(id,[opt]) => Editor实例
  31558. * @desc 提供一个全局的方法得到编辑器实例
  31559. *
  31560. * * ''id'' 放置编辑器的容器id, 如果容器下的编辑器已经存在,就直接返回
  31561. * * ''opt'' 编辑器的可选参数
  31562. * @example
  31563. * UE.getEditor('containerId',{onready:function(){//创建一个编辑器实例
  31564. * this.setContent('hello')
  31565. * }});
  31566. * UE.getEditor('containerId'); //返回刚创建的实例
  31567. *
  31568. */
  31569. UE.getEditor = function (id, opt) {
  31570. var editor = instances[id]
  31571. if (!editor) {
  31572. editor = instances[id] = new UE.ui.Editor(opt)
  31573. editor.render(id)
  31574. }
  31575. return editor
  31576. }
  31577. UE.delEditor = function (id) {
  31578. var editor
  31579. if ((editor = instances[id])) {
  31580. editor.key && editor.destroy()
  31581. delete instances[id]
  31582. }
  31583. }
  31584. UE.registerUI = function (uiName, fn, index, editorId) {
  31585. utils.each(uiName.split(/\s+/), function (name) {
  31586. UE._customizeUI[name] = {
  31587. id: editorId,
  31588. execFn: fn,
  31589. index: index,
  31590. }
  31591. })
  31592. }
  31593. })()
  31594. // adapter/message.js
  31595. UE.registerUI('message', function (editor) {
  31596. var editorui = baidu.editor.ui
  31597. var Message = editorui.Message
  31598. var holder
  31599. var _messageItems = []
  31600. var me = editor
  31601. me.addListener('ready', function () {
  31602. holder = document.getElementById(me.ui.id + '_message_holder')
  31603. updateHolderPos()
  31604. // HaoChuan9421
  31605. // setTimeout(function(){
  31606. // updateHolderPos();
  31607. // }, 500);
  31608. })
  31609. me.addListener('showmessage', function (type, opt) {
  31610. opt = utils.isString(opt)
  31611. ? {
  31612. content: opt,
  31613. }
  31614. : opt
  31615. var message = new Message({
  31616. timeout: opt.timeout,
  31617. type: opt.type,
  31618. content: opt.content,
  31619. keepshow: opt.keepshow,
  31620. editor: me,
  31621. }),
  31622. mid = opt.id || 'msg_' + (+new Date()).toString(36)
  31623. message.render(holder)
  31624. _messageItems[mid] = message
  31625. message.reset(opt)
  31626. updateHolderPos()
  31627. return mid
  31628. })
  31629. me.addListener('updatemessage', function (type, id, opt) {
  31630. opt = utils.isString(opt)
  31631. ? {
  31632. content: opt,
  31633. }
  31634. : opt
  31635. var message = _messageItems[id]
  31636. message.render(holder)
  31637. message && message.reset(opt)
  31638. })
  31639. me.addListener('hidemessage', function (type, id) {
  31640. var message = _messageItems[id]
  31641. message && message.hide()
  31642. })
  31643. function updateHolderPos() {
  31644. var toolbarbox = me.ui.getDom('toolbarbox')
  31645. if (toolbarbox) {
  31646. holder.style.top = toolbarbox.offsetHeight + 3 + 'px'
  31647. }
  31648. holder.style.zIndex =
  31649. Math.max(me.options.zIndex, me.iframe.style.zIndex) + 1
  31650. }
  31651. })
  31652. // adapter/autosave.js
  31653. UE.registerUI('autosave', function (editor) {
  31654. var timer = null,
  31655. uid = null
  31656. editor.on('afterautosave', function () {
  31657. clearTimeout(timer)
  31658. timer = setTimeout(function () {
  31659. if (uid) {
  31660. editor.trigger('hidemessage', uid)
  31661. }
  31662. uid = editor.trigger('showmessage', {
  31663. content: editor.getLang('autosave.success'),
  31664. timeout: 2000,
  31665. })
  31666. }, 2000)
  31667. })
  31668. })
  31669. })()