openrat-cms

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

options.js (6925B)


      1 import { onBlur } from "../display/focus.js"
      2 import { setGuttersForLineNumbers, updateGutters } from "../display/gutters.js"
      3 import { alignHorizontally } from "../display/line_numbers.js"
      4 import { loadMode, resetModeState } from "../display/mode_state.js"
      5 import { initScrollbars, updateScrollbars } from "../display/scrollbars.js"
      6 import { updateSelection } from "../display/selection.js"
      7 import { regChange } from "../display/view_tracking.js"
      8 import { getKeyMap } from "../input/keymap.js"
      9 import { defaultSpecialCharPlaceholder } from "../line/line_data.js"
     10 import { Pos } from "../line/pos.js"
     11 import { findMaxLine } from "../line/spans.js"
     12 import { clearCaches, compensateForHScroll, estimateLineHeights } from "../measurement/position_measurement.js"
     13 import { replaceRange } from "../model/changes.js"
     14 import { mobile, windows } from "../util/browser.js"
     15 import { addClass, rmClass } from "../util/dom.js"
     16 import { off, on } from "../util/event.js"
     17 
     18 import { themeChanged } from "./utils.js"
     19 
     20 export let Init = {toString: function(){return "CodeMirror.Init"}}
     21 
     22 export let defaults = {}
     23 export let optionHandlers = {}
     24 
     25 export function defineOptions(CodeMirror) {
     26   let optionHandlers = CodeMirror.optionHandlers
     27 
     28   function option(name, deflt, handle, notOnInit) {
     29     CodeMirror.defaults[name] = deflt
     30     if (handle) optionHandlers[name] =
     31       notOnInit ? (cm, val, old) => {if (old != Init) handle(cm, val, old)} : handle
     32   }
     33 
     34   CodeMirror.defineOption = option
     35 
     36   // Passed to option handlers when there is no old value.
     37   CodeMirror.Init = Init
     38 
     39   // These two are, on init, called from the constructor because they
     40   // have to be initialized before the editor can start at all.
     41   option("value", "", (cm, val) => cm.setValue(val), true)
     42   option("mode", null, (cm, val) => {
     43     cm.doc.modeOption = val
     44     loadMode(cm)
     45   }, true)
     46 
     47   option("indentUnit", 2, loadMode, true)
     48   option("indentWithTabs", false)
     49   option("smartIndent", true)
     50   option("tabSize", 4, cm => {
     51     resetModeState(cm)
     52     clearCaches(cm)
     53     regChange(cm)
     54   }, true)
     55   option("lineSeparator", null, (cm, val) => {
     56     cm.doc.lineSep = val
     57     if (!val) return
     58     let newBreaks = [], lineNo = cm.doc.first
     59     cm.doc.iter(line => {
     60       for (let pos = 0;;) {
     61         let found = line.text.indexOf(val, pos)
     62         if (found == -1) break
     63         pos = found + val.length
     64         newBreaks.push(Pos(lineNo, found))
     65       }
     66       lineNo++
     67     })
     68     for (let i = newBreaks.length - 1; i >= 0; i--)
     69       replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length))
     70   })
     71   option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, (cm, val, old) => {
     72     cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g")
     73     if (old != Init) cm.refresh()
     74   })
     75   option("specialCharPlaceholder", defaultSpecialCharPlaceholder, cm => cm.refresh(), true)
     76   option("electricChars", true)
     77   option("inputStyle", mobile ? "contenteditable" : "textarea", () => {
     78     throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME
     79   }, true)
     80   option("spellcheck", false, (cm, val) => cm.getInputField().spellcheck = val, true)
     81   option("rtlMoveVisually", !windows)
     82   option("wholeLineUpdateBefore", true)
     83 
     84   option("theme", "default", cm => {
     85     themeChanged(cm)
     86     guttersChanged(cm)
     87   }, true)
     88   option("keyMap", "default", (cm, val, old) => {
     89     let next = getKeyMap(val)
     90     let prev = old != Init && getKeyMap(old)
     91     if (prev && prev.detach) prev.detach(cm, next)
     92     if (next.attach) next.attach(cm, prev || null)
     93   })
     94   option("extraKeys", null)
     95   option("configureMouse", null)
     96 
     97   option("lineWrapping", false, wrappingChanged, true)
     98   option("gutters", [], cm => {
     99     setGuttersForLineNumbers(cm.options)
    100     guttersChanged(cm)
    101   }, true)
    102   option("fixedGutter", true, (cm, val) => {
    103     cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"
    104     cm.refresh()
    105   }, true)
    106   option("coverGutterNextToScrollbar", false, cm => updateScrollbars(cm), true)
    107   option("scrollbarStyle", "native", cm => {
    108     initScrollbars(cm)
    109     updateScrollbars(cm)
    110     cm.display.scrollbars.setScrollTop(cm.doc.scrollTop)
    111     cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft)
    112   }, true)
    113   option("lineNumbers", false, cm => {
    114     setGuttersForLineNumbers(cm.options)
    115     guttersChanged(cm)
    116   }, true)
    117   option("firstLineNumber", 1, guttersChanged, true)
    118   option("lineNumberFormatter", integer => integer, guttersChanged, true)
    119   option("showCursorWhenSelecting", false, updateSelection, true)
    120 
    121   option("resetSelectionOnContextMenu", true)
    122   option("lineWiseCopyCut", true)
    123   option("pasteLinesPerSelection", true)
    124 
    125   option("readOnly", false, (cm, val) => {
    126     if (val == "nocursor") {
    127       onBlur(cm)
    128       cm.display.input.blur()
    129     }
    130     cm.display.input.readOnlyChanged(val)
    131   })
    132   option("disableInput", false, (cm, val) => {if (!val) cm.display.input.reset()}, true)
    133   option("dragDrop", true, dragDropChanged)
    134   option("allowDropFileTypes", null)
    135 
    136   option("cursorBlinkRate", 530)
    137   option("cursorScrollMargin", 0)
    138   option("cursorHeight", 1, updateSelection, true)
    139   option("singleCursorHeightPerLine", true, updateSelection, true)
    140   option("workTime", 100)
    141   option("workDelay", 100)
    142   option("flattenSpans", true, resetModeState, true)
    143   option("addModeClass", false, resetModeState, true)
    144   option("pollInterval", 100)
    145   option("undoDepth", 200, (cm, val) => cm.doc.history.undoDepth = val)
    146   option("historyEventDelay", 1250)
    147   option("viewportMargin", 10, cm => cm.refresh(), true)
    148   option("maxHighlightLength", 10000, resetModeState, true)
    149   option("moveInputWithCursor", true, (cm, val) => {
    150     if (!val) cm.display.input.resetPosition()
    151   })
    152 
    153   option("tabindex", null, (cm, val) => cm.display.input.getField().tabIndex = val || "")
    154   option("autofocus", null)
    155   option("direction", "ltr", (cm, val) => cm.doc.setDirection(val), true)
    156 }
    157 
    158 function guttersChanged(cm) {
    159   updateGutters(cm)
    160   regChange(cm)
    161   alignHorizontally(cm)
    162 }
    163 
    164 function dragDropChanged(cm, value, old) {
    165   let wasOn = old && old != Init
    166   if (!value != !wasOn) {
    167     let funcs = cm.display.dragFunctions
    168     let toggle = value ? on : off
    169     toggle(cm.display.scroller, "dragstart", funcs.start)
    170     toggle(cm.display.scroller, "dragenter", funcs.enter)
    171     toggle(cm.display.scroller, "dragover", funcs.over)
    172     toggle(cm.display.scroller, "dragleave", funcs.leave)
    173     toggle(cm.display.scroller, "drop", funcs.drop)
    174   }
    175 }
    176 
    177 function wrappingChanged(cm) {
    178   if (cm.options.lineWrapping) {
    179     addClass(cm.display.wrapper, "CodeMirror-wrap")
    180     cm.display.sizer.style.minWidth = ""
    181     cm.display.sizerWidth = null
    182   } else {
    183     rmClass(cm.display.wrapper, "CodeMirror-wrap")
    184     findMaxLine(cm)
    185   }
    186   estimateLineHeights(cm)
    187   regChange(cm)
    188   clearCaches(cm)
    189   setTimeout(() => updateScrollbars(cm), 100)
    190 }