....................................../////.===Shadow-Here===./////................................................ > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < ------------------------------------------------------------------------------------------------------------------- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// RIFF¤ WEBPVP8 ˜ ðÑ *ôô>‘HŸK¥¤"§£±¨àð enü¹%½_F‘åè¿2ºQú³íªú`N¿­3ÿƒügµJžaÿ¯ÿ°~¼ÎùnúîÞÖô•òíôÁÉß®Sm¥Ü/ ‡ó˜f£Ùà<˜„xëJ¢Ù€SO3x<ªÔ©4¿+ç¶A`q@Ì“Úñè™ÍÿJÌ´ª-˜ÆtÊÛL]Ïq*‘Ý”ì#ŸÌÏãY]@ê`¿ /ªfkØB4·®£ó z—Üw¥Pxù–ÞLШKÇN¾AkÙTf½è'‰g gÆv›Øuh~ a˜Z— ïj*á¥t d£“uÒ ¨`K˜¹ßþ]b>˜]_ÏÔ6W—è2r4x•íÖ…"ƒÖNîä!¦å Ú}ýxGøÌ —@ ;ÆÚŠ=ɾ1ý8lªË¥ô ^yf®Œ¢u&2©nÙÇ›ñÂñŒ³ aPo['½»øFùà­+4ê“$!lövlüÞ=;N®3ð‚õ›DÉKòÞ>ÄÍ ¥ˆuߤ#ˆ$6ù™¥îЇy’ÍB¼ çxÛ;X"WL£R÷͝*ó-¶Zu}º.s¸sšXqù–DþÿvªhüïwyŸ ¯é³lÀ:KCûÄ£Ëá\…­ ~—ýóî ¼ûûÜTÓüÇy…ŽÆvc»¾×U ñ¸žþоP÷¦ó:Ò¨¨5;Ð#&#ÖúñläÿÁœ GxÉ­/ñ‡áQðìYÉtÒw޼GÔ´zàÒò ð*ëzƒ•4~H]Ø‹f ñÓÈñ`NåWçs'ÆÏW^ø¹!XžµmQ5ÃËoLœÎ: ÞËÍ¥J ù…î èo£ßPÎñ¶ž8.Œ]ʵ~5›ÙË-ù*8ÙÖß±~ ©¹rÓê‚j¶d¸{^Q'˜±Crß ÚH—#¥¥QlÀ×ëã‡DÜ«èî þ&Çæžî;ŽÏºò6ÒLÃXy&ZŒ'j‚¢Ù€IßÚù+–MGi‰*jE€‘JcÜ ÓÌ EÏÚj]o˜ Þr <¾U ûŪæÍ/šÝH¥˜b”¼ ÁñßX GP›ï2›4WŠÏà×£…íÓk†¦H·ÅíMh–*nó÷à]ÁjCº€b7<ب‹¨5車bp2:Á[UªM„QŒçiNMa#<5›áËó¸HýÊ"…×Éw¹¦ì2º–x<›»a±¸3Weü®FÝ⑱ö–î–³|LPÈ~çð~Çå‡|º kD¢µÏàÆAI %1À% ¹Ò – ”ϝS¦‰4&¶£°à Öý”û_Ò Áw°A«Å€?mÇÛgHÉ/8)á¾ÛìáöŽP í¨PŸNÙµº¦‡§Ùš"ÿ«>+ªÕ`Ê÷‡‚ß Õû˜þãÇ-PÍ.¾XV‘€ dÜ"þ4¹ ±Oú‘©t¥¦FªÄÃÄ•b‚znýu½—#cDs˜ÃiÑOˆñ×QO=*IAÊ,¶ŽZƒ;‡wøXè%EÐk:F±Ú” .Ѽ+Áu&Ç`."pÈÉw o&¿dE6‘’EqTuK@Ì¥ã™À(Êk(h‰,H}RÀIXÛš3µ1©_OqÚÒJAñ$ÊÙÜ;D3çŒ[þùœh¬Ã³™ö6ç†NY".Ú‰ï[ªŸŒ '²Ð öø_¨ÂÉ9ué¶³ÒŠõTàîMØ#û¯gN‡bÙ놚X„ö …ÉeüÌ^J ‹€.œ$Æ)βÄeæW#óüßĺŸ€ ÀzwV 9oä»f4V*uB «Ë†¹ì¯žR霓æHXa=&“I4K;¯ç‹h×·"UŠ~<•╪Vêª&ÍSÃÆÅ?ÔqÎ*mTM ˜›µwêd#[C¡©§‘D<©àb†–ÁœøvH/,í:¯( ²£|4-„Æövv„Yͼ™^Á$ˆ„¢Û[6yB.åH*V¨æ?$=˜Ñ€•ñ·­(VlŸ‘ nÀt8W÷´Bûba?q9ú¶Xƒl«ÿ\ù¶’þòUÐj/õ¢Ìµ³g$ƒÎR!¸»|Oߍë’BhîÚÑ¢ñåŒJ„®„£2Ð3•ô02Nt…!£Í]Ïc½Qÿ?ˆ<&ÃA¾Ú,JˆijÌ#5yz„‰Î|ÊŽ5QÏ:‹ÐaóVÔxW—CpeÏzÐïíçôÿÅ_[hãsÐ_/ŽTÝ?BîˆííV$<¿i>²F¬_Eß¿ †bÊŒº­ÿ®Z H“C}”¬,Mp ý/Bá£w>˜YV°aƒúh+cŠ- r/[%|üUMHäQ°X»|û/@|°¥Ð !BÔ Ç¢Ä©š+Õì D«7ìN¶ŽðÔ " ƶ’ÖçtA‰Û×}{tþz­¾GÍ›k¹OEJR$ Â׃ «ëÁ"oÉôž$oUK(Ä)Ãz³Ê-‹êN[Ò3Œñbï8P 4ƒ×q¢bo|?<ÛX¬òÄͰL–±›(™ûG?ýË©ÚÄ–ÂDØÐ_Ç¡ô ¾–ÄÏø ×e8Ë©$ÄF¹Å‹ì[©óìl:F¾f´‹‹Xì²ï®\¬ôùƒ ÿat¥óèÒùHß0äe‚;ü×h:ÆWðHž=Ã8骣"kœ'Y?³}Tûè€>?0l›e1Lòñ„aæKÆw…hÖŠùW…ÈÆÄ0ši·›[pcwËþñiêíY/~-Á5˜!¿†A›™Mÿþ(±“t@â“ö2­´TG5yé]çå僳 .·ÍïçÝ7UÚ±Ð/Nè»,_Ï ùdj7\ï Wì4›„»c¸àešg#ÒÊ⥭áØo5‘?ÌdÝô¯ ¹kzsƒ=´#ëÉK›Ø´±-¥eW?‡çßtòTã…$Ý+qÿ±ƒ÷_3Ô¥í÷:æ–ž<·Ö‡‰Å¢ š‡%Ô—utÌÈìðžgÖÀz²À—ï÷Óîäõ{K'´È÷³yaÏÁjƒô}ž§®æÊydÕÈë5¯èˆõvÕ©ã*çD„ “z„Ó‡^^xÂ3M§A´JG‚öï 3W'ˆ.OvXè¡ÊÕª?5º7†˜(˜Ç¶#çê’¶!ÌdZK§æ 0fãaN]òY³RV ™î$®K2R¨`W!1Ôó\;Ý ýB%qæK•&ÓÈe9È0êI±žeŸß -ú@žQr¦ ö4»M¼Áè¹µmw 9 EÆE_°2ó„ŸXKWÁ×Hóì^´²GѝF©óäR†¦‰ç"V»eØ<3ùd3ÿÚ¤Žú“Gi" —‘_ÙËÎ~Üö¯¥½Î»üŸEÚŽåmÞþí ;ÞólËΦMzA"Âf(´òá;Éï(/7½ûñÌ­cïÕçлþÝz¾-ÍvÑ“pH­–ðÓj$¸Äû¤‚‘ãUBË-n“2åPkS5&‹Â|+g^œ®Ì͆d!OïäîU«c;{Û!ÅŽ«ëZ9Ókóˆ]¯ƒ›né `ÇÒ+tÆš (ØKá¾—=3œ®•vuMñg²\ï Ec€ 05±d™‡×iÇ×›UúvÌ¢£Èþ¡ÕØô¶ßÎA"ß±#Ö²ˆÊŸ¦*Ä~ij|àø.-¼'»Ú¥£h ofº¦‡VsR=N½„Î v˜Z*SÌ{=jÑB‹tê…;’HžH¯8–îDù8ñ¢|Q•bÛçš–‹m³“ê¨ åÏ^m¬Žãþ©ïêO‡½6] µÆ„Ooòü ²x}N¦Ë3ïé¿»€›HA˜m%çÞ/¿í7Fø“‹léUk)É°Œµ8Q8›:ÀŠeT*šõ~ôڝG6 ¢}`ùH­–”¡k ‰P1>š†®9z11!X wKfmÁ¦xÑ,N1Q”–æB¶M…ÒÃv6SMˆhU¬ÊPŽï‘öj=·CŒ¯u¹ƒVIЃsx4’ömÛýcå¡¶7ßŠß 57^\wÒÐÆ k§h,Œý î«q^R½3]J¸ÇðN ‚çU¬ôº^Áì} ³f©Õœ§ˆã:FÄÈ‚é(€™?àýÓüè1Gô£¼éj‚OÅñ  #>×—ßtà 0G¥Åa뀐kßhc™À_ÉñÞ#±)GD" YîäË-ÿÙ̪ ¹™a¯´¢E\ÝÒö‚;™„ë]_ p8‰o¡ñ+^÷ 3‘'dT4œŽ ðVë½° :¬víÑ«£tßÚS-3¶“þ2 †üüʨòrš¹M{É_¤`Û¨0ìjœøJ‡:÷ÃáZ˜†@GP&œÑDGÏs¡þ¦þDGú‘1Yá9Ôþ¼ ûø…§÷8&–ÜÑnÄ_m®^üÆ`;ÉVÁJ£?â€-ßê}suÍ2sõA NÌúA磸‘îÿÚ»ƒìö·á¿±tÑÐ"Tÿü˜[@/äj¬€uüªìù¥Ý˜á8Ý´sõj 8@rˆð äþZÇD®ÿUÏ2ùôõrBzÆÏÞž>Ì™xœ“ wiÎ×7_… ¸ \#€MɁV¶¥üÕÿPÔ9Z‡ø§É8#H:ƒ5ÀÝå9ÍIŒ5åKÙŠ÷qÄ>1AÈøžj"µÂд/ªnÀ qªã}"iŸBå˜ÓÛŽ¦…&ݧ;G@—³b¯“•"´4í¨ôM¨åñC‹ïùÉó¯ÓsSH2Ý@ßáM‡ˆKÀªÛUeø/4\gnm¥‹ŸŒ qÄ b9ÞwÒNÏ_4Ég³ú=܆‚´ •â¥õeíþkjz>éÚyU«Íӝ݃6"8/ø{=Ô¢»G¥ äUw°W«,ô—¿ãㆅү¢³xŠUû™yŒ (øSópÐ 9\åTâ»—*oG$/×ÍT†Y¿1¤Þ¢_‡ ¼ „±ÍçèSaÓ 3ÛMÁBkxs‰’R/¡¤ˆÙçª(*õ„üXÌ´ƒ E§´¬EF"Ù”R/ÐNyÆÂ^°?™6¡œïJ·±$§?º>ÖüœcNÌù¯G ‹ñ2ЁBB„^·úìaz¨k:#¨Æ¨8LÎõލ£^§S&cŒÐU€ü(‡F±Š¼&P>8ÙÁ ‰ p5?0ÊÆƒZl¸aô š¼¡}gÿ¶zÆC²¹¬ÎÖG*HB¡O<º2#ñŒAƒ–¡B˜´É$¥›É:FÀÔx¾u?XÜÏÓvN©RS{2ʈãk9rmP¼Qq̳ è¼ÐFׄ^¡Öì fE“F4A…!ì/…¦Lƒ… … $%´¾yã@CI¬ á—3PþBÏNÿ<ý°4Ü ËÃ#ØÍ~âW«rEñw‹eùMMHß²`¬Öó½íf³:‹k˜¯÷}Z!ã¿<¥,\#öµÀ¯aÒNÆIé,Ћ–lŽ#Àæ9ÀÒS·I’½-Ïp Äz¤Š Â* ­íÄ9­< h>׍3ZkËU¹§˜ŒŠ±f­’¤º³Q ÏB?‹#µíÃ¥®@(Gs«†vI¥Mµ‹Á©e~2ú³ÁP4ìÕi‚²Ê^ö@-DþÓàlÜOÍ]n"µã:žpsŽ¢:! Aõ.ç~ÓBûH÷JCÌ]õVƒd «ú´QÙEA–¯¯Œ!.ˆˆëQ±ù œ·Ì!Õâ )ùL„ÅÀlÚè5@B…o´Æ¸XÓ&Û…O«˜”_#‡ƒ„ûÈt!¤ÁÏ›ÎÝŠ?c9 â\>lÓÁVÄÑ™£eØY]:fÝ–—ù+p{™ðè û³”g±OƒÚSù£áÁÊ„ä,ï7š²G ÕÌBk)~ÑiCµ|h#u¤¶îK¨² #²vݯGãeÖ϶ú…¾múÀ¶þÔñ‚Š9'^($¤§ò “š½{éúp÷J›ušS¹áªCÂubÃH9™D™/ZöØÁ‡¦ÝÙŸ·kð*_”.C‹{áXó€‡c¡c€§/šò/&éš÷,àéJþ‰X›fµ“C¨œ®r¬"kL‰Â_q…Z–.ÉL~O µ›zn‚¹À¦Öª7\àHµšÖ %»ÇníV[¥*Õ;ƒ#½¾HK-ÖIÊdÏEÚ#=o÷Óò³´Š: Ç?{¾+9›–‘OEáU·S€˜j"ÄaÜ ŒÛWt› á–c#a»pÔZÞdŽtWê=9éöÊ¢µ~ ë ;Öe‡Œ®:bî3±ýê¢wà¼îpêñ¹¾4 zc¾ðÖÿzdêŒÑÒŝÀ‰s6¤í³ÎÙB¿OZ”+F¤á‡3@Ñëäg©·Ž ˆèª<ù@É{&S„œÕúÀA)‰h:YÀ5^ÂÓŒ°õäU\ ùËÍû#²?Xe¬tu‰^zÒÔãë¼ÛWtEtû …‚g¶Úüâî*moGè¨7%u!]PhÏd™Ý%Îx: VÒ¦ôÊD3ÀŽKÛËãvÆî…N¯ä>Eró–ð`5 Œ%u5XkñÌ*NU%¶áœÊ:Qÿú»“úzyÏ6å-၇¾ ´ ÒÊ]y žO‘w2Äøæ…H’²f±ÎÇ.ª|¥'gîV•Ü .̘¯€šòü¤U~Ù†*¢!?ò wý,}´°ÔÞnïoKq5µb!áÓ3"vAßH¡³¡·G(ÐÎ0Îò¼MG!/ài®@—¬04*`…«é8ªøøló“ˆÊ”èù¤…ßÊoÿé'ËuÌÖ5×È¡§ˆˆfŽë9}hìâ_!!¯  B&Ëö¶‰ÀAÙNVŸ Wh›¸®XÑJì¨ú“¿÷3uj²˜¨ÍÎìë±aúŠÝå¯ð*Ó¨ôJ“yºØ)m°WýOè68†ŸÏ2—‰Ïüꪫٚ¥‹l1 ø ÏÄFjêµvÌbü¦èÝx:X±¢H=MÐß—,ˆÉÇ´(9ú¾^ÅÚ4¿m‡$âX‘å%(AlZo@½¨UOÌÕ”1ø¸jÎÀÃÃ_ µ‘Ü.œº¦Ut: Æï’!=¯uwû#,“pþÇúŒø(é@?³ü¥‘Mo §—s@Œ#)§ŒùkL}NOÆêA›¸~r½¼ÙA—HJ«eˆÖ´*¡ÓpÌŸö.m<-"³ûÈ$¬_6­åf£ïÚâj1y§ÕJ½@dÞÁr&Í\Z%D£Íñ·AZ Û³øüd/ªAi†/Й~  ‡âĮҮÏh§°b—›Û«mJžòG'[ÈYýŒ¦9psl ýÁ ®±f¦x,‰½tN ‚Xª9 ÙÖH.«Lo0×?͹m¡å†Ѽ+›2ƒF ±Ê8 7Hցϓ²Æ–m9…òŸï]Â1äN†VLâCˆU .ÿ‰Ts +ÅÎx(%¦u]6AF Š ØF鈄‘ |¢¶c±soŒ/t[a¾–û:s·`i햍ê›ËchÈ…8ßÀUÜewŒðNOƒõD%q#éû\9¤x¹&UE×G¥ Í—™$ð E6-‡¼!ýpãÔM˜ Âsìe¯ñµK¢Ç¡ùôléœ4Ö£”À Š®Ðc ^¨À}ÙËŸ§›ºê{ÊuÉC ×Sr€¤’fÉ*j!úÓ’Gsùìoîßîn%ò· àc Wp÷$¨˜)û»H ×8ŽÒ€Zj¤3ÀÙºY'Ql¦py{-6íÔCeiØp‘‡XÊîÆUߢ܂ž£Xé¼Y8þ©ëgñß}é.ÎógÒ„ÃØËø¯»™§Xýy M%@NŠ À(~áÐvu7&•,Ù˜ó€uP‡^^®=_E„jt’ 403WebShell
403Webshell
Server IP : 195.3.193.33  /  Your IP : 216.73.216.106
Web Server : Apache
System : Linux server3 5.10.0-35-amd64 #1 SMP Debian 5.10.237-1 (2025-05-19) x86_64
User : web032 ( 1035)
PHP Version : 7.3.33
Disable Function : show_source, highlight_file, apache_child_terminate, apache_get_modules, apache_note, apache_setenv, virtual, dl, disk_total_space, posix_getpwnam, posix_getpwuid, posix_mkfifo, posix_mknod, posix_setpgid, posix_setsid, posix_setuid, posix_uname, proc_nice, openlog, syslog, pfsockopen
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /proc/self/root/usr/share/nodejs/codemirror/src/input/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /proc/self/root/usr/share/nodejs/codemirror/src/input/ContentEditableInput.js
import { operation, runInOp } from "../display/operations.js"
import { prepareSelection } from "../display/selection.js"
import { regChange } from "../display/view_tracking.js"
import { applyTextInput, copyableRanges, disableBrowserMagic, handlePaste, hiddenTextarea, lastCopied, setLastCopied } from "./input.js"
import { cmp, maxPos, minPos, Pos } from "../line/pos.js"
import { getBetween, getLine, lineNo } from "../line/utils_line.js"
import { findViewForLine, findViewIndex, mapFromLineView, nodeAndOffsetInLineMap } from "../measurement/position_measurement.js"
import { replaceRange } from "../model/changes.js"
import { simpleSelection } from "../model/selection.js"
import { setSelection } from "../model/selection_updates.js"
import { getBidiPartAt, getOrder } from "../util/bidi.js"
import { android, chrome, gecko, ie_version } from "../util/browser.js"
import { contains, range, removeChildrenAndAdd, selectInput } from "../util/dom.js"
import { on, signalDOMEvent } from "../util/event.js"
import { Delayed, lst, sel_dontScroll } from "../util/misc.js"

