openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

CodeMirror.min.js (8581B)


      1 import { Display } from "../display/Display.js"
      2 import { onFocus, onBlur } from "../display/focus.js"
      3 import { setGuttersForLineNumbers, updateGutters } from "../display/gutters.js"
      4 import { maybeUpdateLineNumberWidth } from "../display/line_numbers.js"
      5 import { endOperation, operation, startOperation } from "../display/operations.js"
      6 import { initScrollbars } from "../display/scrollbars.js"
      7 import { onScrollWheel } from "../display/scroll_events.js"
      8 import { setScrollLeft, updateScrollTop } from "../display/scrolling.js"
      9 import { clipPos, Pos } from "../line/pos.js"
     10 import { posFromMouse } from "../measurement/position_measurement.js"
     11 import { eventInWidget } from "../measurement/widgets.js"
     12 import Doc from "../model/Doc.js"
     13 import { attachDoc } from "../model/document_data.js"
     14 import { Range } from "../model/selection.js"
     15 import { extendSelection } from "../model/selection_updates.js"
     16 import { captureRightClick, ie, ie_version, mobile, webkit } from "../util/browser.js"
     17 import { e_preventDefault, e_stop, on, signal, signalDOMEvent } from "../util/event.js"
     18 import { bind, copyObj, Delayed } from "../util/misc.js"
     19 
     20 import { clearDragCursor, onDragOver, onDragStart, onDrop } from "./drop_events.js"
     21 import { ensureGlobalHandlers } from "./global_events.js"
     22 import { onKeyDown, onKeyPress, onKeyUp } from "./key_events.js"
     23 import { clickInGutter, onContextMenu, onMouseDown } from "./mouse_events.js"
     24 import { themeChanged } from "./utils.js"
     25 import { defaults, optionHandlers, Init } from "./options.js"
     26 
     27 // A CodeMirror instance represents an editor. This is the object
     28 // that user code is usually dealing with.
     29 
     30 export function CodeMirror(place, options) {
     31   if (!(this instanceof CodeMirror)) return new CodeMirror(place, options)
     32 
     33   this.options = options = options ? copyObj(options) : {}
     34   // Determine effective options based on given values and defaults.
     35   copyObj(defaults, options, false)
     36   setGuttersForLineNumbers(options)
     37 
     38   let doc = options.value
     39   if (typeof doc == "string") doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction)
     40   this.doc = doc
     41 
     42   let input = new CodeMirror.inputStyles[options.inputStyle](this)
     43   let display = this.display = new Display(place, doc, input)
     44   display.wrapper.CodeMirror = this
     45   updateGutters(this)
     46   themeChanged(this)
     47   if (options.lineWrapping)
     48     this.display.wrapper.className += " CodeMirror-wrap"
     49   initScrollbars(this)
     50 
     51   this.state = {
     52     keyMaps: [],  // stores maps added by addKeyMap
     53     overlays: [], // highlighting overlays, as added by addOverlay
     54     modeGen: 0,   // bumped when mode/overlay changes, used to invalidate highlighting info
     55     overwrite: false,
     56     delayingBlurEvent: false,
     57     focused: false,
     58     suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
     59     pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
     60     selectingText: false,
     61     draggingText: false,
     62     highlight: new Delayed(), // stores highlight worker timeout
     63     keySeq: null,  // Unfinished key sequence
     64     specialChars: null
     65   }
     66 
     67   if (options.autofocus && !mobile) display.input.focus()
     68 
     69   // Override magic textarea content restore that IE sometimes does
     70   // on our hidden textarea on reload
     71   if (ie && ie_version < 11) setTimeout(() => this.display.input.reset(true), 20)
     72 
     73   registerEventHandlers(this)
     74   ensureGlobalHandlers()
     75 
     76   startOperation(this)
     77   this.curOp.forceUpdate = true
     78   attachDoc(this, doc)
     79 
     80   if ((options.autofocus && !mobile) || this.hasFocus())
     81     setTimeout(bind(onFocus, this), 20)
     82   else
     83     onBlur(this)
     84 
     85   for (let opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
     86     optionHandlers[opt](this, options[opt], Init)
     87   maybeUpdateLineNumberWidth(this)
     88   if (options.finishInit) options.finishInit(this)
     89   for (let i = 0; i < initHooks.length; ++i) initHooks[i](this)
     90   endOperation(this)
     91   // Suppress optimizelegibility in Webkit, since it breaks text
     92   // measuring on line wrapping boundaries.
     93   if (webkit && options.lineWrapping &&
     94       getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
     95     display.lineDiv.style.textRendering = "auto"
     96 }
     97 
     98 // The default configuration options.
     99 CodeMirror.defaults = defaults
    100 // Functions to run when options are changed.
    101 CodeMirror.optionHandlers = optionHandlers
    102 
    103 export default CodeMirror
    104 
    105 // Attach the necessary event handlers when initializing the editor
    106 function registerEventHandlers(cm) {
    107   let d = cm.display
    108   on(d.scroller, "mousedown", operation(cm, onMouseDown))
    109   // Older IE's will not fire a second mousedown for a double click
    110   if (ie && ie_version < 11)
    111     on(d.scroller, "dblclick", operation(cm, e => {
    112       if (signalDOMEvent(cm, e)) return
    113       let pos = posFromMouse(cm, e)
    114       if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return
    115       e_preventDefault(e)
    116       let word = cm.findWordAt(pos)
    117       extendSelection(cm.doc, word.anchor, word.head)
    118     }))
    119   else
    120     on(d.scroller, "dblclick", e => signalDOMEvent(cm, e) || e_preventDefault(e))
    121   // Some browsers fire contextmenu *after* opening the menu, at
    122   // which point we can't mess with it anymore. Context menu is
    123   // handled in onMouseDown for these browsers.
    124   if (!captureRightClick) on(d.scroller, "contextmenu", e => onContextMenu(cm, e))
    125 
    126   // Used to suppress mouse event handling when a touch happens
    127   let touchFinished, prevTouch = {end: 0}
    128   function finishTouch() {
    129     if (d.activeTouch) {
    130       touchFinished = setTimeout(() => d.activeTouch = null, 1000)
    131       prevTouch = d.activeTouch
    132       prevTouch.end = +new Date
    133     }
    134   }
    135   function isMouseLikeTouchEvent(e) {
    136     if (e.touches.length != 1) return false
    137     let touch = e.touches[0]
    138     return touch.radiusX <= 1 && touch.radiusY <= 1
    139   }
    140   function farAway(touch, other) {
    141     if (other.left == null) return true
    142     let dx = other.left - touch.left, dy = other.top - touch.top
    143     return dx * dx + dy * dy > 20 * 20
    144   }
    145   on(d.scroller, "touchstart", e => {
    146     if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {
    147       d.input.ensurePolled()
    148       clearTimeout(touchFinished)
    149       let now = +new Date
    150       d.activeTouch = {start: now, moved: false,
    151                        prev: now - prevTouch.end <= 300 ? prevTouch : null}
    152       if (e.touches.length == 1) {
    153         d.activeTouch.left = e.touches[0].pageX
    154         d.activeTouch.top = e.touches[0].pageY
    155       }
    156     }
    157   })
    158   on(d.scroller, "touchmove", () => {
    159     if (d.activeTouch) d.activeTouch.moved = true
    160   })
    161   on(d.scroller, "touchend", e => {
    162     let touch = d.activeTouch
    163     if (touch && !eventInWidget(d, e) && touch.left != null &&
    164         !touch.moved && new Date - touch.start < 300) {
    165       let pos = cm.coordsChar(d.activeTouch, "page"), range
    166       if (!touch.prev || farAway(touch, touch.prev)) // Single tap
    167         range = new Range(pos, pos)
    168       else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
    169         range = cm.findWordAt(pos)
    170       else // Triple tap
    171         range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0)))
    172       cm.setSelection(range.anchor, range.head)
    173       cm.focus()
    174       e_preventDefault(e)
    175     }
    176     finishTouch()
    177   })
    178   on(d.scroller, "touchcancel", finishTouch)
    179 
    180   // Sync scrolling between fake scrollbars and real scrollable
    181   // area, ensure viewport is updated when scrolling.
    182   on(d.scroller, "scroll", () => {
    183     if (d.scroller.clientHeight) {
    184       updateScrollTop(cm, d.scroller.scrollTop)
    185       setScrollLeft(cm, d.scroller.scrollLeft, true)
    186       signal(cm, "scroll", cm)
    187     }
    188   })
    189 
    190   // Listen to wheel events in order to try and update the viewport on time.
    191   on(d.scroller, "mousewheel", e => onScrollWheel(cm, e))
    192   on(d.scroller, "DOMMouseScroll", e => onScrollWheel(cm, e))
    193 
    194   // Prevent wrapper from ever scrolling
    195   on(d.wrapper, "scroll", () => d.wrapper.scrollTop = d.wrapper.scrollLeft = 0)
    196 
    197   d.dragFunctions = {
    198     enter: e => {if (!signalDOMEvent(cm, e)) e_stop(e)},
    199     over: e => {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e) }},
    200     start: e => onDragStart(cm, e),
    201     drop: operation(cm, onDrop),
    202     leave: e => {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm) }}
    203   }
    204 
    205   let inp = d.input.getField()
    206   on(inp, "keyup", e => onKeyUp.call(cm, e))
    207   on(inp, "keydown", operation(cm, onKeyDown))
    208   on(inp, "keypress", operation(cm, onKeyPress))
    209   on(inp, "focus", e => onFocus(cm, e))
    210   on(inp, "blur", e => onBlur(cm, e))
    211 }
    212 
    213 let initHooks = []
    214 CodeMirror.defineInitHook = f => initHooks.push(f)