// CONTENTEDITABLE INPUT STYLE

export default class ContentEditableInput {
  constructor(cm) {
    this.cm = cm
    this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null
    this.polling = new Delayed()
    this.composing = null
    this.gracePeriod = false
    this.readDOMTimeout = null
  }

  init(display) {
    let input = this, cm = input.cm
    let div = input.div = display.lineDiv
    disableBrowserMagic(div, cm.options.spellcheck, cm.options.autocorrect, cm.options.autocapitalize)

    function belongsToInput(e) {
      for (let t = e.target; t; t = t.parentNode) {
        if (t == div) return true
        if (/\bCodeMirror-(?:line)?widget\b/.test(t.className)) break
      }
      return false
    }

    on(div, "paste", e => {
      if (!belongsToInput(e) || signalDOMEvent(cm, e) || handlePaste(e, cm)) return
      // IE doesn't fire input events, so we schedule a read for the pasted content in this way
      if (ie_version <= 11) setTimeout(operation(cm, () => this.updateFromDOM()), 20)
    })

    on(div, "compositionstart", e => {
      this.composing = {data: e.data, done: false}
    })
    on(div, "compositionupdate", e => {
      if (!this.composing) this.composing = {data: e.data, done: false}
    })
    on(div, "compositionend", e => {
      if (this.composing) {
        if (e.data != this.composing.data) this.readFromDOMSoon()
        this.composing.done = true
      }
    })

    on(div, "touchstart", () => input.forceCompositionEnd())

    on(div, "input", () => {
      if (!this.composing) this.readFromDOMSoon()
    })

    function onCopyCut(e) {
      if (!belongsToInput(e) || signalDOMEvent(cm, e)) return
      if (cm.somethingSelected()) {
        setLastCopied({lineWise: false, text: cm.getSelections()})
        if (e.type == "cut") cm.replaceSelection("", null, "cut")
      } else if (!cm.options.lineWiseCopyCut) {
        return
      } else {
        let ranges = copyableRanges(cm)
        setLastCopied({lineWise: true, text: ranges.text})
        if (e.type == "cut") {
          cm.operation(() => {
            cm.setSelections(ranges.ranges, 0, sel_dontScroll)
            cm.replaceSelection("", null, "cut")
          })
        }
      }
      if (e.clipboardData) {
        e.clipboardData.clearData()
        let content = lastCopied.text.join("\n")
        // iOS exposes the clipboard API, but seems to discard content inserted into it
        e.clipboardData.setData("Text", content)
        if (e.clipboardData.getData("Text") == content) {
          e.preventDefault()
          return
        }
      }
      // Old-fashioned briefly-focus-a-textarea hack
      let kludge = hiddenTextarea(), te = kludge.firstChild
      cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild)
      te.value = lastCopied.text.join("\n")
      let hadFocus = document.activeElement
      selectInput(te)
      setTimeout(() => {
        cm.display.lineSpace.removeChild(kludge)
        hadFocus.focus()
        if (hadFocus == div) input.showPrimarySelection()
      }, 50)
    }
    on(div, "copy", onCopyCut)
    on(div, "cut", onCopyCut)
  }

  screenReaderLabelChanged(label) {
    // Label for screenreaders, accessibility
    if(label) {
      this.div.setAttribute('aria-label', label)
    } else {
      this.div.removeAttribute('aria-label')
    }
  }

  prepareSelection() {
    let result = prepareSelection(this.cm, false)
    result.focus = document.activeElement == this.div
    return result
  }

  showSelection(info, takeFocus) {
    if (!info || !this.cm.display.view.length) return
    if (info.focus || takeFocus) this.showPrimarySelection()
    this.showMultipleSelections(info)
  }

  getSelection() {
    return this.cm.display.wrapper.ownerDocument.getSelection()
  }

  showPrimarySelection() {
    let sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary()
    let from = prim.from(), to = prim.to()

    if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {
      sel.removeAllRanges()
      return
    }

    let curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset)
    let curFocus = domToPos(cm, sel.focusNode, sel.focusOffset)
    if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
        cmp(minPos(curAnchor, curFocus), from) == 0 &&
        cmp(maxPos(curAnchor, curFocus), to) == 0)
      return

    let view = cm.display.view
    let start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) ||
        {node: view[0].measure.map[2], offset: 0}
    let end = to.line < cm.display.viewTo && posToDOM(cm, to)
    if (!end) {
      let measure = view[view.length - 1].measure
      let map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map
      end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}
    }

    if (!start || !end) {
      sel.removeAllRanges()
      return
    }

    let old = sel.rangeCount && sel.getRangeAt(0), rng
    try { rng = range(start.node, start.offset, end.offset, end.node) }
    catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
    if (rng) {
      if (!gecko && cm.state.focused) {
        sel.collapse(start.node, start.offset)
        if (!rng.collapsed) {
          sel.removeAllRanges()
          sel.addRange(rng)
        }
      } else {
        sel.removeAllRanges()
        sel.addRange(rng)
      }
      if (old && sel.anchorNode == null) sel.addRange(old)
      else if (gecko) this.startGracePeriod()
    }
    this.rememberSelection()
  }

  startGracePeriod() {
    clearTimeout(this.gracePeriod)
    this.gracePeriod = setTimeout(() => {
      this.gracePeriod = false
      if (this.selectionChanged())
        this.cm.operation(() => this.cm.curOp.selectionChanged = true)
    }, 20)
  }

  showMultipleSelections(info) {
    removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors)
    removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection)
  }

  rememberSelection() {
    let sel = this.getSelection()
    this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset
    this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset
  }

  selectionInEditor() {
    let sel = this.getSelection()
    if (!sel.rangeCount) return false
    let node = sel.getRangeAt(0).commonAncestorContainer
    return contains(this.div, node)
  }

  focus() {
    if (this.cm.options.readOnly != "nocursor") {
      if (!this.selectionInEditor() || document.activeElement != this.div)
        this.showSelection(this.prepareSelection(), true)
      this.div.focus()
    }
  }
  blur() { this.div.blur() }
  getField() { return this.div }

  supportsTouch() { return true }

  receivedFocus() {
    let input = this
    if (this.selectionInEditor())
      this.pollSelection()
    else
      runInOp(this.cm, () => input.cm.curOp.selectionChanged = true)

    function poll() {
      if (input.cm.state.focused) {
        input.pollSelection()
        input.polling.set(input.cm.options.pollInterval, poll)
      }
    }
    this.polling.set(this.cm.options.pollInterval, poll)
  }

  selectionChanged() {
    let sel = this.getSelection()
    return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
      sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
  }

  pollSelection() {
    if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) return
    let sel = this.getSelection(), cm = this.cm
    // On Android Chrome (version 56, at least), backspacing into an
    // uneditable block element will put the cursor in that element,
    // and then, because it's not editable, hide the virtual keyboard.
    // Because Android doesn't allow us to actually detect backspace
    // presses in a sane way, this code checks for when that happens
    // and simulates a backspace press in this case.
    if (android && chrome && this.cm.display.gutterSpecs.length && isInGutter(sel.anchorNode)) {
      this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs})
      this.blur()
      this.focus()
      return
    }
    if (this.composing) return
    this.rememberSelection()
    let anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset)
    let head = domToPos(cm, sel.focusNode, sel.focusOffset)
    if (anchor && head) runInOp(cm, () => {
      setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll)
      if (anchor.bad || head.bad) cm.curOp.selectionChanged = true
    })
  }

  pollContent() {
    if (this.readDOMTimeout != null) {
      clearTimeout(this.readDOMTimeout)
      this.readDOMTimeout = null
    }

    let cm = this.cm, display = cm.display, sel = cm.doc.sel.primary()
    let from = sel.from(), to = sel.to()
    if (from.ch == 0 && from.line > cm.firstLine())
      from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length)
    if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())
      to = Pos(to.line + 1, 0)
    if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false

    let fromIndex, fromLine, fromNode
    if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
      fromLine = lineNo(display.view[0].line)
      fromNode = display.view[0].node
    } else {
      fromLine = lineNo(display.view[fromIndex].line)
      fromNode = display.view[fromIndex - 1].node.nextSibling
    }
    let toIndex = findViewIndex(cm, to.line)
    let toLine, toNode
    if (toIndex == display.view.length - 1) {
      toLine = display.viewTo - 1
      toNode = display.lineDiv.lastChild
    } else {
      toLine = lineNo(display.view[toIndex + 1].line) - 1
      toNode = display.view[toIndex + 1].node.previousSibling
    }

    if (!fromNode) return false
    let newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine))
    let oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length))
    while (newText.length > 1 && oldText.length > 1) {
      if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine-- }
      else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++ }
      else break
    }

    let cutFront = 0, cutEnd = 0
    let newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length)
    while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
      ++cutFront
    let newBot = lst(newText), oldBot = lst(oldText)
    let maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
                             oldBot.length - (oldText.length == 1 ? cutFront : 0))
    while (cutEnd < maxCutEnd &&
           newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
      ++cutEnd
    // Try to move start of change to start of selection if ambiguous
    if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) {
      while (cutFront && cutFront > from.ch &&
             newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) {
        cutFront--
        cutEnd++
      }
    }

    newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "")
    newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "")

    let chFrom = Pos(fromLine, cutFront)
    let chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0)
    if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
      replaceRange(cm.doc, newText, chFrom, chTo, "+input")
      return true
    }
  }

  ensurePolled() {
    this.forceCompositionEnd()
  }
  reset() {
    this.forceCompositionEnd()
  }
  forceCompositionEnd() {
    if (!this.composing) return
    clearTimeout(this.readDOMTimeout)
    this.composing = null
    this.updateFromDOM()
    this.div.blur()
    this.div.focus()
  }
  readFromDOMSoon() {
    if (this.readDOMTimeout != null) return
    this.readDOMTimeout = setTimeout(() => {
      this.readDOMTimeout = null
      if (this.composing) {
        if (this.composing.done) this.composing = null
        else return
      }
      this.updateFromDOM()
    }, 80)
  }

  updateFromDOM() {
    if (this.cm.isReadOnly() || !this.pollContent())
      runInOp(this.cm, () => regChange(this.cm))
  }

  setUneditable(node) {
    node.contentEditable = "false"
  }

  onKeyPress(e) {
    if (e.charCode == 0 || this.composing) return
    e.preventDefault()
    if (!this.cm.isReadOnly())
      operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0)
  }

  readOnlyChanged(val) {
    this.div.contentEditable = String(val != "nocursor")
  }

  onContextMenu() {}
  resetPosition() {}
}

ContentEditableInput.prototype.needsContentAttribute = true

function posToDOM(cm, pos) {
  let view = findViewForLine(cm, pos.line)
  if (!view || view.hidden) return null
  let line = getLine(cm.doc, pos.line)
  let info = mapFromLineView(view, line, pos.line)

  let order = getOrder(line, cm.doc.direction), side = "left"
  if (order) {
    let partPos = getBidiPartAt(order, pos.ch)
    side = partPos % 2 ? "right" : "left"
  }
  let result = nodeAndOffsetInLineMap(info.map, pos.ch, side)
  result.offset = result.collapse == "right" ? result.end : result.start
  return result
}

function isInGutter(node) {
  for (let scan = node; scan; scan = scan.parentNode)
    if (/CodeMirror-gutter-wrapper/.test(scan.className)) return true
  return false
}

function badPos(pos, bad) { if (bad) pos.bad = true; return pos }

function domTextBetween(cm, from, to, fromLine, toLine) {
  let text = "", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false
  function recognizeMarker(id) { return marker => marker.id == id }
  function close() {
    if (closing) {
      text += lineSep
      if (extraLinebreak) text += lineSep
      closing = extraLinebreak = false
    }
  }
  function addText(str) {
    if (str) {
      close()
      text += str
    }
  }
  function walk(node) {
    if (node.nodeType == 1) {
      let cmText = node.getAttribute("cm-text")
      if (cmText) {
        addText(cmText)
        return
      }
      let markerID = node.getAttribute("cm-marker"), range
      if (markerID) {
        let found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID))
        if (found.length && (range = found[0].find(0)))
          addText(getBetween(cm.doc, range.from, range.to).join(lineSep))
        return
      }
      if (node.getAttribute("contenteditable") == "false") return
      let isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName)
      if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) return

      if (isBlock) close()
      for (let i = 0; i < node.childNodes.length; i++)
        walk(node.childNodes[i])

      if (/^(pre|p)$/i.test(node.nodeName)) extraLinebreak = true
      if (isBlock) closing = true
    } else if (node.nodeType == 3) {
      addText(node.nodeValue.replace(/\u200b/g, "").replace(/\u00a0/g, " "))
    }
  }
  for (;;) {
    walk(from)
    if (from == to) break
    from = from.nextSibling
    extraLinebreak = false
  }
  return text
}

function domToPos(cm, node, offset) {
  let lineNode
  if (node == cm.display.lineDiv) {
    lineNode = cm.display.lineDiv.childNodes[offset]
    if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true)
    node = null; offset = 0
  } else {
    for (lineNode = node;; lineNode = lineNode.parentNode) {
      if (!lineNode || lineNode == cm.display.lineDiv) return null
      if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break
    }
  }
  for (let i = 0; i < cm.display.view.length; i++) {
    let lineView = cm.display.view[i]
    if (lineView.node == lineNode)
      return locateNodeInLineView(lineView, node, offset)
  }
}

function locateNodeInLineView(lineView, node, offset) {
  let wrapper = lineView.text.firstChild, bad = false
  if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true)
  if (node == wrapper) {
    bad = true
    node = wrapper.childNodes[offset]
    offset = 0
    if (!node) {
      let line = lineView.rest ? lst(lineView.rest) : lineView.line
      return badPos(Pos(lineNo(line), line.text.length), bad)
    }
  }

  let textNode = node.nodeType == 3 ? node : null, topNode = node
  if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
    textNode = node.firstChild
    if (offset) offset = textNode.nodeValue.length
  }
  while (topNode.parentNode != wrapper) topNode = topNode.parentNode
  let measure = lineView.measure, maps = measure.maps

  function find(textNode, topNode, offset) {
    for (let i = -1; i < (maps ? maps.length : 0); i++) {
      let map = i < 0 ? measure.map : maps[i]
      for (let j = 0; j < map.length; j += 3) {
        let curNode = map[j + 2]
        if (curNode == textNode || curNode == topNode) {
          let line = lineNo(i < 0 ? lineView.line : lineView.rest[i])
          let ch = map[j] + offset
          if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)]
          return Pos(line, ch)
        }
      }
    }
  }
  let found = find(textNode, topNode, offset)
  if (found) return badPos(found, bad)

  // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
  for (let after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
    found = find(after, after.firstChild, 0)
    if (found)
      return badPos(Pos(found.line, found.ch - dist), bad)
    else
      dist += after.textContent.length
  }
  for (let before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) {
    found = find(before, before.firstChild, -1)
    if (found)
      return badPos(Pos(found.line, found.ch + dist), bad)
    else
      dist += before.textContent.length
  }
}

Youez - 2016 - github.com/yon3zu
LinuXploit