MailChimp for WordPress - Version 4.0.7

Version Description

Download this release

Release Info

Developer DvanKooten
Plugin Icon 128x128 MailChimp for WordPress
Version 4.0.7
Comparing to
See all releases

Code changes from version 4.0.6 to 4.0.7

CHANGELOG.md CHANGED
@@ -1,6 +1,22 @@
1
  Changelog
2
  =========
3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  #### 4.0.6 - October 10, 2016
5
 
6
  **Fixes**
1
  Changelog
2
  =========
3
 
4
+ #### 4.0.7 - October 25, 2016
5
+
6
+ **Improvements**
7
+
8
+ - Obfuscate all email addresses in debug log. Thanks [Sauli Lepola](https://twitter.com/SJLfi).
9
+ - Ask for confirmation before disabling double opt-in, which we do not recommend.
10
+ - Allow vertical resizing of debug log.
11
+ - Failsafe against including JavaScript file twice.
12
+ - No longer wrapping CF7 checkbox in paragraph tags.
13
+
14
+ **Additions**
15
+
16
+ - Added `mc4wp_form_api_error` action hook for API errors encountered by forms.
17
+ - Added `element_class` argument to `[mc4wp_form]` shortcode for adding CSS classes.
18
+
19
+
20
  #### 4.0.6 - October 10, 2016
21
 
22
  **Fixes**
assets/css/admin-styles.css CHANGED
@@ -160,6 +160,10 @@
160
  background: #d9edf7;
161
  border: 1px solid #bce8f1;
162
  margin: 1em 0 !important; }
 
 
 
 
163
  #mc4wp-admin .column-ID,
164
  .mc4wp-admin .column-ID {
165
  width: 10%; }
@@ -798,3 +802,8 @@
798
  .rtl #mc4wp-admin .CodeMirror-vscrollbar {
799
  left: 0 !important;
800
  right: auto !important; }
 
 
 
 
 
160
  background: #d9edf7;
161
  border: 1px solid #bce8f1;
162
  margin: 1em 0 !important; }
163
+ #mc4wp-admin .mc4wp-is-dismissible,
164
+ .mc4wp-admin .mc4wp-is-dismissible {
165
+ padding-right: 38px;
166
+ position: relative; }
167
  #mc4wp-admin .column-ID,
168
  .mc4wp-admin .column-ID {
169
  width: 10%; }
802
  .rtl #mc4wp-admin .CodeMirror-vscrollbar {
803
  left: 0 !important;
804
  right: auto !important; }
805
+
806
+ .rtl .mc4wp-is-dismissible {
807
+ padding-left: 38px;
808
+ padding-right: initial;
809
+ position: relative; }
assets/css/admin-styles.min.css CHANGED
@@ -1 +1 @@
1
- #mc4wp-admin .available-fields .in-form,#mc4wp-admin .hover-activated,.mc4wp-admin .available-fields .in-form,.mc4wp-admin .hover-activated{opacity:.5}#mc4wp-admin .cm-em,#mc4wp-admin .help,.mc4wp-admin .cm-em,.mc4wp-admin .help{font-style:italic}#mc4wp-admin .row,.mc4wp-admin .row{margin-left:-20px;margin-right:-20px;float:none}#mc4wp-admin .row .col,.mc4wp-admin .row .col{padding:0 20px;float:left;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#mc4wp-admin .row .col-1,.mc4wp-admin .row .col-1{width:16.666%}#mc4wp-admin .row .col-2,.mc4wp-admin .row .col-2{width:33.333%}#mc4wp-admin .row .col-3,.mc4wp-admin .row .col-3{width:50%}#mc4wp-admin .row .col-4,.mc4wp-admin .row .col-4{width:66.666%}#mc4wp-admin .row .col-5,.mc4wp-admin .row .col-5{width:83.333%}#mc4wp-admin .row .col-6,.mc4wp-admin .row .col-6{width:100%}#mc4wp-admin .clearfix:after,#mc4wp-admin .clearfix:before,#mc4wp-admin .row:after,#mc4wp-admin .row:before,.mc4wp-admin .clearfix:after,.mc4wp-admin .clearfix:before,.mc4wp-admin .row:after,.mc4wp-admin .row:before{content:" ";display:table}#mc4wp-admin .clearfix:after,#mc4wp-admin .row:after,.mc4wp-admin .clearfix:after,.mc4wp-admin .row:after{clear:both}@media (max-width:1200px){#mc4wp-admin .row .col,.mc4wp-admin .row .col{width:100%;float:none;margin:10px 0}}#mc4wp-admin .status,.mc4wp-admin .status{display:inline-block;margin-left:1em;padding:3px 6px;color:#fff;font-size:12px;font-weight:700}#mc4wp-admin .status.positive,.mc4wp-admin .status.positive{background-color:#32cd32}#mc4wp-admin .status.negative,.mc4wp-admin .status.negative{background-color:red}#mc4wp-admin .status.neutral,.mc4wp-admin .status.neutral{background:gray}#mc4wp-admin .valigntop,.mc4wp-admin .valigntop{vertical-align:top!important}#mc4wp-admin .big-margin,.mc4wp-admin .big-margin{margin-top:60px;margin-bottom:60px}#mc4wp-admin .medium-margin,.mc4wp-admin .medium-margin{margin-top:40px;margin-bottom:40px}#mc4wp-admin .small-margin,.mc4wp-admin .small-margin{margin-top:20px;margin-bottom:20px}#mc4wp-admin .tiny-margin,.mc4wp-admin .tiny-margin{margin-top:10px;margin-bottom:10px}#mc4wp-admin .hover-activated:hover,.mc4wp-admin .hover-activated:hover{cursor:pointer;opacity:1}#mc4wp-admin .help-text,.mc4wp-admin .help-text{font-size:14px}#mc4wp-admin .help-text p,.mc4wp-admin .help-text p{margin:10px 0;font-size:14px}#mc4wp-admin .help-text ul,.mc4wp-admin .help-text ul{list-style:square;margin-top:15px;padding-left:40px}#mc4wp-admin .muted,.mc4wp-admin .muted{color:#aaa}#mc4wp-admin .red,.mc4wp-admin .red{color:red}#mc4wp-admin .green,.mc4wp-admin .green{color:#32cd32}#mc4wp-admin .mc4wp-notice,.mc4wp-admin .mc4wp-notice{padding:6px 12px;color:#31708f;background:#d9edf7;border:1px solid #bce8f1;margin:1em 0!important}#mc4wp-admin .column-ID,.mc4wp-admin .column-ID{width:10%}#mc4wp-admin .block,.mc4wp-admin .block{display:block}#mc4wp-admin .code-sample,.mc4wp-admin .code-sample{font-family:Consolas,Monaco,Lucida Console,monospace;font-size:12px;background:#fff}#mc4wp-admin .breadcrumbs,.mc4wp-admin .breadcrumbs{border-bottom:1px solid #ccc;padding-bottom:1em}#mc4wp-admin .mc4wp-loader,.mc4wp-admin .mc4wp-loader{position:relative;display:inline-block;text-indent:-9999999px;border:3px solid rgba(0,0,0,.2);border-left-color:#000;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:load8 1.1s infinite linear;animation:load8 1.1s infinite linear;overflow:hidden;border-radius:50%;vertical-align:middle;width:12px;height:12px;margin-bottom:3px;margin-left:3px;margin-right:3px}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load8{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}#mc4wp-admin .tab,.mc4wp-admin .tab{display:none;background:inherit;border:none;font-weight:initial}#mc4wp-admin .tab.tab-active,.mc4wp-admin .tab.tab-active{display:block}#mc4wp-admin .tab h2,.mc4wp-admin .tab h2{margin-top:20px}#mc4wp-admin .CodeMirror,.mc4wp-admin .CodeMirror{font-family:monospace;height:300px;color:#000}#mc4wp-admin .CodeMirror-lines,.mc4wp-admin .CodeMirror-lines{padding:4px 0}#mc4wp-admin .CodeMirror pre,.mc4wp-admin .CodeMirror pre{padding:0 4px}#mc4wp-admin .CodeMirror-gutter-filler,#mc4wp-admin .CodeMirror-scrollbar-filler,.mc4wp-admin .CodeMirror-gutter-filler,.mc4wp-admin .CodeMirror-scrollbar-filler{background-color:#fff}#mc4wp-admin .CodeMirror-gutters,.mc4wp-admin .CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}#mc4wp-admin .CodeMirror-linenumber,.mc4wp-admin .CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}#mc4wp-admin .CodeMirror-guttermarker,.mc4wp-admin .CodeMirror-guttermarker{color:#000}#mc4wp-admin .CodeMirror-guttermarker-subtle,.mc4wp-admin .CodeMirror-guttermarker-subtle{color:#999}#mc4wp-admin .CodeMirror-cursor,.mc4wp-admin .CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}#mc4wp-admin .CodeMirror div.CodeMirror-secondarycursor,.mc4wp-admin .CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}#mc4wp-admin .cm-fat-cursor .CodeMirror-cursor,.mc4wp-admin .cm-fat-cursor .CodeMirror-cursor{width:auto;border:0;background:#7e7}#mc4wp-admin .cm-fat-cursor div.CodeMirror-cursors,.mc4wp-admin .cm-fat-cursor div.CodeMirror-cursors{z-index:1}#mc4wp-admin .cm-animate-fat-cursor,.mc4wp-admin .cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}#mc4wp-admin .field-wizard td.stretch,.mc4wp-admin .field-wizard td.stretch,.overlay{width:100%}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}#mc4wp-admin .cm-tab,.mc4wp-admin .cm-tab{display:inline-block;text-decoration:inherit}#mc4wp-admin .CodeMirror-ruler,.mc4wp-admin .CodeMirror-ruler{border-left:1px solid #ccc;position:absolute}#mc4wp-admin .cm-s-default .cm-header,.mc4wp-admin .cm-s-default .cm-header{color:#00f}#mc4wp-admin .cm-s-default .cm-quote,.mc4wp-admin .cm-s-default .cm-quote{color:#090}#mc4wp-admin .cm-negative,.mc4wp-admin .cm-negative{color:#d44}#mc4wp-admin .cm-positive,.mc4wp-admin .cm-positive{color:#292}#mc4wp-admin .cm-header,#mc4wp-admin .cm-strong,.mc4wp-admin .cm-header,.mc4wp-admin .cm-strong{font-weight:700}#mc4wp-admin .cm-link,.mc4wp-admin .cm-link{text-decoration:underline}#mc4wp-admin .cm-strikethrough,.mc4wp-admin .cm-strikethrough{text-decoration:line-through}#mc4wp-admin .cm-s-default .cm-keyword,.mc4wp-admin .cm-s-default .cm-keyword{color:#708}#mc4wp-admin .cm-s-default .cm-atom,.mc4wp-admin .cm-s-default .cm-atom{color:#219}#mc4wp-admin .cm-s-default .cm-number,.mc4wp-admin .cm-s-default .cm-number{color:#164}#mc4wp-admin .cm-s-default .cm-def,.mc4wp-admin .cm-s-default .cm-def{color:#00f}#mc4wp-admin .cm-s-default .cm-variable-2,.mc4wp-admin .cm-s-default .cm-variable-2{color:#05a}#mc4wp-admin .cm-s-default .cm-variable-3,.mc4wp-admin .cm-s-default .cm-variable-3{color:#085}#mc4wp-admin .cm-s-default .cm-comment,.mc4wp-admin .cm-s-default .cm-comment{color:#a50}#mc4wp-admin .cm-s-default .cm-string,.mc4wp-admin .cm-s-default .cm-string{color:#a11}#mc4wp-admin .cm-s-default .cm-string-2,.mc4wp-admin .cm-s-default .cm-string-2{color:#f50}#mc4wp-admin .cm-s-default .cm-meta,#mc4wp-admin .cm-s-default .cm-qualifier,.mc4wp-admin .cm-s-default .cm-meta,.mc4wp-admin .cm-s-default .cm-qualifier{color:#555}#mc4wp-admin .cm-s-default .cm-builtin,.mc4wp-admin .cm-s-default .cm-builtin{color:#30a}#mc4wp-admin .cm-s-default .cm-bracket,.mc4wp-admin .cm-s-default .cm-bracket{color:#997}#mc4wp-admin .cm-s-default .cm-tag,.mc4wp-admin .cm-s-default .cm-tag{color:#170}#mc4wp-admin .cm-s-default .cm-attribute,.mc4wp-admin .cm-s-default .cm-attribute{color:#00c}#mc4wp-admin .cm-s-default .cm-hr,.mc4wp-admin .cm-s-default .cm-hr{color:#999}#mc4wp-admin .cm-s-default .cm-link,.mc4wp-admin .cm-s-default .cm-link{color:#00c}#mc4wp-admin .cm-invalidchar,#mc4wp-admin .cm-s-default .cm-error,.mc4wp-admin .cm-invalidchar,.mc4wp-admin .cm-s-default .cm-error{color:red}#mc4wp-admin .CodeMirror-composing,.mc4wp-admin .CodeMirror-composing{border-bottom:2px solid}#mc4wp-admin div.CodeMirror span.CodeMirror-matchingbracket,.mc4wp-admin div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}#mc4wp-admin div.CodeMirror span.CodeMirror-nonmatchingbracket,.mc4wp-admin div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}#mc4wp-admin .CodeMirror-matchingtag,.mc4wp-admin .CodeMirror-matchingtag{background:rgba(255,150,0,.3)}#mc4wp-admin .CodeMirror-activeline-background,.mc4wp-admin .CodeMirror-activeline-background{background:#e8f2ff}#mc4wp-admin .CodeMirror,.mc4wp-admin .CodeMirror{position:relative;overflow:hidden;background:#fff}#mc4wp-admin .CodeMirror-scroll,.mc4wp-admin .CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:0;position:relative}#mc4wp-admin .CodeMirror-sizer,.mc4wp-admin .CodeMirror-sizer{position:relative;border-right:30px solid transparent}#mc4wp-admin .CodeMirror-gutter-filler,#mc4wp-admin .CodeMirror-hscrollbar,#mc4wp-admin .CodeMirror-scrollbar-filler,#mc4wp-admin .CodeMirror-vscrollbar,.mc4wp-admin .CodeMirror-gutter-filler,.mc4wp-admin .CodeMirror-hscrollbar,.mc4wp-admin .CodeMirror-scrollbar-filler,.mc4wp-admin .CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}#mc4wp-admin .CodeMirror-vscrollbar,.mc4wp-admin .CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}#mc4wp-admin .CodeMirror-hscrollbar,.mc4wp-admin .CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}#mc4wp-admin .CodeMirror-scrollbar-filler,.mc4wp-admin .CodeMirror-scrollbar-filler{right:0;bottom:0}#mc4wp-admin .CodeMirror-gutter-filler,.mc4wp-admin .CodeMirror-gutter-filler{left:0;bottom:0}#mc4wp-admin .CodeMirror-gutters,.mc4wp-admin .CodeMirror-gutters{position:absolute;left:0;top:0;z-index:3}#mc4wp-admin .CodeMirror-gutter,.mc4wp-admin .CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-30px}#mc4wp-admin .field-wizard .dashicons,#mc4wp-admin .field-wizard td,#mc4wp-admin .field-wizard tr,.mc4wp-admin .field-wizard .dashicons,.mc4wp-admin .field-wizard td,.mc4wp-admin .field-wizard tr{vertical-align:middle}#mc4wp-admin .CodeMirror-gutter-wrapper,.mc4wp-admin .CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}#mc4wp-admin .CodeMirror-gutter-background,.mc4wp-admin .CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}#mc4wp-admin .CodeMirror-gutter-elt,.mc4wp-admin .CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}#mc4wp-admin .CodeMirror-lines,.mc4wp-admin .CodeMirror-lines{cursor:text;min-height:1px}#mc4wp-admin .CodeMirror pre,.mc4wp-admin .CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent}#mc4wp-admin .CodeMirror-wrap pre,.mc4wp-admin .CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}#mc4wp-admin .CodeMirror-linebackground,.mc4wp-admin .CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}#mc4wp-admin .CodeMirror-linewidget,.mc4wp-admin .CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}#mc4wp-admin .CodeMirror-code,.mc4wp-admin .CodeMirror-code{outline:0}#mc4wp-admin .CodeMirror-gutter,#mc4wp-admin .CodeMirror-gutters,#mc4wp-admin .CodeMirror-linenumber,#mc4wp-admin .CodeMirror-scroll,#mc4wp-admin .CodeMirror-sizer,.mc4wp-admin .CodeMirror-gutter,.mc4wp-admin .CodeMirror-gutters,.mc4wp-admin .CodeMirror-linenumber,.mc4wp-admin .CodeMirror-scroll,.mc4wp-admin .CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}#mc4wp-admin .CodeMirror-measure,.mc4wp-admin .CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}#mc4wp-admin .CodeMirror-cursor,.mc4wp-admin .CodeMirror-cursor{position:absolute}#mc4wp-admin .CodeMirror-measure pre,.mc4wp-admin .CodeMirror-measure pre{position:static}#mc4wp-admin div.CodeMirror-cursors,.mc4wp-admin div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}#mc4wp-admin .CodeMirror-focused div.CodeMirror-cursors,#mc4wp-admin div.CodeMirror-dragcursors,.mc4wp-admin .CodeMirror-focused div.CodeMirror-cursors,.mc4wp-admin div.CodeMirror-dragcursors{visibility:visible}#mc4wp-admin .CodeMirror-selected,.mc4wp-admin .CodeMirror-selected{background:#d9d9d9}#mc4wp-admin .CodeMirror-focused .CodeMirror-selected,#mc4wp-admin .CodeMirror-line::selection,#mc4wp-admin .CodeMirror-line>span::selection,#mc4wp-admin .CodeMirror-line>span>span::selection,.mc4wp-admin .CodeMirror-focused .CodeMirror-selected,.mc4wp-admin .CodeMirror-line::selection,.mc4wp-admin .CodeMirror-line>span::selection,.mc4wp-admin .CodeMirror-line>span>span::selection{background:#d7d4f0}#mc4wp-admin .CodeMirror-crosshair,.mc4wp-admin .CodeMirror-crosshair{cursor:crosshair}#mc4wp-admin .CodeMirror-line::-moz-selection,#mc4wp-admin .CodeMirror-line>span::-moz-selection,#mc4wp-admin .CodeMirror-line>span>span::-moz-selection,.mc4wp-admin .CodeMirror-line::-moz-selection,.mc4wp-admin .CodeMirror-line>span::-moz-selection,.mc4wp-admin .CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}#mc4wp-admin .cm-searching,.mc4wp-admin .cm-searching{background:#ffa;background:rgba(255,255,0,.4)}#mc4wp-admin .cm-force-border,.mc4wp-admin .cm-force-border{padding-right:.1px}@media print{#mc4wp-admin .CodeMirror div.CodeMirror-cursors,.mc4wp-admin .CodeMirror div.CodeMirror-cursors{visibility:hidden}}#mc4wp-admin .cm-tab-wrap-hack:after,.mc4wp-admin .cm-tab-wrap-hack:after{content:''}#mc4wp-admin span.CodeMirror-selectedtext,.mc4wp-admin span.CodeMirror-selectedtext{background:0 0}#mc4wp-admin .CodeMirror,.mc4wp-admin .CodeMirror{border:1px solid #ccc;padding:10px;min-height:500px;font-weight:400}#mc4wp-admin .CodeMirror-empty,.mc4wp-admin .CodeMirror-empty{color:#999}#mc4wp-admin .field-wizard h3,.mc4wp-admin .field-wizard h3{margin-top:0;padding-bottom:12px;border-bottom:1px solid #eee;margin-bottom:12px}#mc4wp-admin .field-wizard code,.mc4wp-admin .field-wizard code{margin-left:10px}#mc4wp-admin .field-wizard>div,.mc4wp-admin .field-wizard>div{margin:24px 0}#mc4wp-admin .field-wizard label,.mc4wp-admin .field-wizard label{font-weight:600;display:block;margin-bottom:3px}#mc4wp-admin .field-wizard table,.mc4wp-admin .field-wizard table{table-layout:fixed;border-collapse:collapse;border-spacing:0}#mc4wp-admin .field-wizard .cb-wrap,.mc4wp-admin .field-wizard .cb-wrap{font-weight:400}#mc4wp-admin .field-wizard .cb-wrap input,.mc4wp-admin .field-wizard .cb-wrap input{margin-right:6px}#mc4wp-admin .field-wizard .limit-height,.mc4wp-admin .field-wizard .limit-height{border:1px solid #eee;padding:6px;max-height:200px;overflow-y:scroll}#mc4wp-admin .field-wizard .help,.mc4wp-admin .field-wizard .help{margin-top:0}#mc4wp-admin .available-fields,.mc4wp-admin .available-fields{border:1px solid #ccc;padding:20px;background:#fff}#mc4wp-admin .available-fields h4,.mc4wp-admin .available-fields h4{font-size:14px;margin-top:0}#mc4wp-admin .available-fields strong,.mc4wp-admin .available-fields strong{display:block;margin-bottom:6px}#mc4wp-admin .available-fields button,.mc4wp-admin .available-fields button{margin:0 6px 6px 0}#mc4wp-admin .available-fields .is-required:after,.mc4wp-admin .available-fields .is-required:after{content:" *";color:red}#mc4wp-admin .available-fields .is-required.not-in-form,.mc4wp-admin .available-fields .is-required.not-in-form{-webkit-box-shadow:0 0 3px 1px red;-moz-box-shadow:0 0 3px 1px red;box-shadow:0 0 3px 1px red}#mc4wp-admin .page-title,.mc4wp-admin .page-title{background:url(../img/icon-large.png) left center no-repeat;padding-left:42px;line-height:32px;margin-bottom:20px}#mc4wp-admin .page-title small,.mc4wp-admin .page-title small{font-size:12px;color:#777;display:inline-block;margin-left:10px}#mc4wp-admin .button .dashicons,#mc4wp-admin .button-secondary .dashicons,#mc4wp-admin .page-title-action .dashicons,.mc4wp-admin .button .dashicons,.mc4wp-admin .button-secondary .dashicons,.mc4wp-admin .page-title-action .dashicons{vertical-align:middle;line-height:16px;margin:0 4px 0 0}#mc4wp-admin .form-table td p,.mc4wp-admin .form-table td p{margin-top:1em}#mc4wp-admin .sidebar,.mc4wp-admin .sidebar{border-left:1px solid #ccc}#mc4wp-admin .sidebar h3,#mc4wp-admin .sidebar h4,.mc4wp-admin .sidebar h3,.mc4wp-admin .sidebar h4{font-size:16px;margin-bottom:0}#mc4wp-admin .sidebar>div,.mc4wp-admin .sidebar>div{border-bottom:1px solid #ccc;margin-bottom:20px;padding-bottom:20px}#mc4wp-admin .sidebar>div:last-of-type,.mc4wp-admin .sidebar>div:last-of-type{border-bottom:0}.overlay{position:fixed;left:0;top:0;z-index:99999;padding:20px;max-width:480px;max-height:100%;background:#fefefe;border:1px solid #ccc;overflow-y:scroll;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.overlay .close{position:absolute;padding:10px;right:0;top:0;font-size:24px;cursor:pointer;opacity:.5}.overlay .close:hover{opacity:1}.overlay-background{z-index:99998;background:rgba(0,0,0,.67);position:fixed;left:0;right:0;bottom:0;top:0}.rtl .overlay .close{right:auto;left:0}.rtl #mc4wp-admin .page-title{background-position:right center;padding-left:0;padding-right:42px}.rtl #mc4wp-admin .CodeMirror-scroll{overflow-y:hidden!important}.rtl #mc4wp-admin .CodeMirror-vscrollbar{left:0!important;right:auto!important}
1
+ #mc4wp-admin .available-fields .in-form,#mc4wp-admin .hover-activated,.mc4wp-admin .available-fields .in-form,.mc4wp-admin .hover-activated{opacity:.5}#mc4wp-admin .cm-em,#mc4wp-admin .help,.mc4wp-admin .cm-em,.mc4wp-admin .help{font-style:italic}#mc4wp-admin .row,.mc4wp-admin .row{margin-left:-20px;margin-right:-20px;float:none}#mc4wp-admin .row .col,.mc4wp-admin .row .col{padding:0 20px;float:left;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}#mc4wp-admin .row .col-1,.mc4wp-admin .row .col-1{width:16.666%}#mc4wp-admin .row .col-2,.mc4wp-admin .row .col-2{width:33.333%}#mc4wp-admin .row .col-3,.mc4wp-admin .row .col-3{width:50%}#mc4wp-admin .row .col-4,.mc4wp-admin .row .col-4{width:66.666%}#mc4wp-admin .row .col-5,.mc4wp-admin .row .col-5{width:83.333%}#mc4wp-admin .row .col-6,.mc4wp-admin .row .col-6{width:100%}#mc4wp-admin .clearfix:after,#mc4wp-admin .clearfix:before,#mc4wp-admin .row:after,#mc4wp-admin .row:before,.mc4wp-admin .clearfix:after,.mc4wp-admin .clearfix:before,.mc4wp-admin .row:after,.mc4wp-admin .row:before{content:" ";display:table}#mc4wp-admin .clearfix:after,#mc4wp-admin .row:after,.mc4wp-admin .clearfix:after,.mc4wp-admin .row:after{clear:both}@media (max-width:1200px){#mc4wp-admin .row .col,.mc4wp-admin .row .col{width:100%;float:none;margin:10px 0}}#mc4wp-admin .status,.mc4wp-admin .status{display:inline-block;margin-left:1em;padding:3px 6px;color:#fff;font-size:12px;font-weight:700}#mc4wp-admin .status.positive,.mc4wp-admin .status.positive{background-color:#32cd32}#mc4wp-admin .status.negative,.mc4wp-admin .status.negative{background-color:red}#mc4wp-admin .status.neutral,.mc4wp-admin .status.neutral{background:gray}#mc4wp-admin .valigntop,.mc4wp-admin .valigntop{vertical-align:top!important}#mc4wp-admin .big-margin,.mc4wp-admin .big-margin{margin-top:60px;margin-bottom:60px}#mc4wp-admin .medium-margin,.mc4wp-admin .medium-margin{margin-top:40px;margin-bottom:40px}#mc4wp-admin .small-margin,.mc4wp-admin .small-margin{margin-top:20px;margin-bottom:20px}#mc4wp-admin .tiny-margin,.mc4wp-admin .tiny-margin{margin-top:10px;margin-bottom:10px}#mc4wp-admin .hover-activated:hover,.mc4wp-admin .hover-activated:hover{cursor:pointer;opacity:1}#mc4wp-admin .help-text,.mc4wp-admin .help-text{font-size:14px}#mc4wp-admin .help-text p,.mc4wp-admin .help-text p{margin:10px 0;font-size:14px}#mc4wp-admin .help-text ul,.mc4wp-admin .help-text ul{list-style:square;margin-top:15px;padding-left:40px}#mc4wp-admin .muted,.mc4wp-admin .muted{color:#aaa}#mc4wp-admin .red,.mc4wp-admin .red{color:red}#mc4wp-admin .green,.mc4wp-admin .green{color:#32cd32}#mc4wp-admin .mc4wp-notice,.mc4wp-admin .mc4wp-notice{padding:6px 12px;color:#31708f;background:#d9edf7;border:1px solid #bce8f1;margin:1em 0!important}#mc4wp-admin .mc4wp-is-dismissible,.mc4wp-admin .mc4wp-is-dismissible{padding-right:38px;position:relative}#mc4wp-admin .column-ID,.mc4wp-admin .column-ID{width:10%}#mc4wp-admin .block,.mc4wp-admin .block{display:block}#mc4wp-admin .code-sample,.mc4wp-admin .code-sample{font-family:Consolas,Monaco,Lucida Console,monospace;font-size:12px;background:#fff}#mc4wp-admin .breadcrumbs,.mc4wp-admin .breadcrumbs{border-bottom:1px solid #ccc;padding-bottom:1em}#mc4wp-admin .mc4wp-loader,.mc4wp-admin .mc4wp-loader{position:relative;display:inline-block;text-indent:-9999999px;border:3px solid rgba(0,0,0,.2);border-left-color:#000;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:load8 1.1s infinite linear;animation:load8 1.1s infinite linear;overflow:hidden;border-radius:50%;vertical-align:middle;width:12px;height:12px;margin-bottom:3px;margin-left:3px;margin-right:3px}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load8{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}#mc4wp-admin .tab,.mc4wp-admin .tab{display:none;background:inherit;border:none;font-weight:initial}#mc4wp-admin .tab.tab-active,.mc4wp-admin .tab.tab-active{display:block}#mc4wp-admin .tab h2,.mc4wp-admin .tab h2{margin-top:20px}#mc4wp-admin .CodeMirror,.mc4wp-admin .CodeMirror{font-family:monospace;height:300px;color:#000}#mc4wp-admin .CodeMirror-lines,.mc4wp-admin .CodeMirror-lines{padding:4px 0}#mc4wp-admin .CodeMirror pre,.mc4wp-admin .CodeMirror pre{padding:0 4px}#mc4wp-admin .CodeMirror-gutter-filler,#mc4wp-admin .CodeMirror-scrollbar-filler,.mc4wp-admin .CodeMirror-gutter-filler,.mc4wp-admin .CodeMirror-scrollbar-filler{background-color:#fff}#mc4wp-admin .CodeMirror-gutters,.mc4wp-admin .CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}#mc4wp-admin .CodeMirror-linenumber,.mc4wp-admin .CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}#mc4wp-admin .CodeMirror-guttermarker,.mc4wp-admin .CodeMirror-guttermarker{color:#000}#mc4wp-admin .CodeMirror-guttermarker-subtle,.mc4wp-admin .CodeMirror-guttermarker-subtle{color:#999}#mc4wp-admin .CodeMirror-cursor,.mc4wp-admin .CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}#mc4wp-admin .CodeMirror div.CodeMirror-secondarycursor,.mc4wp-admin .CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}#mc4wp-admin .cm-fat-cursor .CodeMirror-cursor,.mc4wp-admin .cm-fat-cursor .CodeMirror-cursor{width:auto;border:0;background:#7e7}#mc4wp-admin .cm-fat-cursor div.CodeMirror-cursors,.mc4wp-admin .cm-fat-cursor div.CodeMirror-cursors{z-index:1}#mc4wp-admin .cm-animate-fat-cursor,.mc4wp-admin .cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}#mc4wp-admin .field-wizard td.stretch,.mc4wp-admin .field-wizard td.stretch,.overlay{width:100%}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}#mc4wp-admin .cm-tab,.mc4wp-admin .cm-tab{display:inline-block;text-decoration:inherit}#mc4wp-admin .CodeMirror-ruler,.mc4wp-admin .CodeMirror-ruler{border-left:1px solid #ccc;position:absolute}#mc4wp-admin .cm-s-default .cm-header,.mc4wp-admin .cm-s-default .cm-header{color:#00f}#mc4wp-admin .cm-s-default .cm-quote,.mc4wp-admin .cm-s-default .cm-quote{color:#090}#mc4wp-admin .cm-negative,.mc4wp-admin .cm-negative{color:#d44}#mc4wp-admin .cm-positive,.mc4wp-admin .cm-positive{color:#292}#mc4wp-admin .cm-header,#mc4wp-admin .cm-strong,.mc4wp-admin .cm-header,.mc4wp-admin .cm-strong{font-weight:700}#mc4wp-admin .cm-link,.mc4wp-admin .cm-link{text-decoration:underline}#mc4wp-admin .cm-strikethrough,.mc4wp-admin .cm-strikethrough{text-decoration:line-through}#mc4wp-admin .cm-s-default .cm-keyword,.mc4wp-admin .cm-s-default .cm-keyword{color:#708}#mc4wp-admin .cm-s-default .cm-atom,.mc4wp-admin .cm-s-default .cm-atom{color:#219}#mc4wp-admin .cm-s-default .cm-number,.mc4wp-admin .cm-s-default .cm-number{color:#164}#mc4wp-admin .cm-s-default .cm-def,.mc4wp-admin .cm-s-default .cm-def{color:#00f}#mc4wp-admin .cm-s-default .cm-variable-2,.mc4wp-admin .cm-s-default .cm-variable-2{color:#05a}#mc4wp-admin .cm-s-default .cm-variable-3,.mc4wp-admin .cm-s-default .cm-variable-3{color:#085}#mc4wp-admin .cm-s-default .cm-comment,.mc4wp-admin .cm-s-default .cm-comment{color:#a50}#mc4wp-admin .cm-s-default .cm-string,.mc4wp-admin .cm-s-default .cm-string{color:#a11}#mc4wp-admin .cm-s-default .cm-string-2,.mc4wp-admin .cm-s-default .cm-string-2{color:#f50}#mc4wp-admin .cm-s-default .cm-meta,#mc4wp-admin .cm-s-default .cm-qualifier,.mc4wp-admin .cm-s-default .cm-meta,.mc4wp-admin .cm-s-default .cm-qualifier{color:#555}#mc4wp-admin .cm-s-default .cm-builtin,.mc4wp-admin .cm-s-default .cm-builtin{color:#30a}#mc4wp-admin .cm-s-default .cm-bracket,.mc4wp-admin .cm-s-default .cm-bracket{color:#997}#mc4wp-admin .cm-s-default .cm-tag,.mc4wp-admin .cm-s-default .cm-tag{color:#170}#mc4wp-admin .cm-s-default .cm-attribute,.mc4wp-admin .cm-s-default .cm-attribute{color:#00c}#mc4wp-admin .cm-s-default .cm-hr,.mc4wp-admin .cm-s-default .cm-hr{color:#999}#mc4wp-admin .cm-s-default .cm-link,.mc4wp-admin .cm-s-default .cm-link{color:#00c}#mc4wp-admin .cm-invalidchar,#mc4wp-admin .cm-s-default .cm-error,.mc4wp-admin .cm-invalidchar,.mc4wp-admin .cm-s-default .cm-error{color:red}#mc4wp-admin .CodeMirror-composing,.mc4wp-admin .CodeMirror-composing{border-bottom:2px solid}#mc4wp-admin div.CodeMirror span.CodeMirror-matchingbracket,.mc4wp-admin div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}#mc4wp-admin div.CodeMirror span.CodeMirror-nonmatchingbracket,.mc4wp-admin div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}#mc4wp-admin .CodeMirror-matchingtag,.mc4wp-admin .CodeMirror-matchingtag{background:rgba(255,150,0,.3)}#mc4wp-admin .CodeMirror-activeline-background,.mc4wp-admin .CodeMirror-activeline-background{background:#e8f2ff}#mc4wp-admin .CodeMirror,.mc4wp-admin .CodeMirror{position:relative;overflow:hidden;background:#fff}#mc4wp-admin .CodeMirror-scroll,.mc4wp-admin .CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:0;position:relative}#mc4wp-admin .CodeMirror-sizer,.mc4wp-admin .CodeMirror-sizer{position:relative;border-right:30px solid transparent}#mc4wp-admin .CodeMirror-gutter-filler,#mc4wp-admin .CodeMirror-hscrollbar,#mc4wp-admin .CodeMirror-scrollbar-filler,#mc4wp-admin .CodeMirror-vscrollbar,.mc4wp-admin .CodeMirror-gutter-filler,.mc4wp-admin .CodeMirror-hscrollbar,.mc4wp-admin .CodeMirror-scrollbar-filler,.mc4wp-admin .CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}#mc4wp-admin .CodeMirror-vscrollbar,.mc4wp-admin .CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}#mc4wp-admin .CodeMirror-hscrollbar,.mc4wp-admin .CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}#mc4wp-admin .CodeMirror-scrollbar-filler,.mc4wp-admin .CodeMirror-scrollbar-filler{right:0;bottom:0}#mc4wp-admin .CodeMirror-gutter-filler,.mc4wp-admin .CodeMirror-gutter-filler{left:0;bottom:0}#mc4wp-admin .CodeMirror-gutters,.mc4wp-admin .CodeMirror-gutters{position:absolute;left:0;top:0;z-index:3}#mc4wp-admin .CodeMirror-gutter,.mc4wp-admin .CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-30px}#mc4wp-admin .field-wizard .dashicons,#mc4wp-admin .field-wizard td,#mc4wp-admin .field-wizard tr,.mc4wp-admin .field-wizard .dashicons,.mc4wp-admin .field-wizard td,.mc4wp-admin .field-wizard tr{vertical-align:middle}#mc4wp-admin .CodeMirror-gutter-wrapper,.mc4wp-admin .CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}#mc4wp-admin .CodeMirror-gutter-background,.mc4wp-admin .CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}#mc4wp-admin .CodeMirror-gutter-elt,.mc4wp-admin .CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}#mc4wp-admin .CodeMirror-lines,.mc4wp-admin .CodeMirror-lines{cursor:text;min-height:1px}#mc4wp-admin .CodeMirror pre,.mc4wp-admin .CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent}#mc4wp-admin .CodeMirror-wrap pre,.mc4wp-admin .CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}#mc4wp-admin .CodeMirror-linebackground,.mc4wp-admin .CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}#mc4wp-admin .CodeMirror-linewidget,.mc4wp-admin .CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}#mc4wp-admin .CodeMirror-code,.mc4wp-admin .CodeMirror-code{outline:0}#mc4wp-admin .CodeMirror-gutter,#mc4wp-admin .CodeMirror-gutters,#mc4wp-admin .CodeMirror-linenumber,#mc4wp-admin .CodeMirror-scroll,#mc4wp-admin .CodeMirror-sizer,.mc4wp-admin .CodeMirror-gutter,.mc4wp-admin .CodeMirror-gutters,.mc4wp-admin .CodeMirror-linenumber,.mc4wp-admin .CodeMirror-scroll,.mc4wp-admin .CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}#mc4wp-admin .CodeMirror-measure,.mc4wp-admin .CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}#mc4wp-admin .CodeMirror-cursor,.mc4wp-admin .CodeMirror-cursor{position:absolute}#mc4wp-admin .CodeMirror-measure pre,.mc4wp-admin .CodeMirror-measure pre{position:static}#mc4wp-admin div.CodeMirror-cursors,.mc4wp-admin div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}#mc4wp-admin .CodeMirror-focused div.CodeMirror-cursors,#mc4wp-admin div.CodeMirror-dragcursors,.mc4wp-admin .CodeMirror-focused div.CodeMirror-cursors,.mc4wp-admin div.CodeMirror-dragcursors{visibility:visible}#mc4wp-admin .CodeMirror-selected,.mc4wp-admin .CodeMirror-selected{background:#d9d9d9}#mc4wp-admin .CodeMirror-focused .CodeMirror-selected,.mc4wp-admin .CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}#mc4wp-admin .CodeMirror-crosshair,.mc4wp-admin .CodeMirror-crosshair{cursor:crosshair}#mc4wp-admin .CodeMirror-line::selection,#mc4wp-admin .CodeMirror-line>span::selection,#mc4wp-admin .CodeMirror-line>span>span::selection,.mc4wp-admin .CodeMirror-line::selection,.mc4wp-admin .CodeMirror-line>span::selection,.mc4wp-admin .CodeMirror-line>span>span::selection{background:#d7d4f0}#mc4wp-admin .CodeMirror-line::-moz-selection,#mc4wp-admin .CodeMirror-line>span::-moz-selection,#mc4wp-admin .CodeMirror-line>span>span::-moz-selection,.mc4wp-admin .CodeMirror-line::-moz-selection,.mc4wp-admin .CodeMirror-line>span::-moz-selection,.mc4wp-admin .CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}#mc4wp-admin .cm-searching,.mc4wp-admin .cm-searching{background:#ffa;background:rgba(255,255,0,.4)}#mc4wp-admin .cm-force-border,.mc4wp-admin .cm-force-border{padding-right:.1px}@media print{#mc4wp-admin .CodeMirror div.CodeMirror-cursors,.mc4wp-admin .CodeMirror div.CodeMirror-cursors{visibility:hidden}}#mc4wp-admin .cm-tab-wrap-hack:after,.mc4wp-admin .cm-tab-wrap-hack:after{content:''}#mc4wp-admin span.CodeMirror-selectedtext,.mc4wp-admin span.CodeMirror-selectedtext{background:0 0}#mc4wp-admin .CodeMirror,.mc4wp-admin .CodeMirror{border:1px solid #ccc;padding:10px;min-height:500px;font-weight:400}#mc4wp-admin .CodeMirror-empty,.mc4wp-admin .CodeMirror-empty{color:#999}#mc4wp-admin .field-wizard h3,.mc4wp-admin .field-wizard h3{margin-top:0;padding-bottom:12px;border-bottom:1px solid #eee;margin-bottom:12px}#mc4wp-admin .field-wizard code,.mc4wp-admin .field-wizard code{margin-left:10px}#mc4wp-admin .field-wizard>div,.mc4wp-admin .field-wizard>div{margin:24px 0}#mc4wp-admin .field-wizard label,.mc4wp-admin .field-wizard label{font-weight:600;display:block;margin-bottom:3px}#mc4wp-admin .field-wizard table,.mc4wp-admin .field-wizard table{table-layout:fixed;border-collapse:collapse;border-spacing:0}#mc4wp-admin .field-wizard .cb-wrap,.mc4wp-admin .field-wizard .cb-wrap{font-weight:400}#mc4wp-admin .field-wizard .cb-wrap input,.mc4wp-admin .field-wizard .cb-wrap input{margin-right:6px}#mc4wp-admin .field-wizard .limit-height,.mc4wp-admin .field-wizard .limit-height{border:1px solid #eee;padding:6px;max-height:200px;overflow-y:scroll}#mc4wp-admin .field-wizard .help,.mc4wp-admin .field-wizard .help{margin-top:0}#mc4wp-admin .available-fields,.mc4wp-admin .available-fields{border:1px solid #ccc;padding:20px;background:#fff}#mc4wp-admin .available-fields h4,.mc4wp-admin .available-fields h4{font-size:14px;margin-top:0}#mc4wp-admin .available-fields strong,.mc4wp-admin .available-fields strong{display:block;margin-bottom:6px}#mc4wp-admin .available-fields button,.mc4wp-admin .available-fields button{margin:0 6px 6px 0}#mc4wp-admin .available-fields .is-required:after,.mc4wp-admin .available-fields .is-required:after{content:" *";color:red}#mc4wp-admin .available-fields .is-required.not-in-form,.mc4wp-admin .available-fields .is-required.not-in-form{-webkit-box-shadow:0 0 3px 1px red;-moz-box-shadow:0 0 3px 1px red;box-shadow:0 0 3px 1px red}#mc4wp-admin .page-title,.mc4wp-admin .page-title{background:url(../img/icon-large.png) left center no-repeat;padding-left:42px;line-height:32px;margin-bottom:20px}#mc4wp-admin .page-title small,.mc4wp-admin .page-title small{font-size:12px;color:#777;display:inline-block;margin-left:10px}#mc4wp-admin .button .dashicons,#mc4wp-admin .button-secondary .dashicons,#mc4wp-admin .page-title-action .dashicons,.mc4wp-admin .button .dashicons,.mc4wp-admin .button-secondary .dashicons,.mc4wp-admin .page-title-action .dashicons{vertical-align:middle;line-height:16px;margin:0 4px 0 0}#mc4wp-admin .form-table td p,.mc4wp-admin .form-table td p{margin-top:1em}#mc4wp-admin .sidebar,.mc4wp-admin .sidebar{border-left:1px solid #ccc}#mc4wp-admin .sidebar h3,#mc4wp-admin .sidebar h4,.mc4wp-admin .sidebar h3,.mc4wp-admin .sidebar h4{font-size:16px;margin-bottom:0}#mc4wp-admin .sidebar>div,.mc4wp-admin .sidebar>div{border-bottom:1px solid #ccc;margin-bottom:20px;padding-bottom:20px}#mc4wp-admin .sidebar>div:last-of-type,.mc4wp-admin .sidebar>div:last-of-type{border-bottom:0}.overlay{position:fixed;left:0;top:0;z-index:99999;padding:20px;max-width:480px;max-height:100%;background:#fefefe;border:1px solid #ccc;overflow-y:scroll;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.overlay .close{position:absolute;padding:10px;right:0;top:0;font-size:24px;cursor:pointer;opacity:.5}.overlay .close:hover{opacity:1}.overlay-background{z-index:99998;background:rgba(0,0,0,.67);position:fixed;left:0;right:0;bottom:0;top:0}.rtl .overlay .close{right:auto;left:0}.rtl #mc4wp-admin .page-title{background-position:right center;padding-left:0;padding-right:42px}.rtl #mc4wp-admin .CodeMirror-scroll{overflow-y:hidden!important}.rtl #mc4wp-admin .CodeMirror-vscrollbar{left:0!important;right:auto!important}.rtl .mc4wp-is-dismissible{padding-left:38px;padding-right:initial;position:relative}
assets/css/form-editor.min.css CHANGED
@@ -1 +1 @@
1
- .CodeMirror{font-family:monospace;height:300px;color:#000}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-ruler{border-left:1px solid #ccc;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta,.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-invalidchar,.cm-s-default .cm-error{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative;border-right:30px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-30px}.field-wizard .dashicons,.field-wizard td,.field-wizard tr{vertical-align:middle}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}.CodeMirror-focused div.CodeMirror-cursors,div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected,.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background:#ffa;background:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:''}span.CodeMirror-selectedtext{background:0 0}.CodeMirror{border:1px solid #ccc;padding:10px;min-height:500px;font-weight:400}.CodeMirror-empty{color:#999}.field-wizard h3{margin-top:0;padding-bottom:12px;border-bottom:1px solid #eee;margin-bottom:12px}.field-wizard code{margin-left:10px}.field-wizard>div{margin:24px 0}.field-wizard label{font-weight:600;display:block;margin-bottom:3px}.field-wizard table{table-layout:fixed;border-collapse:collapse;border-spacing:0}.field-wizard td.stretch{width:100%}.field-wizard .cb-wrap{font-weight:400}.field-wizard .cb-wrap input{margin-right:6px}.field-wizard .limit-height{border:1px solid #eee;padding:6px;max-height:200px;overflow-y:scroll}.field-wizard .help{margin-top:0}.available-fields{border:1px solid #ccc;padding:20px;background:#fff}.available-fields h4{font-size:14px;margin-top:0}.available-fields strong{display:block;margin-bottom:6px}.available-fields button{margin:0 6px 6px 0}.available-fields .is-required:after{content:" *";color:red}.available-fields .is-required.not-in-form{-webkit-box-shadow:0 0 3px 1px red;-moz-box-shadow:0 0 3px 1px red;box-shadow:0 0 3px 1px red}.available-fields .in-form{opacity:.5}
1
+ .CodeMirror{font-family:monospace;height:300px;color:#000}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-ruler{border-left:1px solid #ccc;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta,.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-invalidchar,.cm-s-default .cm-error{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative;border-right:30px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-30px}.field-wizard .dashicons,.field-wizard td,.field-wizard tr{vertical-align:middle}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}.CodeMirror-focused div.CodeMirror-cursors,div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background:#ffa;background:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:''}span.CodeMirror-selectedtext{background:0 0}.CodeMirror{border:1px solid #ccc;padding:10px;min-height:500px;font-weight:400}.CodeMirror-empty{color:#999}.field-wizard h3{margin-top:0;padding-bottom:12px;border-bottom:1px solid #eee;margin-bottom:12px}.field-wizard code{margin-left:10px}.field-wizard>div{margin:24px 0}.field-wizard label{font-weight:600;display:block;margin-bottom:3px}.field-wizard table{table-layout:fixed;border-collapse:collapse;border-spacing:0}.field-wizard td.stretch{width:100%}.field-wizard .cb-wrap{font-weight:400}.field-wizard .cb-wrap input{margin-right:6px}.field-wizard .limit-height{border:1px solid #eee;padding:6px;max-height:200px;overflow-y:scroll}.field-wizard .help{margin-top:0}.available-fields{border:1px solid #ccc;padding:20px;background:#fff}.available-fields h4{font-size:14px;margin-top:0}.available-fields strong{display:block;margin-bottom:6px}.available-fields button{margin:0 6px 6px 0}.available-fields .is-required:after{content:" *";color:red}.available-fields .is-required.not-in-form{-webkit-box-shadow:0 0 3px 1px red;-moz-box-shadow:0 0 3px 1px red;box-shadow:0 0 3px 1px red}.available-fields .in-form{opacity:.5}
assets/js/admin.min.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["admin.js"],"names":["require","undefined","define","e","t","n","r","s","o","u","a","i","f","Error","code","l","exports","call","length","1","module","m","window","EventEmitter","context","document","getElementById","events","tabs","helpers","settings","ListFetcher","mount","mc4wp","deps","mithril","./admin/helpers.js","./admin/list-fetcher.js","./admin/settings.js","./admin/tabs.js","wolfy87-eventemitter","2","toggleElement","selector","elements","querySelectorAll","show","clientHeight","style","display","bindEventToElement","element","event","handler","addEventListener","attachEvent","bindEventToElements","Array","prototype","forEach","debounce","func","wait","immediate","timeout","this","args","arguments","later","apply","callNow","clearTimeout","setTimeout","showIfElements","getAttribute","checked","value","conditionMet","config","hide","visibility","opacity","inputs","inputElement","removeAttribute","setAttribute","JSON","parse","parentElements","parentElement","3","working","done","mailchimp","api_connected","lists","fetch","$","jQuery","mc4wp_vars","i18n","preventDefault","post","ajaxurl","action","data","location","reload","always","redraw","bind","view","method","onsubmit","type","fetching_mailchimp_lists","renew_mailchimp_lists","className","disabled","trust","fetching_mailchimp_lists_can_take_a_while","fetching_mailchimp_lists_done","4","Settings","getSelectedListsWhere","searchKey","searchValue","selectedLists","filter","el","getSelectedLists","updateSelectedLists","listInputs","input","push","trigger","toggleVisibleLists","rows","listId","isSelected","replace","querySelector","on","5","URL","Tabs","get","id","open","tab","updateState","$tabs","removeClass","css","$tabNavs","nav","blur","url","setParameter","href","history","pushState","title","refererField","tb_remove","forms","editor","refresh","split","switchTab","tabId","match","urlParams","opened","returnValue","init","activeTab","substring","replaceState","state","$context","find","each","first","text","click","body","./url.js","6","query","hasOwnProperty","b","decodeURIComponent","build","ret","d","encodeURIComponent","join","key","7","global","factory","amd","isFunction","object","isObject","isString","noop","initialize","mock","$document","$location","$cancelAnimationFrame","cancelAnimationFrame","$requestAnimationFrame","requestAnimationFrame","parseTagAttrs","cell","tag","classes","parser","exec","attrs","pair","getVirtualChildren","hasAttrs","children","slice","isArray","assignAttrs","target","classAttr","attrName","hasOwn","pairs","parameterize","list","forKeys","dataToString","toString","injectTextNode","index","insertNode","nodeValue","flatten","concat","node","insertBefore","childNodes","handleKeysDiffer","existing","cached","MOVE","from","nodes","createElement","INSERTION","actions","prop","changes","sort","sortChanges","newCached","change","DELETION","clear","splice","dummy","changeElement","maybeChanged","diffKeys","keysDiffer","cachedCell","diffArray","_","parentNode","indexOf","buildArrayKeys","guid","isDifferentEnough","dataAttrKeys","Object","keys","strategy","configContext","retain","maybeRecreateObject","onunload","controllers","controller","getObjectNamespace","namespace","xmlns","unloadCachedControllers","views","$old","pendingRequests","scheduleConfigsToBeCalled","configs","isNew","buildUpdatedNode","editable","hasKeys","setAttributes","contenteditable","intact","handleNonexistentNodes","$trusted","injectHTML","createTextNode","nodeName","voidElements","constructor","reattachNodes","parentTag","activeElement","innerHTML","nodeType","trim","handleTextNode","shouldReattach","valueOf","getSubArrayCount","item","buildArray","subArrayCount","shouldMaintainIdentities","cacheCount","len","makeCache","parentIndex","parentCache","offset","end","constructNode","is","createElementNS","constructAttrs","constructChildren","reconstructCached","getController","cachedControllers","controllerIndex","updateLists","unloaders","map","checkView","forcing","subtree","markViews","$original","buildObject","copyStyleAttrs","dataAttr","cachedAttr","rule","setSingleAttr","autoredraw","setAttributeNS","shouldUseSetAttribute","trySetAttr","cachedAttrs","message","dataAttrs","removeChild","unload","appendTextFragment","appendChild","createRange","createContextualFragment","insertAdjacentHTML","replaceScriptNodes","tagName","replaceChild","buildExecutableNode","scriptEl","attributes","name","nextSibling","isElement","placeholder","callback","startComputation","endFirstComputation","getCellCacheKey","nodeCache","gettersetter","store","toJSON","component","ctrl","currentArgs","output","checkPrevented","root","isPrevented","roots","currentComponent","topComponent","components","removeRootElement","reset","computePreRedrawHook","render","computePostRedrawHook","lastRedrawId","lastRedrawCallTime","Date","endComputation","normalizeRoute","route","modes","mode","routeByValue","router","path","routeParams","queryStart","parseQueryString","substr","matcher","RegExp","test","values","routeUnobtrusive","ctrlKey","metaKey","shiftKey","which","currentTarget","srcElement","search","setScroll","hash","scrollTo","buildQueryString","prefix","duplicates","str","charAt","params","string","cacheKey","cellCache","propify","promise","initialValue","then","resolve","reject","Deferred","onSuccess","onFailure","finish","REJECTED","next","deferred","RESOLVED","promiseValue","thennable","success","failure","notThennable","count","onerror","fire","REJECTING","RESOLVING","self","TypeError","identity","handleJsonp","options","callbackKey","callbackName","getTime","Math","round","random","script","resp","onload","responseText","status","stringify","error","src","createXhr","xhr","XMLHttpRequest","user","password","onreadystatechange","readyState","serialize","setRequestHeader","deserialize","maybeXhr","FormData","send","ajax","dataType","toLowerCase","bindData","querystring","parameterizeUrl","token","version","AREA","BASE","BR","COL","COMMAND","EMBED","HR","IMG","INPUT","KEYGEN","LINK","META","PARAM","SOURCE","TRACK","WBR","html","form","width","height","documentNode","documentElement","forceRecreation","isDocumentRoot","String","Promise","FRAME_BUDGET","unloader","redrawing","force","withAttr","withAttrCallback","callbackThis","_this","currentRoute","pathname","redirect","isDefaultRoute","arg1","arg2","vdom","source","listener","base","removeEventListener","detachEvent","oldRoute","queryIndex","currentPath","replaceHistory","err","param","sync","synchronizer","pos","resolved","results","outstanding","arg","request","background","extract","isJSONP","jsonp","toUpperCase","ev","response","unwrapSuccess","res","unwrapError","8","indexOfListener","listeners","alias","proto","originalGlobalValue","getListeners","evt","_getEvents","flattenListeners","flatListeners","getListenersAsObject","addListener","listenerIsWrapped","once","addOnceListener","defineEvent","defineEvents","evts","removeListener","off","addListeners","manipulateListeners","removeListeners","remove","single","multiple","removeEvent","_events","removeAllListeners","emitEvent","listenersMap","_getOnceReturnValue","emit","setOnceReturnValue","_onceReturnValue","noConflict"],"mappings":"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","file":"admin.min.js","sourcesContent":["(function () { var require = undefined; var define = undefined; (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){\n'use strict';\n\n// dependencies\nvar m = window.m = require('mithril');\nvar EventEmitter = require('wolfy87-eventemitter');\n\n// vars\nvar context = document.getElementById('mc4wp-admin');\nvar events = new EventEmitter();\nvar tabs = require ('./admin/tabs.js')(context);\nvar helpers = require('./admin/helpers.js');\nvar settings = require('./admin/settings.js')(context, helpers, events);\n\n// list fetcher\nvar ListFetcher = require('./admin/list-fetcher.js');\nvar mount = document.getElementById('mc4wp-list-fetcher');\nif( mount ) {\n m.mount(mount, new ListFetcher);\n}\n\n// expose some things\nwindow.mc4wp = window.mc4wp || {};\nwindow.mc4wp.deps = window.mc4wp.deps || {};\nwindow.mc4wp.deps.mithril = m;\nwindow.mc4wp.helpers = helpers;\nwindow.mc4wp.events = events;\nwindow.mc4wp.settings = settings;\nwindow.mc4wp.tabs = tabs;\n},{\"./admin/helpers.js\":2,\"./admin/list-fetcher.js\":3,\"./admin/settings.js\":4,\"./admin/tabs.js\":5,\"mithril\":7,\"wolfy87-eventemitter\":8}],2:[function(require,module,exports){\n'use strict';\n\nvar helpers = {};\n\nhelpers.toggleElement = function(selector) {\n\tvar elements = document.querySelectorAll(selector);\n\tfor( var i=0; i<elements.length;i++){\n\t\tvar show = elements[i].clientHeight <= 0;\n\t\telements[i].style.display = show ? '' : 'none';\n\t}\n};\n\nhelpers.bindEventToElement = function(element,event,handler) {\n\tif ( element.addEventListener) {\n\t\telement.addEventListener(event, handler);\n\t} else if (element.attachEvent) {\n\t\telement.attachEvent('on' + event, handler);\n\t}\n};\n\nhelpers.bindEventToElements = function( elements, event, handler ) {\n\tArray.prototype.forEach.call( elements, function(element) {\n\t\thelpers.bindEventToElement(element,event,handler);\n\t});\n};\n\n\n// polling\nhelpers.debounce = function(func, wait, immediate) {\n\tvar timeout;\n\treturn function() {\n\t\tvar context = this, args = arguments;\n\t\tvar later = function() {\n\t\t\ttimeout = null;\n\t\t\tif (!immediate) func.apply(context, args);\n\t\t};\n\t\tvar callNow = immediate && !timeout;\n\t\tclearTimeout(timeout);\n\t\ttimeout = setTimeout(later, wait);\n\t\tif (callNow) func.apply(context, args);\n\t};\n};\n\n\n/**\n * Showif.js\n */\n(function() {\n\tvar showIfElements = document.querySelectorAll('[data-showif]');\n\n\t// dependent elements\n\tArray.prototype.forEach.call( showIfElements, function(element) {\n\t\tvar config = JSON.parse( element.getAttribute('data-showif') );\n\t\tvar parentElements = document.querySelectorAll('[name=\"'+ config.element +'\"]');\n\t\tvar inputs = element.querySelectorAll('input,select,textarea:not([readonly])');\n\t\tvar hide = config.hide === undefined || config.hide;\n\n\t\tfunction toggleElement() {\n\n\t\t\t// do nothing with unchecked radio inputs\n\t\t\tif( this.getAttribute('type') === \"radio\" && ! this.checked ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar value = ( this.getAttribute(\"type\") === \"checkbox\" ) ? this.checked : this.value;\n\t\t\tvar conditionMet = ( value == config.value );\n\n\t\t\tif( hide ) {\n\t\t\t\telement.style.display = conditionMet ? '' : 'none';\n\t\t\t\telement.style.visibility = conditionMet ? '' : 'hidden';\n\t\t\t} else {\n\t\t\t\telement.style.opacity = conditionMet ? '' : '0.4';\n\t\t\t}\n\n\t\t\t// disable input fields to stop sending their values to server\n\t\t\tArray.prototype.forEach.call( inputs, function(inputElement) {\n\t\t\t\tconditionMet ? inputElement.removeAttribute('readonly') : inputElement.setAttribute('readonly','readonly');\n\t\t\t});\n\t\t}\n\n\t\t// find checked element and call toggleElement function\n\t\tArray.prototype.forEach.call( parentElements, function( parentElement ) {\n\t\t\ttoggleElement.call(parentElement);\n\t\t});\n\n\t\t// bind on all changes\n\t\thelpers.bindEventToElements(parentElements, 'change', toggleElement);\n\t});\n})();\n\nmodule.exports = helpers;\n},{}],3:[function(require,module,exports){\n'use strict';\n\nvar $ = window.jQuery;\nvar config = mc4wp_vars;\nvar i18n = config.i18n;\n\nfunction ListFetcher() {\n this.working = false;\n this.done = false;\n\n // start fetching right away when no lists but api key given\n if( config.mailchimp.api_connected && config.mailchimp.lists.length == 0 ) {\n this.fetch();\n }\n}\n\nListFetcher.prototype.fetch = function (e) {\n e && e.preventDefault();\n\n this.working = true;\n this.done = false;\n\n $.post(ajaxurl, {\n action: \"mc4wp_renew_mailchimp_lists\"\n }).done(function(data) {\n if(data) {\n window.setTimeout(function() { window.location.reload(); }, 3000 );\n }\n }).always(function (data) {\n this.working = false;\n this.done = true;\n\n m.redraw();\n }.bind(this));\n};\n\nListFetcher.prototype.view = function () {\n return m('form', {\n method: \"POST\",\n onsubmit: this.fetch.bind(this)\n }, [\n m('p', [\n m('input', {\n type: \"submit\",\n value: this.working ? i18n.fetching_mailchimp_lists : i18n.renew_mailchimp_lists,\n className: \"button\",\n disabled: !!this.working\n }),\n m.trust(' &nbsp; '),\n\n this.working ? [\n m('span.mc4wp-loader', \"Loading...\"),\n m.trust(' &nbsp; '),\n m('em.help', i18n.fetching_mailchimp_lists_can_take_a_while)\n ]: '',\n\n this.done ? [\n m( 'em.help.green', i18n.fetching_mailchimp_lists_done )\n ] : ''\n ])\n ]);\n};\n\nmodule.exports = ListFetcher;\n},{}],4:[function(require,module,exports){\nvar Settings = function(context, helpers, events ) {\n\t'use strict';\n\n\t// vars\n\tvar form = context.querySelector('form');\n\tvar listInputs = context.querySelectorAll('.mc4wp-list-input');\n\tvar lists = mc4wp_vars.mailchimp.lists;\n\tvar selectedLists = [];\n\n\t// functions\n\tfunction getSelectedListsWhere(searchKey,searchValue) {\n\t\treturn selectedLists.filter(function(el) {\n\t\t\treturn el[searchKey] === searchValue;\n\t\t});\n\t}\n\n\tfunction getSelectedLists() {\n\t\treturn selectedLists;\n\t}\n\n\tfunction updateSelectedLists() {\n\t\tselectedLists = [];\n\n\t\tArray.prototype.forEach.call(listInputs, function(input) {\n\t\t\t// skip unchecked checkboxes\n\t\t\tif( typeof( input.checked ) === \"boolean\" && ! input.checked ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif( typeof( lists[ input.value ] ) === \"object\" ){\n\t\t\t\tselectedLists.push( lists[ input.value ] );\n\t\t\t}\n\t\t});\n\n\t\tevents.trigger('selectedLists.change', [ selectedLists ]);\n\t\treturn selectedLists;\n\t}\n\n\tfunction toggleVisibleLists() {\n\t\tvar rows = document.querySelectorAll('.lists--only-selected > *');\n\t\tArray.prototype.forEach.call(rows, function(el) {\n\n\t\t\tvar listId = el.getAttribute('data-list-id');\n\t\t\tvar isSelected = getSelectedListsWhere('id', listId).length > 0;\n\n\t\t\tif( isSelected ) {\n\t\t\t\tel.setAttribute('class', el.getAttribute('class').replace('hidden',''));\n\t\t\t} else {\n\t\t\t\tel.setAttribute('class', el.getAttribute('class') + \" hidden\" );\n\t\t\t}\n\t\t});\n\t}\n\n\tevents.on('selectedLists.change', toggleVisibleLists);\n\thelpers.bindEventToElements(listInputs,'change',updateSelectedLists);\n\n\tupdateSelectedLists();\n\n\treturn {\n\t\tgetSelectedLists: getSelectedLists\n\t}\n\n};\n\nmodule.exports = Settings;\n},{}],5:[function(require,module,exports){\n'use strict';\n\nvar URL = require('./url.js');\n\n// Tabs\nvar Tabs = function(context) {\n\n\t// @todo last piece of jQuery... can we get rid of it?\n\tvar $ = window.jQuery;\n\n\tvar $context = $(context);\n\tvar $tabs = $context.find('.tab');\n\tvar $tabNavs = $context.find('.nav-tab');\n\tvar refererField = context.querySelector('input[name=\"_wp_http_referer\"]');\n\tvar tabs = [];\n\n\t$.each($tabs, function(i,t) {\n\t\tvar id = t.id.substring(4);\n\t\tvar title = $(t).find('h2').first().text();\n\n\t\ttabs.push({\n\t\t\tid: id,\n\t\t\ttitle: title,\n\t\t\telement: t,\n\t\t\tnav: context.querySelectorAll('.nav-tab-' + id),\n\t\t\topen: function() { return open(id); }\n\t\t});\n\t});\n\n\tfunction get(id) {\n\n\t\tfor( var i=0; i<tabs.length; i++){\n\t\t\tif(tabs[i].id === id ) {\n\t\t\t\treturn tabs[i];\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tfunction open( tab, updateState ) {\n\n\t\t// make sure we have a tab object\n\t\tif(typeof(tab) === \"string\"){\n\t\t\ttab = get(tab);\n\t\t}\n\n\t\tif(!tab) { return false; }\n\n\t\t// should we update state?\n\t\tif( updateState == undefined ) {\n\t\t\tupdateState = true;\n\t\t}\n\n\t\t// hide all tabs & remove active class\n\t\t$tabs.removeClass('tab-active').css('display', 'none');\n\t\t$tabNavs.removeClass('nav-tab-active');\n\n\t\t// add `nav-tab-active` to this tab\n\t\tArray.prototype.forEach.call(tab.nav, function(nav) {\n\t\t\tnav.className += \" nav-tab-active\";\n\t\t\tnav.blur();\n\t\t});\n\n\t\t// show target tab\n\t\ttab.element.style.display = 'block';\n\t\ttab.element.className += \" tab-active\";\n\n\t\t// create new URL\n\t\tvar url = URL.setParameter(window.location.href, \"tab\", tab.id );\n\n\t\t// update hash\n\t\tif( history.pushState && updateState ) {\n\t\t\thistory.pushState( tab.id, '', url );\n\t\t}\n\n\t\t// update document title\n\t\ttitle(tab);\n\n\t\t// update referer field\n\t\trefererField.value = url;\n\n\t\t// if thickbox is open, close it.\n\t\tif( typeof(tb_remove) === \"function\" ) {\n\t\t\ttb_remove();\n\t\t}\n\n\t\t// refresh editor after switching tabs\n\t\t// TODO: decouple decouple decouple\n\t\tif( tab.id === 'fields' && window.mc4wp && window.mc4wp.forms && window.mc4wp.forms.editor ) {\n\t\t\tmc4wp.forms.editor.refresh();\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction title(tab) {\n\t\tvar title = document.title.split('-');\n\t\tdocument.title = document.title.replace(title[0], tab.title + \" \");\n\t}\n\n\tfunction switchTab(e) {\n\t\te = e || window.event;\n\n\t\t// get from data attribute\n\t\tvar tabId = this.getAttribute('data-tab');\n\n\t\t// get from classname\n\t\tif( ! tabId ) {\n\t\t\tvar match = this.className.match(/nav-tab-(\\w+)?/);\n\t\t\tif( match ) {\n\t\t\t\ttabId = match[1];\n\t\t\t}\n\t\t}\n\n\t\t// get from href\n\t\tif( ! tabId ) {\n\t\t\tvar urlParams = URL.parse( this.href );\n\t\t\tif( ! urlParams.tab ) { return; }\n\t\t\ttabId = urlParams.tab;\n\t\t}\n\n\t\tvar opened = open( tabId );\n\n\t\tif( opened ) {\n\t\t\te.preventDefault();\n\t\t\te.returnValue = false;\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction init() {\n\n\t\t// check for current tab\n\t\tif(! history.pushState) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar activeTab = $tabs.filter(':visible').get(0);\n\t\tif( ! activeTab ) { return; }\n\t\tvar tab = get(activeTab.id.substring(4));\n\t\tif(!tab) return;\n\n\t\t// check if tab is in html5 history\n\t\tif( history.replaceState && history.state === null) {\n\t\t\thistory.replaceState( tab.id, '' );\n\t\t}\n\n\t\t// update document title\n\t\ttitle(tab);\n\t}\n\n\t$tabNavs.click(switchTab);\n\t$(document.body).on('click', '.tab-link', switchTab);\n\tinit();\n\n\tif(window.addEventListener && history.pushState ) {\n\t\twindow.addEventListener('popstate', function(e) {\n\t\t\tif(!e.state) return true;\n\t\t\tvar tabId = e.state;\n\t\t\treturn open(tabId,false);\n\t\t});\n\t}\n\n\treturn {\n\t\topen: open,\n\t\tget: get\n\t}\n\n};\n\nmodule.exports = Tabs;\n},{\"./url.js\":6}],6:[function(require,module,exports){\n'use strict';\n\nvar URL = {\n\tparse: function(url) {\n\t\tvar query = {};\n\t\tvar a = url.split('&');\n\t\tfor (var i in a) {\n\t\t\tif(!a.hasOwnProperty(i)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvar b = a[i].split('=');\n\t\t\tquery[decodeURIComponent(b[0])] = decodeURIComponent(b[1]);\n\t\t}\n\n\t\treturn query;\n\t},\n\tbuild: function(data) {\n\t\tvar ret = [];\n\t\tfor (var d in data)\n\t\t\tret.push(d + \"=\" + encodeURIComponent(data[d]));\n\t\treturn ret.join(\"&\");\n\t},\n\tsetParameter: function( url, key, value ) {\n\t\tvar data = URL.parse( url );\n\t\tdata[ key ] = value;\n\t\treturn URL.build( data );\n\t}\n};\n\nmodule.exports = URL;\n},{}],7:[function(require,module,exports){\n;(function (global, factory) { // eslint-disable-line\r\n\t\"use strict\"\r\n\t/* eslint-disable no-undef */\r\n\tvar m = factory(global)\r\n\tif (typeof module === \"object\" && module != null && module.exports) {\r\n\t\tmodule.exports = m\r\n\t} else if (typeof define === \"function\" && define.amd) {\r\n\t\tdefine(function () { return m })\r\n\t} else {\r\n\t\tglobal.m = m\r\n\t}\r\n\t/* eslint-enable no-undef */\r\n})(typeof window !== \"undefined\" ? window : this, function (global, undefined) { // eslint-disable-line\r\n\t\"use strict\"\r\n\r\n\tm.version = function () {\r\n\t\treturn \"v0.2.5\"\r\n\t}\r\n\r\n\tvar hasOwn = {}.hasOwnProperty\r\n\tvar type = {}.toString\r\n\r\n\tfunction isFunction(object) {\r\n\t\treturn typeof object === \"function\"\r\n\t}\r\n\r\n\tfunction isObject(object) {\r\n\t\treturn type.call(object) === \"[object Object]\"\r\n\t}\r\n\r\n\tfunction isString(object) {\r\n\t\treturn type.call(object) === \"[object String]\"\r\n\t}\r\n\r\n\tvar isArray = Array.isArray || function (object) {\r\n\t\treturn type.call(object) === \"[object Array]\"\r\n\t}\r\n\r\n\tfunction noop() {}\r\n\r\n\tvar voidElements = {\r\n\t\tAREA: 1,\r\n\t\tBASE: 1,\r\n\t\tBR: 1,\r\n\t\tCOL: 1,\r\n\t\tCOMMAND: 1,\r\n\t\tEMBED: 1,\r\n\t\tHR: 1,\r\n\t\tIMG: 1,\r\n\t\tINPUT: 1,\r\n\t\tKEYGEN: 1,\r\n\t\tLINK: 1,\r\n\t\tMETA: 1,\r\n\t\tPARAM: 1,\r\n\t\tSOURCE: 1,\r\n\t\tTRACK: 1,\r\n\t\tWBR: 1\r\n\t}\r\n\r\n\t// caching commonly used variables\r\n\tvar $document, $location, $requestAnimationFrame, $cancelAnimationFrame\r\n\r\n\t// self invoking function needed because of the way mocks work\r\n\tfunction initialize(mock) {\r\n\t\t$document = mock.document\r\n\t\t$location = mock.location\r\n\t\t$cancelAnimationFrame = mock.cancelAnimationFrame || mock.clearTimeout\r\n\t\t$requestAnimationFrame = mock.requestAnimationFrame || mock.setTimeout\r\n\t}\r\n\r\n\t// testing API\r\n\tm.deps = function (mock) {\r\n\t\tinitialize(global = mock || window)\r\n\t\treturn global\r\n\t}\r\n\r\n\tm.deps(global)\r\n\r\n\t/**\r\n\t * @typedef {String} Tag\r\n\t * A string that looks like -> div.classname#id[param=one][param2=two]\r\n\t * Which describes a DOM node\r\n\t */\r\n\r\n\tfunction parseTagAttrs(cell, tag) {\r\n\t\tvar classes = []\r\n\t\tvar parser = /(?:(^|#|\\.)([^#\\.\\[\\]]+))|(\\[.+?\\])/g\r\n\t\tvar match\r\n\r\n\t\twhile ((match = parser.exec(tag))) {\r\n\t\t\tif (match[1] === \"\" && match[2]) {\r\n\t\t\t\tcell.tag = match[2]\r\n\t\t\t} else if (match[1] === \"#\") {\r\n\t\t\t\tcell.attrs.id = match[2]\r\n\t\t\t} else if (match[1] === \".\") {\r\n\t\t\t\tclasses.push(match[2])\r\n\t\t\t} else if (match[3][0] === \"[\") {\r\n\t\t\t\tvar pair = /\\[(.+?)(?:=(\"|'|)(.*?)\\2)?\\]/.exec(match[3])\r\n\t\t\t\tcell.attrs[pair[1]] = pair[3] || \"\"\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn classes\r\n\t}\r\n\r\n\tfunction getVirtualChildren(args, hasAttrs) {\r\n\t\tvar children = hasAttrs ? args.slice(1) : args\r\n\r\n\t\tif (children.length === 1 && isArray(children[0])) {\r\n\t\t\treturn children[0]\r\n\t\t} else {\r\n\t\t\treturn children\r\n\t\t}\r\n\t}\r\n\r\n\tfunction assignAttrs(target, attrs, classes) {\r\n\t\tvar classAttr = \"class\" in attrs ? \"class\" : \"className\"\r\n\r\n\t\tfor (var attrName in attrs) {\r\n\t\t\tif (hasOwn.call(attrs, attrName)) {\r\n\t\t\t\tif (attrName === classAttr &&\r\n\t\t\t\t\t\tattrs[attrName] != null &&\r\n\t\t\t\t\t\tattrs[attrName] !== \"\") {\r\n\t\t\t\t\tclasses.push(attrs[attrName])\r\n\t\t\t\t\t// create key in correct iteration order\r\n\t\t\t\t\ttarget[attrName] = \"\"\r\n\t\t\t\t} else {\r\n\t\t\t\t\ttarget[attrName] = attrs[attrName]\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (classes.length) target[classAttr] = classes.join(\" \")\r\n\t}\r\n\r\n\t/**\r\n\t *\r\n\t * @param {Tag} The DOM node tag\r\n\t * @param {Object=[]} optional key-value pairs to be mapped to DOM attrs\r\n\t * @param {...mNode=[]} Zero or more Mithril child nodes. Can be an array,\r\n\t * or splat (optional)\r\n\t */\r\n\tfunction m(tag, pairs) {\r\n\t\tvar args = []\r\n\r\n\t\tfor (var i = 1, length = arguments.length; i < length; i++) {\r\n\t\t\targs[i - 1] = arguments[i]\r\n\t\t}\r\n\r\n\t\tif (isObject(tag)) return parameterize(tag, args)\r\n\r\n\t\tif (!isString(tag)) {\r\n\t\t\tthrow new Error(\"selector in m(selector, attrs, children) should \" +\r\n\t\t\t\t\"be a string\")\r\n\t\t}\r\n\r\n\t\tvar hasAttrs = pairs != null && isObject(pairs) &&\r\n\t\t\t!(\"tag\" in pairs || \"view\" in pairs || \"subtree\" in pairs)\r\n\r\n\t\tvar attrs = hasAttrs ? pairs : {}\r\n\t\tvar cell = {\r\n\t\t\ttag: \"div\",\r\n\t\t\tattrs: {},\r\n\t\t\tchildren: getVirtualChildren(args, hasAttrs)\r\n\t\t}\r\n\r\n\t\tassignAttrs(cell.attrs, attrs, parseTagAttrs(cell, tag))\r\n\t\treturn cell\r\n\t}\r\n\r\n\tfunction forEach(list, f) {\r\n\t\tfor (var i = 0; i < list.length && !f(list[i], i++);) {\r\n\t\t\t// function called in condition\r\n\t\t}\r\n\t}\r\n\r\n\tfunction forKeys(list, f) {\r\n\t\tforEach(list, function (attrs, i) {\r\n\t\t\treturn (attrs = attrs && attrs.attrs) &&\r\n\t\t\t\tattrs.key != null &&\r\n\t\t\t\tf(attrs, i)\r\n\t\t})\r\n\t}\r\n\t// This function was causing deopts in Chrome.\r\n\tfunction dataToString(data) {\r\n\t\t// data.toString() might throw or return null if data is the return\r\n\t\t// value of Console.log in some versions of Firefox (behavior depends on\r\n\t\t// version)\r\n\t\ttry {\r\n\t\t\tif (data != null && data.toString() != null) return data\r\n\t\t} catch (e) {\r\n\t\t\t// silently ignore errors\r\n\t\t}\r\n\t\treturn \"\"\r\n\t}\r\n\r\n\t// This function was causing deopts in Chrome.\r\n\tfunction injectTextNode(parentElement, first, index, data) {\r\n\t\ttry {\r\n\t\t\tinsertNode(parentElement, first, index)\r\n\t\t\tfirst.nodeValue = data\r\n\t\t} catch (e) {\r\n\t\t\t// IE erroneously throws error when appending an empty text node\r\n\t\t\t// after a null\r\n\t\t}\r\n\t}\r\n\r\n\tfunction flatten(list) {\r\n\t\t// recursively flatten array\r\n\t\tfor (var i = 0; i < list.length; i++) {\r\n\t\t\tif (isArray(list[i])) {\r\n\t\t\t\tlist = list.concat.apply([], list)\r\n\t\t\t\t// check current index again and flatten until there are no more\r\n\t\t\t\t// nested arrays at that index\r\n\t\t\t\ti--\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn list\r\n\t}\r\n\r\n\tfunction insertNode(parentElement, node, index) {\r\n\t\tparentElement.insertBefore(node,\r\n\t\t\tparentElement.childNodes[index] || null)\r\n\t}\r\n\r\n\tvar DELETION = 1\r\n\tvar INSERTION = 2\r\n\tvar MOVE = 3\r\n\r\n\tfunction handleKeysDiffer(data, existing, cached, parentElement) {\r\n\t\tforKeys(data, function (key, i) {\r\n\t\t\texisting[key = key.key] = existing[key] ? {\r\n\t\t\t\taction: MOVE,\r\n\t\t\t\tindex: i,\r\n\t\t\t\tfrom: existing[key].index,\r\n\t\t\t\telement: cached.nodes[existing[key].index] ||\r\n\t\t\t\t\t$document.createElement(\"div\")\r\n\t\t\t} : {action: INSERTION, index: i}\r\n\t\t})\r\n\r\n\t\tvar actions = []\r\n\t\tfor (var prop in existing) {\r\n\t\t\tif (hasOwn.call(existing, prop)) {\r\n\t\t\t\tactions.push(existing[prop])\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar changes = actions.sort(sortChanges)\r\n\t\tvar newCached = new Array(cached.length)\r\n\r\n\t\tnewCached.nodes = cached.nodes.slice()\r\n\r\n\t\tforEach(changes, function (change) {\r\n\t\t\tvar index = change.index\r\n\t\t\tif (change.action === DELETION) {\r\n\t\t\t\tclear(cached[index].nodes, cached[index])\r\n\t\t\t\tnewCached.splice(index, 1)\r\n\t\t\t}\r\n\t\t\tif (change.action === INSERTION) {\r\n\t\t\t\tvar dummy = $document.createElement(\"div\")\r\n\t\t\t\tdummy.key = data[index].attrs.key\r\n\t\t\t\tinsertNode(parentElement, dummy, index)\r\n\t\t\t\tnewCached.splice(index, 0, {\r\n\t\t\t\t\tattrs: {key: data[index].attrs.key},\r\n\t\t\t\t\tnodes: [dummy]\r\n\t\t\t\t})\r\n\t\t\t\tnewCached.nodes[index] = dummy\r\n\t\t\t}\r\n\r\n\t\t\tif (change.action === MOVE) {\r\n\t\t\t\tvar changeElement = change.element\r\n\t\t\t\tvar maybeChanged = parentElement.childNodes[index]\r\n\t\t\t\tif (maybeChanged !== changeElement && changeElement !== null) {\r\n\t\t\t\t\tparentElement.insertBefore(changeElement,\r\n\t\t\t\t\t\tmaybeChanged || null)\r\n\t\t\t\t}\r\n\t\t\t\tnewCached[index] = cached[change.from]\r\n\t\t\t\tnewCached.nodes[index] = changeElement\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\treturn newCached\r\n\t}\r\n\r\n\tfunction diffKeys(data, cached, existing, parentElement) {\r\n\t\tvar keysDiffer = data.length !== cached.length\r\n\r\n\t\tif (!keysDiffer) {\r\n\t\t\tforKeys(data, function (attrs, i) {\r\n\t\t\t\tvar cachedCell = cached[i]\r\n\t\t\t\treturn keysDiffer = cachedCell &&\r\n\t\t\t\t\tcachedCell.attrs &&\r\n\t\t\t\t\tcachedCell.attrs.key !== attrs.key\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\tif (keysDiffer) {\r\n\t\t\treturn handleKeysDiffer(data, existing, cached, parentElement)\r\n\t\t} else {\r\n\t\t\treturn cached\r\n\t\t}\r\n\t}\r\n\r\n\tfunction diffArray(data, cached, nodes) {\r\n\t\t// diff the array itself\r\n\r\n\t\t// update the list of DOM nodes by collecting the nodes from each item\r\n\t\tforEach(data, function (_, i) {\r\n\t\t\tif (cached[i] != null) nodes.push.apply(nodes, cached[i].nodes)\r\n\t\t})\r\n\t\t// remove items from the end of the array if the new array is shorter\r\n\t\t// than the old one. if errors ever happen here, the issue is most\r\n\t\t// likely a bug in the construction of the `cached` data structure\r\n\t\t// somewhere earlier in the program\r\n\t\tforEach(cached.nodes, function (node, i) {\r\n\t\t\tif (node.parentNode != null && nodes.indexOf(node) < 0) {\r\n\t\t\t\tclear([node], [cached[i]])\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\tif (data.length < cached.length) cached.length = data.length\r\n\t\tcached.nodes = nodes\r\n\t}\r\n\r\n\tfunction buildArrayKeys(data) {\r\n\t\tvar guid = 0\r\n\t\tforKeys(data, function () {\r\n\t\t\tforEach(data, function (attrs) {\r\n\t\t\t\tif ((attrs = attrs && attrs.attrs) && attrs.key == null) {\r\n\t\t\t\t\tattrs.key = \"__mithril__\" + guid++\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\treturn 1\r\n\t\t})\r\n\t}\r\n\r\n\tfunction isDifferentEnough(data, cached, dataAttrKeys) {\r\n\t\tif (data.tag !== cached.tag) return true\r\n\r\n\t\tif (dataAttrKeys.sort().join() !==\r\n\t\t\t\tObject.keys(cached.attrs).sort().join()) {\r\n\t\t\treturn true\r\n\t\t}\r\n\r\n\t\tif (data.attrs.id !== cached.attrs.id) {\r\n\t\t\treturn true\r\n\t\t}\r\n\r\n\t\tif (data.attrs.key !== cached.attrs.key) {\r\n\t\t\treturn true\r\n\t\t}\r\n\r\n\t\tif (m.redraw.strategy() === \"all\") {\r\n\t\t\treturn !cached.configContext || cached.configContext.retain !== true\r\n\t\t}\r\n\r\n\t\tif (m.redraw.strategy() === \"diff\") {\r\n\t\t\treturn cached.configContext && cached.configContext.retain === false\r\n\t\t}\r\n\r\n\t\treturn false\r\n\t}\r\n\r\n\tfunction maybeRecreateObject(data, cached, dataAttrKeys) {\r\n\t\t// if an element is different enough from the one in cache, recreate it\r\n\t\tif (isDifferentEnough(data, cached, dataAttrKeys)) {\r\n\t\t\tif (cached.nodes.length) clear(cached.nodes)\r\n\r\n\t\t\tif (cached.configContext &&\r\n\t\t\t\t\tisFunction(cached.configContext.onunload)) {\r\n\t\t\t\tcached.configContext.onunload()\r\n\t\t\t}\r\n\r\n\t\t\tif (cached.controllers) {\r\n\t\t\t\tforEach(cached.controllers, function (controller) {\r\n\t\t\t\t\tif (controller.onunload) {\r\n\t\t\t\t\t\tcontroller.onunload({preventDefault: noop})\r\n\t\t\t\t\t}\r\n\t\t\t\t})\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tfunction getObjectNamespace(data, namespace) {\r\n\t\tif (data.attrs.xmlns) return data.attrs.xmlns\r\n\t\tif (data.tag === \"svg\") return \"http://www.w3.org/2000/svg\"\r\n\t\tif (data.tag === \"math\") return \"http://www.w3.org/1998/Math/MathML\"\r\n\t\treturn namespace\r\n\t}\r\n\r\n\tvar pendingRequests = 0\r\n\tm.startComputation = function () { pendingRequests++ }\r\n\tm.endComputation = function () {\r\n\t\tif (pendingRequests > 1) {\r\n\t\t\tpendingRequests--\r\n\t\t} else {\r\n\t\t\tpendingRequests = 0\r\n\t\t\tm.redraw()\r\n\t\t}\r\n\t}\r\n\r\n\tfunction unloadCachedControllers(cached, views, controllers) {\r\n\t\tif (controllers.length) {\r\n\t\t\tcached.views = views\r\n\t\t\tcached.controllers = controllers\r\n\t\t\tforEach(controllers, function (controller) {\r\n\t\t\t\tif (controller.onunload && controller.onunload.$old) {\r\n\t\t\t\t\tcontroller.onunload = controller.onunload.$old\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (pendingRequests && controller.onunload) {\r\n\t\t\t\t\tvar onunload = controller.onunload\r\n\t\t\t\t\tcontroller.onunload = noop\r\n\t\t\t\t\tcontroller.onunload.$old = onunload\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\t}\r\n\r\n\tfunction scheduleConfigsToBeCalled(configs, data, node, isNew, cached) {\r\n\t\t// schedule configs to be called. They are called after `build` finishes\r\n\t\t// running\r\n\t\tif (isFunction(data.attrs.config)) {\r\n\t\t\tvar context = cached.configContext = cached.configContext || {}\r\n\r\n\t\t\t// bind\r\n\t\t\tconfigs.push(function () {\r\n\t\t\t\treturn data.attrs.config.call(data, node, !isNew, context,\r\n\t\t\t\t\tcached)\r\n\t\t\t})\r\n\t\t}\r\n\t}\r\n\r\n\tfunction buildUpdatedNode(\r\n\t\tcached,\r\n\t\tdata,\r\n\t\teditable,\r\n\t\thasKeys,\r\n\t\tnamespace,\r\n\t\tviews,\r\n\t\tconfigs,\r\n\t\tcontrollers\r\n\t) {\r\n\t\tvar node = cached.nodes[0]\r\n\r\n\t\tif (hasKeys) {\r\n\t\t\tsetAttributes(node, data.tag, data.attrs, cached.attrs, namespace)\r\n\t\t}\r\n\r\n\t\tcached.children = build(\r\n\t\t\tnode,\r\n\t\t\tdata.tag,\r\n\t\t\tundefined,\r\n\t\t\tundefined,\r\n\t\t\tdata.children,\r\n\t\t\tcached.children,\r\n\t\t\tfalse,\r\n\t\t\t0,\r\n\t\t\tdata.attrs.contenteditable ? node : editable,\r\n\t\t\tnamespace,\r\n\t\t\tconfigs\r\n\t\t)\r\n\r\n\t\tcached.nodes.intact = true\r\n\r\n\t\tif (controllers.length) {\r\n\t\t\tcached.views = views\r\n\t\t\tcached.controllers = controllers\r\n\t\t}\r\n\r\n\t\treturn node\r\n\t}\r\n\r\n\tfunction handleNonexistentNodes(data, parentElement, index) {\r\n\t\tvar nodes\r\n\t\tif (data.$trusted) {\r\n\t\t\tnodes = injectHTML(parentElement, index, data)\r\n\t\t} else {\r\n\t\t\tnodes = [$document.createTextNode(data)]\r\n\t\t\tif (!(parentElement.nodeName in voidElements)) {\r\n\t\t\t\tinsertNode(parentElement, nodes[0], index)\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar cached\r\n\r\n\t\tif (typeof data === \"string\" ||\r\n\t\t\t\ttypeof data === \"number\" ||\r\n\t\t\t\ttypeof data === \"boolean\") {\r\n\t\t\tcached = new data.constructor(data)\r\n\t\t} else {\r\n\t\t\tcached = data\r\n\t\t}\r\n\r\n\t\tcached.nodes = nodes\r\n\t\treturn cached\r\n\t}\r\n\r\n\tfunction reattachNodes(\r\n\t\tdata,\r\n\t\tcached,\r\n\t\tparentElement,\r\n\t\teditable,\r\n\t\tindex,\r\n\t\tparentTag\r\n\t) {\r\n\t\tvar nodes = cached.nodes\r\n\t\tif (!editable || editable !== $document.activeElement) {\r\n\t\t\tif (data.$trusted) {\r\n\t\t\t\tclear(nodes, cached)\r\n\t\t\t\tnodes = injectHTML(parentElement, index, data)\r\n\t\t\t} else if (parentTag === \"textarea\") {\r\n\t\t\t\t// <textarea> uses `value` instead of `nodeValue`.\r\n\t\t\t\tparentElement.value = data\r\n\t\t\t} else if (editable) {\r\n\t\t\t\t// contenteditable nodes use `innerHTML` instead of `nodeValue`.\r\n\t\t\t\teditable.innerHTML = data\r\n\t\t\t} else {\r\n\t\t\t\t// was a trusted string\r\n\t\t\t\tif (nodes[0].nodeType === 1 || nodes.length > 1 ||\r\n\t\t\t\t\t\t(nodes[0].nodeValue.trim &&\r\n\t\t\t\t\t\t\t!nodes[0].nodeValue.trim())) {\r\n\t\t\t\t\tclear(cached.nodes, cached)\r\n\t\t\t\t\tnodes = [$document.createTextNode(data)]\r\n\t\t\t\t}\r\n\r\n\t\t\t\tinjectTextNode(parentElement, nodes[0], index, data)\r\n\t\t\t}\r\n\t\t}\r\n\t\tcached = new data.constructor(data)\r\n\t\tcached.nodes = nodes\r\n\t\treturn cached\r\n\t}\r\n\r\n\tfunction handleTextNode(\r\n\t\tcached,\r\n\t\tdata,\r\n\t\tindex,\r\n\t\tparentElement,\r\n\t\tshouldReattach,\r\n\t\teditable,\r\n\t\tparentTag\r\n\t) {\r\n\t\tif (!cached.nodes.length) {\r\n\t\t\treturn handleNonexistentNodes(data, parentElement, index)\r\n\t\t} else if (cached.valueOf() !== data.valueOf() || shouldReattach) {\r\n\t\t\treturn reattachNodes(data, cached, parentElement, editable, index,\r\n\t\t\t\tparentTag)\r\n\t\t} else {\r\n\t\t\treturn (cached.nodes.intact = true, cached)\r\n\t\t}\r\n\t}\r\n\r\n\tfunction getSubArrayCount(item) {\r\n\t\tif (item.$trusted) {\r\n\t\t\t// fix offset of next element if item was a trusted string w/ more\r\n\t\t\t// than one html element\r\n\t\t\t// the first clause in the regexp matches elements\r\n\t\t\t// the second clause (after the pipe) matches text nodes\r\n\t\t\tvar match = item.match(/<[^\\/]|\\>\\s*[^<]/g)\r\n\t\t\tif (match != null) return match.length\r\n\t\t} else if (isArray(item)) {\r\n\t\t\treturn item.length\r\n\t\t}\r\n\t\treturn 1\r\n\t}\r\n\r\n\tfunction buildArray(\r\n\t\tdata,\r\n\t\tcached,\r\n\t\tparentElement,\r\n\t\tindex,\r\n\t\tparentTag,\r\n\t\tshouldReattach,\r\n\t\teditable,\r\n\t\tnamespace,\r\n\t\tconfigs\r\n\t) {\r\n\t\tdata = flatten(data)\r\n\t\tvar nodes = []\r\n\t\tvar intact = cached.length === data.length\r\n\t\tvar subArrayCount = 0\r\n\r\n\t\t// keys algorithm: sort elements without recreating them if keys are\r\n\t\t// present\r\n\t\t//\r\n\t\t// 1) create a map of all existing keys, and mark all for deletion\r\n\t\t// 2) add new keys to map and mark them for addition\r\n\t\t// 3) if key exists in new list, change action from deletion to a move\r\n\t\t// 4) for each key, handle its corresponding action as marked in\r\n\t\t// previous steps\r\n\r\n\t\tvar existing = {}\r\n\t\tvar shouldMaintainIdentities = false\r\n\r\n\t\tforKeys(cached, function (attrs, i) {\r\n\t\t\tshouldMaintainIdentities = true\r\n\t\t\texisting[cached[i].attrs.key] = {action: DELETION, index: i}\r\n\t\t})\r\n\r\n\t\tbuildArrayKeys(data)\r\n\t\tif (shouldMaintainIdentities) {\r\n\t\t\tcached = diffKeys(data, cached, existing, parentElement)\r\n\t\t}\r\n\t\t// end key algorithm\r\n\r\n\t\tvar cacheCount = 0\r\n\t\t// faster explicitly written\r\n\t\tfor (var i = 0, len = data.length; i < len; i++) {\r\n\t\t\t// diff each item in the array\r\n\t\t\tvar item = build(\r\n\t\t\t\tparentElement,\r\n\t\t\t\tparentTag,\r\n\t\t\t\tcached,\r\n\t\t\t\tindex,\r\n\t\t\t\tdata[i],\r\n\t\t\t\tcached[cacheCount],\r\n\t\t\t\tshouldReattach,\r\n\t\t\t\tindex + subArrayCount || subArrayCount,\r\n\t\t\t\teditable,\r\n\t\t\t\tnamespace,\r\n\t\t\t\tconfigs)\r\n\r\n\t\t\tif (item !== undefined) {\r\n\t\t\t\tintact = intact && item.nodes.intact\r\n\t\t\t\tsubArrayCount += getSubArrayCount(item)\r\n\t\t\t\tcached[cacheCount++] = item\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!intact) diffArray(data, cached, nodes)\r\n\t\treturn cached\r\n\t}\r\n\r\n\tfunction makeCache(data, cached, index, parentIndex, parentCache) {\r\n\t\tif (cached != null) {\r\n\t\t\tif (type.call(cached) === type.call(data)) return cached\r\n\r\n\t\t\tif (parentCache && parentCache.nodes) {\r\n\t\t\t\tvar offset = index - parentIndex\r\n\t\t\t\tvar end = offset + (isArray(data) ? data : cached.nodes).length\r\n\t\t\t\tclear(\r\n\t\t\t\t\tparentCache.nodes.slice(offset, end),\r\n\t\t\t\t\tparentCache.slice(offset, end))\r\n\t\t\t} else if (cached.nodes) {\r\n\t\t\t\tclear(cached.nodes, cached)\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tcached = new data.constructor()\r\n\t\t// if constructor creates a virtual dom element, use a blank object as\r\n\t\t// the base cached node instead of copying the virtual el (#277)\r\n\t\tif (cached.tag) cached = {}\r\n\t\tcached.nodes = []\r\n\t\treturn cached\r\n\t}\r\n\r\n\tfunction constructNode(data, namespace) {\r\n\t\tif (data.attrs.is) {\r\n\t\t\tif (namespace == null) {\r\n\t\t\t\treturn $document.createElement(data.tag, data.attrs.is)\r\n\t\t\t} else {\r\n\t\t\t\treturn $document.createElementNS(namespace, data.tag,\r\n\t\t\t\t\tdata.attrs.is)\r\n\t\t\t}\r\n\t\t} else if (namespace == null) {\r\n\t\t\treturn $document.createElement(data.tag)\r\n\t\t} else {\r\n\t\t\treturn $document.createElementNS(namespace, data.tag)\r\n\t\t}\r\n\t}\r\n\r\n\tfunction constructAttrs(data, node, namespace, hasKeys) {\r\n\t\tif (hasKeys) {\r\n\t\t\treturn setAttributes(node, data.tag, data.attrs, {}, namespace)\r\n\t\t} else {\r\n\t\t\treturn data.attrs\r\n\t\t}\r\n\t}\r\n\r\n\tfunction constructChildren(\r\n\t\tdata,\r\n\t\tnode,\r\n\t\tcached,\r\n\t\teditable,\r\n\t\tnamespace,\r\n\t\tconfigs\r\n\t) {\r\n\t\tif (data.children != null && data.children.length > 0) {\r\n\t\t\treturn build(\r\n\t\t\t\tnode,\r\n\t\t\t\tdata.tag,\r\n\t\t\t\tundefined,\r\n\t\t\t\tundefined,\r\n\t\t\t\tdata.children,\r\n\t\t\t\tcached.children,\r\n\t\t\t\ttrue,\r\n\t\t\t\t0,\r\n\t\t\t\tdata.attrs.contenteditable ? node : editable,\r\n\t\t\t\tnamespace,\r\n\t\t\t\tconfigs)\r\n\t\t} else {\r\n\t\t\treturn data.children\r\n\t\t}\r\n\t}\r\n\r\n\tfunction reconstructCached(\r\n\t\tdata,\r\n\t\tattrs,\r\n\t\tchildren,\r\n\t\tnode,\r\n\t\tnamespace,\r\n\t\tviews,\r\n\t\tcontrollers\r\n\t) {\r\n\t\tvar cached = {\r\n\t\t\ttag: data.tag,\r\n\t\t\tattrs: attrs,\r\n\t\t\tchildren: children,\r\n\t\t\tnodes: [node]\r\n\t\t}\r\n\r\n\t\tunloadCachedControllers(cached, views, controllers)\r\n\r\n\t\tif (cached.children && !cached.children.nodes) {\r\n\t\t\tcached.children.nodes = []\r\n\t\t}\r\n\r\n\t\t// edge case: setting value on <select> doesn't work before children\r\n\t\t// exist, so set it again after children have been created\r\n\t\tif (data.tag === \"select\" && \"value\" in data.attrs) {\r\n\t\t\tsetAttributes(node, data.tag, {value: data.attrs.value}, {},\r\n\t\t\t\tnamespace)\r\n\t\t}\r\n\r\n\t\treturn cached\r\n\t}\r\n\r\n\tfunction getController(views, view, cachedControllers, controller) {\r\n\t\tvar controllerIndex\r\n\r\n\t\tif (m.redraw.strategy() === \"diff\" && views) {\r\n\t\t\tcontrollerIndex = views.indexOf(view)\r\n\t\t} else {\r\n\t\t\tcontrollerIndex = -1\r\n\t\t}\r\n\r\n\t\tif (controllerIndex > -1) {\r\n\t\t\treturn cachedControllers[controllerIndex]\r\n\t\t} else if (isFunction(controller)) {\r\n\t\t\treturn new controller()\r\n\t\t} else {\r\n\t\t\treturn {}\r\n\t\t}\r\n\t}\r\n\r\n\tvar unloaders = []\r\n\r\n\tfunction updateLists(views, controllers, view, controller) {\r\n\t\tif (controller.onunload != null &&\r\n\t\t\t\tunloaders.map(function (u) { return u.handler })\r\n\t\t\t\t\t.indexOf(controller.onunload) < 0) {\r\n\t\t\tunloaders.push({\r\n\t\t\t\tcontroller: controller,\r\n\t\t\t\thandler: controller.onunload\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\tviews.push(view)\r\n\t\tcontrollers.push(controller)\r\n\t}\r\n\r\n\tvar forcing = false\r\n\tfunction checkView(\r\n\t\tdata,\r\n\t\tview,\r\n\t\tcached,\r\n\t\tcachedControllers,\r\n\t\tcontrollers,\r\n\t\tviews\r\n\t) {\r\n\t\tvar controller = getController(\r\n\t\t\tcached.views,\r\n\t\t\tview,\r\n\t\t\tcachedControllers,\r\n\t\t\tdata.controller)\r\n\r\n\t\tvar key = data && data.attrs && data.attrs.key\r\n\r\n\t\tif (pendingRequests === 0 ||\r\n\t\t\t\tforcing ||\r\n\t\t\t\tcachedControllers &&\r\n\t\t\t\t\tcachedControllers.indexOf(controller) > -1) {\r\n\t\t\tdata = data.view(controller)\r\n\t\t} else {\r\n\t\t\tdata = {tag: \"placeholder\"}\r\n\t\t}\r\n\r\n\t\tif (data.subtree === \"retain\") return data\r\n\t\tdata.attrs = data.attrs || {}\r\n\t\tdata.attrs.key = key\r\n\t\tupdateLists(views, controllers, view, controller)\r\n\t\treturn data\r\n\t}\r\n\r\n\tfunction markViews(data, cached, views, controllers) {\r\n\t\tvar cachedControllers = cached && cached.controllers\r\n\r\n\t\twhile (data.view != null) {\r\n\t\t\tdata = checkView(\r\n\t\t\t\tdata,\r\n\t\t\t\tdata.view.$original || data.view,\r\n\t\t\t\tcached,\r\n\t\t\t\tcachedControllers,\r\n\t\t\t\tcontrollers,\r\n\t\t\t\tviews)\r\n\t\t}\r\n\r\n\t\treturn data\r\n\t}\r\n\r\n\tfunction buildObject( // eslint-disable-line max-statements\r\n\t\tdata,\r\n\t\tcached,\r\n\t\teditable,\r\n\t\tparentElement,\r\n\t\tindex,\r\n\t\tshouldReattach,\r\n\t\tnamespace,\r\n\t\tconfigs\r\n\t) {\r\n\t\tvar views = []\r\n\t\tvar controllers = []\r\n\r\n\t\tdata = markViews(data, cached, views, controllers)\r\n\r\n\t\tif (data.subtree === \"retain\") return cached\r\n\r\n\t\tif (!data.tag && controllers.length) {\r\n\t\t\tthrow new Error(\"Component template must return a virtual \" +\r\n\t\t\t\t\"element, not an array, string, etc.\")\r\n\t\t}\r\n\r\n\t\tdata.attrs = data.attrs || {}\r\n\t\tcached.attrs = cached.attrs || {}\r\n\r\n\t\tvar dataAttrKeys = Object.keys(data.attrs)\r\n\t\tvar hasKeys = dataAttrKeys.length > (\"key\" in data.attrs ? 1 : 0)\r\n\r\n\t\tmaybeRecreateObject(data, cached, dataAttrKeys)\r\n\r\n\t\tif (!isString(data.tag)) return\r\n\r\n\t\tvar isNew = cached.nodes.length === 0\r\n\r\n\t\tnamespace = getObjectNamespace(data, namespace)\r\n\r\n\t\tvar node\r\n\t\tif (isNew) {\r\n\t\t\tnode = constructNode(data, namespace)\r\n\t\t\t// set attributes first, then create children\r\n\t\t\tvar attrs = constructAttrs(data, node, namespace, hasKeys)\r\n\r\n\t\t\t// add the node to its parent before attaching children to it\r\n\t\t\tinsertNode(parentElement, node, index)\r\n\r\n\t\t\tvar children = constructChildren(data, node, cached, editable,\r\n\t\t\t\tnamespace, configs)\r\n\r\n\t\t\tcached = reconstructCached(\r\n\t\t\t\tdata,\r\n\t\t\t\tattrs,\r\n\t\t\t\tchildren,\r\n\t\t\t\tnode,\r\n\t\t\t\tnamespace,\r\n\t\t\t\tviews,\r\n\t\t\t\tcontrollers)\r\n\t\t} else {\r\n\t\t\tnode = buildUpdatedNode(\r\n\t\t\t\tcached,\r\n\t\t\t\tdata,\r\n\t\t\t\teditable,\r\n\t\t\t\thasKeys,\r\n\t\t\t\tnamespace,\r\n\t\t\t\tviews,\r\n\t\t\t\tconfigs,\r\n\t\t\t\tcontrollers)\r\n\t\t}\r\n\r\n\t\tif (!isNew && shouldReattach === true && node != null) {\r\n\t\t\tinsertNode(parentElement, node, index)\r\n\t\t}\r\n\r\n\t\t// The configs are called after `build` finishes running\r\n\t\tscheduleConfigsToBeCalled(configs, data, node, isNew, cached)\r\n\r\n\t\treturn cached\r\n\t}\r\n\r\n\tfunction build(\r\n\t\tparentElement,\r\n\t\tparentTag,\r\n\t\tparentCache,\r\n\t\tparentIndex,\r\n\t\tdata,\r\n\t\tcached,\r\n\t\tshouldReattach,\r\n\t\tindex,\r\n\t\teditable,\r\n\t\tnamespace,\r\n\t\tconfigs\r\n\t) {\r\n\t\t/*\r\n\t\t * `build` is a recursive function that manages creation/diffing/removal\r\n\t\t * of DOM elements based on comparison between `data` and `cached` the\r\n\t\t * diff algorithm can be summarized as this:\r\n\t\t *\r\n\t\t * 1 - compare `data` and `cached`\r\n\t\t * 2 - if they are different, copy `data` to `cached` and update the DOM\r\n\t\t * based on what the difference is\r\n\t\t * 3 - recursively apply this algorithm for every array and for the\r\n\t\t * children of every virtual element\r\n\t\t *\r\n\t\t * The `cached` data structure is essentially the same as the previous\r\n\t\t * redraw's `data` data structure, with a few additions:\r\n\t\t * - `cached` always has a property called `nodes`, which is a list of\r\n\t\t * DOM elements that correspond to the data represented by the\r\n\t\t * respective virtual element\r\n\t\t * - in order to support attaching `nodes` as a property of `cached`,\r\n\t\t * `cached` is *always* a non-primitive object, i.e. if the data was\r\n\t\t * a string, then cached is a String instance. If data was `null` or\r\n\t\t * `undefined`, cached is `new String(\"\")`\r\n\t\t * - `cached also has a `configContext` property, which is the state\r\n\t\t * storage object exposed by config(element, isInitialized, context)\r\n\t\t * - when `cached` is an Object, it represents a virtual element; when\r\n\t\t * it's an Array, it represents a list of elements; when it's a\r\n\t\t * String, Number or Boolean, it represents a text node\r\n\t\t *\r\n\t\t * `parentElement` is a DOM element used for W3C DOM API calls\r\n\t\t * `parentTag` is only used for handling a corner case for textarea\r\n\t\t * values\r\n\t\t * `parentCache` is used to remove nodes in some multi-node cases\r\n\t\t * `parentIndex` and `index` are used to figure out the offset of nodes.\r\n\t\t * They're artifacts from before arrays started being flattened and are\r\n\t\t * likely refactorable\r\n\t\t * `data` and `cached` are, respectively, the new and old nodes being\r\n\t\t * diffed\r\n\t\t * `shouldReattach` is a flag indicating whether a parent node was\r\n\t\t * recreated (if so, and if this node is reused, then this node must\r\n\t\t * reattach itself to the new parent)\r\n\t\t * `editable` is a flag that indicates whether an ancestor is\r\n\t\t * contenteditable\r\n\t\t * `namespace` indicates the closest HTML namespace as it cascades down\r\n\t\t * from an ancestor\r\n\t\t * `configs` is a list of config functions to run after the topmost\r\n\t\t * `build` call finishes running\r\n\t\t *\r\n\t\t * there's logic that relies on the assumption that null and undefined\r\n\t\t * data are equivalent to empty strings\r\n\t\t * - this prevents lifecycle surprises from procedural helpers that mix\r\n\t\t * implicit and explicit return statements (e.g.\r\n\t\t * function foo() {if (cond) return m(\"div\")}\r\n\t\t * - it simplifies diffing code\r\n\t\t */\r\n\t\tdata = dataToString(data)\r\n\t\tif (data.subtree === \"retain\") return cached\r\n\t\tcached = makeCache(data, cached, index, parentIndex, parentCache)\r\n\r\n\t\tif (isArray(data)) {\r\n\t\t\treturn buildArray(\r\n\t\t\t\tdata,\r\n\t\t\t\tcached,\r\n\t\t\t\tparentElement,\r\n\t\t\t\tindex,\r\n\t\t\t\tparentTag,\r\n\t\t\t\tshouldReattach,\r\n\t\t\t\teditable,\r\n\t\t\t\tnamespace,\r\n\t\t\t\tconfigs)\r\n\t\t} else if (data != null && isObject(data)) {\r\n\t\t\treturn buildObject(\r\n\t\t\t\tdata,\r\n\t\t\t\tcached,\r\n\t\t\t\teditable,\r\n\t\t\t\tparentElement,\r\n\t\t\t\tindex,\r\n\t\t\t\tshouldReattach,\r\n\t\t\t\tnamespace,\r\n\t\t\t\tconfigs)\r\n\t\t} else if (!isFunction(data)) {\r\n\t\t\treturn handleTextNode(\r\n\t\t\t\tcached,\r\n\t\t\t\tdata,\r\n\t\t\t\tindex,\r\n\t\t\t\tparentElement,\r\n\t\t\t\tshouldReattach,\r\n\t\t\t\teditable,\r\n\t\t\t\tparentTag)\r\n\t\t} else {\r\n\t\t\treturn cached\r\n\t\t}\r\n\t}\r\n\r\n\tfunction sortChanges(a, b) {\r\n\t\treturn a.action - b.action || a.index - b.index\r\n\t}\r\n\r\n\tfunction copyStyleAttrs(node, dataAttr, cachedAttr) {\r\n\t\tfor (var rule in dataAttr) {\r\n\t\t\tif (hasOwn.call(dataAttr, rule)) {\r\n\t\t\t\tif (cachedAttr == null || cachedAttr[rule] !== dataAttr[rule]) {\r\n\t\t\t\t\tnode.style[rule] = dataAttr[rule]\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfor (rule in cachedAttr) {\r\n\t\t\tif (hasOwn.call(cachedAttr, rule)) {\r\n\t\t\t\tif (!hasOwn.call(dataAttr, rule)) node.style[rule] = \"\"\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tvar shouldUseSetAttribute = {\r\n\t\tlist: 1,\r\n\t\tstyle: 1,\r\n\t\tform: 1,\r\n\t\ttype: 1,\r\n\t\twidth: 1,\r\n\t\theight: 1\r\n\t}\r\n\r\n\tfunction setSingleAttr(\r\n\t\tnode,\r\n\t\tattrName,\r\n\t\tdataAttr,\r\n\t\tcachedAttr,\r\n\t\ttag,\r\n\t\tnamespace\r\n\t) {\r\n\t\tif (attrName === \"config\" || attrName === \"key\") {\r\n\t\t\t// `config` isn't a real attribute, so ignore it\r\n\t\t\treturn true\r\n\t\t} else if (isFunction(dataAttr) && attrName.slice(0, 2) === \"on\") {\r\n\t\t\t// hook event handlers to the auto-redrawing system\r\n\t\t\tnode[attrName] = autoredraw(dataAttr, node)\r\n\t\t} else if (attrName === \"style\" && dataAttr != null &&\r\n\t\t\t\tisObject(dataAttr)) {\r\n\t\t\t// handle `style: {...}`\r\n\t\t\tcopyStyleAttrs(node, dataAttr, cachedAttr)\r\n\t\t} else if (namespace != null) {\r\n\t\t\t// handle SVG\r\n\t\t\tif (attrName === \"href\") {\r\n\t\t\t\tnode.setAttributeNS(\"http://www.w3.org/1999/xlink\",\r\n\t\t\t\t\t\"href\", dataAttr)\r\n\t\t\t} else {\r\n\t\t\t\tnode.setAttribute(\r\n\t\t\t\t\tattrName === \"className\" ? \"class\" : attrName,\r\n\t\t\t\t\tdataAttr)\r\n\t\t\t}\r\n\t\t} else if (attrName in node && !shouldUseSetAttribute[attrName]) {\r\n\t\t\t// handle cases that are properties (but ignore cases where we\r\n\t\t\t// should use setAttribute instead)\r\n\t\t\t//\r\n\t\t\t// - list and form are typically used as strings, but are DOM\r\n\t\t\t// element references in js\r\n\t\t\t//\r\n\t\t\t// - when using CSS selectors (e.g. `m(\"[style='']\")`), style is\r\n\t\t\t// used as a string, but it's an object in js\r\n\t\t\t//\r\n\t\t\t// #348 don't set the value if not needed - otherwise, cursor\r\n\t\t\t// placement breaks in Chrome\r\n\t\t\ttry {\r\n\t\t\t\tif (tag !== \"input\" || node[attrName] !== dataAttr) {\r\n\t\t\t\t\tnode[attrName] = dataAttr\r\n\t\t\t\t}\r\n\t\t\t} catch (e) {\r\n\t\t\t\tnode.setAttribute(attrName, dataAttr)\r\n\t\t\t}\r\n\t\t}\r\n\t\telse node.setAttribute(attrName, dataAttr)\r\n\t}\r\n\r\n\tfunction trySetAttr(\r\n\t\tnode,\r\n\t\tattrName,\r\n\t\tdataAttr,\r\n\t\tcachedAttr,\r\n\t\tcachedAttrs,\r\n\t\ttag,\r\n\t\tnamespace\r\n\t) {\r\n\t\tif (!(attrName in cachedAttrs) || (cachedAttr !== dataAttr) || ($document.activeElement === node)) {\r\n\t\t\tcachedAttrs[attrName] = dataAttr\r\n\t\t\ttry {\r\n\t\t\t\treturn setSingleAttr(\r\n\t\t\t\t\tnode,\r\n\t\t\t\t\tattrName,\r\n\t\t\t\t\tdataAttr,\r\n\t\t\t\t\tcachedAttr,\r\n\t\t\t\t\ttag,\r\n\t\t\t\t\tnamespace)\r\n\t\t\t} catch (e) {\r\n\t\t\t\t// swallow IE's invalid argument errors to mimic HTML's\r\n\t\t\t\t// fallback-to-doing-nothing-on-invalid-attributes behavior\r\n\t\t\t\tif (e.message.indexOf(\"Invalid argument\") < 0) throw e\r\n\t\t\t}\r\n\t\t} else if (attrName === \"value\" && tag === \"input\" &&\r\n\t\t\t\tnode.value !== dataAttr) {\r\n\t\t\t// #348 dataAttr may not be a string, so use loose comparison\r\n\t\t\tnode.value = dataAttr\r\n\t\t}\r\n\t}\r\n\r\n\tfunction setAttributes(node, tag, dataAttrs, cachedAttrs, namespace) {\r\n\t\tfor (var attrName in dataAttrs) {\r\n\t\t\tif (hasOwn.call(dataAttrs, attrName)) {\r\n\t\t\t\tif (trySetAttr(\r\n\t\t\t\t\t\tnode,\r\n\t\t\t\t\t\tattrName,\r\n\t\t\t\t\t\tdataAttrs[attrName],\r\n\t\t\t\t\t\tcachedAttrs[attrName],\r\n\t\t\t\t\t\tcachedAttrs,\r\n\t\t\t\t\t\ttag,\r\n\t\t\t\t\t\tnamespace)) {\r\n\t\t\t\t\tcontinue\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn cachedAttrs\r\n\t}\r\n\r\n\tfunction clear(nodes, cached) {\r\n\t\tfor (var i = nodes.length - 1; i > -1; i--) {\r\n\t\t\tif (nodes[i] && nodes[i].parentNode) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tnodes[i].parentNode.removeChild(nodes[i])\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\t/* eslint-disable max-len */\r\n\t\t\t\t\t// ignore if this fails due to order of events (see\r\n\t\t\t\t\t// http://stackoverflow.com/questions/21926083/failed-to-execute-removechild-on-node)\r\n\t\t\t\t\t/* eslint-enable max-len */\r\n\t\t\t\t}\r\n\t\t\t\tcached = [].concat(cached)\r\n\t\t\t\tif (cached[i]) unload(cached[i])\r\n\t\t\t}\r\n\t\t}\r\n\t\t// release memory if nodes is an array. This check should fail if nodes\r\n\t\t// is a NodeList (see loop above)\r\n\t\tif (nodes.length) {\r\n\t\t\tnodes.length = 0\r\n\t\t}\r\n\t}\r\n\r\n\tfunction unload(cached) {\r\n\t\tif (cached.configContext && isFunction(cached.configContext.onunload)) {\r\n\t\t\tcached.configContext.onunload()\r\n\t\t\tcached.configContext.onunload = null\r\n\t\t}\r\n\t\tif (cached.controllers) {\r\n\t\t\tforEach(cached.controllers, function (controller) {\r\n\t\t\t\tif (isFunction(controller.onunload)) {\r\n\t\t\t\t\tcontroller.onunload({preventDefault: noop})\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\t\tif (cached.children) {\r\n\t\t\tif (isArray(cached.children)) forEach(cached.children, unload)\r\n\t\t\telse if (cached.children.tag) unload(cached.children)\r\n\t\t}\r\n\t}\r\n\r\n\tfunction appendTextFragment(parentElement, data) {\r\n\t\ttry {\r\n\t\t\tparentElement.appendChild(\r\n\t\t\t\t$document.createRange().createContextualFragment(data))\r\n\t\t} catch (e) {\r\n\t\t\tparentElement.insertAdjacentHTML(\"beforeend\", data)\r\n\t\t\treplaceScriptNodes(parentElement)\r\n\t\t}\r\n\t}\r\n\r\n\t// Replace script tags inside given DOM element with executable ones.\r\n\t// Will also check children recursively and replace any found script\r\n\t// tags in same manner.\r\n\tfunction replaceScriptNodes(node) {\r\n\t\tif (node.tagName === \"SCRIPT\") {\r\n\t\t\tnode.parentNode.replaceChild(buildExecutableNode(node), node)\r\n\t\t} else {\r\n\t\t\tvar children = node.childNodes\r\n\t\t\tif (children && children.length) {\r\n\t\t\t\tfor (var i = 0; i < children.length; i++) {\r\n\t\t\t\t\treplaceScriptNodes(children[i])\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn node\r\n\t}\r\n\r\n\t// Replace script element with one whose contents are executable.\r\n\tfunction buildExecutableNode(node){\r\n\t\tvar scriptEl = document.createElement(\"script\")\r\n\t\tvar attrs = node.attributes\r\n\r\n\t\tfor (var i = 0; i < attrs.length; i++) {\r\n\t\t\tscriptEl.setAttribute(attrs[i].name, attrs[i].value)\r\n\t\t}\r\n\r\n\t\tscriptEl.text = node.innerHTML\r\n\t\treturn scriptEl\r\n\t}\r\n\r\n\tfunction injectHTML(parentElement, index, data) {\r\n\t\tvar nextSibling = parentElement.childNodes[index]\r\n\t\tif (nextSibling) {\r\n\t\t\tvar isElement = nextSibling.nodeType !== 1\r\n\t\t\tvar placeholder = $document.createElement(\"span\")\r\n\t\t\tif (isElement) {\r\n\t\t\t\tparentElement.insertBefore(placeholder, nextSibling || null)\r\n\t\t\t\tplaceholder.insertAdjacentHTML(\"beforebegin\", data)\r\n\t\t\t\tparentElement.removeChild(placeholder)\r\n\t\t\t} else {\r\n\t\t\t\tnextSibling.insertAdjacentHTML(\"beforebegin\", data)\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tappendTextFragment(parentElement, data)\r\n\t\t}\r\n\r\n\t\tvar nodes = []\r\n\r\n\t\twhile (parentElement.childNodes[index] !== nextSibling) {\r\n\t\t\tnodes.push(parentElement.childNodes[index])\r\n\t\t\tindex++\r\n\t\t}\r\n\r\n\t\treturn nodes\r\n\t}\r\n\r\n\tfunction autoredraw(callback, object) {\r\n\t\treturn function (e) {\r\n\t\t\te = e || event\r\n\t\t\tm.redraw.strategy(\"diff\")\r\n\t\t\tm.startComputation()\r\n\t\t\ttry {\r\n\t\t\t\treturn callback.call(object, e)\r\n\t\t\t} finally {\r\n\t\t\t\tendFirstComputation()\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tvar html\r\n\tvar documentNode = {\r\n\t\tappendChild: function (node) {\r\n\t\t\tif (html === undefined) html = $document.createElement(\"html\")\r\n\t\t\tif ($document.documentElement &&\r\n\t\t\t\t\t$document.documentElement !== node) {\r\n\t\t\t\t$document.replaceChild(node, $document.documentElement)\r\n\t\t\t} else {\r\n\t\t\t\t$document.appendChild(node)\r\n\t\t\t}\r\n\r\n\t\t\tthis.childNodes = $document.childNodes\r\n\t\t},\r\n\r\n\t\tinsertBefore: function (node) {\r\n\t\t\tthis.appendChild(node)\r\n\t\t},\r\n\r\n\t\tchildNodes: []\r\n\t}\r\n\r\n\tvar nodeCache = []\r\n\tvar cellCache = {}\r\n\r\n\tm.render = function (root, cell, forceRecreation) {\r\n\t\tif (!root) {\r\n\t\t\tthrow new Error(\"Ensure the DOM element being passed to \" +\r\n\t\t\t\t\"m.route/m.mount/m.render is not undefined.\")\r\n\t\t}\r\n\t\tvar configs = []\r\n\t\tvar id = getCellCacheKey(root)\r\n\t\tvar isDocumentRoot = root === $document\r\n\t\tvar node\r\n\r\n\t\tif (isDocumentRoot || root === $document.documentElement) {\r\n\t\t\tnode = documentNode\r\n\t\t} else {\r\n\t\t\tnode = root\r\n\t\t}\r\n\r\n\t\tif (isDocumentRoot && cell.tag !== \"html\") {\r\n\t\t\tcell = {tag: \"html\", attrs: {}, children: cell}\r\n\t\t}\r\n\r\n\t\tif (cellCache[id] === undefined) clear(node.childNodes)\r\n\t\tif (forceRecreation === true) reset(root)\r\n\r\n\t\tcellCache[id] = build(\r\n\t\t\tnode,\r\n\t\t\tnull,\r\n\t\t\tundefined,\r\n\t\t\tundefined,\r\n\t\t\tcell,\r\n\t\t\tcellCache[id],\r\n\t\t\tfalse,\r\n\t\t\t0,\r\n\t\t\tnull,\r\n\t\t\tundefined,\r\n\t\t\tconfigs)\r\n\r\n\t\tforEach(configs, function (config) { config() })\r\n\t}\r\n\r\n\tfunction getCellCacheKey(element) {\r\n\t\tvar index = nodeCache.indexOf(element)\r\n\t\treturn index < 0 ? nodeCache.push(element) - 1 : index\r\n\t}\r\n\r\n\tm.trust = function (value) {\r\n\t\tvalue = new String(value) // eslint-disable-line no-new-wrappers\r\n\t\tvalue.$trusted = true\r\n\t\treturn value\r\n\t}\r\n\r\n\tfunction gettersetter(store) {\r\n\t\tfunction prop() {\r\n\t\t\tif (arguments.length) store = arguments[0]\r\n\t\t\treturn store\r\n\t\t}\r\n\r\n\t\tprop.toJSON = function () {\r\n\t\t\treturn store\r\n\t\t}\r\n\r\n\t\treturn prop\r\n\t}\r\n\r\n\tm.prop = function (store) {\r\n\t\tif ((store != null && (isObject(store) || isFunction(store)) || ((typeof Promise !== \"undefined\") && (store instanceof Promise))) &&\r\n\t\t\t\tisFunction(store.then)) {\r\n\t\t\treturn propify(store)\r\n\t\t}\r\n\r\n\t\treturn gettersetter(store)\r\n\t}\r\n\r\n\tvar roots = []\r\n\tvar components = []\r\n\tvar controllers = []\r\n\tvar lastRedrawId = null\r\n\tvar lastRedrawCallTime = 0\r\n\tvar computePreRedrawHook = null\r\n\tvar computePostRedrawHook = null\r\n\tvar topComponent\r\n\tvar FRAME_BUDGET = 16 // 60 frames per second = 1 call per 16 ms\r\n\r\n\tfunction parameterize(component, args) {\r\n\t\tfunction controller() {\r\n\t\t\t/* eslint-disable no-invalid-this */\r\n\t\t\treturn (component.controller || noop).apply(this, args) || this\r\n\t\t\t/* eslint-enable no-invalid-this */\r\n\t\t}\r\n\r\n\t\tif (component.controller) {\r\n\t\t\tcontroller.prototype = component.controller.prototype\r\n\t\t}\r\n\r\n\t\tfunction view(ctrl) {\r\n\t\t\tvar currentArgs = [ctrl].concat(args)\r\n\t\t\tfor (var i = 1; i < arguments.length; i++) {\r\n\t\t\t\tcurrentArgs.push(arguments[i])\r\n\t\t\t}\r\n\r\n\t\t\treturn component.view.apply(component, currentArgs)\r\n\t\t}\r\n\r\n\t\tview.$original = component.view\r\n\t\tvar output = {controller: controller, view: view}\r\n\t\tif (args[0] && args[0].key != null) output.attrs = {key: args[0].key}\r\n\t\treturn output\r\n\t}\r\n\r\n\tm.component = function (component) {\r\n\t\tvar args = new Array(arguments.length - 1)\r\n\r\n\t\tfor (var i = 1; i < arguments.length; i++) {\r\n\t\t\targs[i - 1] = arguments[i]\r\n\t\t}\r\n\r\n\t\treturn parameterize(component, args)\r\n\t}\r\n\r\n\tfunction checkPrevented(component, root, index, isPrevented) {\r\n\t\tif (!isPrevented) {\r\n\t\t\tm.redraw.strategy(\"all\")\r\n\t\t\tm.startComputation()\r\n\t\t\troots[index] = root\r\n\t\t\tvar currentComponent\r\n\r\n\t\t\tif (component) {\r\n\t\t\t\tcurrentComponent = topComponent = component\r\n\t\t\t} else {\r\n\t\t\t\tcurrentComponent = topComponent = component = {controller: noop}\r\n\t\t\t}\r\n\r\n\t\t\tvar controller = new (component.controller || noop)()\r\n\r\n\t\t\t// controllers may call m.mount recursively (via m.route redirects,\r\n\t\t\t// for example)\r\n\t\t\t// this conditional ensures only the last recursive m.mount call is\r\n\t\t\t// applied\r\n\t\t\tif (currentComponent === topComponent) {\r\n\t\t\t\tcontrollers[index] = controller\r\n\t\t\t\tcomponents[index] = component\r\n\t\t\t}\r\n\t\t\tendFirstComputation()\r\n\t\t\tif (component === null) {\r\n\t\t\t\tremoveRootElement(root, index)\r\n\t\t\t}\r\n\t\t\treturn controllers[index]\r\n\t\t} else if (component == null) {\r\n\t\t\tremoveRootElement(root, index)\r\n\t\t}\r\n\t}\r\n\r\n\tm.mount = m.module = function (root, component) {\r\n\t\tif (!root) {\r\n\t\t\tthrow new Error(\"Please ensure the DOM element exists before \" +\r\n\t\t\t\t\"rendering a template into it.\")\r\n\t\t}\r\n\r\n\t\tvar index = roots.indexOf(root)\r\n\t\tif (index < 0) index = roots.length\r\n\r\n\t\tvar isPrevented = false\r\n\t\tvar event = {\r\n\t\t\tpreventDefault: function () {\r\n\t\t\t\tisPrevented = true\r\n\t\t\t\tcomputePreRedrawHook = computePostRedrawHook = null\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tforEach(unloaders, function (unloader) {\r\n\t\t\tunloader.handler.call(unloader.controller, event)\r\n\t\t\tunloader.controller.onunload = null\r\n\t\t})\r\n\r\n\t\tif (isPrevented) {\r\n\t\t\tforEach(unloaders, function (unloader) {\r\n\t\t\t\tunloader.controller.onunload = unloader.handler\r\n\t\t\t})\r\n\t\t} else {\r\n\t\t\tunloaders = []\r\n\t\t}\r\n\r\n\t\tif (controllers[index] && isFunction(controllers[index].onunload)) {\r\n\t\t\tcontrollers[index].onunload(event)\r\n\t\t}\r\n\r\n\t\treturn checkPrevented(component, root, index, isPrevented)\r\n\t}\r\n\r\n\tfunction removeRootElement(root, index) {\r\n\t\troots.splice(index, 1)\r\n\t\tcontrollers.splice(index, 1)\r\n\t\tcomponents.splice(index, 1)\r\n\t\treset(root)\r\n\t\tnodeCache.splice(getCellCacheKey(root), 1)\r\n\t}\r\n\r\n\tvar redrawing = false\r\n\tm.redraw = function (force) {\r\n\t\tif (redrawing) return\r\n\t\tredrawing = true\r\n\t\tif (force) forcing = true\r\n\r\n\t\ttry {\r\n\t\t\t// lastRedrawId is a positive number if a second redraw is requested\r\n\t\t\t// before the next animation frame\r\n\t\t\t// lastRedrawId is null if it's the first redraw and not an event\r\n\t\t\t// handler\r\n\t\t\tif (lastRedrawId && !force) {\r\n\t\t\t\t// when setTimeout: only reschedule redraw if time between now\r\n\t\t\t\t// and previous redraw is bigger than a frame, otherwise keep\r\n\t\t\t\t// currently scheduled timeout\r\n\t\t\t\t// when rAF: always reschedule redraw\r\n\t\t\t\tif ($requestAnimationFrame === global.requestAnimationFrame ||\r\n\t\t\t\t\t\tnew Date() - lastRedrawCallTime > FRAME_BUDGET) {\r\n\t\t\t\t\tif (lastRedrawId > 0) $cancelAnimationFrame(lastRedrawId)\r\n\t\t\t\t\tlastRedrawId = $requestAnimationFrame(redraw, FRAME_BUDGET)\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tredraw()\r\n\t\t\t\tlastRedrawId = $requestAnimationFrame(function () {\r\n\t\t\t\t\tlastRedrawId = null\r\n\t\t\t\t}, FRAME_BUDGET)\r\n\t\t\t}\r\n\t\t} finally {\r\n\t\t\tredrawing = forcing = false\r\n\t\t}\r\n\t}\r\n\r\n\tm.redraw.strategy = m.prop()\r\n\tfunction redraw() {\r\n\t\tif (computePreRedrawHook) {\r\n\t\t\tcomputePreRedrawHook()\r\n\t\t\tcomputePreRedrawHook = null\r\n\t\t}\r\n\t\tforEach(roots, function (root, i) {\r\n\t\t\tvar component = components[i]\r\n\t\t\tif (controllers[i]) {\r\n\t\t\t\tvar args = [controllers[i]]\r\n\t\t\t\tm.render(root,\r\n\t\t\t\t\tcomponent.view ? component.view(controllers[i], args) : \"\")\r\n\t\t\t}\r\n\t\t})\r\n\t\t// after rendering within a routed context, we need to scroll back to\r\n\t\t// the top, and fetch the document title for history.pushState\r\n\t\tif (computePostRedrawHook) {\r\n\t\t\tcomputePostRedrawHook()\r\n\t\t\tcomputePostRedrawHook = null\r\n\t\t}\r\n\t\tlastRedrawId = null\r\n\t\tlastRedrawCallTime = new Date()\r\n\t\tm.redraw.strategy(\"diff\")\r\n\t}\r\n\r\n\tfunction endFirstComputation() {\r\n\t\tif (m.redraw.strategy() === \"none\") {\r\n\t\t\tpendingRequests--\r\n\t\t\tm.redraw.strategy(\"diff\")\r\n\t\t} else {\r\n\t\t\tm.endComputation()\r\n\t\t}\r\n\t}\r\n\r\n\tm.withAttr = function (prop, withAttrCallback, callbackThis) {\r\n\t\treturn function (e) {\r\n\t\t\te = e || window.event\r\n\t\t\t/* eslint-disable no-invalid-this */\r\n\t\t\tvar currentTarget = e.currentTarget || this\r\n\t\t\tvar _this = callbackThis || this\r\n\t\t\t/* eslint-enable no-invalid-this */\r\n\t\t\tvar target = prop in currentTarget ?\r\n\t\t\t\tcurrentTarget[prop] :\r\n\t\t\t\tcurrentTarget.getAttribute(prop)\r\n\t\t\twithAttrCallback.call(_this, target)\r\n\t\t}\r\n\t}\r\n\r\n\t// routing\r\n\tvar modes = {pathname: \"\", hash: \"#\", search: \"?\"}\r\n\tvar redirect = noop\r\n\tvar isDefaultRoute = false\r\n\tvar routeParams, currentRoute\r\n\r\n\tm.route = function (root, arg1, arg2, vdom) { // eslint-disable-line\r\n\t\t// m.route()\r\n\t\tif (arguments.length === 0) return currentRoute\r\n\t\t// m.route(el, defaultRoute, routes)\r\n\t\tif (arguments.length === 3 && isString(arg1)) {\r\n\t\t\tredirect = function (source) {\r\n\t\t\t\tvar path = currentRoute = normalizeRoute(source)\r\n\t\t\t\tif (!routeByValue(root, arg2, path)) {\r\n\t\t\t\t\tif (isDefaultRoute) {\r\n\t\t\t\t\t\tthrow new Error(\"Ensure the default route matches \" +\r\n\t\t\t\t\t\t\t\"one of the routes defined in m.route\")\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tisDefaultRoute = true\r\n\t\t\t\t\tm.route(arg1, true)\r\n\t\t\t\t\tisDefaultRoute = false\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvar listener = m.route.mode === \"hash\" ?\r\n\t\t\t\t\"onhashchange\" :\r\n\t\t\t\t\"onpopstate\"\r\n\r\n\t\t\tglobal[listener] = function () {\r\n\t\t\t\tvar path = $location[m.route.mode]\r\n\t\t\t\tif (m.route.mode === \"pathname\") path += $location.search\r\n\t\t\t\tif (currentRoute !== normalizeRoute(path)) redirect(path)\r\n\t\t\t}\r\n\r\n\t\t\tcomputePreRedrawHook = setScroll\r\n\t\t\tglobal[listener]()\r\n\r\n\t\t\treturn\r\n\t\t}\r\n\r\n\t\t// config: m.route\r\n\t\tif (root.addEventListener || root.attachEvent) {\r\n\t\t\tvar base = m.route.mode !== \"pathname\" ? $location.pathname : \"\"\r\n\t\t\troot.href = base + modes[m.route.mode] + vdom.attrs.href\r\n\t\t\tif (root.addEventListener) {\r\n\t\t\t\troot.removeEventListener(\"click\", routeUnobtrusive)\r\n\t\t\t\troot.addEventListener(\"click\", routeUnobtrusive)\r\n\t\t\t} else {\r\n\t\t\t\troot.detachEvent(\"onclick\", routeUnobtrusive)\r\n\t\t\t\troot.attachEvent(\"onclick\", routeUnobtrusive)\r\n\t\t\t}\r\n\r\n\t\t\treturn\r\n\t\t}\r\n\t\t// m.route(route, params, shouldReplaceHistoryEntry)\r\n\t\tif (isString(root)) {\r\n\t\t\tvar oldRoute = currentRoute\r\n\t\t\tcurrentRoute = root\r\n\r\n\t\t\tvar args = arg1 || {}\r\n\t\t\tvar queryIndex = currentRoute.indexOf(\"?\")\r\n\t\t\tvar params\r\n\r\n\t\t\tif (queryIndex > -1) {\r\n\t\t\t\tparams = parseQueryString(currentRoute.slice(queryIndex + 1))\r\n\t\t\t} else {\r\n\t\t\t\tparams = {}\r\n\t\t\t}\r\n\r\n\t\t\tfor (var i in args) {\r\n\t\t\t\tif (hasOwn.call(args, i)) {\r\n\t\t\t\t\tparams[i] = args[i]\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvar querystring = buildQueryString(params)\r\n\t\t\tvar currentPath\r\n\r\n\t\t\tif (queryIndex > -1) {\r\n\t\t\t\tcurrentPath = currentRoute.slice(0, queryIndex)\r\n\t\t\t} else {\r\n\t\t\t\tcurrentPath = currentRoute\r\n\t\t\t}\r\n\r\n\t\t\tif (querystring) {\r\n\t\t\t\tcurrentRoute = currentPath +\r\n\t\t\t\t\t(currentPath.indexOf(\"?\") === -1 ? \"?\" : \"&\") +\r\n\t\t\t\t\tquerystring\r\n\t\t\t}\r\n\r\n\t\t\tvar replaceHistory =\r\n\t\t\t\t(arguments.length === 3 ? arg2 : arg1) === true ||\r\n\t\t\t\toldRoute === root\r\n\r\n\t\t\tif (global.history.pushState) {\r\n\t\t\t\tvar method = replaceHistory ? \"replaceState\" : \"pushState\"\r\n\t\t\t\tcomputePreRedrawHook = setScroll\r\n\t\t\t\tcomputePostRedrawHook = function () {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tglobal.history[method](null, $document.title,\r\n\t\t\t\t\t\t\tmodes[m.route.mode] + currentRoute)\r\n\t\t\t\t\t} catch (err) {\r\n\t\t\t\t\t\t// In the event of a pushState or replaceState failure,\r\n\t\t\t\t\t\t// fallback to a standard redirect. This is specifically\r\n\t\t\t\t\t\t// to address a Safari security error when attempting to\r\n\t\t\t\t\t\t// call pushState more than 100 times.\r\n\t\t\t\t\t\t$location[m.route.mode] = currentRoute\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tredirect(modes[m.route.mode] + currentRoute)\r\n\t\t\t} else {\r\n\t\t\t\t$location[m.route.mode] = currentRoute\r\n\t\t\t\tredirect(modes[m.route.mode] + currentRoute)\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tm.route.param = function (key) {\r\n\t\tif (!routeParams) {\r\n\t\t\tthrow new Error(\"You must call m.route(element, defaultRoute, \" +\r\n\t\t\t\t\"routes) before calling m.route.param()\")\r\n\t\t}\r\n\r\n\t\tif (!key) {\r\n\t\t\treturn routeParams\r\n\t\t}\r\n\r\n\t\treturn routeParams[key]\r\n\t}\r\n\r\n\tm.route.mode = \"search\"\r\n\r\n\tfunction normalizeRoute(route) {\r\n\t\treturn route.slice(modes[m.route.mode].length)\r\n\t}\r\n\r\n\tfunction routeByValue(root, router, path) {\r\n\t\trouteParams = {}\r\n\r\n\t\tvar queryStart = path.indexOf(\"?\")\r\n\t\tif (queryStart !== -1) {\r\n\t\t\trouteParams = parseQueryString(\r\n\t\t\t\tpath.substr(queryStart + 1, path.length))\r\n\t\t\tpath = path.substr(0, queryStart)\r\n\t\t}\r\n\r\n\t\t// Get all routes and check if there's\r\n\t\t// an exact match for the current path\r\n\t\tvar keys = Object.keys(router)\r\n\t\tvar index = keys.indexOf(path)\r\n\r\n\t\tif (index !== -1){\r\n\t\t\tm.mount(root, router[keys [index]])\r\n\t\t\treturn true\r\n\t\t}\r\n\r\n\t\tfor (var route in router) {\r\n\t\t\tif (hasOwn.call(router, route)) {\r\n\t\t\t\tif (route === path) {\r\n\t\t\t\t\tm.mount(root, router[route])\r\n\t\t\t\t\treturn true\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar matcher = new RegExp(\"^\" + route\r\n\t\t\t\t\t.replace(/:[^\\/]+?\\.{3}/g, \"(.*?)\")\r\n\t\t\t\t\t.replace(/:[^\\/]+/g, \"([^\\\\/]+)\") + \"\\/?$\")\r\n\r\n\t\t\t\tif (matcher.test(path)) {\r\n\t\t\t\t\t/* eslint-disable no-loop-func */\r\n\t\t\t\t\tpath.replace(matcher, function () {\r\n\t\t\t\t\t\tvar keys = route.match(/:[^\\/]+/g) || []\r\n\t\t\t\t\t\tvar values = [].slice.call(arguments, 1, -2)\r\n\t\t\t\t\t\tforEach(keys, function (key, i) {\r\n\t\t\t\t\t\t\trouteParams[key.replace(/:|\\./g, \"\")] =\r\n\t\t\t\t\t\t\t\tdecodeURIComponent(values[i])\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t\tm.mount(root, router[route])\r\n\t\t\t\t\t})\r\n\t\t\t\t\t/* eslint-enable no-loop-func */\r\n\t\t\t\t\treturn true\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tfunction routeUnobtrusive(e) {\r\n\t\te = e || event\r\n\t\tif (e.ctrlKey || e.metaKey || e.shiftKey || e.which === 2) return\r\n\r\n\t\tif (e.preventDefault) {\r\n\t\t\te.preventDefault()\r\n\t\t} else {\r\n\t\t\te.returnValue = false\r\n\t\t}\r\n\r\n\t\tvar currentTarget = e.currentTarget || e.srcElement\r\n\t\tvar args\r\n\r\n\t\tif (m.route.mode === \"pathname\" && currentTarget.search) {\r\n\t\t\targs = parseQueryString(currentTarget.search.slice(1))\r\n\t\t} else {\r\n\t\t\targs = {}\r\n\t\t}\r\n\r\n\t\twhile (currentTarget && !/a/i.test(currentTarget.nodeName)) {\r\n\t\t\tcurrentTarget = currentTarget.parentNode\r\n\t\t}\r\n\r\n\t\t// clear pendingRequests because we want an immediate route change\r\n\t\tpendingRequests = 0\r\n\t\tm.route(currentTarget[m.route.mode]\r\n\t\t\t.slice(modes[m.route.mode].length), args)\r\n\t}\r\n\r\n\tfunction setScroll() {\r\n\t\tif (m.route.mode !== \"hash\" && $location.hash) {\r\n\t\t\t$location.hash = $location.hash\r\n\t\t} else {\r\n\t\t\tglobal.scrollTo(0, 0)\r\n\t\t}\r\n\t}\r\n\r\n\tfunction buildQueryString(object, prefix) {\r\n\t\tvar duplicates = {}\r\n\t\tvar str = []\r\n\r\n\t\tfor (var prop in object) {\r\n\t\t\tif (hasOwn.call(object, prop)) {\r\n\t\t\t\tvar key = prefix ? prefix + \"[\" + prop + \"]\" : prop\r\n\t\t\t\tvar value = object[prop]\r\n\r\n\t\t\t\tif (value === null) {\r\n\t\t\t\t\tstr.push(encodeURIComponent(key))\r\n\t\t\t\t} else if (isObject(value)) {\r\n\t\t\t\t\tstr.push(buildQueryString(value, key))\r\n\t\t\t\t} else if (isArray(value)) {\r\n\t\t\t\t\tvar keys = []\r\n\t\t\t\t\tduplicates[key] = duplicates[key] || {}\r\n\t\t\t\t\t/* eslint-disable no-loop-func */\r\n\t\t\t\t\tforEach(value, function (item) {\r\n\t\t\t\t\t\t/* eslint-enable no-loop-func */\r\n\t\t\t\t\t\tif (!duplicates[key][item]) {\r\n\t\t\t\t\t\t\tduplicates[key][item] = true\r\n\t\t\t\t\t\t\tkeys.push(encodeURIComponent(key) + \"=\" +\r\n\t\t\t\t\t\t\t\tencodeURIComponent(item))\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t})\r\n\t\t\t\t\tstr.push(keys.join(\"&\"))\r\n\t\t\t\t} else if (value !== undefined) {\r\n\t\t\t\t\tstr.push(encodeURIComponent(key) + \"=\" +\r\n\t\t\t\t\t\tencodeURIComponent(value))\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn str.join(\"&\")\r\n\t}\r\n\r\n\tfunction parseQueryString(str) {\r\n\t\tif (str === \"\" || str == null) return {}\r\n\t\tif (str.charAt(0) === \"?\") str = str.slice(1)\r\n\r\n\t\tvar pairs = str.split(\"&\")\r\n\t\tvar params = {}\r\n\r\n\t\tforEach(pairs, function (string) {\r\n\t\t\tvar pair = string.split(\"=\")\r\n\t\t\tvar key = decodeURIComponent(pair[0])\r\n\t\t\tvar value = pair.length === 2 ? decodeURIComponent(pair[1]) : null\r\n\t\t\tif (params[key] != null) {\r\n\t\t\t\tif (!isArray(params[key])) params[key] = [params[key]]\r\n\t\t\t\tparams[key].push(value)\r\n\t\t\t}\r\n\t\t\telse params[key] = value\r\n\t\t})\r\n\r\n\t\treturn params\r\n\t}\r\n\r\n\tm.route.buildQueryString = buildQueryString\r\n\tm.route.parseQueryString = parseQueryString\r\n\r\n\tfunction reset(root) {\r\n\t\tvar cacheKey = getCellCacheKey(root)\r\n\t\tclear(root.childNodes, cellCache[cacheKey])\r\n\t\tcellCache[cacheKey] = undefined\r\n\t}\r\n\r\n\tm.deferred = function () {\r\n\t\tvar deferred = new Deferred()\r\n\t\tdeferred.promise = propify(deferred.promise)\r\n\t\treturn deferred\r\n\t}\r\n\r\n\tfunction propify(promise, initialValue) {\r\n\t\tvar prop = m.prop(initialValue)\r\n\t\tpromise.then(prop)\r\n\t\tprop.then = function (resolve, reject) {\r\n\t\t\treturn propify(promise.then(resolve, reject), initialValue)\r\n\t\t}\r\n\r\n\t\tprop.catch = prop.then.bind(null, null)\r\n\t\treturn prop\r\n\t}\r\n\t// Promiz.mithril.js | Zolmeister | MIT\r\n\t// a modified version of Promiz.js, which does not conform to Promises/A+\r\n\t// for two reasons:\r\n\t//\r\n\t// 1) `then` callbacks are called synchronously (because setTimeout is too\r\n\t// slow, and the setImmediate polyfill is too big\r\n\t//\r\n\t// 2) throwing subclasses of Error cause the error to be bubbled up instead\r\n\t// of triggering rejection (because the spec does not account for the\r\n\t// important use case of default browser error handling, i.e. message w/\r\n\t// line number)\r\n\r\n\tvar RESOLVING = 1\r\n\tvar REJECTING = 2\r\n\tvar RESOLVED = 3\r\n\tvar REJECTED = 4\r\n\r\n\tfunction Deferred(onSuccess, onFailure) {\r\n\t\tvar self = this\r\n\t\tvar state = 0\r\n\t\tvar promiseValue = 0\r\n\t\tvar next = []\r\n\r\n\t\tself.promise = {}\r\n\r\n\t\tself.resolve = function (value) {\r\n\t\t\tif (!state) {\r\n\t\t\t\tpromiseValue = value\r\n\t\t\t\tstate = RESOLVING\r\n\r\n\t\t\t\tfire()\r\n\t\t\t}\r\n\r\n\t\t\treturn self\r\n\t\t}\r\n\r\n\t\tself.reject = function (value) {\r\n\t\t\tif (!state) {\r\n\t\t\t\tpromiseValue = value\r\n\t\t\t\tstate = REJECTING\r\n\r\n\t\t\t\tfire()\r\n\t\t\t}\r\n\r\n\t\t\treturn self\r\n\t\t}\r\n\r\n\t\tself.promise.then = function (onSuccess, onFailure) {\r\n\t\t\tvar deferred = new Deferred(onSuccess, onFailure)\r\n\r\n\t\t\tif (state === RESOLVED) {\r\n\t\t\t\tdeferred.resolve(promiseValue)\r\n\t\t\t} else if (state === REJECTED) {\r\n\t\t\t\tdeferred.reject(promiseValue)\r\n\t\t\t} else {\r\n\t\t\t\tnext.push(deferred)\r\n\t\t\t}\r\n\r\n\t\t\treturn deferred.promise\r\n\t\t}\r\n\r\n\t\tfunction finish(type) {\r\n\t\t\tstate = type || REJECTED\r\n\t\t\tnext.map(function (deferred) {\r\n\t\t\t\tif (state === RESOLVED) {\r\n\t\t\t\t\tdeferred.resolve(promiseValue)\r\n\t\t\t\t} else {\r\n\t\t\t\t\tdeferred.reject(promiseValue)\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\tfunction thennable(then, success, failure, notThennable) {\r\n\t\t\tif (((promiseValue != null && isObject(promiseValue)) ||\r\n\t\t\t\t\tisFunction(promiseValue)) && isFunction(then)) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\t// count protects against abuse calls from spec checker\r\n\t\t\t\t\tvar count = 0\r\n\t\t\t\t\tthen.call(promiseValue, function (value) {\r\n\t\t\t\t\t\tif (count++) return\r\n\t\t\t\t\t\tpromiseValue = value\r\n\t\t\t\t\t\tsuccess()\r\n\t\t\t\t\t}, function (value) {\r\n\t\t\t\t\t\tif (count++) return\r\n\t\t\t\t\t\tpromiseValue = value\r\n\t\t\t\t\t\tfailure()\r\n\t\t\t\t\t})\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\tm.deferred.onerror(e)\r\n\t\t\t\t\tpromiseValue = e\r\n\t\t\t\t\tfailure()\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tnotThennable()\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfunction fire() {\r\n\t\t\t// check if it's a thenable\r\n\t\t\tvar then\r\n\t\t\ttry {\r\n\t\t\t\tthen = promiseValue && promiseValue.then\r\n\t\t\t} catch (e) {\r\n\t\t\t\tm.deferred.onerror(e)\r\n\t\t\t\tpromiseValue = e\r\n\t\t\t\tstate = REJECTING\r\n\t\t\t\treturn fire()\r\n\t\t\t}\r\n\r\n\t\t\tif (state === REJECTING) {\r\n\t\t\t\tm.deferred.onerror(promiseValue)\r\n\t\t\t}\r\n\r\n\t\t\tthennable(then, function () {\r\n\t\t\t\tstate = RESOLVING\r\n\t\t\t\tfire()\r\n\t\t\t}, function () {\r\n\t\t\t\tstate = REJECTING\r\n\t\t\t\tfire()\r\n\t\t\t}, function () {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tif (state === RESOLVING && isFunction(onSuccess)) {\r\n\t\t\t\t\t\tpromiseValue = onSuccess(promiseValue)\r\n\t\t\t\t\t} else if (state === REJECTING && isFunction(onFailure)) {\r\n\t\t\t\t\t\tpromiseValue = onFailure(promiseValue)\r\n\t\t\t\t\t\tstate = RESOLVING\r\n\t\t\t\t\t}\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\tm.deferred.onerror(e)\r\n\t\t\t\t\tpromiseValue = e\r\n\t\t\t\t\treturn finish()\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (promiseValue === self) {\r\n\t\t\t\t\tpromiseValue = TypeError()\r\n\t\t\t\t\tfinish()\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthennable(then, function () {\r\n\t\t\t\t\t\tfinish(RESOLVED)\r\n\t\t\t\t\t}, finish, function () {\r\n\t\t\t\t\t\tfinish(state === RESOLVING && RESOLVED)\r\n\t\t\t\t\t})\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\t}\r\n\r\n\tm.deferred.onerror = function (e) {\r\n\t\tif (type.call(e) === \"[object Error]\" &&\r\n\t\t\t\t!/ Error/.test(e.constructor.toString())) {\r\n\t\t\tpendingRequests = 0\r\n\t\t\tthrow e\r\n\t\t}\r\n\t}\r\n\r\n\tm.sync = function (args) {\r\n\t\tvar deferred = m.deferred()\r\n\t\tvar outstanding = args.length\r\n\t\tvar results = []\r\n\t\tvar method = \"resolve\"\r\n\r\n\t\tfunction synchronizer(pos, resolved) {\r\n\t\t\treturn function (value) {\r\n\t\t\t\tresults[pos] = value\r\n\t\t\t\tif (!resolved) method = \"reject\"\r\n\t\t\t\tif (--outstanding === 0) {\r\n\t\t\t\t\tdeferred.promise(results)\r\n\t\t\t\t\tdeferred[method](results)\r\n\t\t\t\t}\r\n\t\t\t\treturn value\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (args.length > 0) {\r\n\t\t\tforEach(args, function (arg, i) {\r\n\t\t\t\targ.then(synchronizer(i, true), synchronizer(i, false))\r\n\t\t\t})\r\n\t\t} else {\r\n\t\t\tdeferred.resolve([])\r\n\t\t}\r\n\r\n\t\treturn deferred.promise\r\n\t}\r\n\r\n\tfunction identity(value) { return value }\r\n\r\n\tfunction handleJsonp(options) {\r\n\t\tvar callbackKey = options.callbackName || \"mithril_callback_\" +\r\n\t\t\tnew Date().getTime() + \"_\" +\r\n\t\t\t(Math.round(Math.random() * 1e16)).toString(36)\r\n\r\n\t\tvar script = $document.createElement(\"script\")\r\n\r\n\t\tglobal[callbackKey] = function (resp) {\r\n\t\t\tscript.parentNode.removeChild(script)\r\n\t\t\toptions.onload({\r\n\t\t\t\ttype: \"load\",\r\n\t\t\t\ttarget: {\r\n\t\t\t\t\tresponseText: resp\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\tglobal[callbackKey] = undefined\r\n\t\t}\r\n\r\n\t\tscript.onerror = function () {\r\n\t\t\tscript.parentNode.removeChild(script)\r\n\r\n\t\t\toptions.onerror({\r\n\t\t\t\ttype: \"error\",\r\n\t\t\t\ttarget: {\r\n\t\t\t\t\tstatus: 500,\r\n\t\t\t\t\tresponseText: JSON.stringify({\r\n\t\t\t\t\t\terror: \"Error making jsonp request\"\r\n\t\t\t\t\t})\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\tglobal[callbackKey] = undefined\r\n\r\n\t\t\treturn false\r\n\t\t}\r\n\r\n\t\tscript.onload = function () {\r\n\t\t\treturn false\r\n\t\t}\r\n\r\n\t\tscript.src = options.url +\r\n\t\t\t(options.url.indexOf(\"?\") > 0 ? \"&\" : \"?\") +\r\n\t\t\t(options.callbackKey ? options.callbackKey : \"callback\") +\r\n\t\t\t\"=\" + callbackKey +\r\n\t\t\t\"&\" + buildQueryString(options.data || {})\r\n\r\n\t\t$document.body.appendChild(script)\r\n\t}\r\n\r\n\tfunction createXhr(options) {\r\n\t\tvar xhr = new global.XMLHttpRequest()\r\n\t\txhr.open(options.method, options.url, true, options.user,\r\n\t\t\toptions.password)\r\n\r\n\t\txhr.onreadystatechange = function () {\r\n\t\t\tif (xhr.readyState === 4) {\r\n\t\t\t\tif (xhr.status >= 200 && xhr.status < 300) {\r\n\t\t\t\t\toptions.onload({type: \"load\", target: xhr})\r\n\t\t\t\t} else {\r\n\t\t\t\t\toptions.onerror({type: \"error\", target: xhr})\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (options.serialize === JSON.stringify &&\r\n\t\t\t\toptions.data &&\r\n\t\t\t\toptions.method !== \"GET\") {\r\n\t\t\txhr.setRequestHeader(\"Content-Type\",\r\n\t\t\t\t\"application/json; charset=utf-8\")\r\n\t\t}\r\n\r\n\t\tif (options.deserialize === JSON.parse) {\r\n\t\t\txhr.setRequestHeader(\"Accept\", \"application/json, text/*\")\r\n\t\t}\r\n\r\n\t\tif (isFunction(options.config)) {\r\n\t\t\tvar maybeXhr = options.config(xhr, options)\r\n\t\t\tif (maybeXhr != null) xhr = maybeXhr\r\n\t\t}\r\n\r\n\t\tvar data = options.method === \"GET\" || !options.data ? \"\" : options.data\r\n\r\n\t\tif (data && !isString(data) && data.constructor !== global.FormData) {\r\n\t\t\tthrow new Error(\"Request data should be either be a string or \" +\r\n\t\t\t\t\"FormData. Check the `serialize` option in `m.request`\")\r\n\t\t}\r\n\r\n\t\txhr.send(data)\r\n\t\treturn xhr\r\n\t}\r\n\r\n\tfunction ajax(options) {\r\n\t\tif (options.dataType && options.dataType.toLowerCase() === \"jsonp\") {\r\n\t\t\treturn handleJsonp(options)\r\n\t\t} else {\r\n\t\t\treturn createXhr(options)\r\n\t\t}\r\n\t}\r\n\r\n\tfunction bindData(options, data, serialize) {\r\n\t\tif (options.method === \"GET\" && options.dataType !== \"jsonp\") {\r\n\t\t\tvar prefix = options.url.indexOf(\"?\") < 0 ? \"?\" : \"&\"\r\n\t\t\tvar querystring = buildQueryString(data)\r\n\t\t\toptions.url += (querystring ? prefix + querystring : \"\")\r\n\t\t} else {\r\n\t\t\toptions.data = serialize(data)\r\n\t\t}\r\n\t}\r\n\r\n\tfunction parameterizeUrl(url, data) {\r\n\t\tif (data) {\r\n\t\t\turl = url.replace(/:[a-z]\\w+/gi, function (token){\r\n\t\t\t\tvar key = token.slice(1)\r\n\t\t\t\tvar value = data[key] || token\r\n\t\t\t\tdelete data[key]\r\n\t\t\t\treturn value\r\n\t\t\t})\r\n\t\t}\r\n\t\treturn url\r\n\t}\r\n\r\n\tm.request = function (options) {\r\n\t\tif (options.background !== true) m.startComputation()\r\n\t\tvar deferred = new Deferred()\r\n\t\tvar isJSONP = options.dataType &&\r\n\t\t\toptions.dataType.toLowerCase() === \"jsonp\"\r\n\r\n\t\tvar serialize, deserialize, extract\r\n\r\n\t\tif (isJSONP) {\r\n\t\t\tserialize = options.serialize =\r\n\t\t\tdeserialize = options.deserialize = identity\r\n\r\n\t\t\textract = function (jsonp) { return jsonp.responseText }\r\n\t\t} else {\r\n\t\t\tserialize = options.serialize = options.serialize || JSON.stringify\r\n\r\n\t\t\tdeserialize = options.deserialize =\r\n\t\t\t\toptions.deserialize || JSON.parse\r\n\t\t\textract = options.extract || function (xhr) {\r\n\t\t\t\tif (xhr.responseText.length || deserialize !== JSON.parse) {\r\n\t\t\t\t\treturn xhr.responseText\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn null\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\toptions.method = (options.method || \"GET\").toUpperCase()\r\n\t\toptions.url = parameterizeUrl(options.url, options.data)\r\n\t\tbindData(options, options.data, serialize)\r\n\t\toptions.onload = options.onerror = function (ev) {\r\n\t\t\ttry {\r\n\t\t\t\tev = ev || event\r\n\t\t\t\tvar response = deserialize(extract(ev.target, options))\r\n\t\t\t\tif (ev.type === \"load\") {\r\n\t\t\t\t\tif (options.unwrapSuccess) {\r\n\t\t\t\t\t\tresponse = options.unwrapSuccess(response, ev.target)\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (isArray(response) && options.type) {\r\n\t\t\t\t\t\tforEach(response, function (res, i) {\r\n\t\t\t\t\t\t\tresponse[i] = new options.type(res)\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t} else if (options.type) {\r\n\t\t\t\t\t\tresponse = new options.type(response)\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tdeferred.resolve(response)\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (options.unwrapError) {\r\n\t\t\t\t\t\tresponse = options.unwrapError(response, ev.target)\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tdeferred.reject(response)\r\n\t\t\t\t}\r\n\t\t\t} catch (e) {\r\n\t\t\t\tdeferred.reject(e)\r\n\t\t\t\tm.deferred.onerror(e)\r\n\t\t\t} finally {\r\n\t\t\t\tif (options.background !== true) m.endComputation()\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tajax(options)\r\n\t\tdeferred.promise = propify(deferred.promise, options.initialValue)\r\n\t\treturn deferred.promise\r\n\t}\r\n\r\n\treturn m\r\n}); // eslint-disable-line\r\n\n},{}],8:[function(require,module,exports){\n/*!\n * EventEmitter v4.2.11 - git.io/ee\n * Unlicense - http://unlicense.org/\n * Oliver Caldwell - http://oli.me.uk/\n * @preserve\n */\n\n;(function () {\n 'use strict';\n\n /**\n * Class for managing events.\n * Can be extended to provide event functionality in other classes.\n *\n * @class EventEmitter Manages event registering and emitting.\n */\n function EventEmitter() {}\n\n // Shortcuts to improve speed and size\n var proto = EventEmitter.prototype;\n var exports = this;\n var originalGlobalValue = exports.EventEmitter;\n\n /**\n * Finds the index of the listener for the event in its storage array.\n *\n * @param {Function[]} listeners Array of listeners to search through.\n * @param {Function} listener Method to look for.\n * @return {Number} Index of the specified listener, -1 if not found\n * @api private\n */\n function indexOfListener(listeners, listener) {\n var i = listeners.length;\n while (i--) {\n if (listeners[i].listener === listener) {\n return i;\n }\n }\n\n return -1;\n }\n\n /**\n * Alias a method while keeping the context correct, to allow for overwriting of target method.\n *\n * @param {String} name The name of the target method.\n * @return {Function} The aliased method\n * @api private\n */\n function alias(name) {\n return function aliasClosure() {\n return this[name].apply(this, arguments);\n };\n }\n\n /**\n * Returns the listener array for the specified event.\n * Will initialise the event object and listener arrays if required.\n * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.\n * Each property in the object response is an array of listener functions.\n *\n * @param {String|RegExp} evt Name of the event to return the listeners from.\n * @return {Function[]|Object} All listener functions for the event.\n */\n proto.getListeners = function getListeners(evt) {\n var events = this._getEvents();\n var response;\n var key;\n\n // Return a concatenated array of all matching events if\n // the selector is a regular expression.\n if (evt instanceof RegExp) {\n response = {};\n for (key in events) {\n if (events.hasOwnProperty(key) && evt.test(key)) {\n response[key] = events[key];\n }\n }\n }\n else {\n response = events[evt] || (events[evt] = []);\n }\n\n return response;\n };\n\n /**\n * Takes a list of listener objects and flattens it into a list of listener functions.\n *\n * @param {Object[]} listeners Raw listener objects.\n * @return {Function[]} Just the listener functions.\n */\n proto.flattenListeners = function flattenListeners(listeners) {\n var flatListeners = [];\n var i;\n\n for (i = 0; i < listeners.length; i += 1) {\n flatListeners.push(listeners[i].listener);\n }\n\n return flatListeners;\n };\n\n /**\n * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.\n *\n * @param {String|RegExp} evt Name of the event to return the listeners from.\n * @return {Object} All listener functions for an event in an object.\n */\n proto.getListenersAsObject = function getListenersAsObject(evt) {\n var listeners = this.getListeners(evt);\n var response;\n\n if (listeners instanceof Array) {\n response = {};\n response[evt] = listeners;\n }\n\n return response || listeners;\n };\n\n /**\n * Adds a listener function to the specified event.\n * The listener will not be added if it is a duplicate.\n * If the listener returns true then it will be removed after it is called.\n * If you pass a regular expression as the event name then the listener will be added to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to attach the listener to.\n * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.addListener = function addListener(evt, listener) {\n var listeners = this.getListenersAsObject(evt);\n var listenerIsWrapped = typeof listener === 'object';\n var key;\n\n for (key in listeners) {\n if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {\n listeners[key].push(listenerIsWrapped ? listener : {\n listener: listener,\n once: false\n });\n }\n }\n\n return this;\n };\n\n /**\n * Alias of addListener\n */\n proto.on = alias('addListener');\n\n /**\n * Semi-alias of addListener. It will add a listener that will be\n * automatically removed after its first execution.\n *\n * @param {String|RegExp} evt Name of the event to attach the listener to.\n * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.addOnceListener = function addOnceListener(evt, listener) {\n return this.addListener(evt, {\n listener: listener,\n once: true\n });\n };\n\n /**\n * Alias of addOnceListener.\n */\n proto.once = alias('addOnceListener');\n\n /**\n * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.\n * You need to tell it what event names should be matched by a regex.\n *\n * @param {String} evt Name of the event to create.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.defineEvent = function defineEvent(evt) {\n this.getListeners(evt);\n return this;\n };\n\n /**\n * Uses defineEvent to define multiple events.\n *\n * @param {String[]} evts An array of event names to define.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.defineEvents = function defineEvents(evts) {\n for (var i = 0; i < evts.length; i += 1) {\n this.defineEvent(evts[i]);\n }\n return this;\n };\n\n /**\n * Removes a listener function from the specified event.\n * When passed a regular expression as the event name, it will remove the listener from all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to remove the listener from.\n * @param {Function} listener Method to remove from the event.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.removeListener = function removeListener(evt, listener) {\n var listeners = this.getListenersAsObject(evt);\n var index;\n var key;\n\n for (key in listeners) {\n if (listeners.hasOwnProperty(key)) {\n index = indexOfListener(listeners[key], listener);\n\n if (index !== -1) {\n listeners[key].splice(index, 1);\n }\n }\n }\n\n return this;\n };\n\n /**\n * Alias of removeListener\n */\n proto.off = alias('removeListener');\n\n /**\n * Adds listeners in bulk using the manipulateListeners method.\n * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.\n * You can also pass it a regular expression to add the array of listeners to all events that match it.\n * Yeah, this function does quite a bit. That's probably a bad thing.\n *\n * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.\n * @param {Function[]} [listeners] An optional array of listener functions to add.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.addListeners = function addListeners(evt, listeners) {\n // Pass through to manipulateListeners\n return this.manipulateListeners(false, evt, listeners);\n };\n\n /**\n * Removes listeners in bulk using the manipulateListeners method.\n * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.\n * You can also pass it an event name and an array of listeners to be removed.\n * You can also pass it a regular expression to remove the listeners from all events that match it.\n *\n * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.\n * @param {Function[]} [listeners] An optional array of listener functions to remove.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.removeListeners = function removeListeners(evt, listeners) {\n // Pass through to manipulateListeners\n return this.manipulateListeners(true, evt, listeners);\n };\n\n /**\n * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.\n * The first argument will determine if the listeners are removed (true) or added (false).\n * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.\n * You can also pass it an event name and an array of listeners to be added/removed.\n * You can also pass it a regular expression to manipulate the listeners of all events that match it.\n *\n * @param {Boolean} remove True if you want to remove listeners, false if you want to add.\n * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.\n * @param {Function[]} [listeners] An optional array of listener functions to add/remove.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {\n var i;\n var value;\n var single = remove ? this.removeListener : this.addListener;\n var multiple = remove ? this.removeListeners : this.addListeners;\n\n // If evt is an object then pass each of its properties to this method\n if (typeof evt === 'object' && !(evt instanceof RegExp)) {\n for (i in evt) {\n if (evt.hasOwnProperty(i) && (value = evt[i])) {\n // Pass the single listener straight through to the singular method\n if (typeof value === 'function') {\n single.call(this, i, value);\n }\n else {\n // Otherwise pass back to the multiple function\n multiple.call(this, i, value);\n }\n }\n }\n }\n else {\n // So evt must be a string\n // And listeners must be an array of listeners\n // Loop over it and pass each one to the multiple method\n i = listeners.length;\n while (i--) {\n single.call(this, evt, listeners[i]);\n }\n }\n\n return this;\n };\n\n /**\n * Removes all listeners from a specified event.\n * If you do not specify an event then all listeners will be removed.\n * That means every event will be emptied.\n * You can also pass a regex to remove all events that match it.\n *\n * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.removeEvent = function removeEvent(evt) {\n var type = typeof evt;\n var events = this._getEvents();\n var key;\n\n // Remove different things depending on the state of evt\n if (type === 'string') {\n // Remove all listeners for the specified event\n delete events[evt];\n }\n else if (evt instanceof RegExp) {\n // Remove all events matching the regex.\n for (key in events) {\n if (events.hasOwnProperty(key) && evt.test(key)) {\n delete events[key];\n }\n }\n }\n else {\n // Remove all listeners in all events\n delete this._events;\n }\n\n return this;\n };\n\n /**\n * Alias of removeEvent.\n *\n * Added to mirror the node API.\n */\n proto.removeAllListeners = alias('removeEvent');\n\n /**\n * Emits an event of your choice.\n * When emitted, every listener attached to that event will be executed.\n * If you pass the optional argument array then those arguments will be passed to every listener upon execution.\n * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.\n * So they will not arrive within the array on the other side, they will be separate.\n * You can also pass a regular expression to emit to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to emit and execute listeners for.\n * @param {Array} [args] Optional array of arguments to be passed to each listener.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.emitEvent = function emitEvent(evt, args) {\n var listenersMap = this.getListenersAsObject(evt);\n var listeners;\n var listener;\n var i;\n var key;\n var response;\n\n for (key in listenersMap) {\n if (listenersMap.hasOwnProperty(key)) {\n listeners = listenersMap[key].slice(0);\n i = listeners.length;\n\n while (i--) {\n // If the listener returns true then it shall be removed from the event\n // The function is executed either with a basic call or an apply if there is an args array\n listener = listeners[i];\n\n if (listener.once === true) {\n this.removeListener(evt, listener.listener);\n }\n\n response = listener.listener.apply(this, args || []);\n\n if (response === this._getOnceReturnValue()) {\n this.removeListener(evt, listener.listener);\n }\n }\n }\n }\n\n return this;\n };\n\n /**\n * Alias of emitEvent\n */\n proto.trigger = alias('emitEvent');\n\n /**\n * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.\n * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to emit and execute listeners for.\n * @param {...*} Optional additional arguments to be passed to each listener.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.emit = function emit(evt) {\n var args = Array.prototype.slice.call(arguments, 1);\n return this.emitEvent(evt, args);\n };\n\n /**\n * Sets the current value to check against when executing listeners. If a\n * listeners return value matches the one set here then it will be removed\n * after execution. This value defaults to true.\n *\n * @param {*} value The new value to check for when executing listeners.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.setOnceReturnValue = function setOnceReturnValue(value) {\n this._onceReturnValue = value;\n return this;\n };\n\n /**\n * Fetches the current value to check against when executing listeners. If\n * the listeners return value matches this one then it should be removed\n * automatically. It will return true by default.\n *\n * @return {*|Boolean} The current value to check for or the default, true.\n * @api private\n */\n proto._getOnceReturnValue = function _getOnceReturnValue() {\n if (this.hasOwnProperty('_onceReturnValue')) {\n return this._onceReturnValue;\n }\n else {\n return true;\n }\n };\n\n /**\n * Fetches the events object and creates one if required.\n *\n * @return {Object} The events storage object.\n * @api private\n */\n proto._getEvents = function _getEvents() {\n return this._events || (this._events = {});\n };\n\n /**\n * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.\n *\n * @return {Function} Non conflicting EventEmitter class.\n */\n EventEmitter.noConflict = function noConflict() {\n exports.EventEmitter = originalGlobalValue;\n return EventEmitter;\n };\n\n // Expose the class either via AMD, CommonJS or the global object\n if (typeof define === 'function' && define.amd) {\n define(function () {\n return EventEmitter;\n });\n }\n else if (typeof module === 'object' && module.exports){\n module.exports = EventEmitter;\n }\n else {\n exports.EventEmitter = EventEmitter;\n }\n}.call(this));\n\n},{}]},{},[1]);\n })();"],"sourceRoot":"/source/"}
1
+ {"version":3,"sources":["admin.js"],"names":["require","undefined","define","e","t","n","r","s","o","u","a","i","f","Error","code","l","exports","call","length","1","module","m","window","EventEmitter","context","document","getElementById","events","tabs","helpers","settings","ListFetcher","mount","mc4wp","deps","mithril","./admin/helpers.js","./admin/list-fetcher.js","./admin/settings.js","./admin/tabs.js","wolfy87-eventemitter","2","toggleElement","selector","elements","querySelectorAll","show","clientHeight","style","display","bindEventToElement","element","event","handler","addEventListener","attachEvent","bindEventToElements","Array","prototype","forEach","debounce","func","wait","immediate","timeout","this","args","arguments","later","apply","callNow","clearTimeout","setTimeout","showIfElements","getAttribute","checked","value","conditionMet","config","hide","visibility","opacity","inputs","inputElement","removeAttribute","setAttribute","JSON","parse","parentElements","parentElement","3","working","done","mailchimp","api_connected","lists","fetch","$","jQuery","mc4wp_vars","i18n","preventDefault","post","ajaxurl","action","data","location","reload","always","redraw","bind","view","method","onsubmit","type","fetching_mailchimp_lists","renew_mailchimp_lists","className","disabled","trust","fetching_mailchimp_lists_can_take_a_while","fetching_mailchimp_lists_done","4","Settings","getSelectedListsWhere","searchKey","searchValue","selectedLists","filter","el","getSelectedLists","updateSelectedLists","listInputs","input","push","trigger","toggleVisibleLists","rows","listId","isSelected","replace","querySelector","on","5","URL","Tabs","get","id","open","tab","updateState","$tabs","removeClass","css","$tabNavs","nav","blur","url","setParameter","href","history","pushState","title","refererField","tb_remove","forms","editor","refresh","split","switchTab","tabId","match","urlParams","opened","returnValue","init","activeTab","substring","replaceState","state","$context","find","each","first","text","click","body","./url.js","6","query","hasOwnProperty","b","decodeURIComponent","build","ret","d","encodeURIComponent","join","key","7","global","factory","amd","isFunction","object","isObject","isString","noop","initialize","mock","$document","$location","$cancelAnimationFrame","cancelAnimationFrame","$requestAnimationFrame","requestAnimationFrame","parseTagAttrs","cell","tag","classes","parser","exec","attrs","pair","getVirtualChildren","hasAttrs","children","slice","isArray","assignAttrs","target","classAttr","attrName","hasOwn","pairs","parameterize","list","forKeys","dataToString","toString","injectTextNode","index","insertNode","nodeValue","flatten","concat","node","insertBefore","childNodes","handleKeysDiffer","existing","cached","MOVE","from","nodes","createElement","INSERTION","actions","prop","changes","sort","sortChanges","newCached","change","DELETION","clear","splice","dummy","changeElement","maybeChanged","diffKeys","keysDiffer","cachedCell","diffArray","_","parentNode","indexOf","buildArrayKeys","guid","isDifferentEnough","dataAttrKeys","Object","keys","strategy","configContext","retain","maybeRecreateObject","onunload","controllers","controller","getObjectNamespace","namespace","xmlns","unloadCachedControllers","views","$old","pendingRequests","scheduleConfigsToBeCalled","configs","isNew","buildUpdatedNode","editable","hasKeys","setAttributes","contenteditable","intact","handleNonexistentNodes","$trusted","injectHTML","createTextNode","nodeName","voidElements","constructor","reattachNodes","parentTag","activeElement","innerHTML","nodeType","trim","handleTextNode","shouldReattach","valueOf","getSubArrayCount","item","buildArray","subArrayCount","shouldMaintainIdentities","cacheCount","len","makeCache","parentIndex","parentCache","offset","end","constructNode","is","createElementNS","constructAttrs","constructChildren","reconstructCached","getController","cachedControllers","controllerIndex","updateLists","unloaders","map","checkView","forcing","subtree","markViews","$original","buildObject","copyStyleAttrs","dataAttr","cachedAttr","rule","setSingleAttr","autoredraw","setAttributeNS","shouldUseSetAttribute","trySetAttr","cachedAttrs","message","dataAttrs","removeChild","unload","appendTextFragment","appendChild","createRange","createContextualFragment","insertAdjacentHTML","replaceScriptNodes","tagName","replaceChild","buildExecutableNode","scriptEl","attributes","name","nextSibling","isElement","placeholder","callback","startComputation","endFirstComputation","getCellCacheKey","nodeCache","gettersetter","store","toJSON","component","ctrl","currentArgs","output","checkPrevented","root","isPrevented","roots","currentComponent","topComponent","components","removeRootElement","reset","computePreRedrawHook","render","computePostRedrawHook","lastRedrawId","lastRedrawCallTime","Date","endComputation","normalizeRoute","route","modes","mode","routeByValue","router","path","routeParams","queryStart","parseQueryString","substr","matcher","RegExp","test","values","routeUnobtrusive","ctrlKey","metaKey","shiftKey","which","currentTarget","srcElement","search","setScroll","hash","scrollTo","buildQueryString","prefix","duplicates","str","charAt","params","string","cacheKey","cellCache","propify","promise","initialValue","then","resolve","reject","Deferred","onSuccess","onFailure","finish","REJECTED","next","deferred","RESOLVED","promiseValue","thennable","success","failure","notThennable","count","onerror","fire","REJECTING","RESOLVING","self","TypeError","identity","handleJsonp","options","callbackKey","callbackName","getTime","Math","round","random","script","resp","onload","responseText","status","stringify","error","src","createXhr","xhr","XMLHttpRequest","user","password","onreadystatechange","readyState","serialize","setRequestHeader","deserialize","maybeXhr","FormData","send","ajax","dataType","toLowerCase","bindData","querystring","parameterizeUrl","token","version","AREA","BASE","BR","COL","COMMAND","EMBED","HR","IMG","INPUT","KEYGEN","LINK","META","PARAM","SOURCE","TRACK","WBR","html","form","width","height","documentNode","documentElement","forceRecreation","isDocumentRoot","String","Promise","FRAME_BUDGET","unloader","redrawing","force","withAttr","withAttrCallback","callbackThis","_this","currentRoute","pathname","redirect","isDefaultRoute","arg1","arg2","vdom","source","listener","base","removeEventListener","detachEvent","oldRoute","queryIndex","currentPath","replaceHistory","err","param","sync","synchronizer","pos","resolved","results","outstanding","arg","request","background","extract","isJSONP","jsonp","toUpperCase","ev","response","unwrapSuccess","res","unwrapError","8","indexOfListener","listeners","alias","proto","originalGlobalValue","getListeners","evt","_getEvents","flattenListeners","flatListeners","getListenersAsObject","addListener","listenerIsWrapped","once","addOnceListener","defineEvent","defineEvents","evts","removeListener","off","addListeners","manipulateListeners","removeListeners","remove","single","multiple","removeEvent","_events","removeAllListeners","emitEvent","listenersMap","_getOnceReturnValue","emit","setOnceReturnValue","_onceReturnValue","noConflict"],"mappings":"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","file":"admin.min.js","sourcesContent":["(function () { var require = undefined; var define = undefined; (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){\n'use strict';\n\n// dependencies\nvar m = window.m = require('mithril');\nvar EventEmitter = require('wolfy87-eventemitter');\n\n// vars\nvar context = document.getElementById('mc4wp-admin');\nvar events = new EventEmitter();\nvar tabs = require ('./admin/tabs.js')(context);\nvar helpers = require('./admin/helpers.js');\nvar settings = require('./admin/settings.js')(context, helpers, events);\n\n// list fetcher\nvar ListFetcher = require('./admin/list-fetcher.js');\nvar mount = document.getElementById('mc4wp-list-fetcher');\nif( mount ) {\n m.mount(mount, new ListFetcher);\n}\n\n// expose some things\nwindow.mc4wp = window.mc4wp || {};\nwindow.mc4wp.deps = window.mc4wp.deps || {};\nwindow.mc4wp.deps.mithril = m;\nwindow.mc4wp.helpers = helpers;\nwindow.mc4wp.events = events;\nwindow.mc4wp.settings = settings;\nwindow.mc4wp.tabs = tabs;\n},{\"./admin/helpers.js\":2,\"./admin/list-fetcher.js\":3,\"./admin/settings.js\":4,\"./admin/tabs.js\":5,\"mithril\":7,\"wolfy87-eventemitter\":8}],2:[function(require,module,exports){\n'use strict';\n\nvar helpers = {};\n\nhelpers.toggleElement = function(selector) {\n\tvar elements = document.querySelectorAll(selector);\n\tfor( var i=0; i<elements.length;i++){\n\t\tvar show = elements[i].clientHeight <= 0;\n\t\telements[i].style.display = show ? '' : 'none';\n\t}\n};\n\nhelpers.bindEventToElement = function(element,event,handler) {\n\tif ( element.addEventListener) {\n\t\telement.addEventListener(event, handler);\n\t} else if (element.attachEvent) {\n\t\telement.attachEvent('on' + event, handler);\n\t}\n};\n\nhelpers.bindEventToElements = function( elements, event, handler ) {\n\tArray.prototype.forEach.call( elements, function(element) {\n\t\thelpers.bindEventToElement(element,event,handler);\n\t});\n};\n\n\n// polling\nhelpers.debounce = function(func, wait, immediate) {\n\tvar timeout;\n\treturn function() {\n\t\tvar context = this, args = arguments;\n\t\tvar later = function() {\n\t\t\ttimeout = null;\n\t\t\tif (!immediate) func.apply(context, args);\n\t\t};\n\t\tvar callNow = immediate && !timeout;\n\t\tclearTimeout(timeout);\n\t\ttimeout = setTimeout(later, wait);\n\t\tif (callNow) func.apply(context, args);\n\t};\n};\n\n\n/**\n * Showif.js\n */\n(function() {\n\tvar showIfElements = document.querySelectorAll('[data-showif]');\n\n\t// dependent elements\n\tArray.prototype.forEach.call( showIfElements, function(element) {\n\t\tvar config = JSON.parse( element.getAttribute('data-showif') );\n\t\tvar parentElements = document.querySelectorAll('[name=\"'+ config.element +'\"]');\n\t\tvar inputs = element.querySelectorAll('input,select,textarea:not([readonly])');\n\t\tvar hide = config.hide === undefined || config.hide;\n\n\t\tfunction toggleElement() {\n\n\t\t\t// do nothing with unchecked radio inputs\n\t\t\tif( this.getAttribute('type') === \"radio\" && ! this.checked ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar value = ( this.getAttribute(\"type\") === \"checkbox\" ) ? this.checked : this.value;\n\t\t\tvar conditionMet = ( value == config.value );\n\n\t\t\tif( hide ) {\n\t\t\t\telement.style.display = conditionMet ? '' : 'none';\n\t\t\t\telement.style.visibility = conditionMet ? '' : 'hidden';\n\t\t\t} else {\n\t\t\t\telement.style.opacity = conditionMet ? '' : '0.4';\n\t\t\t}\n\n\t\t\t// disable input fields to stop sending their values to server\n\t\t\tArray.prototype.forEach.call( inputs, function(inputElement) {\n\t\t\t\tconditionMet ? inputElement.removeAttribute('readonly') : inputElement.setAttribute('readonly','readonly');\n\t\t\t});\n\t\t}\n\n\t\t// find checked element and call toggleElement function\n\t\tArray.prototype.forEach.call( parentElements, function( parentElement ) {\n\t\t\ttoggleElement.call(parentElement);\n\t\t});\n\n\t\t// bind on all changes\n\t\thelpers.bindEventToElements(parentElements, 'change', toggleElement);\n\t});\n})();\n\nmodule.exports = helpers;\n},{}],3:[function(require,module,exports){\n'use strict';\n\nvar $ = window.jQuery;\nvar config = mc4wp_vars;\nvar i18n = config.i18n;\n\nfunction ListFetcher() {\n this.working = false;\n this.done = false;\n\n // start fetching right away when no lists but api key given\n if( config.mailchimp.api_connected && config.mailchimp.lists.length == 0 ) {\n this.fetch();\n }\n}\n\nListFetcher.prototype.fetch = function (e) {\n e && e.preventDefault();\n\n this.working = true;\n this.done = false;\n\n $.post(ajaxurl, {\n action: \"mc4wp_renew_mailchimp_lists\"\n }).done(function(data) {\n if(data) {\n window.setTimeout(function() { window.location.reload(); }, 3000 );\n }\n }).always(function (data) {\n this.working = false;\n this.done = true;\n\n m.redraw();\n }.bind(this));\n};\n\nListFetcher.prototype.view = function () {\n return m('form', {\n method: \"POST\",\n onsubmit: this.fetch.bind(this)\n }, [\n m('p', [\n m('input', {\n type: \"submit\",\n value: this.working ? i18n.fetching_mailchimp_lists : i18n.renew_mailchimp_lists,\n className: \"button\",\n disabled: !!this.working\n }),\n m.trust(' &nbsp; '),\n\n this.working ? [\n m('span.mc4wp-loader', \"Loading...\"),\n m.trust(' &nbsp; '),\n m('em.help', i18n.fetching_mailchimp_lists_can_take_a_while)\n ]: '',\n\n this.done ? [\n m( 'em.help.green', i18n.fetching_mailchimp_lists_done )\n ] : ''\n ])\n ]);\n};\n\nmodule.exports = ListFetcher;\n},{}],4:[function(require,module,exports){\nvar Settings = function(context, helpers, events ) {\n\t'use strict';\n\n\t// vars\n\tvar form = context.querySelector('form');\n\tvar listInputs = context.querySelectorAll('.mc4wp-list-input');\n\tvar lists = mc4wp_vars.mailchimp.lists;\n\tvar selectedLists = [];\n\n\t// functions\n\tfunction getSelectedListsWhere(searchKey,searchValue) {\n\t\treturn selectedLists.filter(function(el) {\n\t\t\treturn el[searchKey] === searchValue;\n\t\t});\n\t}\n\n\tfunction getSelectedLists() {\n\t\treturn selectedLists;\n\t}\n\n\tfunction updateSelectedLists() {\n\t\tselectedLists = [];\n\n\t\tArray.prototype.forEach.call(listInputs, function(input) {\n\t\t\t// skip unchecked checkboxes\n\t\t\tif( typeof( input.checked ) === \"boolean\" && ! input.checked ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif( typeof( lists[ input.value ] ) === \"object\" ){\n\t\t\t\tselectedLists.push( lists[ input.value ] );\n\t\t\t}\n\t\t});\n\n\t\tevents.trigger('selectedLists.change', [ selectedLists ]);\n\t\treturn selectedLists;\n\t}\n\n\tfunction toggleVisibleLists() {\n\t\tvar rows = document.querySelectorAll('.lists--only-selected > *');\n\t\tArray.prototype.forEach.call(rows, function(el) {\n\n\t\t\tvar listId = el.getAttribute('data-list-id');\n\t\t\tvar isSelected = getSelectedListsWhere('id', listId).length > 0;\n\n\t\t\tif( isSelected ) {\n\t\t\t\tel.setAttribute('class', el.getAttribute('class').replace('hidden',''));\n\t\t\t} else {\n\t\t\t\tel.setAttribute('class', el.getAttribute('class') + \" hidden\" );\n\t\t\t}\n\t\t});\n\t}\n\n\tevents.on('selectedLists.change', toggleVisibleLists);\n\thelpers.bindEventToElements(listInputs,'change',updateSelectedLists);\n\n\tupdateSelectedLists();\n\n\treturn {\n\t\tgetSelectedLists: getSelectedLists\n\t}\n\n};\n\nmodule.exports = Settings;\n},{}],5:[function(require,module,exports){\n'use strict';\n\nvar URL = require('./url.js');\n\n// Tabs\nvar Tabs = function(context) {\n\n\t// @todo last piece of jQuery... can we get rid of it?\n\tvar $ = window.jQuery;\n\n\tvar $context = $(context);\n\tvar $tabs = $context.find('.tab');\n\tvar $tabNavs = $context.find('.nav-tab');\n\tvar refererField = context.querySelector('input[name=\"_wp_http_referer\"]');\n\tvar tabs = [];\n\n\t$.each($tabs, function(i,t) {\n\t\tvar id = t.id.substring(4);\n\t\tvar title = $(t).find('h2').first().text();\n\n\t\ttabs.push({\n\t\t\tid: id,\n\t\t\ttitle: title,\n\t\t\telement: t,\n\t\t\tnav: context.querySelectorAll('.nav-tab-' + id),\n\t\t\topen: function() { return open(id); }\n\t\t});\n\t});\n\n\tfunction get(id) {\n\n\t\tfor( var i=0; i<tabs.length; i++){\n\t\t\tif(tabs[i].id === id ) {\n\t\t\t\treturn tabs[i];\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tfunction open( tab, updateState ) {\n\n\t\t// make sure we have a tab object\n\t\tif(typeof(tab) === \"string\"){\n\t\t\ttab = get(tab);\n\t\t}\n\n\t\tif(!tab) { return false; }\n\n\t\t// should we update state?\n\t\tif( updateState == undefined ) {\n\t\t\tupdateState = true;\n\t\t}\n\n\t\t// hide all tabs & remove active class\n\t\t$tabs.removeClass('tab-active').css('display', 'none');\n\t\t$tabNavs.removeClass('nav-tab-active');\n\n\t\t// add `nav-tab-active` to this tab\n\t\tArray.prototype.forEach.call(tab.nav, function(nav) {\n\t\t\tnav.className += \" nav-tab-active\";\n\t\t\tnav.blur();\n\t\t});\n\n\t\t// show target tab\n\t\ttab.element.style.display = 'block';\n\t\ttab.element.className += \" tab-active\";\n\n\t\t// create new URL\n\t\tvar url = URL.setParameter(window.location.href, \"tab\", tab.id );\n\n\t\t// update hash\n\t\tif( history.pushState && updateState ) {\n\t\t\thistory.pushState( tab.id, '', url );\n\t\t}\n\n\t\t// update document title\n\t\ttitle(tab);\n\n\t\t// update referer field\n\t\trefererField.value = url;\n\n\t\t// if thickbox is open, close it.\n\t\tif( typeof(tb_remove) === \"function\" ) {\n\t\t\ttb_remove();\n\t\t}\n\n\t\t// refresh editor after switching tabs\n\t\t// TODO: decouple decouple decouple\n\t\tif( tab.id === 'fields' && window.mc4wp && window.mc4wp.forms && window.mc4wp.forms.editor ) {\n\t\t\tmc4wp.forms.editor.refresh();\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction title(tab) {\n\t\tvar title = document.title.split('-');\n\t\tdocument.title = document.title.replace(title[0], tab.title + \" \");\n\t}\n\n\tfunction switchTab(e) {\n\t\te = e || window.event;\n\n\t\t// get from data attribute\n\t\tvar tabId = this.getAttribute('data-tab');\n\n\t\t// get from classname\n\t\tif( ! tabId ) {\n\t\t\tvar match = this.className.match(/nav-tab-(\\w+)?/);\n\t\t\tif( match ) {\n\t\t\t\ttabId = match[1];\n\t\t\t}\n\t\t}\n\n\t\t// get from href\n\t\tif( ! tabId ) {\n\t\t\tvar urlParams = URL.parse( this.href );\n\t\t\tif( ! urlParams.tab ) { return; }\n\t\t\ttabId = urlParams.tab;\n\t\t}\n\n\t\tvar opened = open( tabId );\n\n\t\tif( opened ) {\n\t\t\te.preventDefault();\n\t\t\te.returnValue = false;\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tfunction init() {\n\n\t\t// check for current tab\n\t\tif(! history.pushState) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar activeTab = $tabs.filter(':visible').get(0);\n\t\tif( ! activeTab ) { return; }\n\t\tvar tab = get(activeTab.id.substring(4));\n\t\tif(!tab) return;\n\n\t\t// check if tab is in html5 history\n\t\tif( history.replaceState && history.state === null) {\n\t\t\thistory.replaceState( tab.id, '' );\n\t\t}\n\n\t\t// update document title\n\t\ttitle(tab);\n\t}\n\n\t$tabNavs.click(switchTab);\n\t$(document.body).on('click', '.tab-link', switchTab);\n\tinit();\n\n\tif(window.addEventListener && history.pushState ) {\n\t\twindow.addEventListener('popstate', function(e) {\n\t\t\tif(!e.state) return true;\n\t\t\tvar tabId = e.state;\n\t\t\treturn open(tabId,false);\n\t\t});\n\t}\n\n\treturn {\n\t\topen: open,\n\t\tget: get\n\t}\n\n};\n\nmodule.exports = Tabs;\n},{\"./url.js\":6}],6:[function(require,module,exports){\n'use strict';\n\nvar URL = {\n\tparse: function(url) {\n\t\tvar query = {};\n\t\tvar a = url.split('&');\n\t\tfor (var i in a) {\n\t\t\tif(!a.hasOwnProperty(i)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvar b = a[i].split('=');\n\t\t\tquery[decodeURIComponent(b[0])] = decodeURIComponent(b[1]);\n\t\t}\n\n\t\treturn query;\n\t},\n\tbuild: function(data) {\n\t\tvar ret = [];\n\t\tfor (var d in data)\n\t\t\tret.push(d + \"=\" + encodeURIComponent(data[d]));\n\t\treturn ret.join(\"&\");\n\t},\n\tsetParameter: function( url, key, value ) {\n\t\tvar data = URL.parse( url );\n\t\tdata[ key ] = value;\n\t\treturn URL.build( data );\n\t}\n};\n\nmodule.exports = URL;\n},{}],7:[function(require,module,exports){\n;(function (global, factory) { // eslint-disable-line\r\n\t\"use strict\"\r\n\t/* eslint-disable no-undef */\r\n\tvar m = factory(global)\r\n\tif (typeof module === \"object\" && module != null && module.exports) {\r\n\t\tmodule.exports = m\r\n\t} else if (typeof define === \"function\" && define.amd) {\r\n\t\tdefine(function () { return m })\r\n\t} else {\r\n\t\tglobal.m = m\r\n\t}\r\n\t/* eslint-enable no-undef */\r\n})(typeof window !== \"undefined\" ? window : this, function (global, undefined) { // eslint-disable-line\r\n\t\"use strict\"\r\n\r\n\tm.version = function () {\r\n\t\treturn \"v0.2.5\"\r\n\t}\r\n\r\n\tvar hasOwn = {}.hasOwnProperty\r\n\tvar type = {}.toString\r\n\r\n\tfunction isFunction(object) {\r\n\t\treturn typeof object === \"function\"\r\n\t}\r\n\r\n\tfunction isObject(object) {\r\n\t\treturn type.call(object) === \"[object Object]\"\r\n\t}\r\n\r\n\tfunction isString(object) {\r\n\t\treturn type.call(object) === \"[object String]\"\r\n\t}\r\n\r\n\tvar isArray = Array.isArray || function (object) {\r\n\t\treturn type.call(object) === \"[object Array]\"\r\n\t}\r\n\r\n\tfunction noop() {}\r\n\r\n\tvar voidElements = {\r\n\t\tAREA: 1,\r\n\t\tBASE: 1,\r\n\t\tBR: 1,\r\n\t\tCOL: 1,\r\n\t\tCOMMAND: 1,\r\n\t\tEMBED: 1,\r\n\t\tHR: 1,\r\n\t\tIMG: 1,\r\n\t\tINPUT: 1,\r\n\t\tKEYGEN: 1,\r\n\t\tLINK: 1,\r\n\t\tMETA: 1,\r\n\t\tPARAM: 1,\r\n\t\tSOURCE: 1,\r\n\t\tTRACK: 1,\r\n\t\tWBR: 1\r\n\t}\r\n\r\n\t// caching commonly used variables\r\n\tvar $document, $location, $requestAnimationFrame, $cancelAnimationFrame\r\n\r\n\t// self invoking function needed because of the way mocks work\r\n\tfunction initialize(mock) {\r\n\t\t$document = mock.document\r\n\t\t$location = mock.location\r\n\t\t$cancelAnimationFrame = mock.cancelAnimationFrame || mock.clearTimeout\r\n\t\t$requestAnimationFrame = mock.requestAnimationFrame || mock.setTimeout\r\n\t}\r\n\r\n\t// testing API\r\n\tm.deps = function (mock) {\r\n\t\tinitialize(global = mock || window)\r\n\t\treturn global\r\n\t}\r\n\r\n\tm.deps(global)\r\n\r\n\t/**\r\n\t * @typedef {String} Tag\r\n\t * A string that looks like -> div.classname#id[param=one][param2=two]\r\n\t * Which describes a DOM node\r\n\t */\r\n\r\n\tfunction parseTagAttrs(cell, tag) {\r\n\t\tvar classes = []\r\n\t\tvar parser = /(?:(^|#|\\.)([^#\\.\\[\\]]+))|(\\[.+?\\])/g\r\n\t\tvar match\r\n\r\n\t\twhile ((match = parser.exec(tag))) {\r\n\t\t\tif (match[1] === \"\" && match[2]) {\r\n\t\t\t\tcell.tag = match[2]\r\n\t\t\t} else if (match[1] === \"#\") {\r\n\t\t\t\tcell.attrs.id = match[2]\r\n\t\t\t} else if (match[1] === \".\") {\r\n\t\t\t\tclasses.push(match[2])\r\n\t\t\t} else if (match[3][0] === \"[\") {\r\n\t\t\t\tvar pair = /\\[(.+?)(?:=(\"|'|)(.*?)\\2)?\\]/.exec(match[3])\r\n\t\t\t\tcell.attrs[pair[1]] = pair[3] || \"\"\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn classes\r\n\t}\r\n\r\n\tfunction getVirtualChildren(args, hasAttrs) {\r\n\t\tvar children = hasAttrs ? args.slice(1) : args\r\n\r\n\t\tif (children.length === 1 && isArray(children[0])) {\r\n\t\t\treturn children[0]\r\n\t\t} else {\r\n\t\t\treturn children\r\n\t\t}\r\n\t}\r\n\r\n\tfunction assignAttrs(target, attrs, classes) {\r\n\t\tvar classAttr = \"class\" in attrs ? \"class\" : \"className\"\r\n\r\n\t\tfor (var attrName in attrs) {\r\n\t\t\tif (hasOwn.call(attrs, attrName)) {\r\n\t\t\t\tif (attrName === classAttr &&\r\n\t\t\t\t\t\tattrs[attrName] != null &&\r\n\t\t\t\t\t\tattrs[attrName] !== \"\") {\r\n\t\t\t\t\tclasses.push(attrs[attrName])\r\n\t\t\t\t\t// create key in correct iteration order\r\n\t\t\t\t\ttarget[attrName] = \"\"\r\n\t\t\t\t} else {\r\n\t\t\t\t\ttarget[attrName] = attrs[attrName]\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (classes.length) target[classAttr] = classes.join(\" \")\r\n\t}\r\n\r\n\t/**\r\n\t *\r\n\t * @param {Tag} The DOM node tag\r\n\t * @param {Object=[]} optional key-value pairs to be mapped to DOM attrs\r\n\t * @param {...mNode=[]} Zero or more Mithril child nodes. Can be an array,\r\n\t * or splat (optional)\r\n\t */\r\n\tfunction m(tag, pairs) {\r\n\t\tvar args = []\r\n\r\n\t\tfor (var i = 1, length = arguments.length; i < length; i++) {\r\n\t\t\targs[i - 1] = arguments[i]\r\n\t\t}\r\n\r\n\t\tif (isObject(tag)) return parameterize(tag, args)\r\n\r\n\t\tif (!isString(tag)) {\r\n\t\t\tthrow new Error(\"selector in m(selector, attrs, children) should \" +\r\n\t\t\t\t\"be a string\")\r\n\t\t}\r\n\r\n\t\tvar hasAttrs = pairs != null && isObject(pairs) &&\r\n\t\t\t!(\"tag\" in pairs || \"view\" in pairs || \"subtree\" in pairs)\r\n\r\n\t\tvar attrs = hasAttrs ? pairs : {}\r\n\t\tvar cell = {\r\n\t\t\ttag: \"div\",\r\n\t\t\tattrs: {},\r\n\t\t\tchildren: getVirtualChildren(args, hasAttrs)\r\n\t\t}\r\n\r\n\t\tassignAttrs(cell.attrs, attrs, parseTagAttrs(cell, tag))\r\n\t\treturn cell\r\n\t}\r\n\r\n\tfunction forEach(list, f) {\r\n\t\tfor (var i = 0; i < list.length && !f(list[i], i++);) {\r\n\t\t\t// function called in condition\r\n\t\t}\r\n\t}\r\n\r\n\tfunction forKeys(list, f) {\r\n\t\tforEach(list, function (attrs, i) {\r\n\t\t\treturn (attrs = attrs && attrs.attrs) &&\r\n\t\t\t\tattrs.key != null &&\r\n\t\t\t\tf(attrs, i)\r\n\t\t})\r\n\t}\r\n\t// This function was causing deopts in Chrome.\r\n\tfunction dataToString(data) {\r\n\t\t// data.toString() might throw or return null if data is the return\r\n\t\t// value of Console.log in some versions of Firefox (behavior depends on\r\n\t\t// version)\r\n\t\ttry {\r\n\t\t\tif (data != null && data.toString() != null) return data\r\n\t\t} catch (e) {\r\n\t\t\t// silently ignore errors\r\n\t\t}\r\n\t\treturn \"\"\r\n\t}\r\n\r\n\t// This function was causing deopts in Chrome.\r\n\tfunction injectTextNode(parentElement, first, index, data) {\r\n\t\ttry {\r\n\t\t\tinsertNode(parentElement, first, index)\r\n\t\t\tfirst.nodeValue = data\r\n\t\t} catch (e) {\r\n\t\t\t// IE erroneously throws error when appending an empty text node\r\n\t\t\t// after a null\r\n\t\t}\r\n\t}\r\n\r\n\tfunction flatten(list) {\r\n\t\t// recursively flatten array\r\n\t\tfor (var i = 0; i < list.length; i++) {\r\n\t\t\tif (isArray(list[i])) {\r\n\t\t\t\tlist = list.concat.apply([], list)\r\n\t\t\t\t// check current index again and flatten until there are no more\r\n\t\t\t\t// nested arrays at that index\r\n\t\t\t\ti--\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn list\r\n\t}\r\n\r\n\tfunction insertNode(parentElement, node, index) {\r\n\t\tparentElement.insertBefore(node,\r\n\t\t\tparentElement.childNodes[index] || null)\r\n\t}\r\n\r\n\tvar DELETION = 1\r\n\tvar INSERTION = 2\r\n\tvar MOVE = 3\r\n\r\n\tfunction handleKeysDiffer(data, existing, cached, parentElement) {\r\n\t\tforKeys(data, function (key, i) {\r\n\t\t\texisting[key = key.key] = existing[key] ? {\r\n\t\t\t\taction: MOVE,\r\n\t\t\t\tindex: i,\r\n\t\t\t\tfrom: existing[key].index,\r\n\t\t\t\telement: cached.nodes[existing[key].index] ||\r\n\t\t\t\t\t$document.createElement(\"div\")\r\n\t\t\t} : {action: INSERTION, index: i}\r\n\t\t})\r\n\r\n\t\tvar actions = []\r\n\t\tfor (var prop in existing) {\r\n\t\t\tif (hasOwn.call(existing, prop)) {\r\n\t\t\t\tactions.push(existing[prop])\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar changes = actions.sort(sortChanges)\r\n\t\tvar newCached = new Array(cached.length)\r\n\r\n\t\tnewCached.nodes = cached.nodes.slice()\r\n\r\n\t\tforEach(changes, function (change) {\r\n\t\t\tvar index = change.index\r\n\t\t\tif (change.action === DELETION) {\r\n\t\t\t\tclear(cached[index].nodes, cached[index])\r\n\t\t\t\tnewCached.splice(index, 1)\r\n\t\t\t}\r\n\t\t\tif (change.action === INSERTION) {\r\n\t\t\t\tvar dummy = $document.createElement(\"div\")\r\n\t\t\t\tdummy.key = data[index].attrs.key\r\n\t\t\t\tinsertNode(parentElement, dummy, index)\r\n\t\t\t\tnewCached.splice(index, 0, {\r\n\t\t\t\t\tattrs: {key: data[index].attrs.key},\r\n\t\t\t\t\tnodes: [dummy]\r\n\t\t\t\t})\r\n\t\t\t\tnewCached.nodes[index] = dummy\r\n\t\t\t}\r\n\r\n\t\t\tif (change.action === MOVE) {\r\n\t\t\t\tvar changeElement = change.element\r\n\t\t\t\tvar maybeChanged = parentElement.childNodes[index]\r\n\t\t\t\tif (maybeChanged !== changeElement && changeElement !== null) {\r\n\t\t\t\t\tparentElement.insertBefore(changeElement,\r\n\t\t\t\t\t\tmaybeChanged || null)\r\n\t\t\t\t}\r\n\t\t\t\tnewCached[index] = cached[change.from]\r\n\t\t\t\tnewCached.nodes[index] = changeElement\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\treturn newCached\r\n\t}\r\n\r\n\tfunction diffKeys(data, cached, existing, parentElement) {\r\n\t\tvar keysDiffer = data.length !== cached.length\r\n\r\n\t\tif (!keysDiffer) {\r\n\t\t\tforKeys(data, function (attrs, i) {\r\n\t\t\t\tvar cachedCell = cached[i]\r\n\t\t\t\treturn keysDiffer = cachedCell &&\r\n\t\t\t\t\tcachedCell.attrs &&\r\n\t\t\t\t\tcachedCell.attrs.key !== attrs.key\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\tif (keysDiffer) {\r\n\t\t\treturn handleKeysDiffer(data, existing, cached, parentElement)\r\n\t\t} else {\r\n\t\t\treturn cached\r\n\t\t}\r\n\t}\r\n\r\n\tfunction diffArray(data, cached, nodes) {\r\n\t\t// diff the array itself\r\n\r\n\t\t// update the list of DOM nodes by collecting the nodes from each item\r\n\t\tforEach(data, function (_, i) {\r\n\t\t\tif (cached[i] != null) nodes.push.apply(nodes, cached[i].nodes)\r\n\t\t})\r\n\t\t// remove items from the end of the array if the new array is shorter\r\n\t\t// than the old one. if errors ever happen here, the issue is most\r\n\t\t// likely a bug in the construction of the `cached` data structure\r\n\t\t// somewhere earlier in the program\r\n\t\tforEach(cached.nodes, function (node, i) {\r\n\t\t\tif (node.parentNode != null && nodes.indexOf(node) < 0) {\r\n\t\t\t\tclear([node], [cached[i]])\r\n\t\t\t}\r\n\t\t})\r\n\r\n\t\tif (data.length < cached.length) cached.length = data.length\r\n\t\tcached.nodes = nodes\r\n\t}\r\n\r\n\tfunction buildArrayKeys(data) {\r\n\t\tvar guid = 0\r\n\t\tforKeys(data, function () {\r\n\t\t\tforEach(data, function (attrs) {\r\n\t\t\t\tif ((attrs = attrs && attrs.attrs) && attrs.key == null) {\r\n\t\t\t\t\tattrs.key = \"__mithril__\" + guid++\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\treturn 1\r\n\t\t})\r\n\t}\r\n\r\n\tfunction isDifferentEnough(data, cached, dataAttrKeys) {\r\n\t\tif (data.tag !== cached.tag) return true\r\n\r\n\t\tif (dataAttrKeys.sort().join() !==\r\n\t\t\t\tObject.keys(cached.attrs).sort().join()) {\r\n\t\t\treturn true\r\n\t\t}\r\n\r\n\t\tif (data.attrs.id !== cached.attrs.id) {\r\n\t\t\treturn true\r\n\t\t}\r\n\r\n\t\tif (data.attrs.key !== cached.attrs.key) {\r\n\t\t\treturn true\r\n\t\t}\r\n\r\n\t\tif (m.redraw.strategy() === \"all\") {\r\n\t\t\treturn !cached.configContext || cached.configContext.retain !== true\r\n\t\t}\r\n\r\n\t\tif (m.redraw.strategy() === \"diff\") {\r\n\t\t\treturn cached.configContext && cached.configContext.retain === false\r\n\t\t}\r\n\r\n\t\treturn false\r\n\t}\r\n\r\n\tfunction maybeRecreateObject(data, cached, dataAttrKeys) {\r\n\t\t// if an element is different enough from the one in cache, recreate it\r\n\t\tif (isDifferentEnough(data, cached, dataAttrKeys)) {\r\n\t\t\tif (cached.nodes.length) clear(cached.nodes)\r\n\r\n\t\t\tif (cached.configContext &&\r\n\t\t\t\t\tisFunction(cached.configContext.onunload)) {\r\n\t\t\t\tcached.configContext.onunload()\r\n\t\t\t}\r\n\r\n\t\t\tif (cached.controllers) {\r\n\t\t\t\tforEach(cached.controllers, function (controller) {\r\n\t\t\t\t\tif (controller.onunload) {\r\n\t\t\t\t\t\tcontroller.onunload({preventDefault: noop})\r\n\t\t\t\t\t}\r\n\t\t\t\t})\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tfunction getObjectNamespace(data, namespace) {\r\n\t\tif (data.attrs.xmlns) return data.attrs.xmlns\r\n\t\tif (data.tag === \"svg\") return \"http://www.w3.org/2000/svg\"\r\n\t\tif (data.tag === \"math\") return \"http://www.w3.org/1998/Math/MathML\"\r\n\t\treturn namespace\r\n\t}\r\n\r\n\tvar pendingRequests = 0\r\n\tm.startComputation = function () { pendingRequests++ }\r\n\tm.endComputation = function () {\r\n\t\tif (pendingRequests > 1) {\r\n\t\t\tpendingRequests--\r\n\t\t} else {\r\n\t\t\tpendingRequests = 0\r\n\t\t\tm.redraw()\r\n\t\t}\r\n\t}\r\n\r\n\tfunction unloadCachedControllers(cached, views, controllers) {\r\n\t\tif (controllers.length) {\r\n\t\t\tcached.views = views\r\n\t\t\tcached.controllers = controllers\r\n\t\t\tforEach(controllers, function (controller) {\r\n\t\t\t\tif (controller.onunload && controller.onunload.$old) {\r\n\t\t\t\t\tcontroller.onunload = controller.onunload.$old\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (pendingRequests && controller.onunload) {\r\n\t\t\t\t\tvar onunload = controller.onunload\r\n\t\t\t\t\tcontroller.onunload = noop\r\n\t\t\t\t\tcontroller.onunload.$old = onunload\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\t}\r\n\r\n\tfunction scheduleConfigsToBeCalled(configs, data, node, isNew, cached) {\r\n\t\t// schedule configs to be called. They are called after `build` finishes\r\n\t\t// running\r\n\t\tif (isFunction(data.attrs.config)) {\r\n\t\t\tvar context = cached.configContext = cached.configContext || {}\r\n\r\n\t\t\t// bind\r\n\t\t\tconfigs.push(function () {\r\n\t\t\t\treturn data.attrs.config.call(data, node, !isNew, context,\r\n\t\t\t\t\tcached)\r\n\t\t\t})\r\n\t\t}\r\n\t}\r\n\r\n\tfunction buildUpdatedNode(\r\n\t\tcached,\r\n\t\tdata,\r\n\t\teditable,\r\n\t\thasKeys,\r\n\t\tnamespace,\r\n\t\tviews,\r\n\t\tconfigs,\r\n\t\tcontrollers\r\n\t) {\r\n\t\tvar node = cached.nodes[0]\r\n\r\n\t\tif (hasKeys) {\r\n\t\t\tsetAttributes(node, data.tag, data.attrs, cached.attrs, namespace)\r\n\t\t}\r\n\r\n\t\tcached.children = build(\r\n\t\t\tnode,\r\n\t\t\tdata.tag,\r\n\t\t\tundefined,\r\n\t\t\tundefined,\r\n\t\t\tdata.children,\r\n\t\t\tcached.children,\r\n\t\t\tfalse,\r\n\t\t\t0,\r\n\t\t\tdata.attrs.contenteditable ? node : editable,\r\n\t\t\tnamespace,\r\n\t\t\tconfigs\r\n\t\t)\r\n\r\n\t\tcached.nodes.intact = true\r\n\r\n\t\tif (controllers.length) {\r\n\t\t\tcached.views = views\r\n\t\t\tcached.controllers = controllers\r\n\t\t}\r\n\r\n\t\treturn node\r\n\t}\r\n\r\n\tfunction handleNonexistentNodes(data, parentElement, index) {\r\n\t\tvar nodes\r\n\t\tif (data.$trusted) {\r\n\t\t\tnodes = injectHTML(parentElement, index, data)\r\n\t\t} else {\r\n\t\t\tnodes = [$document.createTextNode(data)]\r\n\t\t\tif (!(parentElement.nodeName in voidElements)) {\r\n\t\t\t\tinsertNode(parentElement, nodes[0], index)\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar cached\r\n\r\n\t\tif (typeof data === \"string\" ||\r\n\t\t\t\ttypeof data === \"number\" ||\r\n\t\t\t\ttypeof data === \"boolean\") {\r\n\t\t\tcached = new data.constructor(data)\r\n\t\t} else {\r\n\t\t\tcached = data\r\n\t\t}\r\n\r\n\t\tcached.nodes = nodes\r\n\t\treturn cached\r\n\t}\r\n\r\n\tfunction reattachNodes(\r\n\t\tdata,\r\n\t\tcached,\r\n\t\tparentElement,\r\n\t\teditable,\r\n\t\tindex,\r\n\t\tparentTag\r\n\t) {\r\n\t\tvar nodes = cached.nodes\r\n\t\tif (!editable || editable !== $document.activeElement) {\r\n\t\t\tif (data.$trusted) {\r\n\t\t\t\tclear(nodes, cached)\r\n\t\t\t\tnodes = injectHTML(parentElement, index, data)\r\n\t\t\t} else if (parentTag === \"textarea\") {\r\n\t\t\t\t// <textarea> uses `value` instead of `nodeValue`.\r\n\t\t\t\tparentElement.value = data\r\n\t\t\t} else if (editable) {\r\n\t\t\t\t// contenteditable nodes use `innerHTML` instead of `nodeValue`.\r\n\t\t\t\teditable.innerHTML = data\r\n\t\t\t} else {\r\n\t\t\t\t// was a trusted string\r\n\t\t\t\tif (nodes[0].nodeType === 1 || nodes.length > 1 ||\r\n\t\t\t\t\t\t(nodes[0].nodeValue.trim &&\r\n\t\t\t\t\t\t\t!nodes[0].nodeValue.trim())) {\r\n\t\t\t\t\tclear(cached.nodes, cached)\r\n\t\t\t\t\tnodes = [$document.createTextNode(data)]\r\n\t\t\t\t}\r\n\r\n\t\t\t\tinjectTextNode(parentElement, nodes[0], index, data)\r\n\t\t\t}\r\n\t\t}\r\n\t\tcached = new data.constructor(data)\r\n\t\tcached.nodes = nodes\r\n\t\treturn cached\r\n\t}\r\n\r\n\tfunction handleTextNode(\r\n\t\tcached,\r\n\t\tdata,\r\n\t\tindex,\r\n\t\tparentElement,\r\n\t\tshouldReattach,\r\n\t\teditable,\r\n\t\tparentTag\r\n\t) {\r\n\t\tif (!cached.nodes.length) {\r\n\t\t\treturn handleNonexistentNodes(data, parentElement, index)\r\n\t\t} else if (cached.valueOf() !== data.valueOf() || shouldReattach) {\r\n\t\t\treturn reattachNodes(data, cached, parentElement, editable, index,\r\n\t\t\t\tparentTag)\r\n\t\t} else {\r\n\t\t\treturn (cached.nodes.intact = true, cached)\r\n\t\t}\r\n\t}\r\n\r\n\tfunction getSubArrayCount(item) {\r\n\t\tif (item.$trusted) {\r\n\t\t\t// fix offset of next element if item was a trusted string w/ more\r\n\t\t\t// than one html element\r\n\t\t\t// the first clause in the regexp matches elements\r\n\t\t\t// the second clause (after the pipe) matches text nodes\r\n\t\t\tvar match = item.match(/<[^\\/]|\\>\\s*[^<]/g)\r\n\t\t\tif (match != null) return match.length\r\n\t\t} else if (isArray(item)) {\r\n\t\t\treturn item.length\r\n\t\t}\r\n\t\treturn 1\r\n\t}\r\n\r\n\tfunction buildArray(\r\n\t\tdata,\r\n\t\tcached,\r\n\t\tparentElement,\r\n\t\tindex,\r\n\t\tparentTag,\r\n\t\tshouldReattach,\r\n\t\teditable,\r\n\t\tnamespace,\r\n\t\tconfigs\r\n\t) {\r\n\t\tdata = flatten(data)\r\n\t\tvar nodes = []\r\n\t\tvar intact = cached.length === data.length\r\n\t\tvar subArrayCount = 0\r\n\r\n\t\t// keys algorithm: sort elements without recreating them if keys are\r\n\t\t// present\r\n\t\t//\r\n\t\t// 1) create a map of all existing keys, and mark all for deletion\r\n\t\t// 2) add new keys to map and mark them for addition\r\n\t\t// 3) if key exists in new list, change action from deletion to a move\r\n\t\t// 4) for each key, handle its corresponding action as marked in\r\n\t\t// previous steps\r\n\r\n\t\tvar existing = {}\r\n\t\tvar shouldMaintainIdentities = false\r\n\r\n\t\tforKeys(cached, function (attrs, i) {\r\n\t\t\tshouldMaintainIdentities = true\r\n\t\t\texisting[cached[i].attrs.key] = {action: DELETION, index: i}\r\n\t\t})\r\n\r\n\t\tbuildArrayKeys(data)\r\n\t\tif (shouldMaintainIdentities) {\r\n\t\t\tcached = diffKeys(data, cached, existing, parentElement)\r\n\t\t}\r\n\t\t// end key algorithm\r\n\r\n\t\tvar cacheCount = 0\r\n\t\t// faster explicitly written\r\n\t\tfor (var i = 0, len = data.length; i < len; i++) {\r\n\t\t\t// diff each item in the array\r\n\t\t\tvar item = build(\r\n\t\t\t\tparentElement,\r\n\t\t\t\tparentTag,\r\n\t\t\t\tcached,\r\n\t\t\t\tindex,\r\n\t\t\t\tdata[i],\r\n\t\t\t\tcached[cacheCount],\r\n\t\t\t\tshouldReattach,\r\n\t\t\t\tindex + subArrayCount || subArrayCount,\r\n\t\t\t\teditable,\r\n\t\t\t\tnamespace,\r\n\t\t\t\tconfigs)\r\n\r\n\t\t\tif (item !== undefined) {\r\n\t\t\t\tintact = intact && item.nodes.intact\r\n\t\t\t\tsubArrayCount += getSubArrayCount(item)\r\n\t\t\t\tcached[cacheCount++] = item\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!intact) diffArray(data, cached, nodes)\r\n\t\treturn cached\r\n\t}\r\n\r\n\tfunction makeCache(data, cached, index, parentIndex, parentCache) {\r\n\t\tif (cached != null) {\r\n\t\t\tif (type.call(cached) === type.call(data)) return cached\r\n\r\n\t\t\tif (parentCache && parentCache.nodes) {\r\n\t\t\t\tvar offset = index - parentIndex\r\n\t\t\t\tvar end = offset + (isArray(data) ? data : cached.nodes).length\r\n\t\t\t\tclear(\r\n\t\t\t\t\tparentCache.nodes.slice(offset, end),\r\n\t\t\t\t\tparentCache.slice(offset, end))\r\n\t\t\t} else if (cached.nodes) {\r\n\t\t\t\tclear(cached.nodes, cached)\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tcached = new data.constructor()\r\n\t\t// if constructor creates a virtual dom element, use a blank object as\r\n\t\t// the base cached node instead of copying the virtual el (#277)\r\n\t\tif (cached.tag) cached = {}\r\n\t\tcached.nodes = []\r\n\t\treturn cached\r\n\t}\r\n\r\n\tfunction constructNode(data, namespace) {\r\n\t\tif (data.attrs.is) {\r\n\t\t\tif (namespace == null) {\r\n\t\t\t\treturn $document.createElement(data.tag, data.attrs.is)\r\n\t\t\t} else {\r\n\t\t\t\treturn $document.createElementNS(namespace, data.tag,\r\n\t\t\t\t\tdata.attrs.is)\r\n\t\t\t}\r\n\t\t} else if (namespace == null) {\r\n\t\t\treturn $document.createElement(data.tag)\r\n\t\t} else {\r\n\t\t\treturn $document.createElementNS(namespace, data.tag)\r\n\t\t}\r\n\t}\r\n\r\n\tfunction constructAttrs(data, node, namespace, hasKeys) {\r\n\t\tif (hasKeys) {\r\n\t\t\treturn setAttributes(node, data.tag, data.attrs, {}, namespace)\r\n\t\t} else {\r\n\t\t\treturn data.attrs\r\n\t\t}\r\n\t}\r\n\r\n\tfunction constructChildren(\r\n\t\tdata,\r\n\t\tnode,\r\n\t\tcached,\r\n\t\teditable,\r\n\t\tnamespace,\r\n\t\tconfigs\r\n\t) {\r\n\t\tif (data.children != null && data.children.length > 0) {\r\n\t\t\treturn build(\r\n\t\t\t\tnode,\r\n\t\t\t\tdata.tag,\r\n\t\t\t\tundefined,\r\n\t\t\t\tundefined,\r\n\t\t\t\tdata.children,\r\n\t\t\t\tcached.children,\r\n\t\t\t\ttrue,\r\n\t\t\t\t0,\r\n\t\t\t\tdata.attrs.contenteditable ? node : editable,\r\n\t\t\t\tnamespace,\r\n\t\t\t\tconfigs)\r\n\t\t} else {\r\n\t\t\treturn data.children\r\n\t\t}\r\n\t}\r\n\r\n\tfunction reconstructCached(\r\n\t\tdata,\r\n\t\tattrs,\r\n\t\tchildren,\r\n\t\tnode,\r\n\t\tnamespace,\r\n\t\tviews,\r\n\t\tcontrollers\r\n\t) {\r\n\t\tvar cached = {\r\n\t\t\ttag: data.tag,\r\n\t\t\tattrs: attrs,\r\n\t\t\tchildren: children,\r\n\t\t\tnodes: [node]\r\n\t\t}\r\n\r\n\t\tunloadCachedControllers(cached, views, controllers)\r\n\r\n\t\tif (cached.children && !cached.children.nodes) {\r\n\t\t\tcached.children.nodes = []\r\n\t\t}\r\n\r\n\t\t// edge case: setting value on <select> doesn't work before children\r\n\t\t// exist, so set it again after children have been created\r\n\t\tif (data.tag === \"select\" && \"value\" in data.attrs) {\r\n\t\t\tsetAttributes(node, data.tag, {value: data.attrs.value}, {},\r\n\t\t\t\tnamespace)\r\n\t\t}\r\n\r\n\t\treturn cached\r\n\t}\r\n\r\n\tfunction getController(views, view, cachedControllers, controller) {\r\n\t\tvar controllerIndex\r\n\r\n\t\tif (m.redraw.strategy() === \"diff\" && views) {\r\n\t\t\tcontrollerIndex = views.indexOf(view)\r\n\t\t} else {\r\n\t\t\tcontrollerIndex = -1\r\n\t\t}\r\n\r\n\t\tif (controllerIndex > -1) {\r\n\t\t\treturn cachedControllers[controllerIndex]\r\n\t\t} else if (isFunction(controller)) {\r\n\t\t\treturn new controller()\r\n\t\t} else {\r\n\t\t\treturn {}\r\n\t\t}\r\n\t}\r\n\r\n\tvar unloaders = []\r\n\r\n\tfunction updateLists(views, controllers, view, controller) {\r\n\t\tif (controller.onunload != null &&\r\n\t\t\t\tunloaders.map(function (u) { return u.handler })\r\n\t\t\t\t\t.indexOf(controller.onunload) < 0) {\r\n\t\t\tunloaders.push({\r\n\t\t\t\tcontroller: controller,\r\n\t\t\t\thandler: controller.onunload\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\tviews.push(view)\r\n\t\tcontrollers.push(controller)\r\n\t}\r\n\r\n\tvar forcing = false\r\n\tfunction checkView(\r\n\t\tdata,\r\n\t\tview,\r\n\t\tcached,\r\n\t\tcachedControllers,\r\n\t\tcontrollers,\r\n\t\tviews\r\n\t) {\r\n\t\tvar controller = getController(\r\n\t\t\tcached.views,\r\n\t\t\tview,\r\n\t\t\tcachedControllers,\r\n\t\t\tdata.controller)\r\n\r\n\t\tvar key = data && data.attrs && data.attrs.key\r\n\r\n\t\tif (pendingRequests === 0 ||\r\n\t\t\t\tforcing ||\r\n\t\t\t\tcachedControllers &&\r\n\t\t\t\t\tcachedControllers.indexOf(controller) > -1) {\r\n\t\t\tdata = data.view(controller)\r\n\t\t} else {\r\n\t\t\tdata = {tag: \"placeholder\"}\r\n\t\t}\r\n\r\n\t\tif (data.subtree === \"retain\") return data\r\n\t\tdata.attrs = data.attrs || {}\r\n\t\tdata.attrs.key = key\r\n\t\tupdateLists(views, controllers, view, controller)\r\n\t\treturn data\r\n\t}\r\n\r\n\tfunction markViews(data, cached, views, controllers) {\r\n\t\tvar cachedControllers = cached && cached.controllers\r\n\r\n\t\twhile (data.view != null) {\r\n\t\t\tdata = checkView(\r\n\t\t\t\tdata,\r\n\t\t\t\tdata.view.$original || data.view,\r\n\t\t\t\tcached,\r\n\t\t\t\tcachedControllers,\r\n\t\t\t\tcontrollers,\r\n\t\t\t\tviews)\r\n\t\t}\r\n\r\n\t\treturn data\r\n\t}\r\n\r\n\tfunction buildObject( // eslint-disable-line max-statements\r\n\t\tdata,\r\n\t\tcached,\r\n\t\teditable,\r\n\t\tparentElement,\r\n\t\tindex,\r\n\t\tshouldReattach,\r\n\t\tnamespace,\r\n\t\tconfigs\r\n\t) {\r\n\t\tvar views = []\r\n\t\tvar controllers = []\r\n\r\n\t\tdata = markViews(data, cached, views, controllers)\r\n\r\n\t\tif (data.subtree === \"retain\") return cached\r\n\r\n\t\tif (!data.tag && controllers.length) {\r\n\t\t\tthrow new Error(\"Component template must return a virtual \" +\r\n\t\t\t\t\"element, not an array, string, etc.\")\r\n\t\t}\r\n\r\n\t\tdata.attrs = data.attrs || {}\r\n\t\tcached.attrs = cached.attrs || {}\r\n\r\n\t\tvar dataAttrKeys = Object.keys(data.attrs)\r\n\t\tvar hasKeys = dataAttrKeys.length > (\"key\" in data.attrs ? 1 : 0)\r\n\r\n\t\tmaybeRecreateObject(data, cached, dataAttrKeys)\r\n\r\n\t\tif (!isString(data.tag)) return\r\n\r\n\t\tvar isNew = cached.nodes.length === 0\r\n\r\n\t\tnamespace = getObjectNamespace(data, namespace)\r\n\r\n\t\tvar node\r\n\t\tif (isNew) {\r\n\t\t\tnode = constructNode(data, namespace)\r\n\t\t\t// set attributes first, then create children\r\n\t\t\tvar attrs = constructAttrs(data, node, namespace, hasKeys)\r\n\r\n\t\t\t// add the node to its parent before attaching children to it\r\n\t\t\tinsertNode(parentElement, node, index)\r\n\r\n\t\t\tvar children = constructChildren(data, node, cached, editable,\r\n\t\t\t\tnamespace, configs)\r\n\r\n\t\t\tcached = reconstructCached(\r\n\t\t\t\tdata,\r\n\t\t\t\tattrs,\r\n\t\t\t\tchildren,\r\n\t\t\t\tnode,\r\n\t\t\t\tnamespace,\r\n\t\t\t\tviews,\r\n\t\t\t\tcontrollers)\r\n\t\t} else {\r\n\t\t\tnode = buildUpdatedNode(\r\n\t\t\t\tcached,\r\n\t\t\t\tdata,\r\n\t\t\t\teditable,\r\n\t\t\t\thasKeys,\r\n\t\t\t\tnamespace,\r\n\t\t\t\tviews,\r\n\t\t\t\tconfigs,\r\n\t\t\t\tcontrollers)\r\n\t\t}\r\n\r\n\t\tif (!isNew && shouldReattach === true && node != null) {\r\n\t\t\tinsertNode(parentElement, node, index)\r\n\t\t}\r\n\r\n\t\t// The configs are called after `build` finishes running\r\n\t\tscheduleConfigsToBeCalled(configs, data, node, isNew, cached)\r\n\r\n\t\treturn cached\r\n\t}\r\n\r\n\tfunction build(\r\n\t\tparentElement,\r\n\t\tparentTag,\r\n\t\tparentCache,\r\n\t\tparentIndex,\r\n\t\tdata,\r\n\t\tcached,\r\n\t\tshouldReattach,\r\n\t\tindex,\r\n\t\teditable,\r\n\t\tnamespace,\r\n\t\tconfigs\r\n\t) {\r\n\t\t/*\r\n\t\t * `build` is a recursive function that manages creation/diffing/removal\r\n\t\t * of DOM elements based on comparison between `data` and `cached` the\r\n\t\t * diff algorithm can be summarized as this:\r\n\t\t *\r\n\t\t * 1 - compare `data` and `cached`\r\n\t\t * 2 - if they are different, copy `data` to `cached` and update the DOM\r\n\t\t * based on what the difference is\r\n\t\t * 3 - recursively apply this algorithm for every array and for the\r\n\t\t * children of every virtual element\r\n\t\t *\r\n\t\t * The `cached` data structure is essentially the same as the previous\r\n\t\t * redraw's `data` data structure, with a few additions:\r\n\t\t * - `cached` always has a property called `nodes`, which is a list of\r\n\t\t * DOM elements that correspond to the data represented by the\r\n\t\t * respective virtual element\r\n\t\t * - in order to support attaching `nodes` as a property of `cached`,\r\n\t\t * `cached` is *always* a non-primitive object, i.e. if the data was\r\n\t\t * a string, then cached is a String instance. If data was `null` or\r\n\t\t * `undefined`, cached is `new String(\"\")`\r\n\t\t * - `cached also has a `configContext` property, which is the state\r\n\t\t * storage object exposed by config(element, isInitialized, context)\r\n\t\t * - when `cached` is an Object, it represents a virtual element; when\r\n\t\t * it's an Array, it represents a list of elements; when it's a\r\n\t\t * String, Number or Boolean, it represents a text node\r\n\t\t *\r\n\t\t * `parentElement` is a DOM element used for W3C DOM API calls\r\n\t\t * `parentTag` is only used for handling a corner case for textarea\r\n\t\t * values\r\n\t\t * `parentCache` is used to remove nodes in some multi-node cases\r\n\t\t * `parentIndex` and `index` are used to figure out the offset of nodes.\r\n\t\t * They're artifacts from before arrays started being flattened and are\r\n\t\t * likely refactorable\r\n\t\t * `data` and `cached` are, respectively, the new and old nodes being\r\n\t\t * diffed\r\n\t\t * `shouldReattach` is a flag indicating whether a parent node was\r\n\t\t * recreated (if so, and if this node is reused, then this node must\r\n\t\t * reattach itself to the new parent)\r\n\t\t * `editable` is a flag that indicates whether an ancestor is\r\n\t\t * contenteditable\r\n\t\t * `namespace` indicates the closest HTML namespace as it cascades down\r\n\t\t * from an ancestor\r\n\t\t * `configs` is a list of config functions to run after the topmost\r\n\t\t * `build` call finishes running\r\n\t\t *\r\n\t\t * there's logic that relies on the assumption that null and undefined\r\n\t\t * data are equivalent to empty strings\r\n\t\t * - this prevents lifecycle surprises from procedural helpers that mix\r\n\t\t * implicit and explicit return statements (e.g.\r\n\t\t * function foo() {if (cond) return m(\"div\")}\r\n\t\t * - it simplifies diffing code\r\n\t\t */\r\n\t\tdata = dataToString(data)\r\n\t\tif (data.subtree === \"retain\") return cached\r\n\t\tcached = makeCache(data, cached, index, parentIndex, parentCache)\r\n\r\n\t\tif (isArray(data)) {\r\n\t\t\treturn buildArray(\r\n\t\t\t\tdata,\r\n\t\t\t\tcached,\r\n\t\t\t\tparentElement,\r\n\t\t\t\tindex,\r\n\t\t\t\tparentTag,\r\n\t\t\t\tshouldReattach,\r\n\t\t\t\teditable,\r\n\t\t\t\tnamespace,\r\n\t\t\t\tconfigs)\r\n\t\t} else if (data != null && isObject(data)) {\r\n\t\t\treturn buildObject(\r\n\t\t\t\tdata,\r\n\t\t\t\tcached,\r\n\t\t\t\teditable,\r\n\t\t\t\tparentElement,\r\n\t\t\t\tindex,\r\n\t\t\t\tshouldReattach,\r\n\t\t\t\tnamespace,\r\n\t\t\t\tconfigs)\r\n\t\t} else if (!isFunction(data)) {\r\n\t\t\treturn handleTextNode(\r\n\t\t\t\tcached,\r\n\t\t\t\tdata,\r\n\t\t\t\tindex,\r\n\t\t\t\tparentElement,\r\n\t\t\t\tshouldReattach,\r\n\t\t\t\teditable,\r\n\t\t\t\tparentTag)\r\n\t\t} else {\r\n\t\t\treturn cached\r\n\t\t}\r\n\t}\r\n\r\n\tfunction sortChanges(a, b) {\r\n\t\treturn a.action - b.action || a.index - b.index\r\n\t}\r\n\r\n\tfunction copyStyleAttrs(node, dataAttr, cachedAttr) {\r\n\t\tfor (var rule in dataAttr) {\r\n\t\t\tif (hasOwn.call(dataAttr, rule)) {\r\n\t\t\t\tif (cachedAttr == null || cachedAttr[rule] !== dataAttr[rule]) {\r\n\t\t\t\t\tnode.style[rule] = dataAttr[rule]\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfor (rule in cachedAttr) {\r\n\t\t\tif (hasOwn.call(cachedAttr, rule)) {\r\n\t\t\t\tif (!hasOwn.call(dataAttr, rule)) node.style[rule] = \"\"\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tvar shouldUseSetAttribute = {\r\n\t\tlist: 1,\r\n\t\tstyle: 1,\r\n\t\tform: 1,\r\n\t\ttype: 1,\r\n\t\twidth: 1,\r\n\t\theight: 1\r\n\t}\r\n\r\n\tfunction setSingleAttr(\r\n\t\tnode,\r\n\t\tattrName,\r\n\t\tdataAttr,\r\n\t\tcachedAttr,\r\n\t\ttag,\r\n\t\tnamespace\r\n\t) {\r\n\t\tif (attrName === \"config\" || attrName === \"key\") {\r\n\t\t\t// `config` isn't a real attribute, so ignore it\r\n\t\t\treturn true\r\n\t\t} else if (isFunction(dataAttr) && attrName.slice(0, 2) === \"on\") {\r\n\t\t\t// hook event handlers to the auto-redrawing system\r\n\t\t\tnode[attrName] = autoredraw(dataAttr, node)\r\n\t\t} else if (attrName === \"style\" && dataAttr != null &&\r\n\t\t\t\tisObject(dataAttr)) {\r\n\t\t\t// handle `style: {...}`\r\n\t\t\tcopyStyleAttrs(node, dataAttr, cachedAttr)\r\n\t\t} else if (namespace != null) {\r\n\t\t\t// handle SVG\r\n\t\t\tif (attrName === \"href\") {\r\n\t\t\t\tnode.setAttributeNS(\"http://www.w3.org/1999/xlink\",\r\n\t\t\t\t\t\"href\", dataAttr)\r\n\t\t\t} else {\r\n\t\t\t\tnode.setAttribute(\r\n\t\t\t\t\tattrName === \"className\" ? \"class\" : attrName,\r\n\t\t\t\t\tdataAttr)\r\n\t\t\t}\r\n\t\t} else if (attrName in node && !shouldUseSetAttribute[attrName]) {\r\n\t\t\t// handle cases that are properties (but ignore cases where we\r\n\t\t\t// should use setAttribute instead)\r\n\t\t\t//\r\n\t\t\t// - list and form are typically used as strings, but are DOM\r\n\t\t\t// element references in js\r\n\t\t\t//\r\n\t\t\t// - when using CSS selectors (e.g. `m(\"[style='']\")`), style is\r\n\t\t\t// used as a string, but it's an object in js\r\n\t\t\t//\r\n\t\t\t// #348 don't set the value if not needed - otherwise, cursor\r\n\t\t\t// placement breaks in Chrome\r\n\t\t\ttry {\r\n\t\t\t\tif (tag !== \"input\" || node[attrName] !== dataAttr) {\r\n\t\t\t\t\tnode[attrName] = dataAttr\r\n\t\t\t\t}\r\n\t\t\t} catch (e) {\r\n\t\t\t\tnode.setAttribute(attrName, dataAttr)\r\n\t\t\t}\r\n\t\t}\r\n\t\telse node.setAttribute(attrName, dataAttr)\r\n\t}\r\n\r\n\tfunction trySetAttr(\r\n\t\tnode,\r\n\t\tattrName,\r\n\t\tdataAttr,\r\n\t\tcachedAttr,\r\n\t\tcachedAttrs,\r\n\t\ttag,\r\n\t\tnamespace\r\n\t) {\r\n\t\tif (!(attrName in cachedAttrs) || (cachedAttr !== dataAttr) || ($document.activeElement === node)) {\r\n\t\t\tcachedAttrs[attrName] = dataAttr\r\n\t\t\ttry {\r\n\t\t\t\treturn setSingleAttr(\r\n\t\t\t\t\tnode,\r\n\t\t\t\t\tattrName,\r\n\t\t\t\t\tdataAttr,\r\n\t\t\t\t\tcachedAttr,\r\n\t\t\t\t\ttag,\r\n\t\t\t\t\tnamespace)\r\n\t\t\t} catch (e) {\r\n\t\t\t\t// swallow IE's invalid argument errors to mimic HTML's\r\n\t\t\t\t// fallback-to-doing-nothing-on-invalid-attributes behavior\r\n\t\t\t\tif (e.message.indexOf(\"Invalid argument\") < 0) throw e\r\n\t\t\t}\r\n\t\t} else if (attrName === \"value\" && tag === \"input\" &&\r\n\t\t\t\tnode.value !== dataAttr) {\r\n\t\t\t// #348 dataAttr may not be a string, so use loose comparison\r\n\t\t\tnode.value = dataAttr\r\n\t\t}\r\n\t}\r\n\r\n\tfunction setAttributes(node, tag, dataAttrs, cachedAttrs, namespace) {\r\n\t\tfor (var attrName in dataAttrs) {\r\n\t\t\tif (hasOwn.call(dataAttrs, attrName)) {\r\n\t\t\t\tif (trySetAttr(\r\n\t\t\t\t\t\tnode,\r\n\t\t\t\t\t\tattrName,\r\n\t\t\t\t\t\tdataAttrs[attrName],\r\n\t\t\t\t\t\tcachedAttrs[attrName],\r\n\t\t\t\t\t\tcachedAttrs,\r\n\t\t\t\t\t\ttag,\r\n\t\t\t\t\t\tnamespace)) {\r\n\t\t\t\t\tcontinue\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn cachedAttrs\r\n\t}\r\n\r\n\tfunction clear(nodes, cached) {\r\n\t\tfor (var i = nodes.length - 1; i > -1; i--) {\r\n\t\t\tif (nodes[i] && nodes[i].parentNode) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tnodes[i].parentNode.removeChild(nodes[i])\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\t/* eslint-disable max-len */\r\n\t\t\t\t\t// ignore if this fails due to order of events (see\r\n\t\t\t\t\t// http://stackoverflow.com/questions/21926083/failed-to-execute-removechild-on-node)\r\n\t\t\t\t\t/* eslint-enable max-len */\r\n\t\t\t\t}\r\n\t\t\t\tcached = [].concat(cached)\r\n\t\t\t\tif (cached[i]) unload(cached[i])\r\n\t\t\t}\r\n\t\t}\r\n\t\t// release memory if nodes is an array. This check should fail if nodes\r\n\t\t// is a NodeList (see loop above)\r\n\t\tif (nodes.length) {\r\n\t\t\tnodes.length = 0\r\n\t\t}\r\n\t}\r\n\r\n\tfunction unload(cached) {\r\n\t\tif (cached.configContext && isFunction(cached.configContext.onunload)) {\r\n\t\t\tcached.configContext.onunload()\r\n\t\t\tcached.configContext.onunload = null\r\n\t\t}\r\n\t\tif (cached.controllers) {\r\n\t\t\tforEach(cached.controllers, function (controller) {\r\n\t\t\t\tif (isFunction(controller.onunload)) {\r\n\t\t\t\t\tcontroller.onunload({preventDefault: noop})\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\t\tif (cached.children) {\r\n\t\t\tif (isArray(cached.children)) forEach(cached.children, unload)\r\n\t\t\telse if (cached.children.tag) unload(cached.children)\r\n\t\t}\r\n\t}\r\n\r\n\tfunction appendTextFragment(parentElement, data) {\r\n\t\ttry {\r\n\t\t\tparentElement.appendChild(\r\n\t\t\t\t$document.createRange().createContextualFragment(data))\r\n\t\t} catch (e) {\r\n\t\t\tparentElement.insertAdjacentHTML(\"beforeend\", data)\r\n\t\t\treplaceScriptNodes(parentElement)\r\n\t\t}\r\n\t}\r\n\r\n\t// Replace script tags inside given DOM element with executable ones.\r\n\t// Will also check children recursively and replace any found script\r\n\t// tags in same manner.\r\n\tfunction replaceScriptNodes(node) {\r\n\t\tif (node.tagName === \"SCRIPT\") {\r\n\t\t\tnode.parentNode.replaceChild(buildExecutableNode(node), node)\r\n\t\t} else {\r\n\t\t\tvar children = node.childNodes\r\n\t\t\tif (children && children.length) {\r\n\t\t\t\tfor (var i = 0; i < children.length; i++) {\r\n\t\t\t\t\treplaceScriptNodes(children[i])\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn node\r\n\t}\r\n\r\n\t// Replace script element with one whose contents are executable.\r\n\tfunction buildExecutableNode(node){\r\n\t\tvar scriptEl = document.createElement(\"script\")\r\n\t\tvar attrs = node.attributes\r\n\r\n\t\tfor (var i = 0; i < attrs.length; i++) {\r\n\t\t\tscriptEl.setAttribute(attrs[i].name, attrs[i].value)\r\n\t\t}\r\n\r\n\t\tscriptEl.text = node.innerHTML\r\n\t\treturn scriptEl\r\n\t}\r\n\r\n\tfunction injectHTML(parentElement, index, data) {\r\n\t\tvar nextSibling = parentElement.childNodes[index]\r\n\t\tif (nextSibling) {\r\n\t\t\tvar isElement = nextSibling.nodeType !== 1\r\n\t\t\tvar placeholder = $document.createElement(\"span\")\r\n\t\t\tif (isElement) {\r\n\t\t\t\tparentElement.insertBefore(placeholder, nextSibling || null)\r\n\t\t\t\tplaceholder.insertAdjacentHTML(\"beforebegin\", data)\r\n\t\t\t\tparentElement.removeChild(placeholder)\r\n\t\t\t} else {\r\n\t\t\t\tnextSibling.insertAdjacentHTML(\"beforebegin\", data)\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tappendTextFragment(parentElement, data)\r\n\t\t}\r\n\r\n\t\tvar nodes = []\r\n\r\n\t\twhile (parentElement.childNodes[index] !== nextSibling) {\r\n\t\t\tnodes.push(parentElement.childNodes[index])\r\n\t\t\tindex++\r\n\t\t}\r\n\r\n\t\treturn nodes\r\n\t}\r\n\r\n\tfunction autoredraw(callback, object) {\r\n\t\treturn function (e) {\r\n\t\t\te = e || event\r\n\t\t\tm.redraw.strategy(\"diff\")\r\n\t\t\tm.startComputation()\r\n\t\t\ttry {\r\n\t\t\t\treturn callback.call(object, e)\r\n\t\t\t} finally {\r\n\t\t\t\tendFirstComputation()\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tvar html\r\n\tvar documentNode = {\r\n\t\tappendChild: function (node) {\r\n\t\t\tif (html === undefined) html = $document.createElement(\"html\")\r\n\t\t\tif ($document.documentElement &&\r\n\t\t\t\t\t$document.documentElement !== node) {\r\n\t\t\t\t$document.replaceChild(node, $document.documentElement)\r\n\t\t\t} else {\r\n\t\t\t\t$document.appendChild(node)\r\n\t\t\t}\r\n\r\n\t\t\tthis.childNodes = $document.childNodes\r\n\t\t},\r\n\r\n\t\tinsertBefore: function (node) {\r\n\t\t\tthis.appendChild(node)\r\n\t\t},\r\n\r\n\t\tchildNodes: []\r\n\t}\r\n\r\n\tvar nodeCache = []\r\n\tvar cellCache = {}\r\n\r\n\tm.render = function (root, cell, forceRecreation) {\r\n\t\tif (!root) {\r\n\t\t\tthrow new Error(\"Ensure the DOM element being passed to \" +\r\n\t\t\t\t\"m.route/m.mount/m.render is not undefined.\")\r\n\t\t}\r\n\t\tvar configs = []\r\n\t\tvar id = getCellCacheKey(root)\r\n\t\tvar isDocumentRoot = root === $document\r\n\t\tvar node\r\n\r\n\t\tif (isDocumentRoot || root === $document.documentElement) {\r\n\t\t\tnode = documentNode\r\n\t\t} else {\r\n\t\t\tnode = root\r\n\t\t}\r\n\r\n\t\tif (isDocumentRoot && cell.tag !== \"html\") {\r\n\t\t\tcell = {tag: \"html\", attrs: {}, children: cell}\r\n\t\t}\r\n\r\n\t\tif (cellCache[id] === undefined) clear(node.childNodes)\r\n\t\tif (forceRecreation === true) reset(root)\r\n\r\n\t\tcellCache[id] = build(\r\n\t\t\tnode,\r\n\t\t\tnull,\r\n\t\t\tundefined,\r\n\t\t\tundefined,\r\n\t\t\tcell,\r\n\t\t\tcellCache[id],\r\n\t\t\tfalse,\r\n\t\t\t0,\r\n\t\t\tnull,\r\n\t\t\tundefined,\r\n\t\t\tconfigs)\r\n\r\n\t\tforEach(configs, function (config) { config() })\r\n\t}\r\n\r\n\tfunction getCellCacheKey(element) {\r\n\t\tvar index = nodeCache.indexOf(element)\r\n\t\treturn index < 0 ? nodeCache.push(element) - 1 : index\r\n\t}\r\n\r\n\tm.trust = function (value) {\r\n\t\tvalue = new String(value) // eslint-disable-line no-new-wrappers\r\n\t\tvalue.$trusted = true\r\n\t\treturn value\r\n\t}\r\n\r\n\tfunction gettersetter(store) {\r\n\t\tfunction prop() {\r\n\t\t\tif (arguments.length) store = arguments[0]\r\n\t\t\treturn store\r\n\t\t}\r\n\r\n\t\tprop.toJSON = function () {\r\n\t\t\treturn store\r\n\t\t}\r\n\r\n\t\treturn prop\r\n\t}\r\n\r\n\tm.prop = function (store) {\r\n\t\tif ((store != null && (isObject(store) || isFunction(store)) || ((typeof Promise !== \"undefined\") && (store instanceof Promise))) &&\r\n\t\t\t\tisFunction(store.then)) {\r\n\t\t\treturn propify(store)\r\n\t\t}\r\n\r\n\t\treturn gettersetter(store)\r\n\t}\r\n\r\n\tvar roots = []\r\n\tvar components = []\r\n\tvar controllers = []\r\n\tvar lastRedrawId = null\r\n\tvar lastRedrawCallTime = 0\r\n\tvar computePreRedrawHook = null\r\n\tvar computePostRedrawHook = null\r\n\tvar topComponent\r\n\tvar FRAME_BUDGET = 16 // 60 frames per second = 1 call per 16 ms\r\n\r\n\tfunction parameterize(component, args) {\r\n\t\tfunction controller() {\r\n\t\t\t/* eslint-disable no-invalid-this */\r\n\t\t\treturn (component.controller || noop).apply(this, args) || this\r\n\t\t\t/* eslint-enable no-invalid-this */\r\n\t\t}\r\n\r\n\t\tif (component.controller) {\r\n\t\t\tcontroller.prototype = component.controller.prototype\r\n\t\t}\r\n\r\n\t\tfunction view(ctrl) {\r\n\t\t\tvar currentArgs = [ctrl].concat(args)\r\n\t\t\tfor (var i = 1; i < arguments.length; i++) {\r\n\t\t\t\tcurrentArgs.push(arguments[i])\r\n\t\t\t}\r\n\r\n\t\t\treturn component.view.apply(component, currentArgs)\r\n\t\t}\r\n\r\n\t\tview.$original = component.view\r\n\t\tvar output = {controller: controller, view: view}\r\n\t\tif (args[0] && args[0].key != null) output.attrs = {key: args[0].key}\r\n\t\treturn output\r\n\t}\r\n\r\n\tm.component = function (component) {\r\n\t\tvar args = new Array(arguments.length - 1)\r\n\r\n\t\tfor (var i = 1; i < arguments.length; i++) {\r\n\t\t\targs[i - 1] = arguments[i]\r\n\t\t}\r\n\r\n\t\treturn parameterize(component, args)\r\n\t}\r\n\r\n\tfunction checkPrevented(component, root, index, isPrevented) {\r\n\t\tif (!isPrevented) {\r\n\t\t\tm.redraw.strategy(\"all\")\r\n\t\t\tm.startComputation()\r\n\t\t\troots[index] = root\r\n\t\t\tvar currentComponent\r\n\r\n\t\t\tif (component) {\r\n\t\t\t\tcurrentComponent = topComponent = component\r\n\t\t\t} else {\r\n\t\t\t\tcurrentComponent = topComponent = component = {controller: noop}\r\n\t\t\t}\r\n\r\n\t\t\tvar controller = new (component.controller || noop)()\r\n\r\n\t\t\t// controllers may call m.mount recursively (via m.route redirects,\r\n\t\t\t// for example)\r\n\t\t\t// this conditional ensures only the last recursive m.mount call is\r\n\t\t\t// applied\r\n\t\t\tif (currentComponent === topComponent) {\r\n\t\t\t\tcontrollers[index] = controller\r\n\t\t\t\tcomponents[index] = component\r\n\t\t\t}\r\n\t\t\tendFirstComputation()\r\n\t\t\tif (component === null) {\r\n\t\t\t\tremoveRootElement(root, index)\r\n\t\t\t}\r\n\t\t\treturn controllers[index]\r\n\t\t} else if (component == null) {\r\n\t\t\tremoveRootElement(root, index)\r\n\t\t}\r\n\t}\r\n\r\n\tm.mount = m.module = function (root, component) {\r\n\t\tif (!root) {\r\n\t\t\tthrow new Error(\"Please ensure the DOM element exists before \" +\r\n\t\t\t\t\"rendering a template into it.\")\r\n\t\t}\r\n\r\n\t\tvar index = roots.indexOf(root)\r\n\t\tif (index < 0) index = roots.length\r\n\r\n\t\tvar isPrevented = false\r\n\t\tvar event = {\r\n\t\t\tpreventDefault: function () {\r\n\t\t\t\tisPrevented = true\r\n\t\t\t\tcomputePreRedrawHook = computePostRedrawHook = null\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tforEach(unloaders, function (unloader) {\r\n\t\t\tunloader.handler.call(unloader.controller, event)\r\n\t\t\tunloader.controller.onunload = null\r\n\t\t})\r\n\r\n\t\tif (isPrevented) {\r\n\t\t\tforEach(unloaders, function (unloader) {\r\n\t\t\t\tunloader.controller.onunload = unloader.handler\r\n\t\t\t})\r\n\t\t} else {\r\n\t\t\tunloaders = []\r\n\t\t}\r\n\r\n\t\tif (controllers[index] && isFunction(controllers[index].onunload)) {\r\n\t\t\tcontrollers[index].onunload(event)\r\n\t\t}\r\n\r\n\t\treturn checkPrevented(component, root, index, isPrevented)\r\n\t}\r\n\r\n\tfunction removeRootElement(root, index) {\r\n\t\troots.splice(index, 1)\r\n\t\tcontrollers.splice(index, 1)\r\n\t\tcomponents.splice(index, 1)\r\n\t\treset(root)\r\n\t\tnodeCache.splice(getCellCacheKey(root), 1)\r\n\t}\r\n\r\n\tvar redrawing = false\r\n\tm.redraw = function (force) {\r\n\t\tif (redrawing) return\r\n\t\tredrawing = true\r\n\t\tif (force) forcing = true\r\n\r\n\t\ttry {\r\n\t\t\t// lastRedrawId is a positive number if a second redraw is requested\r\n\t\t\t// before the next animation frame\r\n\t\t\t// lastRedrawId is null if it's the first redraw and not an event\r\n\t\t\t// handler\r\n\t\t\tif (lastRedrawId && !force) {\r\n\t\t\t\t// when setTimeout: only reschedule redraw if time between now\r\n\t\t\t\t// and previous redraw is bigger than a frame, otherwise keep\r\n\t\t\t\t// currently scheduled timeout\r\n\t\t\t\t// when rAF: always reschedule redraw\r\n\t\t\t\tif ($requestAnimationFrame === global.requestAnimationFrame ||\r\n\t\t\t\t\t\tnew Date() - lastRedrawCallTime > FRAME_BUDGET) {\r\n\t\t\t\t\tif (lastRedrawId > 0) $cancelAnimationFrame(lastRedrawId)\r\n\t\t\t\t\tlastRedrawId = $requestAnimationFrame(redraw, FRAME_BUDGET)\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tredraw()\r\n\t\t\t\tlastRedrawId = $requestAnimationFrame(function () {\r\n\t\t\t\t\tlastRedrawId = null\r\n\t\t\t\t}, FRAME_BUDGET)\r\n\t\t\t}\r\n\t\t} finally {\r\n\t\t\tredrawing = forcing = false\r\n\t\t}\r\n\t}\r\n\r\n\tm.redraw.strategy = m.prop()\r\n\tfunction redraw() {\r\n\t\tif (computePreRedrawHook) {\r\n\t\t\tcomputePreRedrawHook()\r\n\t\t\tcomputePreRedrawHook = null\r\n\t\t}\r\n\t\tforEach(roots, function (root, i) {\r\n\t\t\tvar component = components[i]\r\n\t\t\tif (controllers[i]) {\r\n\t\t\t\tvar args = [controllers[i]]\r\n\t\t\t\tm.render(root,\r\n\t\t\t\t\tcomponent.view ? component.view(controllers[i], args) : \"\")\r\n\t\t\t}\r\n\t\t})\r\n\t\t// after rendering within a routed context, we need to scroll back to\r\n\t\t// the top, and fetch the document title for history.pushState\r\n\t\tif (computePostRedrawHook) {\r\n\t\t\tcomputePostRedrawHook()\r\n\t\t\tcomputePostRedrawHook = null\r\n\t\t}\r\n\t\tlastRedrawId = null\r\n\t\tlastRedrawCallTime = new Date()\r\n\t\tm.redraw.strategy(\"diff\")\r\n\t}\r\n\r\n\tfunction endFirstComputation() {\r\n\t\tif (m.redraw.strategy() === \"none\") {\r\n\t\t\tpendingRequests--\r\n\t\t\tm.redraw.strategy(\"diff\")\r\n\t\t} else {\r\n\t\t\tm.endComputation()\r\n\t\t}\r\n\t}\r\n\r\n\tm.withAttr = function (prop, withAttrCallback, callbackThis) {\r\n\t\treturn function (e) {\r\n\t\t\te = e || window.event\r\n\t\t\t/* eslint-disable no-invalid-this */\r\n\t\t\tvar currentTarget = e.currentTarget || this\r\n\t\t\tvar _this = callbackThis || this\r\n\t\t\t/* eslint-enable no-invalid-this */\r\n\t\t\tvar target = prop in currentTarget ?\r\n\t\t\t\tcurrentTarget[prop] :\r\n\t\t\t\tcurrentTarget.getAttribute(prop)\r\n\t\t\twithAttrCallback.call(_this, target)\r\n\t\t}\r\n\t}\r\n\r\n\t// routing\r\n\tvar modes = {pathname: \"\", hash: \"#\", search: \"?\"}\r\n\tvar redirect = noop\r\n\tvar isDefaultRoute = false\r\n\tvar routeParams, currentRoute\r\n\r\n\tm.route = function (root, arg1, arg2, vdom) { // eslint-disable-line\r\n\t\t// m.route()\r\n\t\tif (arguments.length === 0) return currentRoute\r\n\t\t// m.route(el, defaultRoute, routes)\r\n\t\tif (arguments.length === 3 && isString(arg1)) {\r\n\t\t\tredirect = function (source) {\r\n\t\t\t\tvar path = currentRoute = normalizeRoute(source)\r\n\t\t\t\tif (!routeByValue(root, arg2, path)) {\r\n\t\t\t\t\tif (isDefaultRoute) {\r\n\t\t\t\t\t\tthrow new Error(\"Ensure the default route matches \" +\r\n\t\t\t\t\t\t\t\"one of the routes defined in m.route\")\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tisDefaultRoute = true\r\n\t\t\t\t\tm.route(arg1, true)\r\n\t\t\t\t\tisDefaultRoute = false\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvar listener = m.route.mode === \"hash\" ?\r\n\t\t\t\t\"onhashchange\" :\r\n\t\t\t\t\"onpopstate\"\r\n\r\n\t\t\tglobal[listener] = function () {\r\n\t\t\t\tvar path = $location[m.route.mode]\r\n\t\t\t\tif (m.route.mode === \"pathname\") path += $location.search\r\n\t\t\t\tif (currentRoute !== normalizeRoute(path)) redirect(path)\r\n\t\t\t}\r\n\r\n\t\t\tcomputePreRedrawHook = setScroll\r\n\t\t\tglobal[listener]()\r\n\r\n\t\t\treturn\r\n\t\t}\r\n\r\n\t\t// config: m.route\r\n\t\tif (root.addEventListener || root.attachEvent) {\r\n\t\t\tvar base = m.route.mode !== \"pathname\" ? $location.pathname : \"\"\r\n\t\t\troot.href = base + modes[m.route.mode] + vdom.attrs.href\r\n\t\t\tif (root.addEventListener) {\r\n\t\t\t\troot.removeEventListener(\"click\", routeUnobtrusive)\r\n\t\t\t\troot.addEventListener(\"click\", routeUnobtrusive)\r\n\t\t\t} else {\r\n\t\t\t\troot.detachEvent(\"onclick\", routeUnobtrusive)\r\n\t\t\t\troot.attachEvent(\"onclick\", routeUnobtrusive)\r\n\t\t\t}\r\n\r\n\t\t\treturn\r\n\t\t}\r\n\t\t// m.route(route, params, shouldReplaceHistoryEntry)\r\n\t\tif (isString(root)) {\r\n\t\t\tvar oldRoute = currentRoute\r\n\t\t\tcurrentRoute = root\r\n\r\n\t\t\tvar args = arg1 || {}\r\n\t\t\tvar queryIndex = currentRoute.indexOf(\"?\")\r\n\t\t\tvar params\r\n\r\n\t\t\tif (queryIndex > -1) {\r\n\t\t\t\tparams = parseQueryString(currentRoute.slice(queryIndex + 1))\r\n\t\t\t} else {\r\n\t\t\t\tparams = {}\r\n\t\t\t}\r\n\r\n\t\t\tfor (var i in args) {\r\n\t\t\t\tif (hasOwn.call(args, i)) {\r\n\t\t\t\t\tparams[i] = args[i]\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tvar querystring = buildQueryString(params)\r\n\t\t\tvar currentPath\r\n\r\n\t\t\tif (queryIndex > -1) {\r\n\t\t\t\tcurrentPath = currentRoute.slice(0, queryIndex)\r\n\t\t\t} else {\r\n\t\t\t\tcurrentPath = currentRoute\r\n\t\t\t}\r\n\r\n\t\t\tif (querystring) {\r\n\t\t\t\tcurrentRoute = currentPath +\r\n\t\t\t\t\t(currentPath.indexOf(\"?\") === -1 ? \"?\" : \"&\") +\r\n\t\t\t\t\tquerystring\r\n\t\t\t}\r\n\r\n\t\t\tvar replaceHistory =\r\n\t\t\t\t(arguments.length === 3 ? arg2 : arg1) === true ||\r\n\t\t\t\toldRoute === root\r\n\r\n\t\t\tif (global.history.pushState) {\r\n\t\t\t\tvar method = replaceHistory ? \"replaceState\" : \"pushState\"\r\n\t\t\t\tcomputePreRedrawHook = setScroll\r\n\t\t\t\tcomputePostRedrawHook = function () {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tglobal.history[method](null, $document.title,\r\n\t\t\t\t\t\t\tmodes[m.route.mode] + currentRoute)\r\n\t\t\t\t\t} catch (err) {\r\n\t\t\t\t\t\t// In the event of a pushState or replaceState failure,\r\n\t\t\t\t\t\t// fallback to a standard redirect. This is specifically\r\n\t\t\t\t\t\t// to address a Safari security error when attempting to\r\n\t\t\t\t\t\t// call pushState more than 100 times.\r\n\t\t\t\t\t\t$location[m.route.mode] = currentRoute\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tredirect(modes[m.route.mode] + currentRoute)\r\n\t\t\t} else {\r\n\t\t\t\t$location[m.route.mode] = currentRoute\r\n\t\t\t\tredirect(modes[m.route.mode] + currentRoute)\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tm.route.param = function (key) {\r\n\t\tif (!routeParams) {\r\n\t\t\tthrow new Error(\"You must call m.route(element, defaultRoute, \" +\r\n\t\t\t\t\"routes) before calling m.route.param()\")\r\n\t\t}\r\n\r\n\t\tif (!key) {\r\n\t\t\treturn routeParams\r\n\t\t}\r\n\r\n\t\treturn routeParams[key]\r\n\t}\r\n\r\n\tm.route.mode = \"search\"\r\n\r\n\tfunction normalizeRoute(route) {\r\n\t\treturn route.slice(modes[m.route.mode].length)\r\n\t}\r\n\r\n\tfunction routeByValue(root, router, path) {\r\n\t\trouteParams = {}\r\n\r\n\t\tvar queryStart = path.indexOf(\"?\")\r\n\t\tif (queryStart !== -1) {\r\n\t\t\trouteParams = parseQueryString(\r\n\t\t\t\tpath.substr(queryStart + 1, path.length))\r\n\t\t\tpath = path.substr(0, queryStart)\r\n\t\t}\r\n\r\n\t\t// Get all routes and check if there's\r\n\t\t// an exact match for the current path\r\n\t\tvar keys = Object.keys(router)\r\n\t\tvar index = keys.indexOf(path)\r\n\r\n\t\tif (index !== -1){\r\n\t\t\tm.mount(root, router[keys [index]])\r\n\t\t\treturn true\r\n\t\t}\r\n\r\n\t\tfor (var route in router) {\r\n\t\t\tif (hasOwn.call(router, route)) {\r\n\t\t\t\tif (route === path) {\r\n\t\t\t\t\tm.mount(root, router[route])\r\n\t\t\t\t\treturn true\r\n\t\t\t\t}\r\n\r\n\t\t\t\tvar matcher = new RegExp(\"^\" + route\r\n\t\t\t\t\t.replace(/:[^\\/]+?\\.{3}/g, \"(.*?)\")\r\n\t\t\t\t\t.replace(/:[^\\/]+/g, \"([^\\\\/]+)\") + \"\\/?$\")\r\n\r\n\t\t\t\tif (matcher.test(path)) {\r\n\t\t\t\t\t/* eslint-disable no-loop-func */\r\n\t\t\t\t\tpath.replace(matcher, function () {\r\n\t\t\t\t\t\tvar keys = route.match(/:[^\\/]+/g) || []\r\n\t\t\t\t\t\tvar values = [].slice.call(arguments, 1, -2)\r\n\t\t\t\t\t\tforEach(keys, function (key, i) {\r\n\t\t\t\t\t\t\trouteParams[key.replace(/:|\\./g, \"\")] =\r\n\t\t\t\t\t\t\t\tdecodeURIComponent(values[i])\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t\tm.mount(root, router[route])\r\n\t\t\t\t\t})\r\n\t\t\t\t\t/* eslint-enable no-loop-func */\r\n\t\t\t\t\treturn true\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tfunction routeUnobtrusive(e) {\r\n\t\te = e || event\r\n\t\tif (e.ctrlKey || e.metaKey || e.shiftKey || e.which === 2) return\r\n\r\n\t\tif (e.preventDefault) {\r\n\t\t\te.preventDefault()\r\n\t\t} else {\r\n\t\t\te.returnValue = false\r\n\t\t}\r\n\r\n\t\tvar currentTarget = e.currentTarget || e.srcElement\r\n\t\tvar args\r\n\r\n\t\tif (m.route.mode === \"pathname\" && currentTarget.search) {\r\n\t\t\targs = parseQueryString(currentTarget.search.slice(1))\r\n\t\t} else {\r\n\t\t\targs = {}\r\n\t\t}\r\n\r\n\t\twhile (currentTarget && !/a/i.test(currentTarget.nodeName)) {\r\n\t\t\tcurrentTarget = currentTarget.parentNode\r\n\t\t}\r\n\r\n\t\t// clear pendingRequests because we want an immediate route change\r\n\t\tpendingRequests = 0\r\n\t\tm.route(currentTarget[m.route.mode]\r\n\t\t\t.slice(modes[m.route.mode].length), args)\r\n\t}\r\n\r\n\tfunction setScroll() {\r\n\t\tif (m.route.mode !== \"hash\" && $location.hash) {\r\n\t\t\t$location.hash = $location.hash\r\n\t\t} else {\r\n\t\t\tglobal.scrollTo(0, 0)\r\n\t\t}\r\n\t}\r\n\r\n\tfunction buildQueryString(object, prefix) {\r\n\t\tvar duplicates = {}\r\n\t\tvar str = []\r\n\r\n\t\tfor (var prop in object) {\r\n\t\t\tif (hasOwn.call(object, prop)) {\r\n\t\t\t\tvar key = prefix ? prefix + \"[\" + prop + \"]\" : prop\r\n\t\t\t\tvar value = object[prop]\r\n\r\n\t\t\t\tif (value === null) {\r\n\t\t\t\t\tstr.push(encodeURIComponent(key))\r\n\t\t\t\t} else if (isObject(value)) {\r\n\t\t\t\t\tstr.push(buildQueryString(value, key))\r\n\t\t\t\t} else if (isArray(value)) {\r\n\t\t\t\t\tvar keys = []\r\n\t\t\t\t\tduplicates[key] = duplicates[key] || {}\r\n\t\t\t\t\t/* eslint-disable no-loop-func */\r\n\t\t\t\t\tforEach(value, function (item) {\r\n\t\t\t\t\t\t/* eslint-enable no-loop-func */\r\n\t\t\t\t\t\tif (!duplicates[key][item]) {\r\n\t\t\t\t\t\t\tduplicates[key][item] = true\r\n\t\t\t\t\t\t\tkeys.push(encodeURIComponent(key) + \"=\" +\r\n\t\t\t\t\t\t\t\tencodeURIComponent(item))\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t})\r\n\t\t\t\t\tstr.push(keys.join(\"&\"))\r\n\t\t\t\t} else if (value !== undefined) {\r\n\t\t\t\t\tstr.push(encodeURIComponent(key) + \"=\" +\r\n\t\t\t\t\t\tencodeURIComponent(value))\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn str.join(\"&\")\r\n\t}\r\n\r\n\tfunction parseQueryString(str) {\r\n\t\tif (str === \"\" || str == null) return {}\r\n\t\tif (str.charAt(0) === \"?\") str = str.slice(1)\r\n\r\n\t\tvar pairs = str.split(\"&\")\r\n\t\tvar params = {}\r\n\r\n\t\tforEach(pairs, function (string) {\r\n\t\t\tvar pair = string.split(\"=\")\r\n\t\t\tvar key = decodeURIComponent(pair[0])\r\n\t\t\tvar value = pair.length === 2 ? decodeURIComponent(pair[1]) : null\r\n\t\t\tif (params[key] != null) {\r\n\t\t\t\tif (!isArray(params[key])) params[key] = [params[key]]\r\n\t\t\t\tparams[key].push(value)\r\n\t\t\t}\r\n\t\t\telse params[key] = value\r\n\t\t})\r\n\r\n\t\treturn params\r\n\t}\r\n\r\n\tm.route.buildQueryString = buildQueryString\r\n\tm.route.parseQueryString = parseQueryString\r\n\r\n\tfunction reset(root) {\r\n\t\tvar cacheKey = getCellCacheKey(root)\r\n\t\tclear(root.childNodes, cellCache[cacheKey])\r\n\t\tcellCache[cacheKey] = undefined\r\n\t}\r\n\r\n\tm.deferred = function () {\r\n\t\tvar deferred = new Deferred()\r\n\t\tdeferred.promise = propify(deferred.promise)\r\n\t\treturn deferred\r\n\t}\r\n\r\n\tfunction propify(promise, initialValue) {\r\n\t\tvar prop = m.prop(initialValue)\r\n\t\tpromise.then(prop)\r\n\t\tprop.then = function (resolve, reject) {\r\n\t\t\treturn propify(promise.then(resolve, reject), initialValue)\r\n\t\t}\r\n\r\n\t\tprop.catch = prop.then.bind(null, null)\r\n\t\treturn prop\r\n\t}\r\n\t// Promiz.mithril.js | Zolmeister | MIT\r\n\t// a modified version of Promiz.js, which does not conform to Promises/A+\r\n\t// for two reasons:\r\n\t//\r\n\t// 1) `then` callbacks are called synchronously (because setTimeout is too\r\n\t// slow, and the setImmediate polyfill is too big\r\n\t//\r\n\t// 2) throwing subclasses of Error cause the error to be bubbled up instead\r\n\t// of triggering rejection (because the spec does not account for the\r\n\t// important use case of default browser error handling, i.e. message w/\r\n\t// line number)\r\n\r\n\tvar RESOLVING = 1\r\n\tvar REJECTING = 2\r\n\tvar RESOLVED = 3\r\n\tvar REJECTED = 4\r\n\r\n\tfunction Deferred(onSuccess, onFailure) {\r\n\t\tvar self = this\r\n\t\tvar state = 0\r\n\t\tvar promiseValue = 0\r\n\t\tvar next = []\r\n\r\n\t\tself.promise = {}\r\n\r\n\t\tself.resolve = function (value) {\r\n\t\t\tif (!state) {\r\n\t\t\t\tpromiseValue = value\r\n\t\t\t\tstate = RESOLVING\r\n\r\n\t\t\t\tfire()\r\n\t\t\t}\r\n\r\n\t\t\treturn self\r\n\t\t}\r\n\r\n\t\tself.reject = function (value) {\r\n\t\t\tif (!state) {\r\n\t\t\t\tpromiseValue = value\r\n\t\t\t\tstate = REJECTING\r\n\r\n\t\t\t\tfire()\r\n\t\t\t}\r\n\r\n\t\t\treturn self\r\n\t\t}\r\n\r\n\t\tself.promise.then = function (onSuccess, onFailure) {\r\n\t\t\tvar deferred = new Deferred(onSuccess, onFailure)\r\n\r\n\t\t\tif (state === RESOLVED) {\r\n\t\t\t\tdeferred.resolve(promiseValue)\r\n\t\t\t} else if (state === REJECTED) {\r\n\t\t\t\tdeferred.reject(promiseValue)\r\n\t\t\t} else {\r\n\t\t\t\tnext.push(deferred)\r\n\t\t\t}\r\n\r\n\t\t\treturn deferred.promise\r\n\t\t}\r\n\r\n\t\tfunction finish(type) {\r\n\t\t\tstate = type || REJECTED\r\n\t\t\tnext.map(function (deferred) {\r\n\t\t\t\tif (state === RESOLVED) {\r\n\t\t\t\t\tdeferred.resolve(promiseValue)\r\n\t\t\t\t} else {\r\n\t\t\t\t\tdeferred.reject(promiseValue)\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\r\n\t\tfunction thennable(then, success, failure, notThennable) {\r\n\t\t\tif (((promiseValue != null && isObject(promiseValue)) ||\r\n\t\t\t\t\tisFunction(promiseValue)) && isFunction(then)) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\t// count protects against abuse calls from spec checker\r\n\t\t\t\t\tvar count = 0\r\n\t\t\t\t\tthen.call(promiseValue, function (value) {\r\n\t\t\t\t\t\tif (count++) return\r\n\t\t\t\t\t\tpromiseValue = value\r\n\t\t\t\t\t\tsuccess()\r\n\t\t\t\t\t}, function (value) {\r\n\t\t\t\t\t\tif (count++) return\r\n\t\t\t\t\t\tpromiseValue = value\r\n\t\t\t\t\t\tfailure()\r\n\t\t\t\t\t})\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\tm.deferred.onerror(e)\r\n\t\t\t\t\tpromiseValue = e\r\n\t\t\t\t\tfailure()\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tnotThennable()\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tfunction fire() {\r\n\t\t\t// check if it's a thenable\r\n\t\t\tvar then\r\n\t\t\ttry {\r\n\t\t\t\tthen = promiseValue && promiseValue.then\r\n\t\t\t} catch (e) {\r\n\t\t\t\tm.deferred.onerror(e)\r\n\t\t\t\tpromiseValue = e\r\n\t\t\t\tstate = REJECTING\r\n\t\t\t\treturn fire()\r\n\t\t\t}\r\n\r\n\t\t\tif (state === REJECTING) {\r\n\t\t\t\tm.deferred.onerror(promiseValue)\r\n\t\t\t}\r\n\r\n\t\t\tthennable(then, function () {\r\n\t\t\t\tstate = RESOLVING\r\n\t\t\t\tfire()\r\n\t\t\t}, function () {\r\n\t\t\t\tstate = REJECTING\r\n\t\t\t\tfire()\r\n\t\t\t}, function () {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tif (state === RESOLVING && isFunction(onSuccess)) {\r\n\t\t\t\t\t\tpromiseValue = onSuccess(promiseValue)\r\n\t\t\t\t\t} else if (state === REJECTING && isFunction(onFailure)) {\r\n\t\t\t\t\t\tpromiseValue = onFailure(promiseValue)\r\n\t\t\t\t\t\tstate = RESOLVING\r\n\t\t\t\t\t}\r\n\t\t\t\t} catch (e) {\r\n\t\t\t\t\tm.deferred.onerror(e)\r\n\t\t\t\t\tpromiseValue = e\r\n\t\t\t\t\treturn finish()\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (promiseValue === self) {\r\n\t\t\t\t\tpromiseValue = TypeError()\r\n\t\t\t\t\tfinish()\r\n\t\t\t\t} else {\r\n\t\t\t\t\tthennable(then, function () {\r\n\t\t\t\t\t\tfinish(RESOLVED)\r\n\t\t\t\t\t}, finish, function () {\r\n\t\t\t\t\t\tfinish(state === RESOLVING && RESOLVED)\r\n\t\t\t\t\t})\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t}\r\n\t}\r\n\r\n\tm.deferred.onerror = function (e) {\r\n\t\tif (type.call(e) === \"[object Error]\" &&\r\n\t\t\t\t!/ Error/.test(e.constructor.toString())) {\r\n\t\t\tpendingRequests = 0\r\n\t\t\tthrow e\r\n\t\t}\r\n\t}\r\n\r\n\tm.sync = function (args) {\r\n\t\tvar deferred = m.deferred()\r\n\t\tvar outstanding = args.length\r\n\t\tvar results = []\r\n\t\tvar method = \"resolve\"\r\n\r\n\t\tfunction synchronizer(pos, resolved) {\r\n\t\t\treturn function (value) {\r\n\t\t\t\tresults[pos] = value\r\n\t\t\t\tif (!resolved) method = \"reject\"\r\n\t\t\t\tif (--outstanding === 0) {\r\n\t\t\t\t\tdeferred.promise(results)\r\n\t\t\t\t\tdeferred[method](results)\r\n\t\t\t\t}\r\n\t\t\t\treturn value\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (args.length > 0) {\r\n\t\t\tforEach(args, function (arg, i) {\r\n\t\t\t\targ.then(synchronizer(i, true), synchronizer(i, false))\r\n\t\t\t})\r\n\t\t} else {\r\n\t\t\tdeferred.resolve([])\r\n\t\t}\r\n\r\n\t\treturn deferred.promise\r\n\t}\r\n\r\n\tfunction identity(value) { return value }\r\n\r\n\tfunction handleJsonp(options) {\r\n\t\tvar callbackKey = options.callbackName || \"mithril_callback_\" +\r\n\t\t\tnew Date().getTime() + \"_\" +\r\n\t\t\t(Math.round(Math.random() * 1e16)).toString(36)\r\n\r\n\t\tvar script = $document.createElement(\"script\")\r\n\r\n\t\tglobal[callbackKey] = function (resp) {\r\n\t\t\tscript.parentNode.removeChild(script)\r\n\t\t\toptions.onload({\r\n\t\t\t\ttype: \"load\",\r\n\t\t\t\ttarget: {\r\n\t\t\t\t\tresponseText: resp\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\tglobal[callbackKey] = undefined\r\n\t\t}\r\n\r\n\t\tscript.onerror = function () {\r\n\t\t\tscript.parentNode.removeChild(script)\r\n\r\n\t\t\toptions.onerror({\r\n\t\t\t\ttype: \"error\",\r\n\t\t\t\ttarget: {\r\n\t\t\t\t\tstatus: 500,\r\n\t\t\t\t\tresponseText: JSON.stringify({\r\n\t\t\t\t\t\terror: \"Error making jsonp request\"\r\n\t\t\t\t\t})\r\n\t\t\t\t}\r\n\t\t\t})\r\n\t\t\tglobal[callbackKey] = undefined\r\n\r\n\t\t\treturn false\r\n\t\t}\r\n\r\n\t\tscript.onload = function () {\r\n\t\t\treturn false\r\n\t\t}\r\n\r\n\t\tscript.src = options.url +\r\n\t\t\t(options.url.indexOf(\"?\") > 0 ? \"&\" : \"?\") +\r\n\t\t\t(options.callbackKey ? options.callbackKey : \"callback\") +\r\n\t\t\t\"=\" + callbackKey +\r\n\t\t\t\"&\" + buildQueryString(options.data || {})\r\n\r\n\t\t$document.body.appendChild(script)\r\n\t}\r\n\r\n\tfunction createXhr(options) {\r\n\t\tvar xhr = new global.XMLHttpRequest()\r\n\t\txhr.open(options.method, options.url, true, options.user,\r\n\t\t\toptions.password)\r\n\r\n\t\txhr.onreadystatechange = function () {\r\n\t\t\tif (xhr.readyState === 4) {\r\n\t\t\t\tif (xhr.status >= 200 && xhr.status < 300) {\r\n\t\t\t\t\toptions.onload({type: \"load\", target: xhr})\r\n\t\t\t\t} else {\r\n\t\t\t\t\toptions.onerror({type: \"error\", target: xhr})\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (options.serialize === JSON.stringify &&\r\n\t\t\t\toptions.data &&\r\n\t\t\t\toptions.method !== \"GET\") {\r\n\t\t\txhr.setRequestHeader(\"Content-Type\",\r\n\t\t\t\t\"application/json; charset=utf-8\")\r\n\t\t}\r\n\r\n\t\tif (options.deserialize === JSON.parse) {\r\n\t\t\txhr.setRequestHeader(\"Accept\", \"application/json, text/*\")\r\n\t\t}\r\n\r\n\t\tif (isFunction(options.config)) {\r\n\t\t\tvar maybeXhr = options.config(xhr, options)\r\n\t\t\tif (maybeXhr != null) xhr = maybeXhr\r\n\t\t}\r\n\r\n\t\tvar data = options.method === \"GET\" || !options.data ? \"\" : options.data\r\n\r\n\t\tif (data && !isString(data) && data.constructor !== global.FormData) {\r\n\t\t\tthrow new Error(\"Request data should be either be a string or \" +\r\n\t\t\t\t\"FormData. Check the `serialize` option in `m.request`\")\r\n\t\t}\r\n\r\n\t\txhr.send(data)\r\n\t\treturn xhr\r\n\t}\r\n\r\n\tfunction ajax(options) {\r\n\t\tif (options.dataType && options.dataType.toLowerCase() === \"jsonp\") {\r\n\t\t\treturn handleJsonp(options)\r\n\t\t} else {\r\n\t\t\treturn createXhr(options)\r\n\t\t}\r\n\t}\r\n\r\n\tfunction bindData(options, data, serialize) {\r\n\t\tif (options.method === \"GET\" && options.dataType !== \"jsonp\") {\r\n\t\t\tvar prefix = options.url.indexOf(\"?\") < 0 ? \"?\" : \"&\"\r\n\t\t\tvar querystring = buildQueryString(data)\r\n\t\t\toptions.url += (querystring ? prefix + querystring : \"\")\r\n\t\t} else {\r\n\t\t\toptions.data = serialize(data)\r\n\t\t}\r\n\t}\r\n\r\n\tfunction parameterizeUrl(url, data) {\r\n\t\tif (data) {\r\n\t\t\turl = url.replace(/:[a-z]\\w+/gi, function (token){\r\n\t\t\t\tvar key = token.slice(1)\r\n\t\t\t\tvar value = data[key] || token\r\n\t\t\t\tdelete data[key]\r\n\t\t\t\treturn value\r\n\t\t\t})\r\n\t\t}\r\n\t\treturn url\r\n\t}\r\n\r\n\tm.request = function (options) {\r\n\t\tif (options.background !== true) m.startComputation()\r\n\t\tvar deferred = new Deferred()\r\n\t\tvar isJSONP = options.dataType &&\r\n\t\t\toptions.dataType.toLowerCase() === \"jsonp\"\r\n\r\n\t\tvar serialize, deserialize, extract\r\n\r\n\t\tif (isJSONP) {\r\n\t\t\tserialize = options.serialize =\r\n\t\t\tdeserialize = options.deserialize = identity\r\n\r\n\t\t\textract = function (jsonp) { return jsonp.responseText }\r\n\t\t} else {\r\n\t\t\tserialize = options.serialize = options.serialize || JSON.stringify\r\n\r\n\t\t\tdeserialize = options.deserialize =\r\n\t\t\t\toptions.deserialize || JSON.parse\r\n\t\t\textract = options.extract || function (xhr) {\r\n\t\t\t\tif (xhr.responseText.length || deserialize !== JSON.parse) {\r\n\t\t\t\t\treturn xhr.responseText\r\n\t\t\t\t} else {\r\n\t\t\t\t\treturn null\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\toptions.method = (options.method || \"GET\").toUpperCase()\r\n\t\toptions.url = parameterizeUrl(options.url, options.data)\r\n\t\tbindData(options, options.data, serialize)\r\n\t\toptions.onload = options.onerror = function (ev) {\r\n\t\t\ttry {\r\n\t\t\t\tev = ev || event\r\n\t\t\t\tvar response = deserialize(extract(ev.target, options))\r\n\t\t\t\tif (ev.type === \"load\") {\r\n\t\t\t\t\tif (options.unwrapSuccess) {\r\n\t\t\t\t\t\tresponse = options.unwrapSuccess(response, ev.target)\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tif (isArray(response) && options.type) {\r\n\t\t\t\t\t\tforEach(response, function (res, i) {\r\n\t\t\t\t\t\t\tresponse[i] = new options.type(res)\r\n\t\t\t\t\t\t})\r\n\t\t\t\t\t} else if (options.type) {\r\n\t\t\t\t\t\tresponse = new options.type(response)\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tdeferred.resolve(response)\r\n\t\t\t\t} else {\r\n\t\t\t\t\tif (options.unwrapError) {\r\n\t\t\t\t\t\tresponse = options.unwrapError(response, ev.target)\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tdeferred.reject(response)\r\n\t\t\t\t}\r\n\t\t\t} catch (e) {\r\n\t\t\t\tdeferred.reject(e)\r\n\t\t\t\tm.deferred.onerror(e)\r\n\t\t\t} finally {\r\n\t\t\t\tif (options.background !== true) m.endComputation()\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tajax(options)\r\n\t\tdeferred.promise = propify(deferred.promise, options.initialValue)\r\n\t\treturn deferred.promise\r\n\t}\r\n\r\n\treturn m\r\n}); // eslint-disable-line\r\n\n},{}],8:[function(require,module,exports){\n/*!\n * EventEmitter v4.2.11 - git.io/ee\n * Unlicense - http://unlicense.org/\n * Oliver Caldwell - http://oli.me.uk/\n * @preserve\n */\n\n;(function () {\n 'use strict';\n\n /**\n * Class for managing events.\n * Can be extended to provide event functionality in other classes.\n *\n * @class EventEmitter Manages event registering and emitting.\n */\n function EventEmitter() {}\n\n // Shortcuts to improve speed and size\n var proto = EventEmitter.prototype;\n var exports = this;\n var originalGlobalValue = exports.EventEmitter;\n\n /**\n * Finds the index of the listener for the event in its storage array.\n *\n * @param {Function[]} listeners Array of listeners to search through.\n * @param {Function} listener Method to look for.\n * @return {Number} Index of the specified listener, -1 if not found\n * @api private\n */\n function indexOfListener(listeners, listener) {\n var i = listeners.length;\n while (i--) {\n if (listeners[i].listener === listener) {\n return i;\n }\n }\n\n return -1;\n }\n\n /**\n * Alias a method while keeping the context correct, to allow for overwriting of target method.\n *\n * @param {String} name The name of the target method.\n * @return {Function} The aliased method\n * @api private\n */\n function alias(name) {\n return function aliasClosure() {\n return this[name].apply(this, arguments);\n };\n }\n\n /**\n * Returns the listener array for the specified event.\n * Will initialise the event object and listener arrays if required.\n * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.\n * Each property in the object response is an array of listener functions.\n *\n * @param {String|RegExp} evt Name of the event to return the listeners from.\n * @return {Function[]|Object} All listener functions for the event.\n */\n proto.getListeners = function getListeners(evt) {\n var events = this._getEvents();\n var response;\n var key;\n\n // Return a concatenated array of all matching events if\n // the selector is a regular expression.\n if (evt instanceof RegExp) {\n response = {};\n for (key in events) {\n if (events.hasOwnProperty(key) && evt.test(key)) {\n response[key] = events[key];\n }\n }\n }\n else {\n response = events[evt] || (events[evt] = []);\n }\n\n return response;\n };\n\n /**\n * Takes a list of listener objects and flattens it into a list of listener functions.\n *\n * @param {Object[]} listeners Raw listener objects.\n * @return {Function[]} Just the listener functions.\n */\n proto.flattenListeners = function flattenListeners(listeners) {\n var flatListeners = [];\n var i;\n\n for (i = 0; i < listeners.length; i += 1) {\n flatListeners.push(listeners[i].listener);\n }\n\n return flatListeners;\n };\n\n /**\n * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.\n *\n * @param {String|RegExp} evt Name of the event to return the listeners from.\n * @return {Object} All listener functions for an event in an object.\n */\n proto.getListenersAsObject = function getListenersAsObject(evt) {\n var listeners = this.getListeners(evt);\n var response;\n\n if (listeners instanceof Array) {\n response = {};\n response[evt] = listeners;\n }\n\n return response || listeners;\n };\n\n /**\n * Adds a listener function to the specified event.\n * The listener will not be added if it is a duplicate.\n * If the listener returns true then it will be removed after it is called.\n * If you pass a regular expression as the event name then the listener will be added to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to attach the listener to.\n * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.addListener = function addListener(evt, listener) {\n var listeners = this.getListenersAsObject(evt);\n var listenerIsWrapped = typeof listener === 'object';\n var key;\n\n for (key in listeners) {\n if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {\n listeners[key].push(listenerIsWrapped ? listener : {\n listener: listener,\n once: false\n });\n }\n }\n\n return this;\n };\n\n /**\n * Alias of addListener\n */\n proto.on = alias('addListener');\n\n /**\n * Semi-alias of addListener. It will add a listener that will be\n * automatically removed after its first execution.\n *\n * @param {String|RegExp} evt Name of the event to attach the listener to.\n * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.addOnceListener = function addOnceListener(evt, listener) {\n return this.addListener(evt, {\n listener: listener,\n once: true\n });\n };\n\n /**\n * Alias of addOnceListener.\n */\n proto.once = alias('addOnceListener');\n\n /**\n * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.\n * You need to tell it what event names should be matched by a regex.\n *\n * @param {String} evt Name of the event to create.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.defineEvent = function defineEvent(evt) {\n this.getListeners(evt);\n return this;\n };\n\n /**\n * Uses defineEvent to define multiple events.\n *\n * @param {String[]} evts An array of event names to define.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.defineEvents = function defineEvents(evts) {\n for (var i = 0; i < evts.length; i += 1) {\n this.defineEvent(evts[i]);\n }\n return this;\n };\n\n /**\n * Removes a listener function from the specified event.\n * When passed a regular expression as the event name, it will remove the listener from all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to remove the listener from.\n * @param {Function} listener Method to remove from the event.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.removeListener = function removeListener(evt, listener) {\n var listeners = this.getListenersAsObject(evt);\n var index;\n var key;\n\n for (key in listeners) {\n if (listeners.hasOwnProperty(key)) {\n index = indexOfListener(listeners[key], listener);\n\n if (index !== -1) {\n listeners[key].splice(index, 1);\n }\n }\n }\n\n return this;\n };\n\n /**\n * Alias of removeListener\n */\n proto.off = alias('removeListener');\n\n /**\n * Adds listeners in bulk using the manipulateListeners method.\n * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.\n * You can also pass it a regular expression to add the array of listeners to all events that match it.\n * Yeah, this function does quite a bit. That's probably a bad thing.\n *\n * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.\n * @param {Function[]} [listeners] An optional array of listener functions to add.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.addListeners = function addListeners(evt, listeners) {\n // Pass through to manipulateListeners\n return this.manipulateListeners(false, evt, listeners);\n };\n\n /**\n * Removes listeners in bulk using the manipulateListeners method.\n * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.\n * You can also pass it an event name and an array of listeners to be removed.\n * You can also pass it a regular expression to remove the listeners from all events that match it.\n *\n * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.\n * @param {Function[]} [listeners] An optional array of listener functions to remove.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.removeListeners = function removeListeners(evt, listeners) {\n // Pass through to manipulateListeners\n return this.manipulateListeners(true, evt, listeners);\n };\n\n /**\n * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.\n * The first argument will determine if the listeners are removed (true) or added (false).\n * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.\n * You can also pass it an event name and an array of listeners to be added/removed.\n * You can also pass it a regular expression to manipulate the listeners of all events that match it.\n *\n * @param {Boolean} remove True if you want to remove listeners, false if you want to add.\n * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.\n * @param {Function[]} [listeners] An optional array of listener functions to add/remove.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {\n var i;\n var value;\n var single = remove ? this.removeListener : this.addListener;\n var multiple = remove ? this.removeListeners : this.addListeners;\n\n // If evt is an object then pass each of its properties to this method\n if (typeof evt === 'object' && !(evt instanceof RegExp)) {\n for (i in evt) {\n if (evt.hasOwnProperty(i) && (value = evt[i])) {\n // Pass the single listener straight through to the singular method\n if (typeof value === 'function') {\n single.call(this, i, value);\n }\n else {\n // Otherwise pass back to the multiple function\n multiple.call(this, i, value);\n }\n }\n }\n }\n else {\n // So evt must be a string\n // And listeners must be an array of listeners\n // Loop over it and pass each one to the multiple method\n i = listeners.length;\n while (i--) {\n single.call(this, evt, listeners[i]);\n }\n }\n\n return this;\n };\n\n /**\n * Removes all listeners from a specified event.\n * If you do not specify an event then all listeners will be removed.\n * That means every event will be emptied.\n * You can also pass a regex to remove all events that match it.\n *\n * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.removeEvent = function removeEvent(evt) {\n var type = typeof evt;\n var events = this._getEvents();\n var key;\n\n // Remove different things depending on the state of evt\n if (type === 'string') {\n // Remove all listeners for the specified event\n delete events[evt];\n }\n else if (evt instanceof RegExp) {\n // Remove all events matching the regex.\n for (key in events) {\n if (events.hasOwnProperty(key) && evt.test(key)) {\n delete events[key];\n }\n }\n }\n else {\n // Remove all listeners in all events\n delete this._events;\n }\n\n return this;\n };\n\n /**\n * Alias of removeEvent.\n *\n * Added to mirror the node API.\n */\n proto.removeAllListeners = alias('removeEvent');\n\n /**\n * Emits an event of your choice.\n * When emitted, every listener attached to that event will be executed.\n * If you pass the optional argument array then those arguments will be passed to every listener upon execution.\n * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.\n * So they will not arrive within the array on the other side, they will be separate.\n * You can also pass a regular expression to emit to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to emit and execute listeners for.\n * @param {Array} [args] Optional array of arguments to be passed to each listener.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.emitEvent = function emitEvent(evt, args) {\n var listenersMap = this.getListenersAsObject(evt);\n var listeners;\n var listener;\n var i;\n var key;\n var response;\n\n for (key in listenersMap) {\n if (listenersMap.hasOwnProperty(key)) {\n listeners = listenersMap[key].slice(0);\n i = listeners.length;\n\n while (i--) {\n // If the listener returns true then it shall be removed from the event\n // The function is executed either with a basic call or an apply if there is an args array\n listener = listeners[i];\n\n if (listener.once === true) {\n this.removeListener(evt, listener.listener);\n }\n\n response = listener.listener.apply(this, args || []);\n\n if (response === this._getOnceReturnValue()) {\n this.removeListener(evt, listener.listener);\n }\n }\n }\n }\n\n return this;\n };\n\n /**\n * Alias of emitEvent\n */\n proto.trigger = alias('emitEvent');\n\n /**\n * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.\n * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to emit and execute listeners for.\n * @param {...*} Optional additional arguments to be passed to each listener.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.emit = function emit(evt) {\n var args = Array.prototype.slice.call(arguments, 1);\n return this.emitEvent(evt, args);\n };\n\n /**\n * Sets the current value to check against when executing listeners. If a\n * listeners return value matches the one set here then it will be removed\n * after execution. This value defaults to true.\n *\n * @param {*} value The new value to check for when executing listeners.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n proto.setOnceReturnValue = function setOnceReturnValue(value) {\n this._onceReturnValue = value;\n return this;\n };\n\n /**\n * Fetches the current value to check against when executing listeners. If\n * the listeners return value matches this one then it should be removed\n * automatically. It will return true by default.\n *\n * @return {*|Boolean} The current value to check for or the default, true.\n * @api private\n */\n proto._getOnceReturnValue = function _getOnceReturnValue() {\n if (this.hasOwnProperty('_onceReturnValue')) {\n return this._onceReturnValue;\n }\n else {\n return true;\n }\n };\n\n /**\n * Fetches the events object and creates one if required.\n *\n * @return {Object} The events storage object.\n * @api private\n */\n proto._getEvents = function _getEvents() {\n return this._events || (this._events = {});\n };\n\n /**\n * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.\n *\n * @return {Function} Non conflicting EventEmitter class.\n */\n EventEmitter.noConflict = function noConflict() {\n exports.EventEmitter = originalGlobalValue;\n return EventEmitter;\n };\n\n // Expose the class either via AMD, CommonJS or the global object\n if (typeof define === 'function' && define.amd) {\n define(function () {\n return EventEmitter;\n });\n }\n else if (typeof module === 'object' && module.exports){\n module.exports = EventEmitter;\n }\n else {\n exports.EventEmitter = EventEmitter;\n }\n}.call(this));\n\n},{}]},{},[1]);\n })();"]}
assets/js/forms-admin.js CHANGED
@@ -2515,8 +2515,8 @@ module.exports = render;
2515
  function Iter(cm, line, ch, range) {
2516
  this.line = line; this.ch = ch;
2517
  this.cm = cm; this.text = cm.getLine(line);
2518
- this.min = range ? range.from : cm.firstLine();
2519
- this.max = range ? range.to - 1 : cm.lastLine();
2520
  }
2521
 
2522
  function tagAt(iter, ch) {
@@ -2685,8959 +2685,9092 @@ module.exports = render;
2685
  // You can find some technical background for some of the code below
2686
  // at http://marijnhaverbeke.nl/blog/#cm-internals .
2687
 
2688
- (function(mod) {
2689
- if (typeof exports == "object" && typeof module == "object") // CommonJS
2690
- module.exports = mod();
2691
- else if (typeof define == "function" && define.amd) // AMD
2692
- return define([], mod);
2693
- else // Plain browser env
2694
- (this || window).CodeMirror = mod();
2695
- })(function() {
2696
- "use strict";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2697
 
2698
- // BROWSER SNIFFING
2699
-
2700
- // Kludges for bugs and behavior differences that can't be feature
2701
- // detected are enabled based on userAgent etc sniffing.
2702
- var userAgent = navigator.userAgent;
2703
- var platform = navigator.platform;
2704
-
2705
- var gecko = /gecko\/\d/i.test(userAgent);
2706
- var ie_upto10 = /MSIE \d/.test(userAgent);
2707
- var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
2708
- var ie = ie_upto10 || ie_11up;
2709
- var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
2710
- var webkit = /WebKit\//.test(userAgent);
2711
- var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
2712
- var chrome = /Chrome\//.test(userAgent);
2713
- var presto = /Opera\//.test(userAgent);
2714
- var safari = /Apple Computer/.test(navigator.vendor);
2715
- var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
2716
- var phantom = /PhantomJS/.test(userAgent);
2717
-
2718
- var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
2719
- // This is woefully incomplete. Suggestions for alternative methods welcome.
2720
- var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
2721
- var mac = ios || /Mac/.test(platform);
2722
- var chromeOS = /\bCrOS\b/.test(userAgent);
2723
- var windows = /win/i.test(platform);
2724
-
2725
- var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
2726
- if (presto_version) presto_version = Number(presto_version[1]);
2727
- if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
2728
- // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
2729
- var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
2730
- var captureRightClick = gecko || (ie && ie_version >= 9);
2731
-
2732
- // Optimize some code when these features are not used.
2733
- var sawReadOnlySpans = false, sawCollapsedSpans = false;
2734
-
2735
- // EDITOR CONSTRUCTOR
2736
-
2737
- // A CodeMirror instance represents an editor. This is the object
2738
- // that user code is usually dealing with.
2739
-
2740
- function CodeMirror(place, options) {
2741
- if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
2742
-
2743
- this.options = options = options ? copyObj(options) : {};
2744
- // Determine effective options based on given values and defaults.
2745
- copyObj(defaults, options, false);
2746
- setGuttersForLineNumbers(options);
2747
-
2748
- var doc = options.value;
2749
- if (typeof doc == "string") doc = new Doc(doc, options.mode, null, options.lineSeparator);
2750
- this.doc = doc;
2751
-
2752
- var input = new CodeMirror.inputStyles[options.inputStyle](this);
2753
- var display = this.display = new Display(place, doc, input);
2754
- display.wrapper.CodeMirror = this;
2755
- updateGutters(this);
2756
- themeChanged(this);
2757
- if (options.lineWrapping)
2758
- this.display.wrapper.className += " CodeMirror-wrap";
2759
- if (options.autofocus && !mobile) display.input.focus();
2760
- initScrollbars(this);
2761
-
2762
- this.state = {
2763
- keyMaps: [], // stores maps added by addKeyMap
2764
- overlays: [], // highlighting overlays, as added by addOverlay
2765
- modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
2766
- overwrite: false,
2767
- delayingBlurEvent: false,
2768
- focused: false,
2769
- suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
2770
- pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
2771
- selectingText: false,
2772
- draggingText: false,
2773
- highlight: new Delayed(), // stores highlight worker timeout
2774
- keySeq: null, // Unfinished key sequence
2775
- specialChars: null
2776
- };
2777
 
2778
- var cm = this;
 
 
2779
 
2780
- // Override magic textarea content restore that IE sometimes does
2781
- // on our hidden textarea on reload
2782
- if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20);
 
 
 
 
 
2783
 
2784
- registerEventHandlers(this);
2785
- ensureGlobalHandlers();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2786
 
2787
- startOperation(this);
2788
- this.curOp.forceUpdate = true;
2789
- attachDoc(this, doc);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2790
 
2791
- if ((options.autofocus && !mobile) || cm.hasFocus())
2792
- setTimeout(bind(onFocus, this), 20);
2793
- else
2794
- onBlur(this);
2795
-
2796
- for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
2797
- optionHandlers[opt](this, options[opt], Init);
2798
- maybeUpdateLineNumberWidth(this);
2799
- if (options.finishInit) options.finishInit(this);
2800
- for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);
2801
- endOperation(this);
2802
- // Suppress optimizelegibility in Webkit, since it breaks text
2803
- // measuring on line wrapping boundaries.
2804
- if (webkit && options.lineWrapping &&
2805
- getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
2806
- display.lineDiv.style.textRendering = "auto";
2807
- }
2808
-
2809
- // DISPLAY CONSTRUCTOR
2810
-
2811
- // The display handles the DOM integration, both for input reading
2812
- // and content drawing. It holds references to DOM nodes and
2813
- // display-related state.
2814
-
2815
- function Display(place, doc, input) {
2816
- var d = this;
2817
- this.input = input;
2818
-
2819
- // Covers bottom-right square when both scrollbars are present.
2820
- d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
2821
- d.scrollbarFiller.setAttribute("cm-not-content", "true");
2822
- // Covers bottom of gutter when coverGutterNextToScrollbar is on
2823
- // and h scrollbar is present.
2824
- d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
2825
- d.gutterFiller.setAttribute("cm-not-content", "true");
2826
- // Will contain the actual code, positioned to cover the viewport.
2827
- d.lineDiv = elt("div", null, "CodeMirror-code");
2828
- // Elements are added to these to represent selection and cursors.
2829
- d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
2830
- d.cursorDiv = elt("div", null, "CodeMirror-cursors");
2831
- // A visibility: hidden element used to find the size of things.
2832
- d.measure = elt("div", null, "CodeMirror-measure");
2833
- // When lines outside of the viewport are measured, they are drawn in this.
2834
- d.lineMeasure = elt("div", null, "CodeMirror-measure");
2835
- // Wraps everything that needs to exist inside the vertically-padded coordinate system
2836
- d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
2837
- null, "position: relative; outline: none");
2838
- // Moved around its parent to cover visible view.
2839
- d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
2840
- // Set to the height of the document, allowing scrolling.
2841
- d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
2842
- d.sizerWidth = null;
2843
- // Behavior of elts with overflow: auto and padding is
2844
- // inconsistent across browsers. This is used to ensure the
2845
- // scrollable area is big enough.
2846
- d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
2847
- // Will contain the gutters, if any.
2848
- d.gutters = elt("div", null, "CodeMirror-gutters");
2849
- d.lineGutter = null;
2850
- // Actual scrollable element.
2851
- d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
2852
- d.scroller.setAttribute("tabIndex", "-1");
2853
- // The element in which the editor lives.
2854
- d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
2855
-
2856
- // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
2857
- if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
2858
- if (!webkit && !(gecko && mobile)) d.scroller.draggable = true;
2859
-
2860
- if (place) {
2861
- if (place.appendChild) place.appendChild(d.wrapper);
2862
- else place(d.wrapper);
2863
- }
2864
-
2865
- // Current rendered range (may be bigger than the view window).
2866
- d.viewFrom = d.viewTo = doc.first;
2867
- d.reportedViewFrom = d.reportedViewTo = doc.first;
2868
- // Information about the rendered lines.
2869
- d.view = [];
2870
- d.renderedView = null;
2871
- // Holds info about a single rendered line when it was rendered
2872
- // for measurement, while not in view.
2873
- d.externalMeasured = null;
2874
- // Empty space (in pixels) above the view
2875
- d.viewOffset = 0;
2876
- d.lastWrapHeight = d.lastWrapWidth = 0;
2877
- d.updateLineNumbers = null;
2878
-
2879
- d.nativeBarWidth = d.barHeight = d.barWidth = 0;
2880
- d.scrollbarsClipped = false;
2881
-
2882
- // Used to only resize the line number gutter when necessary (when
2883
- // the amount of lines crosses a boundary that makes its width change)
2884
- d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
2885
- // Set to true when a non-horizontal-scrolling line widget is
2886
- // added. As an optimization, line widget aligning is skipped when
2887
- // this is false.
2888
- d.alignWidgets = false;
2889
-
2890
- d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
2891
-
2892
- // Tracks the maximum line length so that the horizontal scrollbar
2893
- // can be kept static when scrolling.
2894
- d.maxLine = null;
2895
- d.maxLineLength = 0;
2896
- d.maxLineChanged = false;
2897
-
2898
- // Used for measuring wheel scrolling granularity
2899
- d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
2900
-
2901
- // True when shift is held down.
2902
- d.shift = false;
2903
-
2904
- // Used to track whether anything happened since the context menu
2905
- // was opened.
2906
- d.selForContextMenu = null;
2907
-
2908
- d.activeTouch = null;
2909
-
2910
- input.init(d);
2911
- }
2912
-
2913
- // STATE UPDATES
2914
-
2915
- // Used to get the editor into a consistent state again when options change.
2916
-
2917
- function loadMode(cm) {
2918
- cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
2919
- resetModeState(cm);
2920
- }
2921
-
2922
- function resetModeState(cm) {
2923
- cm.doc.iter(function(line) {
2924
- if (line.stateAfter) line.stateAfter = null;
2925
- if (line.styles) line.styles = null;
2926
- });
2927
- cm.doc.frontier = cm.doc.first;
2928
- startWorker(cm, 100);
2929
- cm.state.modeGen++;
2930
- if (cm.curOp) regChange(cm);
2931
- }
2932
 
2933
- function wrappingChanged(cm) {
2934
- if (cm.options.lineWrapping) {
2935
- addClass(cm.display.wrapper, "CodeMirror-wrap");
2936
- cm.display.sizer.style.minWidth = "";
2937
- cm.display.sizerWidth = null;
2938
- } else {
2939
- rmClass(cm.display.wrapper, "CodeMirror-wrap");
2940
- findMaxLine(cm);
2941
- }
2942
- estimateLineHeights(cm);
2943
- regChange(cm);
2944
- clearCaches(cm);
2945
- setTimeout(function(){updateScrollbars(cm);}, 100);
2946
- }
2947
-
2948
- // Returns a function that estimates the height of a line, to use as
2949
- // first approximation until the line becomes visible (and is thus
2950
- // properly measurable).
2951
- function estimateHeight(cm) {
2952
- var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
2953
- var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
2954
- return function(line) {
2955
- if (lineIsHidden(cm.doc, line)) return 0;
2956
-
2957
- var widgetsHeight = 0;
2958
- if (line.widgets) for (var i = 0; i < line.widgets.length; i++) {
2959
- if (line.widgets[i].height) widgetsHeight += line.widgets[i].height;
2960
- }
2961
 
2962
- if (wrapping)
2963
- return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th;
2964
- else
2965
- return widgetsHeight + th;
2966
- };
2967
- }
 
2968
 
2969
- function estimateLineHeights(cm) {
2970
- var doc = cm.doc, est = estimateHeight(cm);
2971
- doc.iter(function(line) {
2972
- var estHeight = est(line);
2973
- if (estHeight != line.height) updateLineHeight(line, estHeight);
2974
- });
 
 
 
 
 
 
 
 
2975
  }
 
2976
 
2977
- function themeChanged(cm) {
2978
- cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
2979
- cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
2980
- clearCaches(cm);
2981
- }
2982
 
2983
- function guttersChanged(cm) {
2984
- updateGutters(cm);
2985
- regChange(cm);
2986
- setTimeout(function(){alignHorizontally(cm);}, 20);
2987
- }
2988
 
2989
- // Rebuild the gutter elements, ensure the margin to the left of the
2990
- // code matches their width.
2991
- function updateGutters(cm) {
2992
- var gutters = cm.display.gutters, specs = cm.options.gutters;
2993
- removeChildren(gutters);
2994
- for (var i = 0; i < specs.length; ++i) {
2995
- var gutterClass = specs[i];
2996
- var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
2997
- if (gutterClass == "CodeMirror-linenumbers") {
2998
- cm.display.lineGutter = gElt;
2999
- gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
3000
- }
3001
- }
3002
- gutters.style.display = i ? "" : "none";
3003
- updateGutterSpace(cm);
3004
- }
3005
-
3006
- function updateGutterSpace(cm) {
3007
- var width = cm.display.gutters.offsetWidth;
3008
- cm.display.sizer.style.marginLeft = width + "px";
3009
- }
3010
-
3011
- // Compute the character length of a line, taking into account
3012
- // collapsed ranges (see markText) that might hide parts, and join
3013
- // other lines onto it.
3014
- function lineLength(line) {
3015
- if (line.height == 0) return 0;
3016
- var len = line.text.length, merged, cur = line;
3017
- while (merged = collapsedSpanAtStart(cur)) {
3018
- var found = merged.find(0, true);
3019
- cur = found.from.line;
3020
- len += found.from.ch - found.to.ch;
3021
- }
3022
- cur = line;
3023
- while (merged = collapsedSpanAtEnd(cur)) {
3024
- var found = merged.find(0, true);
3025
- len -= cur.text.length - found.from.ch;
3026
- cur = found.to.line;
3027
- len += cur.text.length - found.to.ch;
3028
- }
3029
- return len;
3030
- }
3031
-
3032
- // Find the longest line in the document.
3033
- function findMaxLine(cm) {
3034
- var d = cm.display, doc = cm.doc;
3035
- d.maxLine = getLine(doc, doc.first);
3036
- d.maxLineLength = lineLength(d.maxLine);
3037
- d.maxLineChanged = true;
3038
- doc.iter(function(line) {
3039
- var len = lineLength(line);
3040
- if (len > d.maxLineLength) {
3041
- d.maxLineLength = len;
3042
- d.maxLine = line;
3043
- }
3044
- });
3045
  }
 
3046
 
3047
- // Make sure the gutters options contains the element
3048
- // "CodeMirror-linenumbers" when the lineNumbers option is true.
3049
- function setGuttersForLineNumbers(options) {
3050
- var found = indexOf(options.gutters, "CodeMirror-linenumbers");
3051
- if (found == -1 && options.lineNumbers) {
3052
- options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
3053
- } else if (found > -1 && !options.lineNumbers) {
3054
- options.gutters = options.gutters.slice(0);
3055
- options.gutters.splice(found, 1);
3056
- }
3057
- }
3058
 
3059
- // SCROLLBARS
3060
 
3061
- // Prepare DOM reads needed to update the scrollbars. Done in one
3062
- // shot to minimize update/measure roundtrips.
3063
- function measureForScrollbars(cm) {
3064
- var d = cm.display, gutterW = d.gutters.offsetWidth;
3065
- var docH = Math.round(cm.doc.height + paddingVert(cm.display));
3066
- return {
3067
- clientHeight: d.scroller.clientHeight,
3068
- viewHeight: d.wrapper.clientHeight,
3069
- scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
3070
- viewWidth: d.wrapper.clientWidth,
3071
- barLeft: cm.options.fixedGutter ? gutterW : 0,
3072
- docHeight: docH,
3073
- scrollHeight: docH + scrollGap(cm) + d.barHeight,
3074
- nativeBarWidth: d.nativeBarWidth,
3075
- gutterWidth: gutterW
3076
- };
3077
- }
3078
 
3079
- function NativeScrollbars(place, scroll, cm) {
3080
- this.cm = cm;
3081
- var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
3082
- var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
3083
- place(vert); place(horiz);
3084
 
3085
- on(vert, "scroll", function() {
3086
- if (vert.clientHeight) scroll(vert.scrollTop, "vertical");
3087
- });
3088
- on(horiz, "scroll", function() {
3089
- if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
3090
- });
3091
 
3092
- this.checkedZeroWidth = false;
3093
- // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
3094
- if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
 
 
 
 
3095
  }
 
 
 
3096
 
3097
- NativeScrollbars.prototype = copyObj({
3098
- update: function(measure) {
3099
- var needsH = measure.scrollWidth > measure.clientWidth + 1;
3100
- var needsV = measure.scrollHeight > measure.clientHeight + 1;
3101
- var sWidth = measure.nativeBarWidth;
3102
-
3103
- if (needsV) {
3104
- this.vert.style.display = "block";
3105
- this.vert.style.bottom = needsH ? sWidth + "px" : "0";
3106
- var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
3107
- // A bug in IE8 can cause this value to be negative, so guard it.
3108
- this.vert.firstChild.style.height =
3109
- Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
3110
- } else {
3111
- this.vert.style.display = "";
3112
- this.vert.firstChild.style.height = "0";
3113
- }
3114
 
3115
- if (needsH) {
3116
- this.horiz.style.display = "block";
3117
- this.horiz.style.right = needsV ? sWidth + "px" : "0";
3118
- this.horiz.style.left = measure.barLeft + "px";
3119
- var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
3120
- this.horiz.firstChild.style.width =
3121
- (measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
3122
- } else {
3123
- this.horiz.style.display = "";
3124
- this.horiz.firstChild.style.width = "0";
3125
- }
3126
 
3127
- if (!this.checkedZeroWidth && measure.clientHeight > 0) {
3128
- if (sWidth == 0) this.zeroWidthHack();
3129
- this.checkedZeroWidth = true;
3130
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3131
 
3132
- return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
3133
- },
3134
- setScrollLeft: function(pos) {
3135
- if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
3136
- if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz);
3137
- },
3138
- setScrollTop: function(pos) {
3139
- if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
3140
- if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert);
3141
- },
3142
- zeroWidthHack: function() {
3143
- var w = mac && !mac_geMountainLion ? "12px" : "18px";
3144
- this.horiz.style.height = this.vert.style.width = w;
3145
- this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
3146
- this.disableHoriz = new Delayed;
3147
- this.disableVert = new Delayed;
3148
- },
3149
- enableZeroWidthBar: function(bar, delay) {
3150
- bar.style.pointerEvents = "auto";
3151
- function maybeDisable() {
3152
- // To find out whether the scrollbar is still visible, we
3153
- // check whether the element under the pixel in the bottom
3154
- // left corner of the scrollbar box is the scrollbar box
3155
- // itself (when the bar is still visible) or its filler child
3156
- // (when the bar is hidden). If it is still visible, we keep
3157
- // it enabled, if it's hidden, we disable pointer events.
3158
- var box = bar.getBoundingClientRect();
3159
- var elt = document.elementFromPoint(box.left + 1, box.bottom - 1);
3160
- if (elt != bar) bar.style.pointerEvents = "none";
3161
- else delay.set(1000, maybeDisable);
3162
- }
3163
- delay.set(1000, maybeDisable);
3164
- },
3165
- clear: function() {
3166
- var parent = this.horiz.parentNode;
3167
- parent.removeChild(this.horiz);
3168
- parent.removeChild(this.vert);
3169
- }
3170
- }, NativeScrollbars.prototype);
3171
-
3172
- function NullScrollbars() {}
3173
-
3174
- NullScrollbars.prototype = copyObj({
3175
- update: function() { return {bottom: 0, right: 0}; },
3176
- setScrollLeft: function() {},
3177
- setScrollTop: function() {},
3178
- clear: function() {}
3179
- }, NullScrollbars.prototype);
3180
-
3181
- CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
3182
-
3183
- function initScrollbars(cm) {
3184
- if (cm.display.scrollbars) {
3185
- cm.display.scrollbars.clear();
3186
- if (cm.display.scrollbars.addClass)
3187
- rmClass(cm.display.wrapper, cm.display.scrollbars.addClass);
3188
- }
3189
-
3190
- cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) {
3191
- cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
3192
- // Prevent clicks in the scrollbars from killing focus
3193
- on(node, "mousedown", function() {
3194
- if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0);
3195
- });
3196
- node.setAttribute("cm-not-content", "true");
3197
- }, function(pos, axis) {
3198
- if (axis == "horizontal") setScrollLeft(cm, pos);
3199
- else setScrollTop(cm, pos);
3200
- }, cm);
3201
- if (cm.display.scrollbars.addClass)
3202
- addClass(cm.display.wrapper, cm.display.scrollbars.addClass);
3203
- }
3204
-
3205
- function updateScrollbars(cm, measure) {
3206
- if (!measure) measure = measureForScrollbars(cm);
3207
- var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
3208
- updateScrollbarsInner(cm, measure);
3209
- for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
3210
- if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
3211
- updateHeightsInViewport(cm);
3212
- updateScrollbarsInner(cm, measureForScrollbars(cm));
3213
- startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
3214
- }
3215
- }
3216
-
3217
- // Re-synchronize the fake scrollbars with the actual size of the
3218
- // content.
3219
- function updateScrollbarsInner(cm, measure) {
3220
- var d = cm.display;
3221
- var sizes = d.scrollbars.update(measure);
3222
-
3223
- d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
3224
- d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
3225
- d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent"
3226
-
3227
- if (sizes.right && sizes.bottom) {
3228
- d.scrollbarFiller.style.display = "block";
3229
- d.scrollbarFiller.style.height = sizes.bottom + "px";
3230
- d.scrollbarFiller.style.width = sizes.right + "px";
3231
- } else d.scrollbarFiller.style.display = "";
3232
- if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
3233
- d.gutterFiller.style.display = "block";
3234
- d.gutterFiller.style.height = sizes.bottom + "px";
3235
- d.gutterFiller.style.width = measure.gutterWidth + "px";
3236
- } else d.gutterFiller.style.display = "";
3237
- }
3238
-
3239
- // Compute the lines that are visible in a given viewport (defaults
3240
- // the the current scroll position). viewport may contain top,
3241
- // height, and ensure (see op.scrollToPos) properties.
3242
- function visibleLines(display, doc, viewport) {
3243
- var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
3244
- top = Math.floor(top - paddingTop(display));
3245
- var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
3246
-
3247
- var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
3248
- // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
3249
- // forces those lines into the viewport (if possible).
3250
- if (viewport && viewport.ensure) {
3251
- var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
3252
- if (ensureFrom < from) {
3253
- from = ensureFrom;
3254
- to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
3255
- } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
3256
- from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
3257
- to = ensureTo;
3258
- }
3259
  }
3260
- return {from: from, to: Math.max(to, from + 1)};
3261
  }
 
 
3262
 
3263
- // LINE NUMBERS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3264
 
3265
- // Re-align line numbers and gutter marks to compensate for
3266
- // horizontal scrolling.
3267
- function alignHorizontally(cm) {
3268
- var display = cm.display, view = display.view;
3269
- if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
3270
- var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
3271
- var gutterW = display.gutters.offsetWidth, left = comp + "px";
3272
- for (var i = 0; i < view.length; i++) if (!view[i].hidden) {
3273
- if (cm.options.fixedGutter) {
3274
- if (view[i].gutter)
3275
- view[i].gutter.style.left = left;
3276
- if (view[i].gutterBackground)
3277
- view[i].gutterBackground.style.left = left;
3278
- }
3279
- var align = view[i].alignable;
3280
- if (align) for (var j = 0; j < align.length; j++)
3281
- align[j].style.left = left;
3282
- }
3283
- if (cm.options.fixedGutter)
3284
- display.gutters.style.left = (comp + gutterW) + "px";
3285
- }
3286
-
3287
- // Used to ensure that the line number gutter is still the right
3288
- // size for the current document size. Returns true when an update
3289
- // is needed.
3290
- function maybeUpdateLineNumberWidth(cm) {
3291
- if (!cm.options.lineNumbers) return false;
3292
- var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
3293
- if (last.length != display.lineNumChars) {
3294
- var test = display.measure.appendChild(elt("div", [elt("div", last)],
3295
- "CodeMirror-linenumber CodeMirror-gutter-elt"));
3296
- var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
3297
- display.lineGutter.style.width = "";
3298
- display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
3299
- display.lineNumWidth = display.lineNumInnerWidth + padding;
3300
- display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
3301
- display.lineGutter.style.width = display.lineNumWidth + "px";
3302
- updateGutterSpace(cm);
3303
- return true;
3304
- }
3305
- return false;
3306
- }
3307
-
3308
- function lineNumberFor(options, i) {
3309
- return String(options.lineNumberFormatter(i + options.firstLineNumber));
3310
- }
3311
-
3312
- // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
3313
- // but using getBoundingClientRect to get a sub-pixel-accurate
3314
- // result.
3315
- function compensateForHScroll(display) {
3316
- return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;
3317
- }
3318
-
3319
- // DISPLAY DRAWING
3320
-
3321
- function DisplayUpdate(cm, viewport, force) {
3322
- var display = cm.display;
3323
-
3324
- this.viewport = viewport;
3325
- // Store some values that we'll need later (but don't want to force a relayout for)
3326
- this.visible = visibleLines(display, cm.doc, viewport);
3327
- this.editorIsHidden = !display.wrapper.offsetWidth;
3328
- this.wrapperHeight = display.wrapper.clientHeight;
3329
- this.wrapperWidth = display.wrapper.clientWidth;
3330
- this.oldDisplayWidth = displayWidth(cm);
3331
- this.force = force;
3332
- this.dims = getDimensions(cm);
3333
- this.events = [];
3334
- }
3335
-
3336
- DisplayUpdate.prototype.signal = function(emitter, type) {
3337
- if (hasHandler(emitter, type))
3338
- this.events.push(arguments);
3339
- };
3340
- DisplayUpdate.prototype.finish = function() {
3341
- for (var i = 0; i < this.events.length; i++)
3342
- signal.apply(null, this.events[i]);
3343
- };
3344
 
3345
- function maybeClipScrollbars(cm) {
3346
- var display = cm.display;
3347
- if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
3348
- display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
3349
- display.heightForcer.style.height = scrollGap(cm) + "px";
3350
- display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
3351
- display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
3352
- display.scrollbarsClipped = true;
 
3353
  }
3354
  }
 
 
3355
 
3356
- // Does the actual updating of the line display. Bails out
3357
- // (returning false) when there is nothing to be done and forced is
3358
- // false.
3359
- function updateDisplayIfNeeded(cm, update) {
3360
- var display = cm.display, doc = cm.doc;
3361
-
3362
- if (update.editorIsHidden) {
3363
- resetView(cm);
3364
- return false;
3365
- }
3366
-
3367
- // Bail out if the visible area is already rendered and nothing changed.
3368
- if (!update.force &&
3369
- update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
3370
- (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
3371
- display.renderedView == display.view && countDirtyView(cm) == 0)
3372
- return false;
3373
-
3374
- if (maybeUpdateLineNumberWidth(cm)) {
3375
- resetView(cm);
3376
- update.dims = getDimensions(cm);
3377
- }
3378
 
3379
- // Compute a suitable new viewport (from & to)
3380
- var end = doc.first + doc.size;
3381
- var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
3382
- var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
3383
- if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);
3384
- if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo);
3385
- if (sawCollapsedSpans) {
3386
- from = visualLineNo(cm.doc, from);
3387
- to = visualLineEndNo(cm.doc, to);
3388
- }
3389
 
3390
- var different = from != display.viewFrom || to != display.viewTo ||
3391
- display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
3392
- adjustView(cm, from, to);
3393
 
3394
- display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
3395
- // Position the mover div to align with the current scroll position
3396
- cm.display.mover.style.top = display.viewOffset + "px";
 
 
3397
 
3398
- var toUpdate = countDirtyView(cm);
3399
- if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
3400
- (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
3401
- return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3402
 
3403
- // For big changes, we hide the enclosing element during the
3404
- // update, since that speeds up the operations on most browsers.
3405
- var focused = activeElt();
3406
- if (toUpdate > 4) display.lineDiv.style.display = "none";
3407
- patchDisplay(cm, display.updateLineNumbers, update.dims);
3408
- if (toUpdate > 4) display.lineDiv.style.display = "";
3409
- display.renderedView = display.view;
3410
- // There might have been a widget with a focused element that got
3411
- // hidden or updated, if so re-focus it.
3412
- if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
3413
 
3414
- // Prevent selection and cursors from interfering with the scroll
3415
- // width and height.
3416
- removeChildren(display.cursorDiv);
3417
- removeChildren(display.selectionDiv);
3418
- display.gutters.style.height = display.sizer.style.minHeight = 0;
3419
 
3420
- if (different) {
3421
- display.lastWrapHeight = update.wrapperHeight;
3422
- display.lastWrapWidth = update.wrapperWidth;
3423
- startWorker(cm, 400);
3424
- }
3425
 
3426
- display.updateLineNumbers = null;
 
 
 
3427
 
3428
- return true;
3429
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3430
 
3431
- function postUpdateDisplay(cm, update) {
3432
- var viewport = update.viewport;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3433
 
3434
- for (var first = true;; first = false) {
3435
- if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
3436
- // Clip forced viewport to actual scrollable area.
3437
- if (viewport && viewport.top != null)
3438
- viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)};
3439
- // Updated line heights might result in the drawn area not
3440
- // actually covering the viewport. Keep looping until it does.
3441
- update.visible = visibleLines(cm.display, cm.doc, viewport);
3442
- if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
3443
- break;
3444
- }
3445
- if (!updateDisplayIfNeeded(cm, update)) break;
3446
- updateHeightsInViewport(cm);
3447
- var barMeasure = measureForScrollbars(cm);
3448
- updateSelection(cm);
3449
- updateScrollbars(cm, barMeasure);
3450
- setDocumentHeight(cm, barMeasure);
3451
- }
3452
-
3453
- update.signal(cm, "update", cm);
3454
- if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
3455
- update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
3456
- cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
3457
- }
3458
- }
3459
-
3460
- function updateDisplaySimple(cm, viewport) {
3461
- var update = new DisplayUpdate(cm, viewport);
3462
- if (updateDisplayIfNeeded(cm, update)) {
3463
- updateHeightsInViewport(cm);
3464
- postUpdateDisplay(cm, update);
3465
- var barMeasure = measureForScrollbars(cm);
3466
- updateSelection(cm);
3467
- updateScrollbars(cm, barMeasure);
3468
- setDocumentHeight(cm, barMeasure);
3469
- update.finish();
3470
- }
3471
- }
3472
-
3473
- function setDocumentHeight(cm, measure) {
3474
- cm.display.sizer.style.minHeight = measure.docHeight + "px";
3475
- cm.display.heightForcer.style.top = measure.docHeight + "px";
3476
- cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
3477
- }
3478
-
3479
- // Read the actual heights of the rendered lines, and update their
3480
- // stored heights to match.
3481
- function updateHeightsInViewport(cm) {
3482
- var display = cm.display;
3483
- var prevBottom = display.lineDiv.offsetTop;
3484
- for (var i = 0; i < display.view.length; i++) {
3485
- var cur = display.view[i], height;
3486
- if (cur.hidden) continue;
3487
- if (ie && ie_version < 8) {
3488
- var bot = cur.node.offsetTop + cur.node.offsetHeight;
3489
- height = bot - prevBottom;
3490
- prevBottom = bot;
3491
  } else {
3492
- var box = cur.node.getBoundingClientRect();
3493
- height = box.bottom - box.top;
3494
- }
3495
- var diff = cur.line.height - height;
3496
- if (height < 2) height = textHeight(display);
3497
- if (diff > .001 || diff < -.001) {
3498
- updateLineHeight(cur.line, height);
3499
- updateWidgetHeight(cur.line);
3500
- if (cur.rest) for (var j = 0; j < cur.rest.length; j++)
3501
- updateWidgetHeight(cur.rest[j]);
3502
  }
3503
  }
3504
  }
 
 
 
3505
 
3506
- // Read and store the height of line widgets associated with the
3507
- // given line.
3508
- function updateWidgetHeight(line) {
3509
- if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
3510
- line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight;
 
 
 
 
 
 
3511
  }
 
 
3512
 
3513
- // Do a bulk-read of the DOM positions and sizes needed to draw the
3514
- // view, so that we don't interleave reading and writing to the DOM.
3515
- function getDimensions(cm) {
3516
- var d = cm.display, left = {}, width = {};
3517
- var gutterLeft = d.gutters.clientLeft;
3518
- for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
3519
- left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
3520
- width[cm.options.gutters[i]] = n.clientWidth;
3521
- }
3522
- return {fixedPos: compensateForHScroll(d),
3523
- gutterTotalWidth: d.gutters.offsetWidth,
3524
- gutterLeft: left,
3525
- gutterWidth: width,
3526
- wrapperWidth: d.wrapper.clientWidth};
3527
  }
 
 
 
3528
 
3529
- // Sync the actual display DOM structure with display.view, removing
3530
- // nodes for lines that are no longer in view, and creating the ones
3531
- // that are not there yet, and updating the ones that are out of
3532
- // date.
3533
- function patchDisplay(cm, updateNumbersFrom, dims) {
3534
- var display = cm.display, lineNumbers = cm.options.lineNumbers;
3535
- var container = display.lineDiv, cur = container.firstChild;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3536
 
3537
- function rm(node) {
3538
- var next = node.nextSibling;
3539
- // Works around a throw-scroll bug in OS X Webkit
3540
- if (webkit && mac && cm.display.currentWheelTarget == node)
3541
- node.style.display = "none";
3542
- else
3543
- node.parentNode.removeChild(node);
3544
- return next;
3545
- }
3546
-
3547
- var view = display.view, lineN = display.viewFrom;
3548
- // Loop over the elements in the view, syncing cur (the DOM nodes
3549
- // in display.lineDiv) with the view as we go.
3550
- for (var i = 0; i < view.length; i++) {
3551
- var lineView = view[i];
3552
- if (lineView.hidden) {
3553
- } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
3554
- var node = buildLineElement(cm, lineView, lineN, dims);
3555
- container.insertBefore(node, cur);
3556
- } else { // Already drawn
3557
- while (cur != lineView.node) cur = rm(cur);
3558
- var updateNumber = lineNumbers && updateNumbersFrom != null &&
3559
- updateNumbersFrom <= lineN && lineView.lineNumber;
3560
- if (lineView.changes) {
3561
- if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false;
3562
- updateLineForChanges(cm, lineView, lineN, dims);
3563
- }
3564
- if (updateNumber) {
3565
- removeChildren(lineView.lineNumber);
3566
- lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
3567
- }
3568
- cur = lineView.node.nextSibling;
3569
- }
3570
- lineN += lineView.size;
3571
- }
3572
- while (cur) cur = rm(cur);
3573
- }
3574
-
3575
- // When an aspect of a line changes, a string is added to
3576
- // lineView.changes. This updates the relevant part of the line's
3577
- // DOM structure.
3578
- function updateLineForChanges(cm, lineView, lineN, dims) {
3579
- for (var j = 0; j < lineView.changes.length; j++) {
3580
- var type = lineView.changes[j];
3581
- if (type == "text") updateLineText(cm, lineView);
3582
- else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims);
3583
- else if (type == "class") updateLineClasses(lineView);
3584
- else if (type == "widget") updateLineWidgets(cm, lineView, dims);
3585
- }
3586
- lineView.changes = null;
3587
- }
3588
-
3589
- // Lines with gutter elements, widgets or a background class need to
3590
- // be wrapped, and have the extra elements added to the wrapper div
3591
- function ensureLineWrapped(lineView) {
3592
- if (lineView.node == lineView.text) {
3593
- lineView.node = elt("div", null, null, "position: relative");
3594
- if (lineView.text.parentNode)
3595
- lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
3596
- lineView.node.appendChild(lineView.text);
3597
- if (ie && ie_version < 8) lineView.node.style.zIndex = 2;
3598
- }
3599
- return lineView.node;
3600
- }
3601
-
3602
- function updateLineBackground(lineView) {
3603
- var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
3604
- if (cls) cls += " CodeMirror-linebackground";
3605
- if (lineView.background) {
3606
- if (cls) lineView.background.className = cls;
3607
- else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
3608
- } else if (cls) {
3609
- var wrap = ensureLineWrapped(lineView);
3610
- lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
3611
- }
3612
- }
3613
-
3614
- // Wrapper around buildLineContent which will reuse the structure
3615
- // in display.externalMeasured when possible.
3616
- function getLineContent(cm, lineView) {
3617
- var ext = cm.display.externalMeasured;
3618
- if (ext && ext.line == lineView.line) {
3619
- cm.display.externalMeasured = null;
3620
- lineView.measure = ext.measure;
3621
- return ext.built;
3622
- }
3623
- return buildLineContent(cm, lineView);
3624
- }
3625
-
3626
- // Redraw the line's text. Interacts with the background and text
3627
- // classes because the mode may output tokens that influence these
3628
- // classes.
3629
- function updateLineText(cm, lineView) {
3630
- var cls = lineView.text.className;
3631
- var built = getLineContent(cm, lineView);
3632
- if (lineView.text == lineView.node) lineView.node = built.pre;
3633
- lineView.text.parentNode.replaceChild(built.pre, lineView.text);
3634
- lineView.text = built.pre;
3635
- if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
3636
- lineView.bgClass = built.bgClass;
3637
- lineView.textClass = built.textClass;
3638
- updateLineClasses(lineView);
3639
- } else if (cls) {
3640
- lineView.text.className = cls;
3641
- }
3642
- }
3643
-
3644
- function updateLineClasses(lineView) {
3645
- updateLineBackground(lineView);
3646
- if (lineView.line.wrapClass)
3647
- ensureLineWrapped(lineView).className = lineView.line.wrapClass;
3648
- else if (lineView.node != lineView.text)
3649
- lineView.node.className = "";
3650
- var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
3651
- lineView.text.className = textClass || "";
3652
- }
3653
-
3654
- function updateLineGutter(cm, lineView, lineN, dims) {
3655
- if (lineView.gutter) {
3656
- lineView.node.removeChild(lineView.gutter);
3657
- lineView.gutter = null;
3658
- }
3659
- if (lineView.gutterBackground) {
3660
- lineView.node.removeChild(lineView.gutterBackground);
3661
- lineView.gutterBackground = null;
3662
- }
3663
- if (lineView.line.gutterClass) {
3664
- var wrap = ensureLineWrapped(lineView);
3665
- lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
3666
- "left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) +
3667
- "px; width: " + dims.gutterTotalWidth + "px");
3668
- wrap.insertBefore(lineView.gutterBackground, lineView.text);
3669
- }
3670
- var markers = lineView.line.gutterMarkers;
3671
- if (cm.options.lineNumbers || markers) {
3672
- var wrap = ensureLineWrapped(lineView);
3673
- var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " +
3674
- (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px");
3675
- cm.display.input.setUneditable(gutterWrap);
3676
- wrap.insertBefore(gutterWrap, lineView.text);
3677
- if (lineView.line.gutterClass)
3678
- gutterWrap.className += " " + lineView.line.gutterClass;
3679
- if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
3680
- lineView.lineNumber = gutterWrap.appendChild(
3681
- elt("div", lineNumberFor(cm.options, lineN),
3682
- "CodeMirror-linenumber CodeMirror-gutter-elt",
3683
- "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
3684
- + cm.display.lineNumInnerWidth + "px"));
3685
- if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) {
3686
- var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
3687
- if (found)
3688
- gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
3689
- dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
3690
- }
3691
- }
3692
- }
3693
 
3694
- function updateLineWidgets(cm, lineView, dims) {
3695
- if (lineView.alignable) lineView.alignable = null;
3696
- for (var node = lineView.node.firstChild, next; node; node = next) {
3697
- var next = node.nextSibling;
3698
- if (node.className == "CodeMirror-linewidget")
3699
- lineView.node.removeChild(node);
3700
- }
3701
- insertLineWidgets(cm, lineView, dims);
3702
- }
 
 
 
 
 
 
 
 
 
3703
 
3704
- // Build a line's DOM representation from scratch
3705
- function buildLineElement(cm, lineView, lineN, dims) {
3706
- var built = getLineContent(cm, lineView);
3707
- lineView.text = lineView.node = built.pre;
3708
- if (built.bgClass) lineView.bgClass = built.bgClass;
3709
- if (built.textClass) lineView.textClass = built.textClass;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3710
 
3711
- updateLineClasses(lineView);
3712
- updateLineGutter(cm, lineView, lineN, dims);
3713
- insertLineWidgets(cm, lineView, dims);
3714
- return lineView.node;
3715
- }
 
 
 
 
 
3716
 
3717
- // A lineView may contain multiple logical lines (when merged by
3718
- // collapsed spans). The widgets for all of them need to be drawn.
3719
- function insertLineWidgets(cm, lineView, dims) {
3720
- insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
3721
- if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
3722
- insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false);
 
3723
  }
 
 
3724
 
3725
- function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
3726
- if (!line.widgets) return;
3727
- var wrap = ensureLineWrapped(lineView);
3728
- for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
3729
- var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
3730
- if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true");
3731
- positionLineWidget(widget, node, lineView, dims);
3732
- cm.display.input.setUneditable(node);
3733
- if (allowAbove && widget.above)
3734
- wrap.insertBefore(node, lineView.gutter || lineView.text);
3735
- else
3736
- wrap.appendChild(node);
3737
- signalLater(widget, "redraw");
3738
- }
3739
- }
3740
 
3741
- function positionLineWidget(widget, node, lineView, dims) {
3742
- if (widget.noHScroll) {
3743
- (lineView.alignable || (lineView.alignable = [])).push(node);
3744
- var width = dims.wrapperWidth;
3745
- node.style.left = dims.fixedPos + "px";
3746
- if (!widget.coverGutter) {
3747
- width -= dims.gutterTotalWidth;
3748
- node.style.paddingLeft = dims.gutterTotalWidth + "px";
3749
- }
3750
- node.style.width = width + "px";
3751
- }
3752
- if (widget.coverGutter) {
3753
- node.style.zIndex = 5;
3754
- node.style.position = "relative";
3755
- if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
3756
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3757
  }
 
3758
 
3759
- // POSITION OBJECT
 
 
3760
 
3761
- // A Pos instance represents a position within the text.
3762
- var Pos = CodeMirror.Pos = function(line, ch) {
3763
- if (!(this instanceof Pos)) return new Pos(line, ch);
3764
- this.line = line; this.ch = ch;
3765
- };
 
 
 
 
 
 
 
 
 
 
3766
 
3767
- // Compare two positions, return 0 if they are the same, a negative
3768
- // number when a is less, and a positive number otherwise.
3769
- var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3770
 
3771
- function copyPos(x) {return Pos(x.line, x.ch);}
3772
- function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; }
3773
- function minPos(a, b) { return cmp(a, b) < 0 ? a : b; }
 
 
 
 
 
 
 
 
 
 
 
3774
 
3775
- // INPUT HANDLING
3776
 
3777
- function ensureFocus(cm) {
3778
- if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
 
 
 
 
 
 
 
3779
  }
 
 
3780
 
3781
- // This will be set to a {lineWise: bool, text: [string]} object, so
3782
- // that, when pasting, we know what kind of selections the copied
3783
- // text was made out of.
3784
- var lastCopied = null;
3785
 
3786
- function applyTextInput(cm, inserted, deleted, sel, origin) {
3787
- var doc = cm.doc;
3788
- cm.display.shift = false;
3789
- if (!sel) sel = doc.sel;
 
 
3790
 
3791
- var paste = cm.state.pasteIncoming || origin == "paste";
3792
- var textLines = doc.splitLines(inserted), multiPaste = null
3793
- // When pasing N lines into N selections, insert one line per selection
3794
- if (paste && sel.ranges.length > 1) {
3795
- if (lastCopied && lastCopied.text.join("\n") == inserted) {
3796
- if (sel.ranges.length % lastCopied.text.length == 0) {
3797
- multiPaste = [];
3798
- for (var i = 0; i < lastCopied.text.length; i++)
3799
- multiPaste.push(doc.splitLines(lastCopied.text[i]));
3800
- }
3801
- } else if (textLines.length == sel.ranges.length) {
3802
- multiPaste = map(textLines, function(l) { return [l]; });
3803
- }
3804
- }
3805
 
3806
- // Normal behavior is to insert the new text into every selection
3807
- for (var i = sel.ranges.length - 1; i >= 0; i--) {
3808
- var range = sel.ranges[i];
3809
- var from = range.from(), to = range.to();
3810
- if (range.empty()) {
3811
- if (deleted && deleted > 0) // Handle deletion
3812
- from = Pos(from.line, from.ch - deleted);
3813
- else if (cm.state.overwrite && !paste) // Handle overwrite
3814
- to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));
3815
- else if (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted)
3816
- from = to = Pos(from.line, 0)
3817
- }
3818
- var updateInput = cm.curOp.updateInput;
3819
- var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines,
3820
- origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")};
3821
- makeChange(cm.doc, changeEvent);
3822
- signalLater(cm, "inputRead", cm, changeEvent);
3823
- }
3824
- if (inserted && !paste)
3825
- triggerElectric(cm, inserted);
3826
-
3827
- ensureCursorVisible(cm);
3828
- cm.curOp.updateInput = updateInput;
3829
- cm.curOp.typing = true;
3830
- cm.state.pasteIncoming = cm.state.cutIncoming = false;
3831
- }
3832
-
3833
- function handlePaste(e, cm) {
3834
- var pasted = e.clipboardData && e.clipboardData.getData("Text");
3835
- if (pasted) {
3836
- e.preventDefault();
3837
- if (!cm.isReadOnly() && !cm.options.disableInput)
3838
- runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); });
3839
- return true;
3840
- }
3841
- }
3842
-
3843
- function triggerElectric(cm, inserted) {
3844
- // When an 'electric' character is inserted, immediately trigger a reindent
3845
- if (!cm.options.electricChars || !cm.options.smartIndent) return;
3846
- var sel = cm.doc.sel;
3847
-
3848
- for (var i = sel.ranges.length - 1; i >= 0; i--) {
3849
- var range = sel.ranges[i];
3850
- if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue;
3851
- var mode = cm.getModeAt(range.head);
3852
- var indented = false;
3853
- if (mode.electricChars) {
3854
- for (var j = 0; j < mode.electricChars.length; j++)
3855
- if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
3856
- indented = indentLine(cm, range.head.line, "smart");
3857
- break;
3858
- }
3859
- } else if (mode.electricInput) {
3860
- if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch)))
3861
- indented = indentLine(cm, range.head.line, "smart");
3862
  }
3863
- if (indented) signalLater(cm, "electricInput", cm, range.head.line);
3864
  }
3865
  }
 
 
3866
 
3867
- function copyableRanges(cm) {
3868
- var text = [], ranges = [];
3869
- for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
3870
- var line = cm.doc.sel.ranges[i].head.line;
3871
- var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
3872
- ranges.push(lineRange);
3873
- text.push(cm.getRange(lineRange.anchor, lineRange.head));
3874
- }
3875
- return {text: text, ranges: ranges};
3876
- }
3877
 
3878
- function disableBrowserMagic(field, spellcheck) {
3879
- field.setAttribute("autocorrect", "off");
3880
- field.setAttribute("autocapitalize", "off");
3881
- field.setAttribute("spellcheck", !!spellcheck);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3882
  }
 
3883
 
3884
- // TEXTAREA INPUT STYLE
3885
-
3886
- function TextareaInput(cm) {
3887
- this.cm = cm;
3888
- // See input.poll and input.reset
3889
- this.prevInput = "";
3890
-
3891
- // Flag that indicates whether we expect input to appear real soon
3892
- // now (after some event like 'keypress' or 'input') and are
3893
- // polling intensively.
3894
- this.pollingFast = false;
3895
- // Self-resetting timeout for the poller
3896
- this.polling = new Delayed();
3897
- // Tracks when input.reset has punted to just putting a short
3898
- // string into the textarea instead of the full selection.
3899
- this.inaccurateSelection = false;
3900
- // Used to work around IE issue with selection being forgotten when focus moves away from textarea
3901
- this.hasSelection = false;
3902
- this.composing = null;
3903
- };
3904
 
3905
- function hiddenTextarea() {
3906
- var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none");
3907
- var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
3908
- // The textarea is kept positioned near the cursor to prevent the
3909
- // fact that it'll be scrolled into view on input from scrolling
3910
- // our fake cursor out of view. On webkit, when wrap=off, paste is
3911
- // very slow. So make the area wide instead.
3912
- if (webkit) te.style.width = "1000px";
3913
- else te.setAttribute("wrap", "off");
3914
- // If border: 0; -- iOS fails to open keyboard (issue #1287)
3915
- if (ios) te.style.border = "1px solid black";
3916
- disableBrowserMagic(te);
3917
- return div;
3918
- }
3919
-
3920
- TextareaInput.prototype = copyObj({
3921
- init: function(display) {
3922
- var input = this, cm = this.cm;
3923
-
3924
- // Wraps and hides input textarea
3925
- var div = this.wrapper = hiddenTextarea();
3926
- // The semihidden textarea that is focused when the editor is
3927
- // focused, and receives input.
3928
- var te = this.textarea = div.firstChild;
3929
- display.wrapper.insertBefore(div, display.wrapper.firstChild);
3930
-
3931
- // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
3932
- if (ios) te.style.width = "0px";
3933
-
3934
- on(te, "input", function() {
3935
- if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null;
3936
- input.poll();
3937
- });
3938
-
3939
- on(te, "paste", function(e) {
3940
- if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return
3941
-
3942
- cm.state.pasteIncoming = true;
3943
- input.fastPoll();
3944
- });
3945
-
3946
- function prepareCopyCut(e) {
3947
- if (signalDOMEvent(cm, e)) return
3948
- if (cm.somethingSelected()) {
3949
- lastCopied = {lineWise: false, text: cm.getSelections()};
3950
- if (input.inaccurateSelection) {
3951
- input.prevInput = "";
3952
- input.inaccurateSelection = false;
3953
- te.value = lastCopied.text.join("\n");
3954
- selectInput(te);
3955
- }
3956
- } else if (!cm.options.lineWiseCopyCut) {
3957
- return;
3958
- } else {
3959
- var ranges = copyableRanges(cm);
3960
- lastCopied = {lineWise: true, text: ranges.text};
3961
- if (e.type == "cut") {
3962
- cm.setSelections(ranges.ranges, null, sel_dontScroll);
3963
- } else {
3964
- input.prevInput = "";
3965
- te.value = ranges.text.join("\n");
3966
- selectInput(te);
3967
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3968
  }
3969
- if (e.type == "cut") cm.state.cutIncoming = true;
3970
  }
3971
- on(te, "cut", prepareCopyCut);
3972
- on(te, "copy", prepareCopyCut);
3973
-
3974
- on(display.scroller, "paste", function(e) {
3975
- if (eventInWidget(display, e) || signalDOMEvent(cm, e)) return;
3976
- cm.state.pasteIncoming = true;
3977
- input.focus();
3978
- });
3979
-
3980
- // Prevent normal selection in the editor (we handle our own)
3981
- on(display.lineSpace, "selectstart", function(e) {
3982
- if (!eventInWidget(display, e)) e_preventDefault(e);
3983
- });
3984
-
3985
- on(te, "compositionstart", function() {
3986
- var start = cm.getCursor("from");
3987
- if (input.composing) input.composing.range.clear()
3988
- input.composing = {
3989
- start: start,
3990
- range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
3991
- };
3992
- });
3993
- on(te, "compositionend", function() {
3994
- if (input.composing) {
3995
- input.poll();
3996
- input.composing.range.clear();
3997
- input.composing = null;
3998
- }
3999
- });
4000
- },
4001
 
4002
- prepareSelection: function() {
4003
- // Redraw the selection and/or cursor
4004
- var cm = this.cm, display = cm.display, doc = cm.doc;
4005
- var result = prepareSelection(cm);
4006
-
4007
- // Move the hidden textarea near the cursor to prevent scrolling artifacts
4008
- if (cm.options.moveInputWithCursor) {
4009
- var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
4010
- var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
4011
- result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
4012
- headPos.top + lineOff.top - wrapOff.top));
4013
- result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
4014
- headPos.left + lineOff.left - wrapOff.left));
4015
- }
4016
 
4017
- return result;
4018
- },
 
 
 
 
 
 
4019
 
4020
- showSelection: function(drawn) {
4021
- var cm = this.cm, display = cm.display;
4022
- removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
4023
- removeChildrenAndAdd(display.selectionDiv, drawn.selection);
4024
- if (drawn.teTop != null) {
4025
- this.wrapper.style.top = drawn.teTop + "px";
4026
- this.wrapper.style.left = drawn.teLeft + "px";
4027
- }
4028
- },
4029
 
4030
- // Reset the input to correspond to the selection (or to be empty,
4031
- // when not typing and nothing is selected)
4032
- reset: function(typing) {
4033
- if (this.contextMenuPending) return;
4034
- var minimal, selected, cm = this.cm, doc = cm.doc;
4035
- if (cm.somethingSelected()) {
4036
- this.prevInput = "";
4037
- var range = doc.sel.primary();
4038
- minimal = hasCopyEvent &&
4039
- (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000);
4040
- var content = minimal ? "-" : selected || cm.getSelection();
4041
- this.textarea.value = content;
4042
- if (cm.state.focused) selectInput(this.textarea);
4043
- if (ie && ie_version >= 9) this.hasSelection = content;
4044
- } else if (!typing) {
4045
- this.prevInput = this.textarea.value = "";
4046
- if (ie && ie_version >= 9) this.hasSelection = null;
4047
- }
4048
- this.inaccurateSelection = minimal;
4049
- },
4050
 
4051
- getField: function() { return this.textarea; },
 
 
 
 
 
 
 
 
 
 
4052
 
4053
- supportsTouch: function() { return false; },
 
 
 
 
 
4054
 
4055
- focus: function() {
4056
- if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
4057
- try { this.textarea.focus(); }
4058
- catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
4059
- }
4060
- },
 
 
 
 
 
4061
 
4062
- blur: function() { this.textarea.blur(); },
 
 
 
 
 
4063
 
4064
- resetPosition: function() {
4065
- this.wrapper.style.top = this.wrapper.style.left = 0;
4066
- },
 
 
 
 
 
 
4067
 
4068
- receivedFocus: function() { this.slowPoll(); },
4069
-
4070
- // Poll for input changes, using the normal rate of polling. This
4071
- // runs as long as the editor is focused.
4072
- slowPoll: function() {
4073
- var input = this;
4074
- if (input.pollingFast) return;
4075
- input.polling.set(this.cm.options.pollInterval, function() {
4076
- input.poll();
4077
- if (input.cm.state.focused) input.slowPoll();
4078
- });
4079
- },
4080
 
4081
- // When an event has just come in that is likely to add or change
4082
- // something in the input textarea, we poll faster, to ensure that
4083
- // the change appears on the screen quickly.
4084
- fastPoll: function() {
4085
- var missed = false, input = this;
4086
- input.pollingFast = true;
4087
- function p() {
4088
- var changed = input.poll();
4089
- if (!changed && !missed) {missed = true; input.polling.set(60, p);}
4090
- else {input.pollingFast = false; input.slowPoll();}
4091
- }
4092
- input.polling.set(20, p);
4093
- },
4094
 
4095
- // Read input from the textarea, and update the document to match.
4096
- // When something is selected, it is present in the textarea, and
4097
- // selected (unless it is huge, in which case a placeholder is
4098
- // used). When nothing is selected, the cursor sits after previously
4099
- // seen text (can be empty), which is stored in prevInput (we must
4100
- // not reset the textarea when typing, because that breaks IME).
4101
- poll: function() {
4102
- var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
4103
- // Since this is called a *lot*, try to bail out as cheaply as
4104
- // possible when it is clear that nothing happened. hasSelection
4105
- // will be the case when there is a lot of text in the textarea,
4106
- // in which case reading its value would be expensive.
4107
- if (this.contextMenuPending || !cm.state.focused ||
4108
- (hasSelection(input) && !prevInput && !this.composing) ||
4109
- cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
4110
- return false;
4111
 
4112
- var text = input.value;
4113
- // If nothing changed, bail.
4114
- if (text == prevInput && !cm.somethingSelected()) return false;
4115
- // Work around nonsensical selection resetting in IE9/10, and
4116
- // inexplicable appearance of private area unicode characters on
4117
- // some key combos in Mac (#2689).
4118
- if (ie && ie_version >= 9 && this.hasSelection === text ||
4119
- mac && /[\uf700-\uf7ff]/.test(text)) {
4120
- cm.display.input.reset();
4121
- return false;
4122
- }
4123
 
4124
- if (cm.doc.sel == cm.display.selForContextMenu) {
4125
- var first = text.charCodeAt(0);
4126
- if (first == 0x200b && !prevInput) prevInput = "\u200b";
4127
- if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); }
4128
- }
4129
- // Find the part of the input that is actually new
4130
- var same = 0, l = Math.min(prevInput.length, text.length);
4131
- while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
4132
-
4133
- var self = this;
4134
- runInOp(cm, function() {
4135
- applyTextInput(cm, text.slice(same), prevInput.length - same,
4136
- null, self.composing ? "*compose" : null);
4137
-
4138
- // Don't leave long text in the textarea, since it makes further polling slow
4139
- if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = "";
4140
- else self.prevInput = text;
4141
-
4142
- if (self.composing) {
4143
- self.composing.range.clear();
4144
- self.composing.range = cm.markText(self.composing.start, cm.getCursor("to"),
4145
- {className: "CodeMirror-composing"});
4146
- }
4147
- });
4148
- return true;
4149
- },
4150
 
4151
- ensurePolled: function() {
4152
- if (this.pollingFast && this.poll()) this.pollingFast = false;
4153
- },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4154
 
4155
- onKeyPress: function() {
4156
- if (ie && ie_version >= 9) this.hasSelection = null;
4157
- this.fastPoll();
4158
- },
 
 
 
 
 
 
 
4159
 
4160
- onContextMenu: function(e) {
4161
- var input = this, cm = input.cm, display = cm.display, te = input.textarea;
4162
- var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
4163
- if (!pos || presto) return; // Opera is difficult.
4164
-
4165
- // Reset the current text selection only if the click is done outside of the selection
4166
- // and 'resetSelectionOnContextMenu' option is true.
4167
- var reset = cm.options.resetSelectionOnContextMenu;
4168
- if (reset && cm.doc.sel.contains(pos) == -1)
4169
- operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
4170
-
4171
- var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;
4172
- input.wrapper.style.cssText = "position: absolute"
4173
- var wrapperBox = input.wrapper.getBoundingClientRect()
4174
- te.style.cssText = "position: absolute; width: 30px; height: 30px; top: " + (e.clientY - wrapperBox.top - 5) +
4175
- "px; left: " + (e.clientX - wrapperBox.left - 5) + "px; z-index: 1000; background: " +
4176
- (ie ? "rgba(255, 255, 255, .05)" : "transparent") +
4177
- "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
4178
- if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)
4179
- display.input.focus();
4180
- if (webkit) window.scrollTo(null, oldScrollY);
4181
- display.input.reset();
4182
- // Adds "Select all" to context menu in FF
4183
- if (!cm.somethingSelected()) te.value = input.prevInput = " ";
4184
- input.contextMenuPending = true;
4185
- display.selForContextMenu = cm.doc.sel;
4186
- clearTimeout(display.detectingSelectAll);
4187
-
4188
- // Select-all will be greyed out if there's nothing to select, so
4189
- // this adds a zero-width space so that we can later check whether
4190
- // it got selected.
4191
- function prepareSelectAllHack() {
4192
- if (te.selectionStart != null) {
4193
- var selected = cm.somethingSelected();
4194
- var extval = "\u200b" + (selected ? te.value : "");
4195
- te.value = "\u21da"; // Used to catch context-menu undo
4196
- te.value = extval;
4197
- input.prevInput = selected ? "" : "\u200b";
4198
- te.selectionStart = 1; te.selectionEnd = extval.length;
4199
- // Re-set this, in case some other handler touched the
4200
- // selection in the meantime.
4201
- display.selForContextMenu = cm.doc.sel;
4202
- }
4203
- }
4204
- function rehide() {
4205
- input.contextMenuPending = false;
4206
- input.wrapper.style.cssText = oldWrapperCSS
4207
- te.style.cssText = oldCSS;
4208
- if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);
4209
-
4210
- // Try to detect the user choosing select-all
4211
- if (te.selectionStart != null) {
4212
- if (!ie || (ie && ie_version < 9)) prepareSelectAllHack();
4213
- var i = 0, poll = function() {
4214
- if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
4215
- te.selectionEnd > 0 && input.prevInput == "\u200b")
4216
- operation(cm, commands.selectAll)(cm);
4217
- else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500);
4218
- else display.input.reset();
4219
- };
4220
- display.detectingSelectAll = setTimeout(poll, 200);
4221
- }
4222
- }
4223
 
4224
- if (ie && ie_version >= 9) prepareSelectAllHack();
4225
- if (captureRightClick) {
4226
- e_stop(e);
4227
- var mouseup = function() {
4228
- off(window, "mouseup", mouseup);
4229
- setTimeout(rehide, 20);
4230
- };
4231
- on(window, "mouseup", mouseup);
4232
- } else {
4233
- setTimeout(rehide, 50);
4234
- }
4235
- },
 
 
 
4236
 
4237
- readOnlyChanged: function(val) {
4238
- if (!val) this.reset();
4239
- },
 
 
 
 
 
 
 
 
 
 
 
4240
 
4241
- setUneditable: nothing,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4242
 
4243
- needsContentAttribute: false
4244
- }, TextareaInput.prototype);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4245
 
4246
- // CONTENTEDITABLE INPUT STYLE
 
 
 
 
 
 
4247
 
4248
- function ContentEditableInput(cm) {
4249
- this.cm = cm;
4250
- this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
4251
- this.polling = new Delayed();
4252
- this.gracePeriod = false;
 
 
 
4253
  }
 
 
4254
 
4255
- ContentEditableInput.prototype = copyObj({
4256
- init: function(display) {
4257
- var input = this, cm = input.cm;
4258
- var div = input.div = display.lineDiv;
4259
- disableBrowserMagic(div, cm.options.spellcheck);
4260
-
4261
- on(div, "paste", function(e) {
4262
- if (signalDOMEvent(cm, e) || handlePaste(e, cm)) return
4263
- // IE doesn't fire input events, so we schedule a read for the pasted content in this way
4264
- if (ie_version <= 11) setTimeout(operation(cm, function() {
4265
- if (!input.pollContent()) regChange(cm);
4266
- }), 20)
4267
- })
4268
 
4269
- on(div, "compositionstart", function(e) {
4270
- var data = e.data;
4271
- input.composing = {sel: cm.doc.sel, data: data, startData: data};
4272
- if (!data) return;
4273
- var prim = cm.doc.sel.primary();
4274
- var line = cm.getLine(prim.head.line);
4275
- var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length));
4276
- if (found > -1 && found <= prim.head.ch)
4277
- input.composing.sel = simpleSelection(Pos(prim.head.line, found),
4278
- Pos(prim.head.line, found + data.length));
4279
- });
4280
- on(div, "compositionupdate", function(e) {
4281
- input.composing.data = e.data;
4282
- });
4283
- on(div, "compositionend", function(e) {
4284
- var ours = input.composing;
4285
- if (!ours) return;
4286
- if (e.data != ours.startData && !/\u200b/.test(e.data))
4287
- ours.data = e.data;
4288
- // Need a small delay to prevent other code (input event,
4289
- // selection polling) from doing damage when fired right after
4290
- // compositionend.
4291
- setTimeout(function() {
4292
- if (!ours.handled)
4293
- input.applyComposition(ours);
4294
- if (input.composing == ours)
4295
- input.composing = null;
4296
- }, 50);
4297
- });
4298
-
4299
- on(div, "touchstart", function() {
4300
- input.forceCompositionEnd();
4301
- });
4302
-
4303
- on(div, "input", function() {
4304
- if (input.composing) return;
4305
- if (cm.isReadOnly() || !input.pollContent())
4306
- runInOp(input.cm, function() {regChange(cm);});
4307
- });
4308
-
4309
- function onCopyCut(e) {
4310
- if (signalDOMEvent(cm, e)) return
4311
- if (cm.somethingSelected()) {
4312
- lastCopied = {lineWise: false, text: cm.getSelections()};
4313
- if (e.type == "cut") cm.replaceSelection("", null, "cut");
4314
- } else if (!cm.options.lineWiseCopyCut) {
4315
- return;
4316
- } else {
4317
- var ranges = copyableRanges(cm);
4318
- lastCopied = {lineWise: true, text: ranges.text};
4319
- if (e.type == "cut") {
4320
- cm.operation(function() {
4321
- cm.setSelections(ranges.ranges, 0, sel_dontScroll);
4322
- cm.replaceSelection("", null, "cut");
4323
- });
4324
- }
4325
- }
4326
- if (e.clipboardData) {
4327
- e.clipboardData.clearData();
4328
- var content = lastCopied.text.join("\n")
4329
- // iOS exposes the clipboard API, but seems to discard content inserted into it
4330
- e.clipboardData.setData("Text", content);
4331
- if (e.clipboardData.getData("Text") == content) {
4332
- e.preventDefault();
4333
- return
4334
- }
4335
- }
4336
- // Old-fashioned briefly-focus-a-textarea hack
4337
- var kludge = hiddenTextarea(), te = kludge.firstChild;
4338
- cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
4339
- te.value = lastCopied.text.join("\n");
4340
- var hadFocus = document.activeElement;
4341
- selectInput(te);
4342
- setTimeout(function() {
4343
- cm.display.lineSpace.removeChild(kludge);
4344
- hadFocus.focus();
4345
- if (hadFocus == div) input.showPrimarySelection()
4346
- }, 50);
4347
- }
4348
- on(div, "copy", onCopyCut);
4349
- on(div, "cut", onCopyCut);
4350
- },
4351
 
4352
- prepareSelection: function() {
4353
- var result = prepareSelection(this.cm, false);
4354
- result.focus = this.cm.state.focused;
4355
- return result;
4356
- },
4357
 
4358
- showSelection: function(info, takeFocus) {
4359
- if (!info || !this.cm.display.view.length) return;
4360
- if (info.focus || takeFocus) this.showPrimarySelection();
4361
- this.showMultipleSelections(info);
4362
- },
4363
 
4364
- showPrimarySelection: function() {
4365
- var sel = window.getSelection(), prim = this.cm.doc.sel.primary();
4366
- var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset);
4367
- var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset);
4368
- if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
4369
- cmp(minPos(curAnchor, curFocus), prim.from()) == 0 &&
4370
- cmp(maxPos(curAnchor, curFocus), prim.to()) == 0)
4371
- return;
4372
 
4373
- var start = posToDOM(this.cm, prim.from());
4374
- var end = posToDOM(this.cm, prim.to());
4375
- if (!start && !end) return;
4376
-
4377
- var view = this.cm.display.view;
4378
- var old = sel.rangeCount && sel.getRangeAt(0);
4379
- if (!start) {
4380
- start = {node: view[0].measure.map[2], offset: 0};
4381
- } else if (!end) { // FIXME dangerously hacky
4382
- var measure = view[view.length - 1].measure;
4383
- var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
4384
- end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]};
4385
- }
 
 
 
 
 
 
 
 
 
4386
 
4387
- try { var rng = range(start.node, start.offset, end.offset, end.node); }
4388
- catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
4389
- if (rng) {
4390
- if (!gecko && this.cm.state.focused) {
4391
- sel.collapse(start.node, start.offset);
4392
- if (!rng.collapsed) sel.addRange(rng);
4393
- } else {
4394
- sel.removeAllRanges();
4395
- sel.addRange(rng);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4396
  }
4397
- if (old && sel.anchorNode == null) sel.addRange(old);
4398
- else if (gecko) this.startGracePeriod();
4399
  }
4400
- this.rememberSelection();
4401
- },
4402
 
4403
- startGracePeriod: function() {
4404
- var input = this;
4405
- clearTimeout(this.gracePeriod);
4406
- this.gracePeriod = setTimeout(function() {
4407
- input.gracePeriod = false;
4408
- if (input.selectionChanged())
4409
- input.cm.operation(function() { input.cm.curOp.selectionChanged = true; });
4410
- }, 20);
4411
- },
4412
 
4413
- showMultipleSelections: function(info) {
4414
- removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
4415
- removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
4416
- },
4417
 
4418
- rememberSelection: function() {
4419
- var sel = window.getSelection();
4420
- this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
4421
- this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
4422
- },
 
 
 
 
 
 
 
4423
 
4424
- selectionInEditor: function() {
4425
- var sel = window.getSelection();
4426
- if (!sel.rangeCount) return false;
4427
- var node = sel.getRangeAt(0).commonAncestorContainer;
4428
- return contains(this.div, node);
4429
- },
 
 
 
 
 
 
 
 
 
4430
 
4431
- focus: function() {
4432
- if (this.cm.options.readOnly != "nocursor") this.div.focus();
4433
- },
4434
- blur: function() { this.div.blur(); },
4435
- getField: function() { return this.div; },
 
 
 
 
 
 
 
 
4436
 
4437
- supportsTouch: function() { return true; },
 
 
 
 
 
4438
 
4439
- receivedFocus: function() {
4440
- var input = this;
4441
- if (this.selectionInEditor())
4442
- this.pollSelection();
4443
- else
4444
- runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; });
 
 
4445
 
4446
- function poll() {
4447
- if (input.cm.state.focused) {
4448
- input.pollSelection();
4449
- input.polling.set(input.cm.options.pollInterval, poll);
4450
- }
4451
- }
4452
- this.polling.set(this.cm.options.pollInterval, poll);
4453
- },
 
 
 
 
 
 
 
 
 
 
 
 
 
4454
 
4455
- selectionChanged: function() {
4456
- var sel = window.getSelection();
4457
- return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
4458
- sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset;
4459
- },
 
 
 
 
 
 
 
 
4460
 
4461
- pollSelection: function() {
4462
- if (!this.composing && !this.gracePeriod && this.selectionChanged()) {
4463
- var sel = window.getSelection(), cm = this.cm;
4464
- this.rememberSelection();
4465
- var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
4466
- var head = domToPos(cm, sel.focusNode, sel.focusOffset);
4467
- if (anchor && head) runInOp(cm, function() {
4468
- setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
4469
- if (anchor.bad || head.bad) cm.curOp.selectionChanged = true;
4470
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4471
  }
4472
- },
4473
-
4474
- pollContent: function() {
4475
- var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
4476
- var from = sel.from(), to = sel.to();
4477
- if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false;
 
 
 
 
 
 
 
4478
 
4479
- var fromIndex;
4480
- if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
4481
- var fromLine = lineNo(display.view[0].line);
4482
- var fromNode = display.view[0].node;
4483
- } else {
4484
- var fromLine = lineNo(display.view[fromIndex].line);
4485
- var fromNode = display.view[fromIndex - 1].node.nextSibling;
4486
- }
4487
- var toIndex = findViewIndex(cm, to.line);
4488
- if (toIndex == display.view.length - 1) {
4489
- var toLine = display.viewTo - 1;
4490
- var toNode = display.lineDiv.lastChild;
4491
- } else {
4492
- var toLine = lineNo(display.view[toIndex + 1].line) - 1;
4493
- var toNode = display.view[toIndex + 1].node.previousSibling;
4494
- }
 
 
 
 
4495
 
4496
- var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
4497
- var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
4498
- while (newText.length > 1 && oldText.length > 1) {
4499
- if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
4500
- else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
4501
- else break;
4502
- }
4503
 
4504
- var cutFront = 0, cutEnd = 0;
4505
- var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
4506
- while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
4507
- ++cutFront;
4508
- var newBot = lst(newText), oldBot = lst(oldText);
4509
- var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
4510
- oldBot.length - (oldText.length == 1 ? cutFront : 0));
4511
- while (cutEnd < maxCutEnd &&
4512
- newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
4513
- ++cutEnd;
4514
-
4515
- newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd);
4516
- newText[0] = newText[0].slice(cutFront);
4517
-
4518
- var chFrom = Pos(fromLine, cutFront);
4519
- var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
4520
- if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
4521
- replaceRange(cm.doc, newText, chFrom, chTo, "+input");
4522
- return true;
4523
- }
4524
- },
 
 
4525
 
4526
- ensurePolled: function() {
4527
- this.forceCompositionEnd();
4528
- },
4529
- reset: function() {
4530
- this.forceCompositionEnd();
4531
- },
4532
- forceCompositionEnd: function() {
4533
- if (!this.composing || this.composing.handled) return;
4534
- this.applyComposition(this.composing);
4535
- this.composing.handled = true;
4536
- this.div.blur();
4537
- this.div.focus();
4538
- },
4539
- applyComposition: function(composing) {
4540
- if (this.cm.isReadOnly())
4541
- operation(this.cm, regChange)(this.cm)
4542
- else if (composing.data && composing.data != composing.startData)
4543
- operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);
4544
- },
4545
 
4546
- setUneditable: function(node) {
4547
- node.contentEditable = "false"
4548
- },
 
 
 
 
 
 
 
 
4549
 
4550
- onKeyPress: function(e) {
4551
- e.preventDefault();
4552
- if (!this.cm.isReadOnly())
4553
- operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
4554
- },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4555
 
4556
- readOnlyChanged: function(val) {
4557
- this.div.contentEditable = String(val != "nocursor")
4558
- },
 
 
 
4559
 
4560
- onContextMenu: nothing,
4561
- resetPosition: nothing,
 
4562
 
4563
- needsContentAttribute: true
4564
- }, ContentEditableInput.prototype);
4565
 
4566
- function posToDOM(cm, pos) {
4567
- var view = findViewForLine(cm, pos.line);
4568
- if (!view || view.hidden) return null;
4569
- var line = getLine(cm.doc, pos.line);
4570
- var info = mapFromLineView(view, line, pos.line);
 
4571
 
4572
- var order = getOrder(line), side = "left";
4573
- if (order) {
4574
- var partPos = getBidiPartAt(order, pos.ch);
4575
- side = partPos % 2 ? "right" : "left";
4576
- }
4577
- var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
4578
- result.offset = result.collapse == "right" ? result.end : result.start;
4579
- return result;
4580
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4581
 
4582
- function badPos(pos, bad) { if (bad) pos.bad = true; return pos; }
 
 
 
 
 
 
 
 
 
 
 
4583
 
4584
- function domToPos(cm, node, offset) {
4585
- var lineNode;
4586
- if (node == cm.display.lineDiv) {
4587
- lineNode = cm.display.lineDiv.childNodes[offset];
4588
- if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true);
4589
- node = null; offset = 0;
4590
- } else {
4591
- for (lineNode = node;; lineNode = lineNode.parentNode) {
4592
- if (!lineNode || lineNode == cm.display.lineDiv) return null;
4593
- if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break;
 
 
4594
  }
4595
- }
4596
- for (var i = 0; i < cm.display.view.length; i++) {
4597
- var lineView = cm.display.view[i];
4598
- if (lineView.node == lineNode)
4599
- return locateNodeInLineView(lineView, node, offset);
4600
  }
4601
  }
 
4602
 
4603
- function locateNodeInLineView(lineView, node, offset) {
4604
- var wrapper = lineView.text.firstChild, bad = false;
4605
- if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true);
4606
- if (node == wrapper) {
4607
- bad = true;
4608
- node = wrapper.childNodes[offset];
4609
- offset = 0;
4610
- if (!node) {
4611
- var line = lineView.rest ? lst(lineView.rest) : lineView.line;
4612
- return badPos(Pos(lineNo(line), line.text.length), bad);
4613
- }
4614
- }
 
 
 
4615
 
4616
- var textNode = node.nodeType == 3 ? node : null, topNode = node;
4617
- if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
4618
- textNode = node.firstChild;
4619
- if (offset) offset = textNode.nodeValue.length;
4620
- }
4621
- while (topNode.parentNode != wrapper) topNode = topNode.parentNode;
4622
- var measure = lineView.measure, maps = measure.maps;
4623
-
4624
- function find(textNode, topNode, offset) {
4625
- for (var i = -1; i < (maps ? maps.length : 0); i++) {
4626
- var map = i < 0 ? measure.map : maps[i];
4627
- for (var j = 0; j < map.length; j += 3) {
4628
- var curNode = map[j + 2];
4629
- if (curNode == textNode || curNode == topNode) {
4630
- var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
4631
- var ch = map[j] + offset;
4632
- if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)];
4633
- return Pos(line, ch);
 
 
 
 
 
 
 
4634
  }
 
 
 
 
 
 
 
 
 
4635
  }
4636
  }
4637
- }
4638
- var found = find(textNode, topNode, offset);
4639
- if (found) return badPos(found, bad);
4640
 
4641
- // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
4642
- for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
4643
- found = find(after, after.firstChild, 0);
4644
- if (found)
4645
- return badPos(Pos(found.line, found.ch - dist), bad);
4646
- else
4647
- dist += after.textContent.length;
4648
- }
4649
- for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) {
4650
- found = find(before, before.firstChild, -1);
4651
- if (found)
4652
- return badPos(Pos(found.line, found.ch + dist), bad);
4653
- else
4654
- dist += before.textContent.length;
4655
  }
4656
- }
4657
 
4658
- function domTextBetween(cm, from, to, fromLine, toLine) {
4659
- var text = "", closing = false, lineSep = cm.doc.lineSeparator();
4660
- function recognizeMarker(id) { return function(marker) { return marker.id == id; }; }
4661
- function walk(node) {
4662
- if (node.nodeType == 1) {
4663
- var cmText = node.getAttribute("cm-text");
4664
- if (cmText != null) {
4665
- if (cmText == "") cmText = node.textContent.replace(/\u200b/g, "");
4666
- text += cmText;
4667
- return;
4668
- }
4669
- var markerID = node.getAttribute("cm-marker"), range;
4670
- if (markerID) {
4671
- var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
4672
- if (found.length && (range = found[0].find()))
4673
- text += getBetween(cm.doc, range.from, range.to).join(lineSep);
4674
- return;
4675
- }
4676
- if (node.getAttribute("contenteditable") == "false") return;
4677
- for (var i = 0; i < node.childNodes.length; i++)
4678
- walk(node.childNodes[i]);
4679
- if (/^(pre|div|p)$/i.test(node.nodeName))
4680
- closing = true;
4681
- } else if (node.nodeType == 3) {
4682
- var val = node.nodeValue;
4683
- if (!val) return;
4684
- if (closing) {
4685
- text += lineSep;
4686
- closing = false;
4687
  }
4688
- text += val;
 
 
4689
  }
 
 
4690
  }
4691
- for (;;) {
4692
- walk(from);
4693
- if (from == to) break;
4694
- from = from.nextSibling;
4695
- }
4696
- return text;
4697
  }
 
4698
 
4699
- CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
4700
 
4701
- // SELECTION / CURSOR
 
 
 
 
 
 
 
 
 
 
 
 
4702
 
4703
- // Selection objects are immutable. A new one is created every time
4704
- // the selection changes. A selection is one or more non-overlapping
4705
- // (and non-touching) ranges, sorted, and an integer that indicates
4706
- // which one is the primary selection (the one that's scrolled into
4707
- // view, that getCursor returns, etc).
4708
- function Selection(ranges, primIndex) {
4709
- this.ranges = ranges;
4710
- this.primIndex = primIndex;
4711
  }
 
 
4712
 
4713
- Selection.prototype = {
4714
- primary: function() { return this.ranges[this.primIndex]; },
4715
- equals: function(other) {
4716
- if (other == this) return true;
4717
- if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false;
4718
- for (var i = 0; i < this.ranges.length; i++) {
4719
- var here = this.ranges[i], there = other.ranges[i];
4720
- if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false;
4721
- }
4722
- return true;
4723
- },
4724
- deepCopy: function() {
4725
- for (var out = [], i = 0; i < this.ranges.length; i++)
4726
- out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head));
4727
- return new Selection(out, this.primIndex);
4728
- },
4729
- somethingSelected: function() {
4730
- for (var i = 0; i < this.ranges.length; i++)
4731
- if (!this.ranges[i].empty()) return true;
4732
- return false;
4733
- },
4734
- contains: function(pos, end) {
4735
- if (!end) end = pos;
4736
- for (var i = 0; i < this.ranges.length; i++) {
4737
- var range = this.ranges[i];
4738
- if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
4739
- return i;
4740
- }
4741
- return -1;
4742
  }
4743
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4744
 
4745
- function Range(anchor, head) {
4746
- this.anchor = anchor; this.head = head;
 
 
4747
  }
 
4748
 
4749
- Range.prototype = {
4750
- from: function() { return minPos(this.anchor, this.head); },
4751
- to: function() { return maxPos(this.anchor, this.head); },
4752
- empty: function() {
4753
- return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch;
4754
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4755
  };
4756
 
4757
- // Take an unsorted, potentially overlapping set of ranges, and
4758
- // build a selection out of it. 'Consumes' ranges array (modifying
4759
- // it).
4760
- function normalizeSelection(ranges, primIndex) {
4761
- var prim = ranges[primIndex];
4762
- ranges.sort(function(a, b) { return cmp(a.from(), b.from()); });
4763
- primIndex = indexOf(ranges, prim);
4764
- for (var i = 1; i < ranges.length; i++) {
4765
- var cur = ranges[i], prev = ranges[i - 1];
4766
- if (cmp(prev.to(), cur.from()) >= 0) {
4767
- var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
4768
- var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
4769
- if (i <= primIndex) --primIndex;
4770
- ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
4771
- }
4772
- }
4773
- return new Selection(ranges, primIndex);
4774
- }
4775
-
4776
- function simpleSelection(anchor, head) {
4777
- return new Selection([new Range(anchor, head || anchor)], 0);
4778
- }
4779
-
4780
- // Most of the external API clips given positions to make sure they
4781
- // actually exist within the document.
4782
- function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));}
4783
- function clipPos(doc, pos) {
4784
- if (pos.line < doc.first) return Pos(doc.first, 0);
4785
- var last = doc.first + doc.size - 1;
4786
- if (pos.line > last) return Pos(last, getLine(doc, last).text.length);
4787
- return clipToLen(pos, getLine(doc, pos.line).text.length);
4788
- }
4789
- function clipToLen(pos, linelen) {
4790
- var ch = pos.ch;
4791
- if (ch == null || ch > linelen) return Pos(pos.line, linelen);
4792
- else if (ch < 0) return Pos(pos.line, 0);
4793
- else return pos;
4794
- }
4795
- function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;}
4796
- function clipPosArray(doc, array) {
4797
- for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]);
4798
- return out;
4799
- }
4800
-
4801
- // SELECTION UPDATES
4802
-
4803
- // The 'scroll' parameter given to many of these indicated whether
4804
- // the new cursor position should be scrolled into view after
4805
- // modifying the selection.
4806
-
4807
- // If shift is held or the extend flag is set, extends a range to
4808
- // include a given position (and optionally a second position).
4809
- // Otherwise, simply returns the range between the given positions.
4810
- // Used for cursor motion and such.
4811
- function extendRange(doc, range, head, other) {
4812
- if (doc.cm && doc.cm.display.shift || doc.extend) {
4813
- var anchor = range.anchor;
4814
- if (other) {
4815
- var posBefore = cmp(head, anchor) < 0;
4816
- if (posBefore != (cmp(other, anchor) < 0)) {
4817
- anchor = head;
4818
- head = other;
4819
- } else if (posBefore != (cmp(head, other) < 0)) {
4820
- head = other;
4821
- }
4822
- }
4823
- return new Range(anchor, head);
4824
- } else {
4825
- return new Range(other || head, head);
4826
- }
4827
  }
 
4828
 
4829
- // Extend the primary selection range, discard the rest.
4830
- function extendSelection(doc, head, other, options) {
4831
- setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options);
 
 
 
 
 
4832
  }
 
 
4833
 
4834
- // Extend all selections (pos is an array of selections with length
4835
- // equal the number of selections)
4836
- function extendSelections(doc, heads, options) {
4837
- for (var out = [], i = 0; i < doc.sel.ranges.length; i++)
4838
- out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null);
4839
- var newSel = normalizeSelection(out, doc.sel.primIndex);
4840
- setSelection(doc, newSel, options);
 
 
 
 
 
 
 
 
4841
  }
 
 
 
 
 
 
 
 
 
 
 
4842
 
4843
- // Updates a single range in the selection.
4844
- function replaceOneSelection(doc, i, range, options) {
4845
- var ranges = doc.sel.ranges.slice(0);
4846
- ranges[i] = range;
4847
- setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4848
  }
 
4849
 
4850
- // Reset the selection to a single range.
4851
- function setSimpleSelection(doc, anchor, head, options) {
4852
- setSelection(doc, simpleSelection(anchor, head), options);
 
 
 
4853
  }
 
 
4854
 
4855
- // Give beforeSelectionChange handlers a change to influence a
4856
- // selection update.
4857
- function filterSelectionChange(doc, sel, options) {
4858
- var obj = {
4859
- ranges: sel.ranges,
4860
- update: function(ranges) {
4861
- this.ranges = [];
4862
- for (var i = 0; i < ranges.length; i++)
4863
- this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
4864
- clipPos(doc, ranges[i].head));
4865
- },
4866
- origin: options && options.origin
4867
- };
4868
- signal(doc, "beforeSelectionChange", doc, obj);
4869
- if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
4870
- if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1);
4871
- else return sel;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4872
  }
 
4873
 
4874
- function setSelectionReplaceHistory(doc, sel, options) {
4875
- var done = doc.history.done, last = lst(done);
4876
- if (last && last.ranges) {
4877
- done[done.length - 1] = sel;
4878
- setSelectionNoUndo(doc, sel, options);
4879
- } else {
4880
- setSelection(doc, sel, options);
 
4881
  }
 
4882
  }
4883
-
4884
- // Set a new selection.
4885
- function setSelection(doc, sel, options) {
4886
- setSelectionNoUndo(doc, sel, options);
4887
- addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
4888
  }
 
4889
 
4890
- function setSelectionNoUndo(doc, sel, options) {
4891
- if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
4892
- sel = filterSelectionChange(doc, sel, options);
4893
-
4894
- var bias = options && options.bias ||
4895
- (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
4896
- setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
 
 
 
 
 
 
 
4897
 
4898
- if (!(options && options.scroll === false) && doc.cm)
4899
- ensureCursorVisible(doc.cm);
 
 
 
 
4900
  }
 
4901
 
4902
- function setSelectionInner(doc, sel) {
4903
- if (sel.equals(doc.sel)) return;
 
 
 
 
 
 
 
 
 
 
4904
 
4905
- doc.sel = sel;
 
 
 
 
 
 
4906
 
4907
- if (doc.cm) {
4908
- doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
4909
- signalCursorActivity(doc.cm);
4910
- }
4911
- signalLater(doc, "cursorActivity", doc);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4912
  }
 
4913
 
4914
- // Verify that the selection does not partially select any atomic
4915
- // marked ranges.
4916
- function reCheckSelection(doc) {
4917
- setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll);
4918
- }
 
 
 
 
 
 
 
 
4919
 
4920
- // Return a selection that does not partially select any atomic
4921
- // ranges.
4922
- function skipAtomicInSelection(doc, sel, bias, mayClear) {
4923
- var out;
4924
- for (var i = 0; i < sel.ranges.length; i++) {
4925
- var range = sel.ranges[i];
4926
- var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
4927
- var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
4928
- var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
4929
- if (out || newAnchor != range.anchor || newHead != range.head) {
4930
- if (!out) out = sel.ranges.slice(0, i);
4931
- out[i] = new Range(newAnchor, newHead);
4932
- }
4933
- }
4934
- return out ? normalizeSelection(out, sel.primIndex) : sel;
4935
- }
4936
 
4937
- function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
4938
- var line = getLine(doc, pos.line);
4939
- if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
4940
- var sp = line.markedSpans[i], m = sp.marker;
4941
- if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
4942
- (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
4943
- if (mayClear) {
4944
- signal(m, "beforeCursorEnter");
4945
- if (m.explicitlyCleared) {
4946
- if (!line.markedSpans) break;
4947
- else {--i; continue;}
4948
- }
4949
- }
4950
- if (!m.atomic) continue;
4951
-
4952
- if (oldPos) {
4953
- var near = m.find(dir < 0 ? 1 : -1), diff;
4954
- if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)
4955
- near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null);
4956
- if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
4957
- return skipAtomicInner(doc, near, pos, dir, mayClear);
4958
- }
4959
 
4960
- var far = m.find(dir < 0 ? -1 : 1);
4961
- if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)
4962
- far = movePos(doc, far, dir, far.line == pos.line ? line : null);
4963
- return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null;
4964
- }
4965
- }
4966
- return pos;
4967
- }
4968
 
4969
- // Ensure a given position is not inside an atomic range.
4970
- function skipAtomic(doc, pos, oldPos, bias, mayClear) {
4971
- var dir = bias || 1;
4972
- var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
4973
- (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
4974
- skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
4975
- (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
4976
- if (!found) {
4977
- doc.cantEdit = true;
4978
- return Pos(doc.first, 0);
4979
- }
4980
- return found;
 
 
 
 
 
 
 
 
 
 
4981
  }
 
4982
 
4983
- function movePos(doc, pos, dir, line) {
4984
- if (dir < 0 && pos.ch == 0) {
4985
- if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1));
4986
- else return null;
4987
- } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
4988
- if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0);
4989
- else return null;
4990
- } else {
4991
- return new Pos(pos.line, pos.ch + dir);
4992
- }
4993
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4994
 
4995
- // SELECTION DRAWING
 
 
 
 
 
 
 
 
4996
 
4997
- function updateSelection(cm) {
4998
- cm.display.input.showSelection(cm.display.input.prepareSelection());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4999
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5000
 
5001
- function prepareSelection(cm, primary) {
5002
- var doc = cm.doc, result = {};
5003
- var curFragment = result.cursors = document.createDocumentFragment();
5004
- var selFragment = result.selection = document.createDocumentFragment();
 
 
 
 
 
 
 
5005
 
5006
- for (var i = 0; i < doc.sel.ranges.length; i++) {
5007
- if (primary === false && i == doc.sel.primIndex) continue;
5008
- var range = doc.sel.ranges[i];
5009
- if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) continue;
5010
- var collapsed = range.empty();
5011
- if (collapsed || cm.options.showCursorWhenSelecting)
5012
- drawSelectionCursor(cm, range.head, curFragment);
5013
- if (!collapsed)
5014
- drawSelectionRange(cm, range, selFragment);
5015
- }
5016
- return result;
5017
  }
 
5018
 
5019
- // Draws a cursor for the given range
5020
- function drawSelectionCursor(cm, head, output) {
5021
- var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine);
 
 
 
5022
 
5023
- var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
5024
- cursor.style.left = pos.left + "px";
5025
- cursor.style.top = pos.top + "px";
5026
- cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
 
 
5027
 
5028
- if (pos.other) {
5029
- // Secondary cursor, shown when on a 'jump' in bi-directional text
5030
- var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
5031
- otherCursor.style.display = "";
5032
- otherCursor.style.left = pos.other.left + "px";
5033
- otherCursor.style.top = pos.other.top + "px";
5034
- otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
5035
- }
5036
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5037
 
5038
- // Draws the given range as a highlighted selection
5039
- function drawSelectionRange(cm, range, output) {
5040
- var display = cm.display, doc = cm.doc;
5041
- var fragment = document.createDocumentFragment();
5042
- var padding = paddingH(cm.display), leftSide = padding.left;
5043
- var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
 
 
 
 
 
 
 
 
 
 
 
 
5044
 
5045
- function add(left, top, width, bottom) {
5046
- if (top < 0) top = 0;
5047
- top = Math.round(top);
5048
- bottom = Math.round(bottom);
5049
- fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
5050
- "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) +
5051
- "px; height: " + (bottom - top) + "px"));
5052
- }
5053
 
5054
- function drawForLine(line, fromArg, toArg) {
5055
- var lineObj = getLine(doc, line);
5056
- var lineLen = lineObj.text.length;
5057
- var start, end;
5058
- function coords(ch, bias) {
5059
- return charCoords(cm, Pos(line, ch), "div", lineObj, bias);
5060
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5061
 
5062
- iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {
5063
- var leftPos = coords(from, "left"), rightPos, left, right;
5064
- if (from == to) {
5065
- rightPos = leftPos;
5066
- left = right = leftPos.left;
5067
- } else {
5068
- rightPos = coords(to - 1, "right");
5069
- if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }
5070
- left = leftPos.left;
5071
- right = rightPos.right;
5072
- }
5073
- if (fromArg == null && from == 0) left = leftSide;
5074
- if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
5075
- add(left, leftPos.top, null, leftPos.bottom);
5076
- left = leftSide;
5077
- if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
5078
- }
5079
- if (toArg == null && to == lineLen) right = rightSide;
5080
- if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
5081
- start = leftPos;
5082
- if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
5083
- end = rightPos;
5084
- if (left < leftSide + 1) left = leftSide;
5085
- add(left, rightPos.top, right - left, rightPos.bottom);
5086
- });
5087
- return {start: start, end: end};
5088
- }
5089
-
5090
- var sFrom = range.from(), sTo = range.to();
5091
- if (sFrom.line == sTo.line) {
5092
- drawForLine(sFrom.line, sFrom.ch, sTo.ch);
5093
- } else {
5094
- var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
5095
- var singleVLine = visualLine(fromLine) == visualLine(toLine);
5096
- var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
5097
- var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
5098
- if (singleVLine) {
5099
- if (leftEnd.top < rightStart.top - 2) {
5100
- add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
5101
- add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
5102
- } else {
5103
- add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
5104
- }
5105
- }
5106
- if (leftEnd.bottom < rightStart.top)
5107
- add(leftSide, leftEnd.bottom, null, rightStart.top);
5108
- }
5109
-
5110
- output.appendChild(fragment);
5111
- }
5112
-
5113
- // Cursor-blinking
5114
- function restartBlink(cm) {
5115
- if (!cm.state.focused) return;
5116
- var display = cm.display;
5117
- clearInterval(display.blinker);
5118
- var on = true;
5119
- display.cursorDiv.style.visibility = "";
5120
- if (cm.options.cursorBlinkRate > 0)
5121
- display.blinker = setInterval(function() {
5122
- display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden";
5123
- }, cm.options.cursorBlinkRate);
5124
- else if (cm.options.cursorBlinkRate < 0)
5125
- display.cursorDiv.style.visibility = "hidden";
5126
- }
5127
-
5128
- // HIGHLIGHT WORKER
5129
-
5130
- function startWorker(cm, time) {
5131
- if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)
5132
- cm.state.highlight.set(time, bind(highlightWorker, cm));
5133
- }
5134
-
5135
- function highlightWorker(cm) {
5136
- var doc = cm.doc;
5137
- if (doc.frontier < doc.first) doc.frontier = doc.first;
5138
- if (doc.frontier >= cm.display.viewTo) return;
5139
- var end = +new Date + cm.options.workTime;
5140
- var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
5141
- var changedLines = [];
5142
-
5143
- doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
5144
- if (doc.frontier >= cm.display.viewFrom) { // Visible
5145
- var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength;
5146
- var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true);
5147
- line.styles = highlighted.styles;
5148
- var oldCls = line.styleClasses, newCls = highlighted.classes;
5149
- if (newCls) line.styleClasses = newCls;
5150
- else if (oldCls) line.styleClasses = null;
5151
- var ischange = !oldStyles || oldStyles.length != line.styles.length ||
5152
- oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
5153
- for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
5154
- if (ischange) changedLines.push(doc.frontier);
5155
- line.stateAfter = tooLong ? state : copyState(doc.mode, state);
5156
- } else {
5157
- if (line.text.length <= cm.options.maxHighlightLength)
5158
- processLine(cm, line.text, state);
5159
- line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
5160
- }
5161
- ++doc.frontier;
5162
- if (+new Date > end) {
5163
- startWorker(cm, cm.options.workDelay);
5164
- return true;
5165
- }
5166
- });
5167
- if (changedLines.length) runInOp(cm, function() {
5168
- for (var i = 0; i < changedLines.length; i++)
5169
- regLineChange(cm, changedLines[i], "text");
5170
- });
5171
- }
5172
 
5173
- // Finds the line to start with when starting a parse. Tries to
5174
- // find a line with a stateAfter, so that it can start with a
5175
- // valid state. If that fails, it returns the line with the
5176
- // smallest indentation, which tends to need the least context to
5177
- // parse correctly.
5178
- function findStartLine(cm, n, precise) {
5179
- var minindent, minline, doc = cm.doc;
5180
- var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
5181
- for (var search = n; search > lim; --search) {
5182
- if (search <= doc.first) return doc.first;
5183
- var line = getLine(doc, search - 1);
5184
- if (line.stateAfter && (!precise || search <= doc.frontier)) return search;
5185
- var indented = countColumn(line.text, null, cm.options.tabSize);
5186
- if (minline == null || minindent > indented) {
5187
- minline = search - 1;
5188
- minindent = indented;
5189
- }
5190
- }
5191
- return minline;
5192
- }
5193
 
5194
- function getStateBefore(cm, n, precise) {
5195
- var doc = cm.doc, display = cm.display;
5196
- if (!doc.mode.startState) return true;
5197
- var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter;
5198
- if (!state) state = startState(doc.mode);
5199
- else state = copyState(doc.mode, state);
5200
- doc.iter(pos, n, function(line) {
5201
- processLine(cm, line.text, state);
5202
- var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo;
5203
- line.stateAfter = save ? copyState(doc.mode, state) : null;
5204
- ++pos;
5205
- });
5206
- if (precise) doc.frontier = pos;
5207
- return state;
5208
- }
5209
-
5210
- // POSITION MEASUREMENT
5211
-
5212
- function paddingTop(display) {return display.lineSpace.offsetTop;}
5213
- function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;}
5214
- function paddingH(display) {
5215
- if (display.cachedPaddingH) return display.cachedPaddingH;
5216
- var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
5217
- var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
5218
- var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
5219
- if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data;
5220
- return data;
5221
- }
5222
-
5223
- function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; }
5224
- function displayWidth(cm) {
5225
- return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth;
5226
- }
5227
- function displayHeight(cm) {
5228
- return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight;
5229
- }
5230
-
5231
- // Ensure the lineView.wrapping.heights array is populated. This is
5232
- // an array of bottom offsets for the lines that make up a drawn
5233
- // line. When lineWrapping is on, there might be more than one
5234
- // height.
5235
- function ensureLineHeights(cm, lineView, rect) {
5236
- var wrapping = cm.options.lineWrapping;
5237
- var curWidth = wrapping && displayWidth(cm);
5238
- if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
5239
- var heights = lineView.measure.heights = [];
5240
- if (wrapping) {
5241
- lineView.measure.width = curWidth;
5242
- var rects = lineView.text.firstChild.getClientRects();
5243
- for (var i = 0; i < rects.length - 1; i++) {
5244
- var cur = rects[i], next = rects[i + 1];
5245
- if (Math.abs(cur.bottom - next.bottom) > 2)
5246
- heights.push((cur.bottom + next.top) / 2 - rect.top);
5247
- }
5248
- }
5249
- heights.push(rect.bottom - rect.top);
5250
- }
5251
- }
5252
-
5253
- // Find a line map (mapping character offsets to text nodes) and a
5254
- // measurement cache for the given line number. (A line view might
5255
- // contain multiple lines when collapsed ranges are present.)
5256
- function mapFromLineView(lineView, line, lineN) {
5257
- if (lineView.line == line)
5258
- return {map: lineView.measure.map, cache: lineView.measure.cache};
5259
- for (var i = 0; i < lineView.rest.length; i++)
5260
- if (lineView.rest[i] == line)
5261
- return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]};
5262
- for (var i = 0; i < lineView.rest.length; i++)
5263
- if (lineNo(lineView.rest[i]) > lineN)
5264
- return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true};
5265
- }
5266
-
5267
- // Render a line into the hidden node display.externalMeasured. Used
5268
- // when measurement is needed for a line that's not in the viewport.
5269
- function updateExternalMeasurement(cm, line) {
5270
- line = visualLine(line);
5271
- var lineN = lineNo(line);
5272
- var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
5273
- view.lineN = lineN;
5274
- var built = view.built = buildLineContent(cm, view);
5275
- view.text = built.pre;
5276
- removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
5277
- return view;
5278
- }
5279
-
5280
- // Get a {top, bottom, left, right} box (in line-local coordinates)
5281
- // for a given character.
5282
- function measureChar(cm, line, ch, bias) {
5283
- return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias);
5284
- }
5285
-
5286
- // Find a line view that corresponds to the given line number.
5287
- function findViewForLine(cm, lineN) {
5288
- if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
5289
- return cm.display.view[findViewIndex(cm, lineN)];
5290
- var ext = cm.display.externalMeasured;
5291
- if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
5292
- return ext;
5293
- }
5294
-
5295
- // Measurement can be split in two steps, the set-up work that
5296
- // applies to the whole line, and the measurement of the actual
5297
- // character. Functions like coordsChar, that need to do a lot of
5298
- // measurements in a row, can thus ensure that the set-up work is
5299
- // only done once.
5300
- function prepareMeasureForLine(cm, line) {
5301
- var lineN = lineNo(line);
5302
- var view = findViewForLine(cm, lineN);
5303
- if (view && !view.text) {
5304
- view = null;
5305
- } else if (view && view.changes) {
5306
- updateLineForChanges(cm, view, lineN, getDimensions(cm));
5307
- cm.curOp.forceUpdate = true;
5308
- }
5309
- if (!view)
5310
- view = updateExternalMeasurement(cm, line);
5311
-
5312
- var info = mapFromLineView(view, line, lineN);
5313
- return {
5314
- line: line, view: view, rect: null,
5315
- map: info.map, cache: info.cache, before: info.before,
5316
- hasHeights: false
5317
- };
5318
  }
 
5319
 
5320
- // Given a prepared measurement object, measures the position of an
5321
- // actual character (or fetches it from the cache).
5322
- function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
5323
- if (prepared.before) ch = -1;
5324
- var key = ch + (bias || ""), found;
5325
- if (prepared.cache.hasOwnProperty(key)) {
5326
- found = prepared.cache[key];
5327
- } else {
5328
- if (!prepared.rect)
5329
- prepared.rect = prepared.view.text.getBoundingClientRect();
5330
- if (!prepared.hasHeights) {
5331
- ensureLineHeights(cm, prepared.view, prepared.rect);
5332
- prepared.hasHeights = true;
5333
- }
5334
- found = measureCharInner(cm, prepared, ch, bias);
5335
- if (!found.bogus) prepared.cache[key] = found;
5336
- }
5337
- return {left: found.left, right: found.right,
5338
- top: varHeight ? found.rtop : found.top,
5339
- bottom: varHeight ? found.rbottom : found.bottom};
5340
- }
5341
-
5342
- var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
5343
-
5344
- function nodeAndOffsetInLineMap(map, ch, bias) {
5345
- var node, start, end, collapse;
5346
- // First, search the line map for the text node corresponding to,
5347
- // or closest to, the target character.
5348
- for (var i = 0; i < map.length; i += 3) {
5349
- var mStart = map[i], mEnd = map[i + 1];
5350
- if (ch < mStart) {
5351
- start = 0; end = 1;
5352
- collapse = "left";
5353
- } else if (ch < mEnd) {
5354
- start = ch - mStart;
5355
- end = start + 1;
5356
- } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
5357
- end = mEnd - mStart;
5358
- start = end - 1;
5359
- if (ch >= mEnd) collapse = "right";
5360
- }
5361
- if (start != null) {
5362
- node = map[i + 2];
5363
- if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
5364
- collapse = bias;
5365
- if (bias == "left" && start == 0)
5366
- while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
5367
- node = map[(i -= 3) + 2];
5368
- collapse = "left";
5369
- }
5370
- if (bias == "right" && start == mEnd - mStart)
5371
- while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
5372
- node = map[(i += 3) + 2];
5373
- collapse = "right";
5374
- }
5375
- break;
5376
  }
 
 
 
5377
  }
5378
- return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd};
5379
- }
5380
-
5381
- function getUsefulRect(rects, bias) {
5382
- var rect = nullRect
5383
- if (bias == "left") for (var i = 0; i < rects.length; i++) {
5384
- if ((rect = rects[i]).left != rect.right) break
5385
- } else for (var i = rects.length - 1; i >= 0; i--) {
5386
- if ((rect = rects[i]).left != rect.right) break
5387
  }
5388
- return rect
 
 
5389
  }
 
5390
 
5391
- function measureCharInner(cm, prepared, ch, bias) {
5392
- var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
5393
- var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5394
 
5395
- var rect;
5396
- if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
5397
- for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned
5398
- while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start;
5399
- while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end;
5400
- if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)
5401
- rect = node.parentNode.getBoundingClientRect();
5402
- else
5403
- rect = getUsefulRect(range(node, start, end).getClientRects(), bias)
5404
- if (rect.left || rect.right || start == 0) break;
5405
- end = start;
5406
- start = start - 1;
5407
- collapse = "right";
5408
- }
5409
- if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect);
5410
- } else { // If it is a widget, simply get the box for the whole widget.
5411
- if (start > 0) collapse = bias = "right";
5412
- var rects;
5413
- if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
5414
- rect = rects[bias == "right" ? rects.length - 1 : 0];
5415
- else
5416
- rect = node.getBoundingClientRect();
5417
- }
5418
- if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
5419
- var rSpan = node.parentNode.getClientRects()[0];
5420
- if (rSpan)
5421
- rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom};
5422
- else
5423
- rect = nullRect;
5424
- }
5425
 
5426
- var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
5427
- var mid = (rtop + rbot) / 2;
5428
- var heights = prepared.view.measure.heights;
5429
- for (var i = 0; i < heights.length - 1; i++)
5430
- if (mid < heights[i]) break;
5431
- var top = i ? heights[i - 1] : 0, bot = heights[i];
5432
- var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
5433
- right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
5434
- top: top, bottom: bot};
5435
- if (!rect.left && !rect.right) result.bogus = true;
5436
- if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
 
 
 
 
5437
 
5438
- return result;
5439
- }
 
 
 
 
5440
 
5441
- // Work around problem with bounding client rects on ranges being
5442
- // returned incorrectly when zoomed on IE10 and below.
5443
- function maybeUpdateRectForZooming(measure, rect) {
5444
- if (!window.screen || screen.logicalXDPI == null ||
5445
- screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
5446
- return rect;
5447
- var scaleX = screen.logicalXDPI / screen.deviceXDPI;
5448
- var scaleY = screen.logicalYDPI / screen.deviceYDPI;
5449
- return {left: rect.left * scaleX, right: rect.right * scaleX,
5450
- top: rect.top * scaleY, bottom: rect.bottom * scaleY};
5451
- }
5452
-
5453
- function clearLineMeasurementCacheFor(lineView) {
5454
- if (lineView.measure) {
5455
- lineView.measure.cache = {};
5456
- lineView.measure.heights = null;
5457
- if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
5458
- lineView.measure.caches[i] = {};
5459
- }
5460
- }
5461
-
5462
- function clearLineMeasurementCache(cm) {
5463
- cm.display.externalMeasure = null;
5464
- removeChildren(cm.display.lineMeasure);
5465
- for (var i = 0; i < cm.display.view.length; i++)
5466
- clearLineMeasurementCacheFor(cm.display.view[i]);
5467
- }
5468
-
5469
- function clearCaches(cm) {
5470
- clearLineMeasurementCache(cm);
5471
- cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
5472
- if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;
5473
- cm.display.lineNumChars = null;
5474
- }
5475
-
5476
- function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }
5477
- function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }
5478
-
5479
- // Converts a {top, bottom, left, right} box from line-local
5480
- // coordinates into another coordinate system. Context may be one of
5481
- // "line", "div" (display.lineDiv), "local"/null (editor), "window",
5482
- // or "page".
5483
- function intoCoordSystem(cm, lineObj, rect, context) {
5484
- if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
5485
- var size = widgetHeight(lineObj.widgets[i]);
5486
- rect.top += size; rect.bottom += size;
5487
- }
5488
- if (context == "line") return rect;
5489
- if (!context) context = "local";
5490
- var yOff = heightAtLine(lineObj);
5491
- if (context == "local") yOff += paddingTop(cm.display);
5492
- else yOff -= cm.display.viewOffset;
5493
- if (context == "page" || context == "window") {
5494
- var lOff = cm.display.lineSpace.getBoundingClientRect();
5495
- yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
5496
- var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
5497
- rect.left += xOff; rect.right += xOff;
5498
- }
5499
- rect.top += yOff; rect.bottom += yOff;
5500
- return rect;
5501
- }
5502
-
5503
- // Coverts a box from "div" coords to another coordinate system.
5504
- // Context may be "window", "page", "div", or "local"/null.
5505
- function fromCoordSystem(cm, coords, context) {
5506
- if (context == "div") return coords;
5507
- var left = coords.left, top = coords.top;
5508
- // First move into "page" coordinate system
5509
- if (context == "page") {
5510
- left -= pageScrollX();
5511
- top -= pageScrollY();
5512
- } else if (context == "local" || !context) {
5513
- var localBox = cm.display.sizer.getBoundingClientRect();
5514
- left += localBox.left;
5515
- top += localBox.top;
5516
- }
5517
-
5518
- var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
5519
- return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top};
5520
- }
5521
-
5522
- function charCoords(cm, pos, context, lineObj, bias) {
5523
- if (!lineObj) lineObj = getLine(cm.doc, pos.line);
5524
- return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context);
5525
- }
5526
-
5527
- // Returns a box for a given cursor position, which may have an
5528
- // 'other' property containing the position of the secondary cursor
5529
- // on a bidi boundary.
5530
- function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
5531
- lineObj = lineObj || getLine(cm.doc, pos.line);
5532
- if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);
5533
- function get(ch, right) {
5534
- var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
5535
- if (right) m.left = m.right; else m.right = m.left;
5536
- return intoCoordSystem(cm, lineObj, m, context);
5537
- }
5538
- function getBidi(ch, partPos) {
5539
- var part = order[partPos], right = part.level % 2;
5540
- if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
5541
- part = order[--partPos];
5542
- ch = bidiRight(part) - (part.level % 2 ? 0 : 1);
5543
- right = true;
5544
- } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
5545
- part = order[++partPos];
5546
- ch = bidiLeft(part) - part.level % 2;
5547
- right = false;
5548
- }
5549
- if (right && ch == part.to && ch > part.from) return get(ch - 1);
5550
- return get(ch, right);
5551
- }
5552
- var order = getOrder(lineObj), ch = pos.ch;
5553
- if (!order) return get(ch);
5554
- var partPos = getBidiPartAt(order, ch);
5555
- var val = getBidi(ch, partPos);
5556
- if (bidiOther != null) val.other = getBidi(ch, bidiOther);
5557
- return val;
5558
- }
5559
-
5560
- // Used to cheaply estimate the coordinates for a position. Used for
5561
- // intermediate scroll updates.
5562
- function estimateCoords(cm, pos) {
5563
- var left = 0, pos = clipPos(cm.doc, pos);
5564
- if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch;
5565
- var lineObj = getLine(cm.doc, pos.line);
5566
- var top = heightAtLine(lineObj) + paddingTop(cm.display);
5567
- return {left: left, right: left, top: top, bottom: top + lineObj.height};
5568
- }
5569
-
5570
- // Positions returned by coordsChar contain some extra information.
5571
- // xRel is the relative x position of the input coordinates compared
5572
- // to the found position (so xRel > 0 means the coordinates are to
5573
- // the right of the character position, for example). When outside
5574
- // is true, that means the coordinates lie outside the line's
5575
- // vertical range.
5576
- function PosWithInfo(line, ch, outside, xRel) {
5577
- var pos = Pos(line, ch);
5578
- pos.xRel = xRel;
5579
- if (outside) pos.outside = true;
5580
- return pos;
5581
- }
5582
-
5583
- // Compute the character position closest to the given coordinates.
5584
- // Input must be lineSpace-local ("div" coordinate system).
5585
- function coordsChar(cm, x, y) {
5586
- var doc = cm.doc;
5587
- y += cm.display.viewOffset;
5588
- if (y < 0) return PosWithInfo(doc.first, 0, true, -1);
5589
- var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
5590
- if (lineN > last)
5591
- return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);
5592
- if (x < 0) x = 0;
5593
-
5594
- var lineObj = getLine(doc, lineN);
5595
- for (;;) {
5596
- var found = coordsCharInner(cm, lineObj, lineN, x, y);
5597
- var merged = collapsedSpanAtEnd(lineObj);
5598
- var mergedPos = merged && merged.find(0, true);
5599
- if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
5600
- lineN = lineNo(lineObj = mergedPos.to.line);
5601
- else
5602
- return found;
5603
- }
5604
  }
 
5605
 
5606
- function coordsCharInner(cm, lineObj, lineNo, x, y) {
5607
- var innerOff = y - heightAtLine(lineObj);
5608
- var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;
5609
- var preparedMeasure = prepareMeasureForLine(cm, lineObj);
 
 
 
5610
 
5611
- function getX(ch) {
5612
- var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure);
5613
- wrongLine = true;
5614
- if (innerOff > sp.bottom) return sp.left - adjust;
5615
- else if (innerOff < sp.top) return sp.left + adjust;
5616
- else wrongLine = false;
5617
- return sp.left;
5618
- }
5619
-
5620
- var bidi = getOrder(lineObj), dist = lineObj.text.length;
5621
- var from = lineLeft(lineObj), to = lineRight(lineObj);
5622
- var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;
5623
-
5624
- if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);
5625
- // Do a binary search between these bounds.
5626
- for (;;) {
5627
- if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
5628
- var ch = x < fromX || x - fromX <= toX - x ? from : to;
5629
- var outside = ch == from ? fromOutside : toOutside
5630
- var xDiff = x - (ch == from ? fromX : toX);
5631
- // This is a kludge to handle the case where the coordinates
5632
- // are after a line-wrapped line. We should replace it with a
5633
- // more general handling of cursor positions around line
5634
- // breaks. (Issue #4078)
5635
- if (toOutside && !bidi && !/\s/.test(lineObj.text.charAt(ch)) && xDiff > 0 &&
5636
- ch < lineObj.text.length && preparedMeasure.view.measure.heights.length > 1) {
5637
- var charSize = measureCharPrepared(cm, preparedMeasure, ch, "right");
5638
- if (innerOff <= charSize.bottom && innerOff >= charSize.top && Math.abs(x - charSize.right) < xDiff) {
5639
- outside = false
5640
- ch++
5641
- xDiff = x - charSize.right
5642
- }
5643
- }
5644
- while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;
5645
- var pos = PosWithInfo(lineNo, ch, outside, xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0);
5646
- return pos;
5647
- }
5648
- var step = Math.ceil(dist / 2), middle = from + step;
5649
- if (bidi) {
5650
- middle = from;
5651
- for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
5652
- }
5653
- var middleX = getX(middle);
5654
- if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;}
5655
- else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;}
5656
- }
5657
- }
5658
-
5659
- var measureText;
5660
- // Compute the default text height.
5661
- function textHeight(display) {
5662
- if (display.cachedTextHeight != null) return display.cachedTextHeight;
5663
- if (measureText == null) {
5664
- measureText = elt("pre");
5665
- // Measure a bunch of lines, for browsers that compute
5666
- // fractional heights.
5667
- for (var i = 0; i < 49; ++i) {
5668
- measureText.appendChild(document.createTextNode("x"));
5669
- measureText.appendChild(elt("br"));
5670
- }
5671
- measureText.appendChild(document.createTextNode("x"));
5672
- }
5673
- removeChildrenAndAdd(display.measure, measureText);
5674
- var height = measureText.offsetHeight / 50;
5675
- if (height > 3) display.cachedTextHeight = height;
5676
- removeChildren(display.measure);
5677
- return height || 1;
5678
- }
5679
-
5680
- // Compute the default character width.
5681
- function charWidth(display) {
5682
- if (display.cachedCharWidth != null) return display.cachedCharWidth;
5683
- var anchor = elt("span", "xxxxxxxxxx");
5684
- var pre = elt("pre", [anchor]);
5685
- removeChildrenAndAdd(display.measure, pre);
5686
- var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
5687
- if (width > 2) display.cachedCharWidth = width;
5688
- return width || 10;
5689
- }
5690
-
5691
- // OPERATIONS
5692
-
5693
- // Operations are used to wrap a series of changes to the editor
5694
- // state in such a way that each change won't have to update the
5695
- // cursor and display (which would be awkward, slow, and
5696
- // error-prone). Instead, display updates are batched and then all
5697
- // combined and executed at once.
5698
-
5699
- var operationGroup = null;
5700
-
5701
- var nextOpId = 0;
5702
- // Start a new operation.
5703
- function startOperation(cm) {
5704
- cm.curOp = {
5705
- cm: cm,
5706
- viewChanged: false, // Flag that indicates that lines might need to be redrawn
5707
- startHeight: cm.doc.height, // Used to detect need to update scrollbar
5708
- forceUpdate: false, // Used to force a redraw
5709
- updateInput: null, // Whether to reset the input textarea
5710
- typing: false, // Whether this reset should be careful to leave existing text (for compositing)
5711
- changeObjs: null, // Accumulated changes, for firing change events
5712
- cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
5713
- cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
5714
- selectionChanged: false, // Whether the selection needs to be redrawn
5715
- updateMaxLine: false, // Set when the widest line needs to be determined anew
5716
- scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
5717
- scrollToPos: null, // Used to scroll to a specific position
5718
- focus: false,
5719
- id: ++nextOpId // Unique ID
5720
- };
5721
- if (operationGroup) {
5722
- operationGroup.ops.push(cm.curOp);
5723
- } else {
5724
- cm.curOp.ownsGroup = operationGroup = {
5725
- ops: [cm.curOp],
5726
- delayedCallbacks: []
5727
- };
5728
- }
5729
- }
5730
 
5731
- function fireCallbacksForOps(group) {
5732
- // Calls delayed callbacks and cursorActivity handlers until no
5733
- // new ones appear
5734
- var callbacks = group.delayedCallbacks, i = 0;
5735
- do {
5736
- for (; i < callbacks.length; i++)
5737
- callbacks[i].call(null);
5738
- for (var j = 0; j < group.ops.length; j++) {
5739
- var op = group.ops[j];
5740
- if (op.cursorActivityHandlers)
5741
- while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
5742
- op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm);
5743
- }
5744
- } while (i < callbacks.length);
5745
  }
 
5746
 
5747
- // Finish an operation, updating the display and signalling delayed events
5748
- function endOperation(cm) {
5749
- var op = cm.curOp, group = op.ownsGroup;
5750
- if (!group) return;
5751
 
5752
- try { fireCallbacksForOps(group); }
5753
- finally {
5754
- operationGroup = null;
5755
- for (var i = 0; i < group.ops.length; i++)
5756
- group.ops[i].cm.curOp = null;
5757
- endOperations(group);
5758
- }
5759
- }
 
 
 
 
 
 
 
 
 
5760
 
5761
- // The DOM updates done when an operation finishes are batched so
5762
- // that the minimum number of relayouts are required.
5763
- function endOperations(group) {
5764
- var ops = group.ops;
5765
- for (var i = 0; i < ops.length; i++) // Read DOM
5766
- endOperation_R1(ops[i]);
5767
- for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
5768
- endOperation_W1(ops[i]);
5769
- for (var i = 0; i < ops.length; i++) // Read DOM
5770
- endOperation_R2(ops[i]);
5771
- for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
5772
- endOperation_W2(ops[i]);
5773
- for (var i = 0; i < ops.length; i++) // Read DOM
5774
- endOperation_finish(ops[i]);
5775
- }
5776
 
5777
- function endOperation_R1(op) {
5778
- var cm = op.cm, display = cm.display;
5779
- maybeClipScrollbars(cm);
5780
- if (op.updateMaxLine) findMaxLine(cm);
5781
 
5782
- op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
5783
- op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
5784
- op.scrollToPos.to.line >= display.viewTo) ||
5785
- display.maxLineChanged && cm.options.lineWrapping;
5786
- op.update = op.mustUpdate &&
5787
- new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
 
5788
  }
 
5789
 
5790
- function endOperation_W1(op) {
5791
- op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5792
  }
5793
 
5794
- function endOperation_R2(op) {
5795
- var cm = op.cm, display = cm.display;
5796
- if (op.updatedDisplay) updateHeightsInViewport(cm);
5797
-
5798
- op.barMeasure = measureForScrollbars(cm);
5799
-
5800
- // If the max line changed since it was last measured, measure it,
5801
- // and ensure the document's width matches it.
5802
- // updateDisplay_W2 will use these properties to do the actual resizing
5803
- if (display.maxLineChanged && !cm.options.lineWrapping) {
5804
- op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
5805
- cm.display.sizerWidth = op.adjustWidthTo;
5806
- op.barMeasure.scrollWidth =
5807
- Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
5808
- op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
5809
- }
5810
-
5811
- if (op.updatedDisplay || op.selectionChanged)
5812
- op.preparedSelection = display.input.prepareSelection(op.focus);
5813
- }
5814
-
5815
- function endOperation_W2(op) {
5816
- var cm = op.cm;
5817
-
5818
- if (op.adjustWidthTo != null) {
5819
- cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
5820
- if (op.maxScrollLeft < cm.doc.scrollLeft)
5821
- setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true);
5822
- cm.display.maxLineChanged = false;
5823
- }
5824
-
5825
- var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus())
5826
- if (op.preparedSelection)
5827
- cm.display.input.showSelection(op.preparedSelection, takeFocus);
5828
- if (op.updatedDisplay || op.startHeight != cm.doc.height)
5829
- updateScrollbars(cm, op.barMeasure);
5830
- if (op.updatedDisplay)
5831
- setDocumentHeight(cm, op.barMeasure);
5832
-
5833
- if (op.selectionChanged) restartBlink(cm);
5834
-
5835
- if (cm.state.focused && op.updateInput)
5836
- cm.display.input.reset(op.typing);
5837
- if (takeFocus) ensureFocus(op.cm);
5838
- }
5839
-
5840
- function endOperation_finish(op) {
5841
- var cm = op.cm, display = cm.display, doc = cm.doc;
5842
-
5843
- if (op.updatedDisplay) postUpdateDisplay(cm, op.update);
5844
-
5845
- // Abort mouse wheel delta measurement, when scrolling explicitly
5846
- if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
5847
- display.wheelStartX = display.wheelStartY = null;
5848
-
5849
- // Propagate the scroll position to the actual DOM scroller
5850
- if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
5851
- doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
5852
- display.scrollbars.setScrollTop(doc.scrollTop);
5853
- display.scroller.scrollTop = doc.scrollTop;
5854
- }
5855
- if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
5856
- doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft));
5857
- display.scrollbars.setScrollLeft(doc.scrollLeft);
5858
- display.scroller.scrollLeft = doc.scrollLeft;
5859
- alignHorizontally(cm);
5860
- }
5861
- // If we need to scroll a specific position into view, do so.
5862
- if (op.scrollToPos) {
5863
- var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
5864
- clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
5865
- if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords);
5866
- }
5867
-
5868
- // Fire events for markers that are hidden/unidden by editing or
5869
- // undoing
5870
- var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
5871
- if (hidden) for (var i = 0; i < hidden.length; ++i)
5872
- if (!hidden[i].lines.length) signal(hidden[i], "hide");
5873
- if (unhidden) for (var i = 0; i < unhidden.length; ++i)
5874
- if (unhidden[i].lines.length) signal(unhidden[i], "unhide");
5875
 
5876
- if (display.wrapper.offsetHeight)
5877
- doc.scrollTop = cm.display.scroller.scrollTop;
 
 
 
 
 
 
 
 
 
 
 
5878
 
5879
- // Fire change events, and delayed event handlers
5880
- if (op.changeObjs)
5881
- signal(cm, "changes", cm, op.changeObjs);
5882
- if (op.update)
5883
- op.update.finish();
5884
- }
5885
 
5886
- // Run the given function in an operation
5887
- function runInOp(cm, f) {
5888
- if (cm.curOp) return f();
5889
- startOperation(cm);
5890
- try { return f(); }
5891
- finally { endOperation(cm); }
5892
- }
5893
- // Wraps a function in an operation. Returns the wrapped function.
5894
- function operation(cm, f) {
5895
- return function() {
5896
- if (cm.curOp) return f.apply(cm, arguments);
5897
- startOperation(cm);
5898
- try { return f.apply(cm, arguments); }
5899
- finally { endOperation(cm); }
5900
- };
5901
- }
5902
- // Used to add methods to editor and doc instances, wrapping them in
5903
- // operations.
5904
- function methodOp(f) {
5905
- return function() {
5906
- if (this.curOp) return f.apply(this, arguments);
5907
- startOperation(this);
5908
- try { return f.apply(this, arguments); }
5909
- finally { endOperation(this); }
5910
- };
5911
- }
5912
- function docMethodOp(f) {
5913
- return function() {
5914
- var cm = this.cm;
5915
- if (!cm || cm.curOp) return f.apply(this, arguments);
5916
- startOperation(cm);
5917
- try { return f.apply(this, arguments); }
5918
- finally { endOperation(cm); }
5919
- };
5920
- }
5921
 
5922
- // VIEW TRACKING
5923
-
5924
- // These objects are used to represent the visible (currently drawn)
5925
- // part of the document. A LineView may correspond to multiple
5926
- // logical lines, if those are connected by collapsed ranges.
5927
- function LineView(doc, line, lineN) {
5928
- // The starting line
5929
- this.line = line;
5930
- // Continuing lines, if any
5931
- this.rest = visualLineContinued(line);
5932
- // Number of logical lines in this visual line
5933
- this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
5934
- this.node = this.text = null;
5935
- this.hidden = lineIsHidden(doc, line);
5936
- }
5937
-
5938
- // Create a range of LineView objects for the given lines.
5939
- function buildViewArray(cm, from, to) {
5940
- var array = [], nextPos;
5941
- for (var pos = from; pos < to; pos = nextPos) {
5942
- var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
5943
- nextPos = pos + view.size;
5944
- array.push(view);
5945
- }
5946
- return array;
5947
- }
5948
-
5949
- // Updates the display.view data structure for a given change to the
5950
- // document. From and to are in pre-change coordinates. Lendiff is
5951
- // the amount of lines added or subtracted by the change. This is
5952
- // used for changes that span multiple lines, or change the way
5953
- // lines are divided into visual lines. regLineChange (below)
5954
- // registers single-line changes.
5955
- function regChange(cm, from, to, lendiff) {
5956
- if (from == null) from = cm.doc.first;
5957
- if (to == null) to = cm.doc.first + cm.doc.size;
5958
- if (!lendiff) lendiff = 0;
5959
-
5960
- var display = cm.display;
5961
- if (lendiff && to < display.viewTo &&
5962
- (display.updateLineNumbers == null || display.updateLineNumbers > from))
5963
- display.updateLineNumbers = from;
5964
-
5965
- cm.curOp.viewChanged = true;
5966
-
5967
- if (from >= display.viewTo) { // Change after
5968
- if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
5969
- resetView(cm);
5970
- } else if (to <= display.viewFrom) { // Change before
5971
- if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
5972
- resetView(cm);
5973
- } else {
5974
- display.viewFrom += lendiff;
5975
- display.viewTo += lendiff;
5976
- }
5977
- } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
5978
- resetView(cm);
5979
- } else if (from <= display.viewFrom) { // Top overlap
5980
- var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
5981
- if (cut) {
5982
- display.view = display.view.slice(cut.index);
5983
- display.viewFrom = cut.lineN;
5984
- display.viewTo += lendiff;
5985
- } else {
5986
- resetView(cm);
5987
- }
5988
- } else if (to >= display.viewTo) { // Bottom overlap
5989
- var cut = viewCuttingPoint(cm, from, from, -1);
5990
- if (cut) {
5991
- display.view = display.view.slice(0, cut.index);
5992
- display.viewTo = cut.lineN;
5993
- } else {
5994
- resetView(cm);
5995
- }
5996
- } else { // Gap in the middle
5997
- var cutTop = viewCuttingPoint(cm, from, from, -1);
5998
- var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
5999
- if (cutTop && cutBot) {
6000
- display.view = display.view.slice(0, cutTop.index)
6001
- .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
6002
- .concat(display.view.slice(cutBot.index));
6003
- display.viewTo += lendiff;
6004
- } else {
6005
- resetView(cm);
6006
- }
6007
- }
6008
 
6009
- var ext = display.externalMeasured;
6010
- if (ext) {
6011
- if (to < ext.lineN)
6012
- ext.lineN += lendiff;
6013
- else if (from < ext.lineN + ext.size)
6014
- display.externalMeasured = null;
6015
- }
6016
- }
6017
-
6018
- // Register a change to a single line. Type must be one of "text",
6019
- // "gutter", "class", "widget"
6020
- function regLineChange(cm, line, type) {
6021
- cm.curOp.viewChanged = true;
6022
- var display = cm.display, ext = cm.display.externalMeasured;
6023
- if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
6024
- display.externalMeasured = null;
6025
-
6026
- if (line < display.viewFrom || line >= display.viewTo) return;
6027
- var lineView = display.view[findViewIndex(cm, line)];
6028
- if (lineView.node == null) return;
6029
- var arr = lineView.changes || (lineView.changes = []);
6030
- if (indexOf(arr, type) == -1) arr.push(type);
6031
- }
6032
-
6033
- // Clear the view.
6034
- function resetView(cm) {
6035
- cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
6036
- cm.display.view = [];
6037
- cm.display.viewOffset = 0;
6038
- }
6039
-
6040
- // Find the view element corresponding to a given line. Return null
6041
- // when the line isn't visible.
6042
- function findViewIndex(cm, n) {
6043
- if (n >= cm.display.viewTo) return null;
6044
- n -= cm.display.viewFrom;
6045
- if (n < 0) return null;
6046
- var view = cm.display.view;
6047
- for (var i = 0; i < view.length; i++) {
6048
- n -= view[i].size;
6049
- if (n < 0) return i;
6050
- }
6051
- }
6052
-
6053
- function viewCuttingPoint(cm, oldN, newN, dir) {
6054
- var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
6055
- if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
6056
- return {index: index, lineN: newN};
6057
- for (var i = 0, n = cm.display.viewFrom; i < index; i++)
6058
- n += view[i].size;
6059
- if (n != oldN) {
6060
- if (dir > 0) {
6061
- if (index == view.length - 1) return null;
6062
- diff = (n + view[index].size) - oldN;
6063
- index++;
6064
- } else {
6065
- diff = n - oldN;
6066
- }
6067
- oldN += diff; newN += diff;
6068
  }
6069
- while (visualLineNo(cm.doc, newN) != newN) {
6070
- if (index == (dir < 0 ? 0 : view.length - 1)) return null;
6071
- newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
6072
- index += dir;
6073
- }
6074
- return {index: index, lineN: newN};
6075
  }
 
 
 
 
6076
 
6077
- // Force the view to cover a given range, adding empty view element
6078
- // or clipping off existing ones as needed.
6079
- function adjustView(cm, from, to) {
6080
- var display = cm.display, view = display.view;
6081
- if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
6082
- display.view = buildViewArray(cm, from, to);
6083
- display.viewFrom = from;
6084
- } else {
6085
- if (display.viewFrom > from)
6086
- display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view);
6087
- else if (display.viewFrom < from)
6088
- display.view = display.view.slice(findViewIndex(cm, from));
6089
- display.viewFrom = from;
6090
- if (display.viewTo < to)
6091
- display.view = display.view.concat(buildViewArray(cm, display.viewTo, to));
6092
- else if (display.viewTo > to)
6093
- display.view = display.view.slice(0, findViewIndex(cm, to));
6094
- }
6095
- display.viewTo = to;
6096
- }
6097
-
6098
- // Count the number of lines in the view whose DOM representation is
6099
- // out of date (or nonexistent).
6100
- function countDirtyView(cm) {
6101
- var view = cm.display.view, dirty = 0;
6102
- for (var i = 0; i < view.length; i++) {
6103
- var lineView = view[i];
6104
- if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty;
6105
- }
6106
- return dirty;
6107
- }
6108
-
6109
- // EVENT HANDLERS
6110
-
6111
- // Attach the necessary event handlers when initializing the editor
6112
- function registerEventHandlers(cm) {
6113
- var d = cm.display;
6114
- on(d.scroller, "mousedown", operation(cm, onMouseDown));
6115
- // Older IE's will not fire a second mousedown for a double click
6116
- if (ie && ie_version < 11)
6117
- on(d.scroller, "dblclick", operation(cm, function(e) {
6118
- if (signalDOMEvent(cm, e)) return;
6119
- var pos = posFromMouse(cm, e);
6120
- if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;
6121
- e_preventDefault(e);
6122
- var word = cm.findWordAt(pos);
6123
- extendSelection(cm.doc, word.anchor, word.head);
6124
- }));
6125
- else
6126
- on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });
6127
- // Some browsers fire contextmenu *after* opening the menu, at
6128
- // which point we can't mess with it anymore. Context menu is
6129
- // handled in onMouseDown for these browsers.
6130
- if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});
6131
-
6132
- // Used to suppress mouse event handling when a touch happens
6133
- var touchFinished, prevTouch = {end: 0};
6134
- function finishTouch() {
6135
- if (d.activeTouch) {
6136
- touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000);
6137
- prevTouch = d.activeTouch;
6138
- prevTouch.end = +new Date;
6139
- }
6140
- };
6141
- function isMouseLikeTouchEvent(e) {
6142
- if (e.touches.length != 1) return false;
6143
- var touch = e.touches[0];
6144
- return touch.radiusX <= 1 && touch.radiusY <= 1;
6145
- }
6146
- function farAway(touch, other) {
6147
- if (other.left == null) return true;
6148
- var dx = other.left - touch.left, dy = other.top - touch.top;
6149
- return dx * dx + dy * dy > 20 * 20;
6150
- }
6151
- on(d.scroller, "touchstart", function(e) {
6152
- if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) {
6153
- clearTimeout(touchFinished);
6154
- var now = +new Date;
6155
- d.activeTouch = {start: now, moved: false,
6156
- prev: now - prevTouch.end <= 300 ? prevTouch : null};
6157
- if (e.touches.length == 1) {
6158
- d.activeTouch.left = e.touches[0].pageX;
6159
- d.activeTouch.top = e.touches[0].pageY;
6160
- }
6161
- }
6162
- });
6163
- on(d.scroller, "touchmove", function() {
6164
- if (d.activeTouch) d.activeTouch.moved = true;
6165
- });
6166
- on(d.scroller, "touchend", function(e) {
6167
- var touch = d.activeTouch;
6168
- if (touch && !eventInWidget(d, e) && touch.left != null &&
6169
- !touch.moved && new Date - touch.start < 300) {
6170
- var pos = cm.coordsChar(d.activeTouch, "page"), range;
6171
- if (!touch.prev || farAway(touch, touch.prev)) // Single tap
6172
- range = new Range(pos, pos);
6173
- else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
6174
- range = cm.findWordAt(pos);
6175
- else // Triple tap
6176
- range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0)));
6177
- cm.setSelection(range.anchor, range.head);
6178
- cm.focus();
6179
- e_preventDefault(e);
6180
- }
6181
- finishTouch();
6182
- });
6183
- on(d.scroller, "touchcancel", finishTouch);
6184
-
6185
- // Sync scrolling between fake scrollbars and real scrollable
6186
- // area, ensure viewport is updated when scrolling.
6187
- on(d.scroller, "scroll", function() {
6188
- if (d.scroller.clientHeight) {
6189
- setScrollTop(cm, d.scroller.scrollTop);
6190
- setScrollLeft(cm, d.scroller.scrollLeft, true);
6191
- signal(cm, "scroll", cm);
6192
- }
6193
- });
6194
-
6195
- // Listen to wheel events in order to try and update the viewport on time.
6196
- on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
6197
- on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
6198
 
6199
- // Prevent wrapper from ever scrolling
6200
- on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6201
 
6202
- d.dragFunctions = {
6203
- enter: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);},
6204
- over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
6205
- start: function(e){onDragStart(cm, e);},
6206
- drop: operation(cm, onDrop),
6207
- leave: function(e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}
6208
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
6209
 
6210
- var inp = d.input.getField();
6211
- on(inp, "keyup", function(e) { onKeyUp.call(cm, e); });
6212
- on(inp, "keydown", operation(cm, onKeyDown));
6213
- on(inp, "keypress", operation(cm, onKeyPress));
6214
- on(inp, "focus", bind(onFocus, cm));
6215
- on(inp, "blur", bind(onBlur, cm));
6216
- }
6217
-
6218
- function dragDropChanged(cm, value, old) {
6219
- var wasOn = old && old != CodeMirror.Init;
6220
- if (!value != !wasOn) {
6221
- var funcs = cm.display.dragFunctions;
6222
- var toggle = value ? on : off;
6223
- toggle(cm.display.scroller, "dragstart", funcs.start);
6224
- toggle(cm.display.scroller, "dragenter", funcs.enter);
6225
- toggle(cm.display.scroller, "dragover", funcs.over);
6226
- toggle(cm.display.scroller, "dragleave", funcs.leave);
6227
- toggle(cm.display.scroller, "drop", funcs.drop);
6228
- }
6229
- }
6230
-
6231
- // Called when the window resizes
6232
- function onResize(cm) {
6233
- var d = cm.display;
6234
- if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)
6235
- return;
6236
- // Might be a text scaling operation, clear size caches.
6237
- d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
6238
- d.scrollbarsClipped = false;
6239
- cm.setSize();
6240
- }
6241
-
6242
- // MOUSE EVENTS
6243
-
6244
- // Return true when the given mouse event happened in a widget
6245
- function eventInWidget(display, e) {
6246
- for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
6247
- if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
6248
- (n.parentNode == display.sizer && n != display.mover))
6249
- return true;
6250
- }
6251
- }
6252
-
6253
- // Given a mouse event, find the corresponding position. If liberal
6254
- // is false, it checks whether a gutter or scrollbar was clicked,
6255
- // and returns null if it was. forRect is used by rectangular
6256
- // selections, and tries to estimate a character position even for
6257
- // coordinates beyond the right of the text.
6258
- function posFromMouse(cm, e, liberal, forRect) {
6259
- var display = cm.display;
6260
- if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null;
6261
-
6262
- var x, y, space = display.lineSpace.getBoundingClientRect();
6263
- // Fails unpredictably on IE[67] when mouse is dragged around quickly.
6264
- try { x = e.clientX - space.left; y = e.clientY - space.top; }
6265
- catch (e) { return null; }
6266
- var coords = coordsChar(cm, x, y), line;
6267
- if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
6268
- var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
6269
- coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
6270
- }
6271
- return coords;
6272
- }
6273
-
6274
- // A mouse down can be a single click, double click, triple click,
6275
- // start of selection drag, start of text drag, new cursor
6276
- // (ctrl-click), rectangle drag (alt-drag), or xwin
6277
- // middle-click-paste. Or it might be a click on something we should
6278
- // not interfere with, such as a scrollbar or widget.
6279
- function onMouseDown(e) {
6280
- var cm = this, display = cm.display;
6281
- if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) return;
6282
- display.shift = e.shiftKey;
6283
-
6284
- if (eventInWidget(display, e)) {
6285
- if (!webkit) {
6286
- // Briefly turn off draggability, to allow widgets to do
6287
- // normal dragging things.
6288
- display.scroller.draggable = false;
6289
- setTimeout(function(){display.scroller.draggable = true;}, 100);
6290
- }
6291
- return;
6292
- }
6293
- if (clickInGutter(cm, e)) return;
6294
- var start = posFromMouse(cm, e);
6295
- window.focus();
6296
-
6297
- switch (e_button(e)) {
6298
- case 1:
6299
- // #3261: make sure, that we're not starting a second selection
6300
- if (cm.state.selectingText)
6301
- cm.state.selectingText(e);
6302
- else if (start)
6303
- leftButtonDown(cm, e, start);
6304
- else if (e_target(e) == display.scroller)
6305
- e_preventDefault(e);
6306
- break;
6307
- case 2:
6308
- if (webkit) cm.state.lastMiddleDown = +new Date;
6309
- if (start) extendSelection(cm.doc, start);
6310
- setTimeout(function() {display.input.focus();}, 20);
6311
- e_preventDefault(e);
6312
- break;
6313
- case 3:
6314
- if (captureRightClick) onContextMenu(cm, e);
6315
- else delayBlurEvent(cm);
6316
- break;
6317
- }
6318
- }
6319
-
6320
- var lastClick, lastDoubleClick;
6321
- function leftButtonDown(cm, e, start) {
6322
- if (ie) setTimeout(bind(ensureFocus, cm), 0);
6323
- else cm.curOp.focus = activeElt();
6324
-
6325
- var now = +new Date, type;
6326
- if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) {
6327
- type = "triple";
6328
- } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) {
6329
- type = "double";
6330
- lastDoubleClick = {time: now, pos: start};
6331
  } else {
6332
- type = "single";
6333
- lastClick = {time: now, pos: start};
6334
  }
6335
-
6336
- var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;
6337
- if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
6338
- type == "single" && (contained = sel.contains(start)) > -1 &&
6339
- (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) &&
6340
- (cmp(contained.to(), start) > 0 || start.xRel < 0))
6341
- leftButtonStartDrag(cm, e, start, modifier);
6342
- else
6343
- leftButtonSelect(cm, e, start, type, modifier);
6344
- }
6345
-
6346
- // Start a text drag. When it ends, see if any dragging actually
6347
- // happen, and treat as a click if it didn't.
6348
- function leftButtonStartDrag(cm, e, start, modifier) {
6349
- var display = cm.display, startTime = +new Date;
6350
- var dragEnd = operation(cm, function(e2) {
6351
- if (webkit) display.scroller.draggable = false;
6352
- cm.state.draggingText = false;
6353
- off(document, "mouseup", dragEnd);
6354
- off(display.scroller, "drop", dragEnd);
6355
- if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
6356
- e_preventDefault(e2);
6357
- if (!modifier && +new Date - 200 < startTime)
6358
- extendSelection(cm.doc, start);
6359
- // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
6360
- if (webkit || ie && ie_version == 9)
6361
- setTimeout(function() {document.body.focus(); display.input.focus();}, 20);
6362
- else
6363
- display.input.focus();
6364
- }
6365
- });
6366
- // Let the drag handler handle this.
6367
- if (webkit) display.scroller.draggable = true;
6368
- cm.state.draggingText = dragEnd;
6369
- dragEnd.copy = mac ? e.altKey : e.ctrlKey
6370
- // IE's approach to draggable
6371
- if (display.scroller.dragDrop) display.scroller.dragDrop();
6372
- on(document, "mouseup", dragEnd);
6373
- on(display.scroller, "drop", dragEnd);
6374
- }
6375
-
6376
- // Normal selection, as opposed to text dragging.
6377
- function leftButtonSelect(cm, e, start, type, addNew) {
6378
- var display = cm.display, doc = cm.doc;
6379
- e_preventDefault(e);
6380
-
6381
- var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
6382
- if (addNew && !e.shiftKey) {
6383
- ourIndex = doc.sel.contains(start);
6384
- if (ourIndex > -1)
6385
- ourRange = ranges[ourIndex];
6386
- else
6387
- ourRange = new Range(start, start);
6388
- } else {
6389
- ourRange = doc.sel.primary();
6390
- ourIndex = doc.sel.primIndex;
6391
- }
6392
-
6393
- if (chromeOS ? e.shiftKey && e.metaKey : e.altKey) {
6394
- type = "rect";
6395
- if (!addNew) ourRange = new Range(start, start);
6396
- start = posFromMouse(cm, e, true, true);
6397
- ourIndex = -1;
6398
- } else if (type == "double") {
6399
- var word = cm.findWordAt(start);
6400
- if (cm.display.shift || doc.extend)
6401
- ourRange = extendRange(doc, ourRange, word.anchor, word.head);
6402
- else
6403
- ourRange = word;
6404
- } else if (type == "triple") {
6405
- var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0)));
6406
- if (cm.display.shift || doc.extend)
6407
- ourRange = extendRange(doc, ourRange, line.anchor, line.head);
6408
- else
6409
- ourRange = line;
6410
- } else {
6411
- ourRange = extendRange(doc, ourRange, start);
6412
- }
6413
-
6414
- if (!addNew) {
6415
- ourIndex = 0;
6416
- setSelection(doc, new Selection([ourRange], 0), sel_mouse);
6417
- startSel = doc.sel;
6418
- } else if (ourIndex == -1) {
6419
- ourIndex = ranges.length;
6420
- setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
6421
- {scroll: false, origin: "*mouse"});
6422
- } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) {
6423
- setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
6424
- {scroll: false, origin: "*mouse"});
6425
- startSel = doc.sel;
6426
- } else {
6427
- replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
6428
- }
6429
-
6430
- var lastPos = start;
6431
- function extendTo(pos) {
6432
- if (cmp(lastPos, pos) == 0) return;
6433
- lastPos = pos;
6434
-
6435
- if (type == "rect") {
6436
- var ranges = [], tabSize = cm.options.tabSize;
6437
- var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
6438
- var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
6439
- var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
6440
- for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
6441
- line <= end; line++) {
6442
- var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
6443
- if (left == right)
6444
- ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos)));
6445
- else if (text.length > leftPos)
6446
- ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize))));
6447
- }
6448
- if (!ranges.length) ranges.push(new Range(start, start));
6449
- setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
6450
- {origin: "*mouse", scroll: false});
6451
- cm.scrollIntoView(pos);
6452
- } else {
6453
- var oldRange = ourRange;
6454
- var anchor = oldRange.anchor, head = pos;
6455
- if (type != "single") {
6456
- if (type == "double")
6457
- var range = cm.findWordAt(pos);
6458
- else
6459
- var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0)));
6460
- if (cmp(range.anchor, anchor) > 0) {
6461
- head = range.head;
6462
- anchor = minPos(oldRange.from(), range.anchor);
6463
- } else {
6464
- head = range.anchor;
6465
- anchor = maxPos(oldRange.to(), range.head);
6466
- }
6467
- }
6468
- var ranges = startSel.ranges.slice(0);
6469
- ranges[ourIndex] = new Range(clipPos(doc, anchor), head);
6470
- setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse);
6471
- }
6472
  }
 
 
6473
 
6474
- var editorSize = display.wrapper.getBoundingClientRect();
6475
- // Used to ensure timeout re-tries don't fire when another extend
6476
- // happened in the meantime (clearTimeout isn't reliable -- at
6477
- // least on Chrome, the timeouts still happen even when cleared,
6478
- // if the clear happens after their scheduled firing time).
6479
- var counter = 0;
6480
-
6481
- function extend(e) {
6482
- var curCount = ++counter;
6483
- var cur = posFromMouse(cm, e, true, type == "rect");
6484
- if (!cur) return;
6485
- if (cmp(cur, lastPos) != 0) {
6486
- cm.curOp.focus = activeElt();
6487
- extendTo(cur);
6488
- var visible = visibleLines(display, doc);
6489
- if (cur.line >= visible.to || cur.line < visible.from)
6490
- setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);
6491
- } else {
6492
- var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
6493
- if (outside) setTimeout(operation(cm, function() {
6494
- if (counter != curCount) return;
6495
- display.scroller.scrollTop += outside;
6496
- extend(e);
6497
- }), 50);
6498
- }
6499
- }
6500
 
6501
- function done(e) {
6502
- cm.state.selectingText = false;
6503
- counter = Infinity;
6504
- e_preventDefault(e);
6505
- display.input.focus();
6506
- off(document, "mousemove", move);
6507
- off(document, "mouseup", up);
6508
- doc.history.lastSelOrigin = null;
6509
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6510
 
6511
- var move = operation(cm, function(e) {
6512
- if (!e_button(e)) done(e);
6513
- else extend(e);
6514
- });
6515
- var up = operation(cm, done);
6516
- cm.state.selectingText = up;
6517
- on(document, "mousemove", move);
6518
- on(document, "mouseup", up);
6519
- }
6520
-
6521
- // Determines whether an event happened in the gutter, and fires the
6522
- // handlers for the corresponding event.
6523
- function gutterEvent(cm, e, type, prevent) {
6524
- try { var mX = e.clientX, mY = e.clientY; }
6525
- catch(e) { return false; }
6526
- if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
6527
- if (prevent) e_preventDefault(e);
6528
-
6529
- var display = cm.display;
6530
- var lineBox = display.lineDiv.getBoundingClientRect();
6531
-
6532
- if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);
6533
- mY -= lineBox.top - display.viewOffset;
6534
-
6535
- for (var i = 0; i < cm.options.gutters.length; ++i) {
6536
- var g = display.gutters.childNodes[i];
6537
- if (g && g.getBoundingClientRect().right >= mX) {
6538
- var line = lineAtHeight(cm.doc, mY);
6539
- var gutter = cm.options.gutters[i];
6540
- signal(cm, type, cm, line, gutter, e);
6541
- return e_defaultPrevented(e);
6542
- }
6543
- }
6544
- }
6545
 
6546
- function clickInGutter(cm, e) {
6547
- return gutterEvent(cm, e, "gutterClick", true);
6548
- }
6549
-
6550
- // Kludge to work around strange IE behavior where it'll sometimes
6551
- // re-fire a series of drag-related events right after the drop (#1551)
6552
- var lastDrop = 0;
6553
-
6554
- function onDrop(e) {
6555
- var cm = this;
6556
- clearDragCursor(cm);
6557
- if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
6558
- return;
6559
- e_preventDefault(e);
6560
- if (ie) lastDrop = +new Date;
6561
- var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
6562
- if (!pos || cm.isReadOnly()) return;
6563
- // Might be a file drop, in which case we simply extract the text
6564
- // and insert it.
6565
- if (files && files.length && window.FileReader && window.File) {
6566
- var n = files.length, text = Array(n), read = 0;
6567
- var loadFile = function(file, i) {
6568
- if (cm.options.allowDropFileTypes &&
6569
- indexOf(cm.options.allowDropFileTypes, file.type) == -1)
6570
- return;
6571
-
6572
- var reader = new FileReader;
6573
- reader.onload = operation(cm, function() {
6574
- var content = reader.result;
6575
- if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = "";
6576
- text[i] = content;
6577
- if (++read == n) {
6578
- pos = clipPos(cm.doc, pos);
6579
- var change = {from: pos, to: pos,
6580
- text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
6581
- origin: "paste"};
6582
- makeChange(cm.doc, change);
6583
- setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
6584
- }
6585
- });
6586
- reader.readAsText(file);
6587
- };
6588
- for (var i = 0; i < n; ++i) loadFile(files[i], i);
6589
- } else { // Normal drop
6590
- // Don't do a replace if the drop happened inside of the selected text.
6591
- if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
6592
- cm.state.draggingText(e);
6593
- // Ensure the editor is re-focused
6594
- setTimeout(function() {cm.display.input.focus();}, 20);
6595
- return;
6596
- }
6597
- try {
6598
- var text = e.dataTransfer.getData("Text");
6599
- if (text) {
6600
- if (cm.state.draggingText && !cm.state.draggingText.copy)
6601
- var selected = cm.listSelections();
6602
- setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
6603
- if (selected) for (var i = 0; i < selected.length; ++i)
6604
- replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag");
6605
- cm.replaceSelection(text, "around", "paste");
6606
- cm.display.input.focus();
6607
  }
6608
  }
6609
- catch(e){}
6610
  }
6611
  }
6612
 
6613
- function onDragStart(cm, e) {
6614
- if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
6615
- if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;
6616
-
6617
- e.dataTransfer.setData("Text", cm.getSelection());
6618
- e.dataTransfer.effectAllowed = "copyMove"
6619
-
6620
- // Use dummy image instead of default browsers image.
6621
- // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
6622
- if (e.dataTransfer.setDragImage && !safari) {
6623
- var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
6624
- img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
6625
- if (presto) {
6626
- img.width = img.height = 1;
6627
- cm.display.wrapper.appendChild(img);
6628
- // Force a relayout, or Opera won't use our image for some obscure reason
6629
- img._top = img.offsetTop;
6630
- }
6631
- e.dataTransfer.setDragImage(img, 0, 0);
6632
- if (presto) img.parentNode.removeChild(img);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6633
  }
6634
  }
 
6635
 
6636
- function onDragOver(cm, e) {
6637
- var pos = posFromMouse(cm, e);
6638
- if (!pos) return;
6639
- var frag = document.createDocumentFragment();
6640
- drawSelectionCursor(cm, pos, frag);
6641
- if (!cm.display.dragCursor) {
6642
- cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
6643
- cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
6644
- }
6645
- removeChildrenAndAdd(cm.display.dragCursor, frag);
6646
- }
6647
 
6648
- function clearDragCursor(cm) {
6649
- if (cm.display.dragCursor) {
6650
- cm.display.lineSpace.removeChild(cm.display.dragCursor);
6651
- cm.display.dragCursor = null;
6652
- }
 
 
 
 
 
 
 
 
 
 
6653
  }
 
6654
 
6655
- // SCROLL EVENTS
6656
-
6657
- // Sync the scrollable area and scrollbars, ensure the viewport
6658
- // covers the visible area.
6659
- function setScrollTop(cm, val) {
6660
- if (Math.abs(cm.doc.scrollTop - val) < 2) return;
6661
- cm.doc.scrollTop = val;
6662
- if (!gecko) updateDisplaySimple(cm, {top: val});
6663
- if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
6664
- cm.display.scrollbars.setScrollTop(val);
6665
- if (gecko) updateDisplaySimple(cm);
6666
- startWorker(cm, 100);
6667
- }
6668
- // Sync scroller and scrollbar, ensure the gutter elements are
6669
- // aligned.
6670
- function setScrollLeft(cm, val, isScroller) {
6671
- if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;
6672
- val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
6673
- cm.doc.scrollLeft = val;
6674
- alignHorizontally(cm);
6675
- if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
6676
- cm.display.scrollbars.setScrollLeft(val);
6677
- }
6678
 
6679
- // Since the delta values reported on mouse wheel events are
6680
- // unstandardized between browsers and even browser versions, and
6681
- // generally horribly unpredictable, this code starts by measuring
6682
- // the scroll effect that the first few mouse wheel events have,
6683
- // and, from that, detects the way it can convert deltas to pixel
6684
- // offsets afterwards.
6685
- //
6686
- // The reason we want to know the amount a wheel event will scroll
6687
- // is that it gives us a chance to update the display before the
6688
- // actual scrolling happens, reducing flickering.
6689
-
6690
- var wheelSamples = 0, wheelPixelsPerUnit = null;
6691
- // Fill in a browser-detected starting value on browsers where we
6692
- // know one. These don't have to be accurate -- the result of them
6693
- // being wrong would just be a slight flicker on the first wheel
6694
- // scroll (if it is large enough).
6695
- if (ie) wheelPixelsPerUnit = -.53;
6696
- else if (gecko) wheelPixelsPerUnit = 15;
6697
- else if (chrome) wheelPixelsPerUnit = -.7;
6698
- else if (safari) wheelPixelsPerUnit = -1/3;
6699
-
6700
- var wheelEventDelta = function(e) {
6701
- var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
6702
- if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
6703
- if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
6704
- else if (dy == null) dy = e.wheelDelta;
6705
- return {x: dx, y: dy};
6706
- };
6707
- CodeMirror.wheelEventPixels = function(e) {
6708
- var delta = wheelEventDelta(e);
6709
- delta.x *= wheelPixelsPerUnit;
6710
- delta.y *= wheelPixelsPerUnit;
6711
- return delta;
6712
- };
6713
 
6714
- function onScrollWheel(cm, e) {
6715
- var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
6716
-
6717
- var display = cm.display, scroll = display.scroller;
6718
- // Quit if there's nothing to scroll here
6719
- var canScrollX = scroll.scrollWidth > scroll.clientWidth;
6720
- var canScrollY = scroll.scrollHeight > scroll.clientHeight;
6721
- if (!(dx && canScrollX || dy && canScrollY)) return;
6722
-
6723
- // Webkit browsers on OS X abort momentum scrolls when the target
6724
- // of the scroll event is removed from the scrollable element.
6725
- // This hack (see related code in patchDisplay) makes sure the
6726
- // element is kept around.
6727
- if (dy && mac && webkit) {
6728
- outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
6729
- for (var i = 0; i < view.length; i++) {
6730
- if (view[i].node == cur) {
6731
- cm.display.currentWheelTarget = cur;
6732
- break outer;
6733
- }
6734
- }
6735
- }
6736
  }
6737
 
6738
- // On some browsers, horizontal scrolling will cause redraws to
6739
- // happen before the gutter has been realigned, causing it to
6740
- // wriggle around in a most unseemly way. When we have an
6741
- // estimated pixels/delta value, we just handle horizontal
6742
- // scrolling entirely here. It'll be slightly off from native, but
6743
- // better than glitching out.
6744
- if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
6745
- if (dy && canScrollY)
6746
- setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
6747
- setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
6748
- // Only prevent default scrolling if vertical scrolling is
6749
- // actually possible. Otherwise, it causes vertical scroll
6750
- // jitter on OSX trackpads when deltaX is small and deltaY
6751
- // is large (issue #3579)
6752
- if (!dy || (dy && canScrollY))
6753
- e_preventDefault(e);
6754
- display.wheelStartX = null; // Abort measurement, if in progress
6755
- return;
6756
- }
6757
-
6758
- // 'Project' the visible viewport to cover the area that is being
6759
- // scrolled into view (if we know enough to estimate it).
6760
- if (dy && wheelPixelsPerUnit != null) {
6761
- var pixels = dy * wheelPixelsPerUnit;
6762
- var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
6763
- if (pixels < 0) top = Math.max(0, top + pixels - 50);
6764
- else bot = Math.min(cm.doc.height, bot + pixels + 50);
6765
- updateDisplaySimple(cm, {top: top, bottom: bot});
6766
- }
6767
-
6768
- if (wheelSamples < 20) {
6769
- if (display.wheelStartX == null) {
6770
- display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
6771
- display.wheelDX = dx; display.wheelDY = dy;
6772
- setTimeout(function() {
6773
- if (display.wheelStartX == null) return;
6774
- var movedX = scroll.scrollLeft - display.wheelStartX;
6775
- var movedY = scroll.scrollTop - display.wheelStartY;
6776
- var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
6777
- (movedX && display.wheelDX && movedX / display.wheelDX);
6778
- display.wheelStartX = display.wheelStartY = null;
6779
- if (!sample) return;
6780
- wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
6781
- ++wheelSamples;
6782
- }, 200);
6783
- } else {
6784
- display.wheelDX += dx; display.wheelDY += dy;
6785
- }
6786
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6787
  }
 
6788
 
6789
- // KEY EVENTS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6790
 
6791
- // Run a handler that was bound to a key.
6792
- function doHandleBinding(cm, bound, dropShift) {
6793
- if (typeof bound == "string") {
6794
- bound = commands[bound];
6795
- if (!bound) return false;
6796
- }
6797
- // Ensure previous input has been read, so that the handler sees a
6798
- // consistent view of the document
6799
- cm.display.input.ensurePolled();
6800
- var prevShift = cm.display.shift, done = false;
6801
- try {
6802
- if (cm.isReadOnly()) cm.state.suppressEdits = true;
6803
- if (dropShift) cm.display.shift = false;
6804
- done = bound(cm) != Pass;
6805
- } finally {
6806
- cm.display.shift = prevShift;
6807
- cm.state.suppressEdits = false;
6808
- }
6809
- return done;
6810
- }
6811
-
6812
- function lookupKeyForEditor(cm, name, handle) {
6813
- for (var i = 0; i < cm.state.keyMaps.length; i++) {
6814
- var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
6815
- if (result) return result;
6816
- }
6817
- return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
6818
- || lookupKey(name, cm.options.keyMap, handle, cm);
6819
- }
6820
-
6821
- var stopSeq = new Delayed;
6822
- function dispatchKey(cm, name, e, handle) {
6823
- var seq = cm.state.keySeq;
6824
- if (seq) {
6825
- if (isModifierKey(name)) return "handled";
6826
- stopSeq.set(50, function() {
6827
- if (cm.state.keySeq == seq) {
6828
- cm.state.keySeq = null;
6829
- cm.display.input.reset();
6830
- }
6831
- });
6832
- name = seq + " " + name;
6833
- }
6834
- var result = lookupKeyForEditor(cm, name, handle);
6835
 
6836
- if (result == "multi")
6837
- cm.state.keySeq = name;
6838
- if (result == "handled")
6839
- signalLater(cm, "keyHandled", cm, name, e);
6840
 
6841
- if (result == "handled" || result == "multi") {
6842
- e_preventDefault(e);
6843
- restartBlink(cm);
6844
- }
6845
 
6846
- if (seq && !result && /\'$/.test(name)) {
6847
- e_preventDefault(e);
6848
- return true;
6849
- }
6850
- return !!result;
 
 
 
6851
  }
 
6852
 
6853
- // Handle a key from the keydown event.
6854
- function handleKeyBinding(cm, e) {
6855
- var name = keyName(e, true);
6856
- if (!name) return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6857
 
6858
- if (e.shiftKey && !cm.state.keySeq) {
6859
- // First try to resolve full name (including 'Shift-'). Failing
6860
- // that, see if there is a cursor-motion command (starting with
6861
- // 'go') bound to the keyname without 'Shift-'.
6862
- return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);})
6863
- || dispatchKey(cm, name, e, function(b) {
6864
- if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
6865
- return doHandleBinding(cm, b);
6866
- });
6867
- } else {
6868
- return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); });
6869
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6870
  }
 
 
6871
 
6872
- // Handle a key from the keypress event
6873
- function handleCharBinding(cm, e, ch) {
6874
- return dispatchKey(cm, "'" + ch + "'", e,
6875
- function(b) { return doHandleBinding(cm, b, true); });
 
 
 
 
 
 
 
 
 
 
6876
  }
 
6877
 
6878
- var lastStoppedKey = null;
6879
- function onKeyDown(e) {
6880
- var cm = this;
6881
- cm.curOp.focus = activeElt();
6882
- if (signalDOMEvent(cm, e)) return;
6883
- // IE does strange things with escape.
6884
- if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false;
6885
- var code = e.keyCode;
6886
- cm.display.shift = code == 16 || e.shiftKey;
6887
- var handled = handleKeyBinding(cm, e);
6888
- if (presto) {
6889
- lastStoppedKey = handled ? code : null;
6890
- // Opera has no cut event... we try to at least catch the key combo
6891
- if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
6892
- cm.replaceSelection("", null, "cut");
6893
- }
 
 
 
 
 
 
 
 
 
 
 
 
6894
 
6895
- // Turn mouse into crosshair when Alt is held on Mac.
6896
- if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
6897
- showCrossHair(cm);
6898
- }
 
 
 
 
 
6899
 
6900
- function showCrossHair(cm) {
6901
- var lineDiv = cm.display.lineDiv;
6902
- addClass(lineDiv, "CodeMirror-crosshair");
 
 
 
 
 
 
 
 
 
 
 
 
6903
 
6904
- function up(e) {
6905
- if (e.keyCode == 18 || !e.altKey) {
6906
- rmClass(lineDiv, "CodeMirror-crosshair");
6907
- off(document, "keyup", up);
6908
- off(document, "mouseover", up);
6909
- }
6910
- }
6911
- on(document, "keyup", up);
6912
- on(document, "mouseover", up);
6913
- }
 
 
6914
 
6915
- function onKeyUp(e) {
6916
- if (e.keyCode == 16) this.doc.sel.shift = false;
6917
- signalDOMEvent(this, e);
6918
- }
6919
 
6920
- function onKeyPress(e) {
6921
- var cm = this;
6922
- if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return;
6923
- var keyCode = e.keyCode, charCode = e.charCode;
6924
- if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
6925
- if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return;
6926
- var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
6927
- if (handleCharBinding(cm, e, ch)) return;
6928
- cm.display.input.onKeyPress(e);
6929
- }
6930
 
6931
- // FOCUS/BLUR EVENTS
6932
 
6933
- function delayBlurEvent(cm) {
6934
- cm.state.delayingBlurEvent = true;
6935
- setTimeout(function() {
6936
- if (cm.state.delayingBlurEvent) {
6937
- cm.state.delayingBlurEvent = false;
6938
- onBlur(cm);
6939
- }
6940
- }, 100);
6941
- }
6942
-
6943
- function onFocus(cm) {
6944
- if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false;
6945
-
6946
- if (cm.options.readOnly == "nocursor") return;
6947
- if (!cm.state.focused) {
6948
- signal(cm, "focus", cm);
6949
- cm.state.focused = true;
6950
- addClass(cm.display.wrapper, "CodeMirror-focused");
6951
- // This test prevents this from firing when a context
6952
- // menu is closed (since the input reset would kill the
6953
- // select-all detection hack)
6954
- if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
6955
- cm.display.input.reset();
6956
- if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730
6957
- }
6958
- cm.display.input.receivedFocus();
6959
- }
6960
- restartBlink(cm);
6961
  }
6962
- function onBlur(cm) {
6963
- if (cm.state.delayingBlurEvent) return;
6964
 
6965
- if (cm.state.focused) {
6966
- signal(cm, "blur", cm);
6967
- cm.state.focused = false;
6968
- rmClass(cm.display.wrapper, "CodeMirror-focused");
6969
- }
6970
- clearInterval(cm.display.blinker);
6971
- setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150);
6972
- }
6973
 
6974
- // CONTEXT MENU HANDLING
 
6975
 
6976
- // To make the context menu work, we need to briefly unhide the
6977
- // textarea (making it as unobtrusive as possible) to let the
6978
- // right-click take effect on it.
6979
- function onContextMenu(cm, e) {
6980
- if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;
6981
- if (signalDOMEvent(cm, e, "contextmenu")) return;
6982
- cm.display.input.onContextMenu(e);
6983
  }
6984
 
6985
- function contextMenuInGutter(cm, e) {
6986
- if (!hasHandler(cm, "gutterContextMenu")) return false;
6987
- return gutterEvent(cm, e, "gutterContextMenu", false);
6988
- }
 
 
 
6989
 
6990
- // UPDATING
6991
 
6992
- // Compute the position of the end of a change (its 'to' property
6993
- // refers to the pre-change end).
6994
- var changeEnd = CodeMirror.changeEnd = function(change) {
6995
- if (!change.text) return change.to;
6996
- return Pos(change.from.line + change.text.length - 1,
6997
- lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));
6998
- };
6999
 
7000
- // Adjust a position to refer to the post-change position of the
7001
- // same text, or the end of the change if the change covers it.
7002
- function adjustForChange(pos, change) {
7003
- if (cmp(pos, change.from) < 0) return pos;
7004
- if (cmp(pos, change.to) <= 0) return changeEnd(change);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7005
 
7006
- var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
7007
- if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch;
7008
- return Pos(line, ch);
 
 
 
 
 
 
 
 
 
 
 
7009
  }
7010
-
7011
- function computeSelAfterChange(doc, change) {
7012
- var out = [];
7013
- for (var i = 0; i < doc.sel.ranges.length; i++) {
7014
- var range = doc.sel.ranges[i];
7015
- out.push(new Range(adjustForChange(range.anchor, change),
7016
- adjustForChange(range.head, change)));
7017
- }
7018
- return normalizeSelection(out, doc.sel.primIndex);
 
 
 
 
 
 
 
 
 
7019
  }
 
7020
 
7021
- function offsetPos(pos, old, nw) {
7022
- if (pos.line == old.line)
7023
- return Pos(nw.line, pos.ch - old.ch + nw.ch);
7024
- else
7025
- return Pos(nw.line + (pos.line - old.line), pos.ch);
7026
- }
7027
-
7028
- // Used by replaceSelections to allow moving the selection to the
7029
- // start or around the replaced test. Hint may be "start" or "around".
7030
- function computeReplacedSel(doc, changes, hint) {
7031
- var out = [];
7032
- var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
7033
- for (var i = 0; i < changes.length; i++) {
7034
- var change = changes[i];
7035
- var from = offsetPos(change.from, oldPrev, newPrev);
7036
- var to = offsetPos(changeEnd(change), oldPrev, newPrev);
7037
- oldPrev = change.to;
7038
- newPrev = to;
7039
- if (hint == "around") {
7040
- var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
7041
- out[i] = new Range(inv ? to : from, inv ? from : to);
7042
- } else {
7043
- out[i] = new Range(from, from);
7044
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7045
  }
7046
- return new Selection(out, doc.sel.primIndex);
7047
  }
7048
 
7049
- // Allow "beforeChange" event handlers to influence a change
7050
- function filterChange(doc, change, update) {
7051
- var obj = {
7052
- canceled: false,
7053
- from: change.from,
7054
- to: change.to,
7055
- text: change.text,
7056
- origin: change.origin,
7057
- cancel: function() { this.canceled = true; }
7058
- };
7059
- if (update) obj.update = function(from, to, text, origin) {
7060
- if (from) this.from = clipPos(doc, from);
7061
- if (to) this.to = clipPos(doc, to);
7062
- if (text) this.text = text;
7063
- if (origin !== undefined) this.origin = origin;
7064
- };
7065
- signal(doc, "beforeChange", doc, obj);
7066
- if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj);
7067
-
7068
- if (obj.canceled) return null;
7069
- return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin};
7070
  }
 
7071
 
7072
- // Apply a change to a document, and add it to the document's
7073
- // history, and propagating it to all linked documents.
7074
- function makeChange(doc, change, ignoreReadOnly) {
7075
- if (doc.cm) {
7076
- if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly);
7077
- if (doc.cm.state.suppressEdits) return;
7078
- }
 
 
 
 
 
 
 
7079
 
7080
- if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
7081
- change = filterChange(doc, change, true);
7082
- if (!change) return;
7083
- }
 
 
7084
 
7085
- // Possibly split or suppress the update based on the presence
7086
- // of read-only spans in its range.
7087
- var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
7088
- if (split) {
7089
- for (var i = split.length - 1; i >= 0; --i)
7090
- makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text});
 
 
 
 
 
 
7091
  } else {
7092
- makeChangeInner(doc, change);
7093
  }
 
7094
  }
 
 
 
 
 
 
 
7095
 
7096
- function makeChangeInner(doc, change) {
7097
- if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return;
7098
- var selAfter = computeSelAfterChange(doc, change);
7099
- addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
7100
-
7101
- makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
7102
- var rebased = [];
 
 
 
 
 
 
 
 
 
 
 
 
 
7103
 
7104
- linkedDocs(doc, function(doc, sharedHist) {
7105
- if (!sharedHist && indexOf(rebased, doc.history) == -1) {
7106
- rebaseHist(doc.history, change);
7107
- rebased.push(doc.history);
7108
- }
7109
- makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
7110
- });
7111
  }
 
 
7112
 
7113
- // Revert a change stored in a document's history.
7114
- function makeChangeFromHistory(doc, type, allowSelectionOnly) {
7115
- if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) return;
7116
-
7117
- var hist = doc.history, event, selAfter = doc.sel;
7118
- var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
7119
 
7120
- // Verify that there is a useable event (so that ctrl-z won't
7121
- // needlessly clear selection events)
7122
- for (var i = 0; i < source.length; i++) {
7123
- event = source[i];
7124
- if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
7125
- break;
7126
- }
7127
- if (i == source.length) return;
7128
- hist.lastOrigin = hist.lastSelOrigin = null;
7129
 
7130
- for (;;) {
7131
- event = source.pop();
7132
- if (event.ranges) {
7133
- pushSelectionToHistory(event, dest);
7134
- if (allowSelectionOnly && !event.equals(doc.sel)) {
7135
- setSelection(doc, event, {clearRedo: false});
7136
- return;
7137
- }
7138
- selAfter = event;
7139
- }
7140
- else break;
7141
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7142
 
7143
- // Build up a reverse change object to add to the opposite history
7144
- // stack (redo when undoing, and vice versa).
7145
- var antiChanges = [];
7146
- pushSelectionToHistory(selAfter, dest);
7147
- dest.push({changes: antiChanges, generation: hist.generation});
7148
- hist.generation = event.generation || ++hist.maxGeneration;
 
 
 
 
 
 
 
 
 
 
7149
 
7150
- var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
 
 
 
 
 
7151
 
7152
- for (var i = event.changes.length - 1; i >= 0; --i) {
7153
- var change = event.changes[i];
7154
- change.origin = type;
7155
- if (filter && !filterChange(doc, change, false)) {
7156
- source.length = 0;
7157
- return;
7158
- }
7159
 
7160
- antiChanges.push(historyChangeFromChange(doc, change));
 
 
 
 
 
 
 
 
 
7161
 
7162
- var after = i ? computeSelAfterChange(doc, change) : lst(source);
7163
- makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
7164
- if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)});
7165
- var rebased = [];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7166
 
7167
- // Propagate to the linked documents
7168
- linkedDocs(doc, function(doc, sharedHist) {
7169
- if (!sharedHist && indexOf(rebased, doc.history) == -1) {
7170
- rebaseHist(doc.history, change);
7171
- rebased.push(doc.history);
7172
- }
7173
- makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
7174
- });
7175
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7176
  }
 
7177
 
7178
- // Sub-views need their line numbers shifted when text is added
7179
- // above or below them in the parent document.
7180
- function shiftDoc(doc, distance) {
7181
- if (distance == 0) return;
7182
- doc.first += distance;
7183
- doc.sel = new Selection(map(doc.sel.ranges, function(range) {
7184
- return new Range(Pos(range.anchor.line + distance, range.anchor.ch),
7185
- Pos(range.head.line + distance, range.head.ch));
7186
- }), doc.sel.primIndex);
7187
- if (doc.cm) {
7188
- regChange(doc.cm, doc.first, doc.first - distance, distance);
7189
- for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
7190
- regLineChange(doc.cm, l, "gutter");
7191
- }
7192
  }
 
7193
 
7194
- // More lower-level change function, handling only a single document
7195
- // (not linked ones).
7196
- function makeChangeSingleDoc(doc, change, selAfter, spans) {
7197
- if (doc.cm && !doc.cm.curOp)
7198
- return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7199
 
7200
- if (change.to.line < doc.first) {
7201
- shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
7202
- return;
7203
- }
7204
- if (change.from.line > doc.lastLine()) return;
7205
 
7206
- // Clip the change to the size of this doc
7207
- if (change.from.line < doc.first) {
7208
- var shift = change.text.length - 1 - (doc.first - change.from.line);
7209
- shiftDoc(doc, shift);
7210
- change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
7211
- text: [lst(change.text)], origin: change.origin};
7212
- }
7213
- var last = doc.lastLine();
7214
- if (change.to.line > last) {
7215
- change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
7216
- text: [change.text[0]], origin: change.origin};
7217
- }
7218
 
7219
- change.removed = getBetween(doc, change.from, change.to);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7220
 
7221
- if (!selAfter) selAfter = computeSelAfterChange(doc, change);
7222
- if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans);
7223
- else updateDoc(doc, change, spans);
7224
- setSelectionNoUndo(doc, selAfter, sel_dontScroll);
 
 
 
 
 
7225
  }
 
7226
 
7227
- // Handle the interaction of a change to a document with the editor
7228
- // that this document is part of.
7229
- function makeChangeSingleDocInEditor(cm, change, spans) {
7230
- var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
 
 
 
 
 
7231
 
7232
- var recomputeMaxLength = false, checkWidthStart = from.line;
7233
- if (!cm.options.lineWrapping) {
7234
- checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
7235
- doc.iter(checkWidthStart, to.line + 1, function(line) {
7236
- if (line == display.maxLine) {
7237
- recomputeMaxLength = true;
7238
- return true;
7239
- }
7240
- });
 
7241
  }
 
 
 
 
7242
 
7243
- if (doc.sel.contains(change.from, change.to) > -1)
7244
- signalCursorActivity(cm);
 
 
 
 
 
7245
 
7246
- updateDoc(doc, change, spans, estimateHeight(cm));
 
 
 
 
 
7247
 
7248
- if (!cm.options.lineWrapping) {
7249
- doc.iter(checkWidthStart, from.line + change.text.length, function(line) {
7250
- var len = lineLength(line);
7251
- if (len > display.maxLineLength) {
7252
- display.maxLine = line;
7253
- display.maxLineLength = len;
7254
- display.maxLineChanged = true;
7255
- recomputeMaxLength = false;
7256
- }
7257
- });
7258
- if (recomputeMaxLength) cm.curOp.updateMaxLine = true;
7259
  }
 
 
 
7260
 
7261
- // Adjust frontier, schedule worker
7262
- doc.frontier = Math.min(doc.frontier, from.line);
7263
- startWorker(cm, 400);
7264
 
7265
- var lendiff = change.text.length - (to.line - from.line) - 1;
7266
- // Remember that these lines changed, for updating the display
7267
- if (change.full)
7268
- regChange(cm);
7269
- else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
7270
- regLineChange(cm, from.line, "text");
7271
- else
7272
- regChange(cm, from.line, to.line + 1, lendiff);
7273
-
7274
- var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
7275
- if (changeHandler || changesHandler) {
7276
- var obj = {
7277
- from: from, to: to,
7278
- text: change.text,
7279
- removed: change.removed,
7280
- origin: change.origin
7281
- };
7282
- if (changeHandler) signalLater(cm, "change", cm, obj);
7283
- if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj);
7284
- }
7285
- cm.display.selForContextMenu = null;
7286
- }
7287
-
7288
- function replaceRange(doc, code, from, to, origin) {
7289
- if (!to) to = from;
7290
- if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }
7291
- if (typeof code == "string") code = doc.splitLines(code);
7292
- makeChange(doc, {from: from, to: to, text: code, origin: origin});
7293
- }
7294
-
7295
- // SCROLLING THINGS INTO VIEW
7296
-
7297
- // If an editor sits on the top or bottom of the window, partially
7298
- // scrolled out of view, this ensures that the cursor is visible.
7299
- function maybeScrollWindow(cm, coords) {
7300
- if (signalDOMEvent(cm, "scrollCursorIntoView")) return;
7301
-
7302
- var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
7303
- if (coords.top + box.top < 0) doScroll = true;
7304
- else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
7305
- if (doScroll != null && !phantom) {
7306
- var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
7307
- (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " +
7308
- (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " +
7309
- coords.left + "px; width: 2px;");
7310
- cm.display.lineSpace.appendChild(scrollNode);
7311
- scrollNode.scrollIntoView(doScroll);
7312
- cm.display.lineSpace.removeChild(scrollNode);
7313
- }
7314
- }
7315
-
7316
- // Scroll a given position into view (immediately), verifying that
7317
- // it actually became visible (as line heights are accurately
7318
- // measured, the position of something may 'drift' during drawing).
7319
- function scrollPosIntoView(cm, pos, end, margin) {
7320
- if (margin == null) margin = 0;
7321
- for (var limit = 0; limit < 5; limit++) {
7322
- var changed = false, coords = cursorCoords(cm, pos);
7323
- var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
7324
- var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
7325
- Math.min(coords.top, endCoords.top) - margin,
7326
- Math.max(coords.left, endCoords.left),
7327
- Math.max(coords.bottom, endCoords.bottom) + margin);
7328
- var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
7329
- if (scrollPos.scrollTop != null) {
7330
- setScrollTop(cm, scrollPos.scrollTop);
7331
- if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true;
7332
- }
7333
- if (scrollPos.scrollLeft != null) {
7334
- setScrollLeft(cm, scrollPos.scrollLeft);
7335
- if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
7336
- }
7337
- if (!changed) break;
7338
- }
7339
- return coords;
7340
- }
7341
-
7342
- // Scroll a given set of coordinates into view (immediately).
7343
- function scrollIntoView(cm, x1, y1, x2, y2) {
7344
- var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
7345
- if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
7346
- if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
7347
- }
7348
-
7349
- // Calculate a new scroll position needed to scroll the given
7350
- // rectangle into view. Returns an object with scrollTop and
7351
- // scrollLeft properties. When these are undefined, the
7352
- // vertical/horizontal position does not need to be adjusted.
7353
- function calculateScrollPos(cm, x1, y1, x2, y2) {
7354
- var display = cm.display, snapMargin = textHeight(cm.display);
7355
- if (y1 < 0) y1 = 0;
7356
- var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
7357
- var screen = displayHeight(cm), result = {};
7358
- if (y2 - y1 > screen) y2 = y1 + screen;
7359
- var docBottom = cm.doc.height + paddingVert(display);
7360
- var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
7361
- if (y1 < screentop) {
7362
- result.scrollTop = atTop ? 0 : y1;
7363
- } else if (y2 > screentop + screen) {
7364
- var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);
7365
- if (newTop != screentop) result.scrollTop = newTop;
7366
- }
7367
-
7368
- var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
7369
- var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
7370
- var tooWide = x2 - x1 > screenw;
7371
- if (tooWide) x2 = x1 + screenw;
7372
- if (x1 < 10)
7373
- result.scrollLeft = 0;
7374
- else if (x1 < screenleft)
7375
- result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
7376
- else if (x2 > screenw + screenleft - 3)
7377
- result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
7378
- return result;
7379
  }
 
7380
 
7381
- // Store a relative adjustment to the scroll position in the current
7382
- // operation (to be applied when the operation finishes).
7383
- function addToScrollPos(cm, left, top) {
7384
- if (left != null || top != null) resolveScrollToPos(cm);
7385
- if (left != null)
7386
- cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left;
7387
- if (top != null)
7388
- cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
7389
- }
7390
-
7391
- // Make sure that at the end of the operation the current cursor is
7392
- // shown.
7393
- function ensureCursorVisible(cm) {
7394
- resolveScrollToPos(cm);
7395
- var cur = cm.getCursor(), from = cur, to = cur;
7396
- if (!cm.options.lineWrapping) {
7397
- from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur;
7398
- to = Pos(cur.line, cur.ch + 1);
7399
- }
7400
- cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true};
7401
- }
7402
-
7403
- // When an operation has its scrollToPos property set, and another
7404
- // scroll action is applied before the end of the operation, this
7405
- // 'simulates' scrolling that position into view in a cheap way, so
7406
- // that the effect of intermediate scroll commands is not ignored.
7407
- function resolveScrollToPos(cm) {
7408
- var range = cm.curOp.scrollToPos;
7409
- if (range) {
7410
- cm.curOp.scrollToPos = null;
7411
- var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);
7412
- var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),
7413
- Math.min(from.top, to.top) - range.margin,
7414
- Math.max(from.right, to.right),
7415
- Math.max(from.bottom, to.bottom) + range.margin);
7416
- cm.scrollTo(sPos.scrollLeft, sPos.scrollTop);
7417
- }
7418
- }
7419
-
7420
- // API UTILITIES
7421
-
7422
- // Indent the given line. The how parameter can be "smart",
7423
- // "add"/null, "subtract", or "prev". When aggressive is false
7424
- // (typically set to true for forced single-line indents), empty
7425
- // lines are not indented, and places where the mode returns Pass
7426
- // are left alone.
7427
- function indentLine(cm, n, how, aggressive) {
7428
- var doc = cm.doc, state;
7429
- if (how == null) how = "add";
7430
- if (how == "smart") {
7431
- // Fall back to "prev" when the mode doesn't have an indentation
7432
- // method.
7433
- if (!doc.mode.indent) how = "prev";
7434
- else state = getStateBefore(cm, n);
7435
- }
7436
-
7437
- var tabSize = cm.options.tabSize;
7438
- var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
7439
- if (line.stateAfter) line.stateAfter = null;
7440
- var curSpaceString = line.text.match(/^\s*/)[0], indentation;
7441
- if (!aggressive && !/\S/.test(line.text)) {
7442
- indentation = 0;
7443
- how = "not";
7444
- } else if (how == "smart") {
7445
- indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
7446
- if (indentation == Pass || indentation > 150) {
7447
- if (!aggressive) return;
7448
- how = "prev";
7449
- }
7450
- }
7451
- if (how == "prev") {
7452
- if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);
7453
- else indentation = 0;
7454
- } else if (how == "add") {
7455
- indentation = curSpace + cm.options.indentUnit;
7456
- } else if (how == "subtract") {
7457
- indentation = curSpace - cm.options.indentUnit;
7458
- } else if (typeof how == "number") {
7459
- indentation = curSpace + how;
7460
- }
7461
- indentation = Math.max(0, indentation);
7462
-
7463
- var indentString = "", pos = 0;
7464
- if (cm.options.indentWithTabs)
7465
- for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
7466
- if (pos < indentation) indentString += spaceStr(indentation - pos);
7467
-
7468
- if (indentString != curSpaceString) {
7469
- replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
7470
- line.stateAfter = null;
7471
- return true;
7472
  } else {
7473
- // Ensure that, if the cursor was in the whitespace at the start
7474
- // of the line, it is moved to the end of that space.
7475
- for (var i = 0; i < doc.sel.ranges.length; i++) {
7476
- var range = doc.sel.ranges[i];
7477
- if (range.head.line == n && range.head.ch < curSpaceString.length) {
7478
- var pos = Pos(n, curSpaceString.length);
7479
- replaceOneSelection(doc, i, new Range(pos, pos));
7480
- break;
7481
- }
7482
- }
7483
  }
7484
  }
 
 
7485
 
7486
- // Utility for applying a change to a line by handle or number,
7487
- // returning the number and optionally registering the line as
7488
- // changed.
7489
- function changeLine(doc, handle, changeType, op) {
7490
- var no = handle, line = handle;
7491
- if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
7492
- else no = lineNo(handle);
7493
- if (no == null) return null;
7494
- if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType);
7495
- return line;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7496
  }
7497
 
7498
- // Helper for deleting text near the selection(s), used to implement
7499
- // backspace, delete, and similar functionality.
7500
- function deleteNearSelection(cm, compute) {
7501
- var ranges = cm.doc.sel.ranges, kill = [];
7502
- // Build up a set of ranges to kill first, merging overlapping
7503
- // ranges.
7504
- for (var i = 0; i < ranges.length; i++) {
7505
- var toKill = compute(ranges[i]);
7506
- while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
7507
- var replaced = kill.pop();
7508
- if (cmp(replaced.from, toKill.from) < 0) {
7509
- toKill.from = replaced.from;
7510
- break;
7511
- }
7512
- }
7513
- kill.push(toKill);
7514
- }
7515
- // Next, remove those actual ranges.
7516
- runInOp(cm, function() {
7517
- for (var i = kill.length - 1; i >= 0; i--)
7518
- replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete");
7519
- ensureCursorVisible(cm);
7520
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7521
  }
 
7522
 
7523
- // Used for horizontal relative motion. Dir is -1 or 1 (left or
7524
- // right), unit can be "char", "column" (like char, but doesn't
7525
- // cross line boundaries), "word" (across next word), or "group" (to
7526
- // the start of next group of word or non-word-non-whitespace
7527
- // chars). The visually param controls whether, in right-to-left
7528
- // text, direction 1 means to move towards the next index in the
7529
- // string, or towards the character to the right of the current
7530
- // position. The resulting position will have a hitSide=true
7531
- // property if it reached the end of the document.
7532
- function findPosH(doc, pos, dir, unit, visually) {
7533
- var line = pos.line, ch = pos.ch, origDir = dir;
7534
- var lineObj = getLine(doc, line);
7535
- function findNextLine() {
7536
- var l = line + dir;
7537
- if (l < doc.first || l >= doc.first + doc.size) return false
7538
- line = l;
7539
- return lineObj = getLine(doc, l);
7540
- }
7541
- function moveOnce(boundToLine) {
7542
- var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
7543
- if (next == null) {
7544
- if (!boundToLine && findNextLine()) {
7545
- if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
7546
- else ch = dir < 0 ? lineObj.text.length : 0;
7547
- } else return false
7548
- } else ch = next;
7549
- return true;
7550
- }
7551
-
7552
- if (unit == "char") {
7553
- moveOnce()
7554
- } else if (unit == "column") {
7555
- moveOnce(true)
7556
- } else if (unit == "word" || unit == "group") {
7557
- var sawType = null, group = unit == "group";
7558
- var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
7559
- for (var first = true;; first = false) {
7560
- if (dir < 0 && !moveOnce(!first)) break;
7561
- var cur = lineObj.text.charAt(ch) || "\n";
7562
- var type = isWordChar(cur, helper) ? "w"
7563
- : group && cur == "\n" ? "n"
7564
- : !group || /\s/.test(cur) ? null
7565
- : "p";
7566
- if (group && !first && !type) type = "s";
7567
- if (sawType && sawType != type) {
7568
- if (dir < 0) {dir = 1; moveOnce();}
7569
- break;
7570
- }
7571
 
7572
- if (type) sawType = type;
7573
- if (dir > 0 && !moveOnce(!first)) break;
7574
- }
7575
- }
7576
- var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true);
7577
- if (!cmp(pos, result)) result.hitSide = true;
7578
- return result;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7579
  }
 
 
7580
 
7581
- // For relative vertical movement. Dir may be -1 or 1. Unit can be
7582
- // "page" or "line". The resulting position will have a hitSide=true
7583
- // property if it reached the end of the document.
7584
- function findPosV(cm, pos, dir, unit) {
7585
- var doc = cm.doc, x = pos.left, y;
7586
- if (unit == "page") {
7587
- var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
7588
- y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display));
7589
- } else if (unit == "line") {
7590
- y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
7591
- }
7592
- for (;;) {
7593
- var target = coordsChar(cm, x, y);
7594
- if (!target.outside) break;
7595
- if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }
7596
- y += dir * 5;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7597
  }
7598
- return target;
7599
  }
 
 
7600
 
7601
- // EDITOR METHODS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7602
 
7603
- // The publicly visible API. Note that methodOp(f) means
7604
- // 'wrap f in an operation, performed on its `this` parameter'.
 
 
7605
 
7606
- // This is not the complete set of editor methods. Most of the
7607
- // methods defined on the Doc type are also injected into
7608
- // CodeMirror.prototype, for backwards compatibility and
7609
- // convenience.
 
 
 
 
 
7610
 
7611
- CodeMirror.prototype = {
7612
- constructor: CodeMirror,
7613
- focus: function(){window.focus(); this.display.input.focus();},
 
 
 
7614
 
7615
- setOption: function(option, value) {
7616
- var options = this.options, old = options[option];
7617
- if (options[option] == value && option != "mode") return;
7618
- options[option] = value;
7619
- if (optionHandlers.hasOwnProperty(option))
7620
- operation(this, optionHandlers[option])(this, value, old);
7621
- },
7622
 
7623
- getOption: function(option) {return this.options[option];},
7624
- getDoc: function() {return this.doc;},
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7625
 
7626
- addKeyMap: function(map, bottom) {
7627
- this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map));
7628
- },
7629
- removeKeyMap: function(map) {
7630
- var maps = this.state.keyMaps;
7631
- for (var i = 0; i < maps.length; ++i)
7632
- if (maps[i] == map || maps[i].name == map) {
7633
- maps.splice(i, 1);
7634
- return true;
7635
- }
7636
- },
7637
 
7638
- addOverlay: methodOp(function(spec, options) {
7639
- var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
7640
- if (mode.startState) throw new Error("Overlays may not be stateful.");
7641
- insertSorted(this.state.overlays,
7642
- {mode: mode, modeSpec: spec, opaque: options && options.opaque,
7643
- priority: (options && options.priority) || 0},
7644
- function(overlay) { return overlay.priority })
7645
- this.state.modeGen++;
7646
- regChange(this);
7647
- }),
7648
- removeOverlay: methodOp(function(spec) {
7649
- var overlays = this.state.overlays;
7650
- for (var i = 0; i < overlays.length; ++i) {
7651
- var cur = overlays[i].modeSpec;
7652
- if (cur == spec || typeof spec == "string" && cur.name == spec) {
7653
- overlays.splice(i, 1);
7654
- this.state.modeGen++;
7655
- regChange(this);
7656
- return;
7657
- }
7658
- }
7659
- }),
7660
 
7661
- indentLine: methodOp(function(n, dir, aggressive) {
7662
- if (typeof dir != "string" && typeof dir != "number") {
7663
- if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
7664
- else dir = dir ? "add" : "subtract";
7665
- }
7666
- if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);
7667
- }),
7668
- indentSelection: methodOp(function(how) {
7669
- var ranges = this.doc.sel.ranges, end = -1;
7670
- for (var i = 0; i < ranges.length; i++) {
7671
- var range = ranges[i];
7672
- if (!range.empty()) {
7673
- var from = range.from(), to = range.to();
7674
- var start = Math.max(end, from.line);
7675
- end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
7676
- for (var j = start; j < end; ++j)
7677
- indentLine(this, j, how);
7678
- var newRanges = this.doc.sel.ranges;
7679
- if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
7680
- replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll);
7681
- } else if (range.head.line > end) {
7682
- indentLine(this, range.head.line, how, true);
7683
- end = range.head.line;
7684
- if (i == this.doc.sel.primIndex) ensureCursorVisible(this);
7685
- }
7686
- }
7687
- }),
7688
 
7689
- // Fetch the parser token for a given character. Useful for hacks
7690
- // that want to inspect the mode state (say, for completion).
7691
- getTokenAt: function(pos, precise) {
7692
- return takeToken(this, pos, precise);
7693
- },
7694
 
7695
- getLineTokens: function(line, precise) {
7696
- return takeToken(this, Pos(line), precise, true);
7697
- },
7698
 
7699
- getTokenTypeAt: function(pos) {
7700
- pos = clipPos(this.doc, pos);
7701
- var styles = getLineStyles(this, getLine(this.doc, pos.line));
7702
- var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
7703
- var type;
7704
- if (ch == 0) type = styles[2];
7705
- else for (;;) {
7706
- var mid = (before + after) >> 1;
7707
- if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
7708
- else if (styles[mid * 2 + 1] < ch) before = mid + 1;
7709
- else { type = styles[mid * 2 + 2]; break; }
7710
- }
7711
- var cut = type ? type.indexOf("cm-overlay ") : -1;
7712
- return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1);
7713
- },
7714
 
7715
- getModeAt: function(pos) {
7716
- var mode = this.doc.mode;
7717
- if (!mode.innerMode) return mode;
7718
- return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;
7719
- },
7720
 
7721
- getHelper: function(pos, type) {
7722
- return this.getHelpers(pos, type)[0];
7723
- },
 
 
 
7724
 
7725
- getHelpers: function(pos, type) {
7726
- var found = [];
7727
- if (!helpers.hasOwnProperty(type)) return found;
7728
- var help = helpers[type], mode = this.getModeAt(pos);
7729
- if (typeof mode[type] == "string") {
7730
- if (help[mode[type]]) found.push(help[mode[type]]);
7731
- } else if (mode[type]) {
7732
- for (var i = 0; i < mode[type].length; i++) {
7733
- var val = help[mode[type][i]];
7734
- if (val) found.push(val);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7735
  }
7736
- } else if (mode.helperType && help[mode.helperType]) {
7737
- found.push(help[mode.helperType]);
7738
- } else if (help[mode.name]) {
7739
- found.push(help[mode.name]);
7740
  }
7741
- for (var i = 0; i < help._global.length; i++) {
7742
- var cur = help._global[i];
7743
- if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
7744
- found.push(cur.val);
 
 
 
 
7745
  }
7746
- return found;
7747
- },
7748
 
7749
- getStateAfter: function(line, precise) {
7750
- var doc = this.doc;
7751
- line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
7752
- return getStateBefore(this, line + 1, precise);
7753
- },
 
 
 
7754
 
7755
- cursorCoords: function(start, mode) {
7756
- var pos, range = this.doc.sel.primary();
7757
- if (start == null) pos = range.head;
7758
- else if (typeof start == "object") pos = clipPos(this.doc, start);
7759
- else pos = start ? range.from() : range.to();
7760
- return cursorCoords(this, pos, mode || "page");
7761
- },
 
 
 
 
 
 
7762
 
7763
- charCoords: function(pos, mode) {
7764
- return charCoords(this, clipPos(this.doc, pos), mode || "page");
7765
- },
 
 
 
 
 
 
 
 
7766
 
7767
- coordsChar: function(coords, mode) {
7768
- coords = fromCoordSystem(this, coords, mode || "page");
7769
- return coordsChar(this, coords.left, coords.top);
7770
- },
7771
 
7772
- lineAtHeight: function(height, mode) {
7773
- height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
7774
- return lineAtHeight(this.doc, height + this.display.viewOffset);
7775
- },
7776
- heightAtLine: function(line, mode) {
7777
- var end = false, lineObj;
7778
- if (typeof line == "number") {
7779
- var last = this.doc.first + this.doc.size - 1;
7780
- if (line < this.doc.first) line = this.doc.first;
7781
- else if (line > last) { line = last; end = true; }
7782
- lineObj = getLine(this.doc, line);
7783
- } else {
7784
- lineObj = line;
7785
- }
7786
- return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top +
7787
- (end ? this.doc.height - heightAtLine(lineObj) : 0);
7788
- },
 
 
 
 
 
 
 
7789
 
7790
- defaultTextHeight: function() { return textHeight(this.display); },
7791
- defaultCharWidth: function() { return charWidth(this.display); },
 
 
 
 
 
7792
 
7793
- setGutterMarker: methodOp(function(line, gutterID, value) {
7794
- return changeLine(this.doc, line, "gutter", function(line) {
7795
- var markers = line.gutterMarkers || (line.gutterMarkers = {});
7796
- markers[gutterID] = value;
7797
- if (!value && isEmpty(markers)) line.gutterMarkers = null;
7798
- return true;
7799
- });
7800
- }),
7801
 
7802
- clearGutter: methodOp(function(gutterID) {
7803
- var cm = this, doc = cm.doc, i = doc.first;
7804
- doc.iter(function(line) {
7805
- if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
7806
- line.gutterMarkers[gutterID] = null;
7807
- regLineChange(cm, i, "gutter");
7808
- if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
7809
- }
7810
- ++i;
7811
- });
7812
- }),
7813
 
7814
- lineInfo: function(line) {
7815
- if (typeof line == "number") {
7816
- if (!isLine(this.doc, line)) return null;
7817
- var n = line;
7818
- line = getLine(this.doc, line);
7819
- if (!line) return null;
7820
- } else {
7821
- var n = lineNo(line);
7822
- if (n == null) return null;
7823
- }
7824
- return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
7825
- textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
7826
- widgets: line.widgets};
7827
- },
7828
 
7829
- getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};},
 
7830
 
7831
- addWidget: function(pos, node, scroll, vert, horiz) {
7832
- var display = this.display;
7833
- pos = cursorCoords(this, clipPos(this.doc, pos));
7834
- var top = pos.bottom, left = pos.left;
7835
- node.style.position = "absolute";
7836
- node.setAttribute("cm-ignore-events", "true");
7837
- this.display.input.setUneditable(node);
7838
- display.sizer.appendChild(node);
7839
- if (vert == "over") {
7840
- top = pos.top;
7841
- } else if (vert == "above" || vert == "near") {
7842
- var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
7843
- hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
7844
- // Default to positioning above (if specified and possible); otherwise default to positioning below
7845
- if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
7846
- top = pos.top - node.offsetHeight;
7847
- else if (pos.bottom + node.offsetHeight <= vspace)
7848
- top = pos.bottom;
7849
- if (left + node.offsetWidth > hspace)
7850
- left = hspace - node.offsetWidth;
7851
- }
7852
- node.style.top = top + "px";
7853
- node.style.left = node.style.right = "";
7854
- if (horiz == "right") {
7855
- left = display.sizer.clientWidth - node.offsetWidth;
7856
- node.style.right = "0px";
7857
- } else {
7858
- if (horiz == "left") left = 0;
7859
- else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
7860
- node.style.left = left + "px";
7861
- }
7862
- if (scroll)
7863
- scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
7864
- },
7865
 
7866
- triggerOnKeyDown: methodOp(onKeyDown),
7867
- triggerOnKeyPress: methodOp(onKeyPress),
7868
- triggerOnKeyUp: onKeyUp,
7869
 
7870
- execCommand: function(cmd) {
7871
- if (commands.hasOwnProperty(cmd))
7872
- return commands[cmd].call(null, this);
7873
- },
7874
 
7875
- triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
 
 
 
 
 
 
 
 
 
7876
 
7877
- findPosH: function(from, amount, unit, visually) {
7878
- var dir = 1;
7879
- if (amount < 0) { dir = -1; amount = -amount; }
7880
- for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
7881
- cur = findPosH(this.doc, cur, dir, unit, visually);
7882
- if (cur.hitSide) break;
 
7883
  }
7884
- return cur;
7885
- },
 
 
7886
 
7887
- moveH: methodOp(function(dir, unit) {
7888
- var cm = this;
7889
- cm.extendSelectionsBy(function(range) {
7890
- if (cm.display.shift || cm.doc.extend || range.empty())
7891
- return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually);
7892
- else
7893
- return dir < 0 ? range.from() : range.to();
7894
- }, sel_move);
7895
- }),
7896
 
7897
- deleteH: methodOp(function(dir, unit) {
7898
- var sel = this.doc.sel, doc = this.doc;
7899
- if (sel.somethingSelected())
7900
- doc.replaceSelection("", null, "+delete");
7901
- else
7902
- deleteNearSelection(this, function(range) {
7903
- var other = findPosH(doc, range.head, dir, unit, false);
7904
- return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other};
7905
- });
7906
- }),
7907
 
7908
- findPosV: function(from, amount, unit, goalColumn) {
7909
- var dir = 1, x = goalColumn;
7910
- if (amount < 0) { dir = -1; amount = -amount; }
7911
- for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
7912
- var coords = cursorCoords(this, cur, "div");
7913
- if (x == null) x = coords.left;
7914
- else coords.left = x;
7915
- cur = findPosV(this, coords, dir, unit);
7916
- if (cur.hitSide) break;
7917
- }
7918
- return cur;
7919
- },
7920
 
7921
- moveV: methodOp(function(dir, unit) {
7922
- var cm = this, doc = this.doc, goals = [];
7923
- var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected();
7924
- doc.extendSelectionsBy(function(range) {
7925
- if (collapse)
7926
- return dir < 0 ? range.from() : range.to();
7927
- var headPos = cursorCoords(cm, range.head, "div");
7928
- if (range.goalColumn != null) headPos.left = range.goalColumn;
7929
- goals.push(headPos.left);
7930
- var pos = findPosV(cm, headPos, dir, unit);
7931
- if (unit == "page" && range == doc.sel.primary())
7932
- addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top);
7933
- return pos;
7934
- }, sel_move);
7935
- if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++)
7936
- doc.sel.ranges[i].goalColumn = goals[i];
7937
- }),
7938
 
7939
- // Find the word at the given position (as returned by coordsChar).
7940
- findWordAt: function(pos) {
7941
- var doc = this.doc, line = getLine(doc, pos.line).text;
7942
- var start = pos.ch, end = pos.ch;
7943
- if (line) {
7944
- var helper = this.getHelper(pos, "wordChars");
7945
- if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end;
7946
- var startChar = line.charAt(start);
7947
- var check = isWordChar(startChar, helper)
7948
- ? function(ch) { return isWordChar(ch, helper); }
7949
- : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);}
7950
- : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
7951
- while (start > 0 && check(line.charAt(start - 1))) --start;
7952
- while (end < line.length && check(line.charAt(end))) ++end;
7953
  }
7954
- return new Range(Pos(pos.line, start), Pos(pos.line, end));
7955
- },
 
7956
 
7957
- toggleOverwrite: function(value) {
7958
- if (value != null && value == this.state.overwrite) return;
7959
- if (this.state.overwrite = !this.state.overwrite)
7960
- addClass(this.display.cursorDiv, "CodeMirror-overwrite");
7961
- else
7962
- rmClass(this.display.cursorDiv, "CodeMirror-overwrite");
7963
 
7964
- signal(this, "overwriteToggle", this, this.state.overwrite);
7965
- },
7966
- hasFocus: function() { return this.display.input.getField() == activeElt(); },
7967
- isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit); },
7968
 
7969
- scrollTo: methodOp(function(x, y) {
7970
- if (x != null || y != null) resolveScrollToPos(this);
7971
- if (x != null) this.curOp.scrollLeft = x;
7972
- if (y != null) this.curOp.scrollTop = y;
7973
- }),
7974
- getScrollInfo: function() {
7975
- var scroller = this.display.scroller;
7976
- return {left: scroller.scrollLeft, top: scroller.scrollTop,
7977
- height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
7978
- width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
7979
- clientHeight: displayHeight(this), clientWidth: displayWidth(this)};
7980
- },
 
 
 
7981
 
7982
- scrollIntoView: methodOp(function(range, margin) {
7983
- if (range == null) {
7984
- range = {from: this.doc.sel.primary().head, to: null};
7985
- if (margin == null) margin = this.options.cursorScrollMargin;
7986
- } else if (typeof range == "number") {
7987
- range = {from: Pos(range, 0), to: null};
7988
- } else if (range.from == null) {
7989
- range = {from: range, to: null};
7990
- }
7991
- if (!range.to) range.to = range.from;
7992
- range.margin = margin || 0;
7993
 
7994
- if (range.from.line != null) {
7995
- resolveScrollToPos(this);
7996
- this.curOp.scrollToPos = range;
7997
- } else {
7998
- var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left),
7999
- Math.min(range.from.top, range.to.top) - range.margin,
8000
- Math.max(range.from.right, range.to.right),
8001
- Math.max(range.from.bottom, range.to.bottom) + range.margin);
8002
- this.scrollTo(sPos.scrollLeft, sPos.scrollTop);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8003
  }
8004
- }),
 
8005
 
8006
- setSize: methodOp(function(width, height) {
8007
- var cm = this;
8008
- function interpret(val) {
8009
- return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
 
 
 
 
 
 
 
 
 
8010
  }
8011
- if (width != null) cm.display.wrapper.style.width = interpret(width);
8012
- if (height != null) cm.display.wrapper.style.height = interpret(height);
8013
- if (cm.options.lineWrapping) clearLineMeasurementCache(this);
8014
- var lineNo = cm.display.viewFrom;
8015
- cm.doc.iter(lineNo, cm.display.viewTo, function(line) {
8016
- if (line.widgets) for (var i = 0; i < line.widgets.length; i++)
8017
- if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; }
8018
- ++lineNo;
8019
- });
8020
- cm.curOp.forceUpdate = true;
8021
- signal(cm, "refresh", this);
8022
- }),
8023
 
8024
- operation: function(f){return runInOp(this, f);},
 
 
8025
 
8026
- refresh: methodOp(function() {
8027
- var oldHeight = this.display.cachedTextHeight;
8028
- regChange(this);
8029
- this.curOp.forceUpdate = true;
8030
- clearCaches(this);
8031
- this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
8032
- updateGutterSpace(this);
8033
- if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
8034
- estimateLineHeights(this);
8035
- signal(this, "refresh", this);
8036
- }),
8037
 
8038
- swapDoc: methodOp(function(doc) {
8039
- var old = this.doc;
8040
- old.cm = null;
8041
- attachDoc(this, doc);
8042
- clearCaches(this);
8043
- this.display.input.reset();
8044
- this.scrollTo(doc.scrollLeft, doc.scrollTop);
8045
- this.curOp.forceScroll = true;
8046
- signalLater(this, "swapDoc", this, old);
8047
- return old;
8048
- }),
 
 
8049
 
8050
- getInputField: function(){return this.display.input.getField();},
8051
- getWrapperElement: function(){return this.display.wrapper;},
8052
- getScrollerElement: function(){return this.display.scroller;},
8053
- getGutterElement: function(){return this.display.gutters;}
8054
- };
8055
- eventMixin(CodeMirror);
8056
 
8057
- // OPTION DEFAULTS
8058
 
8059
- // The default configuration options.
8060
- var defaults = CodeMirror.defaults = {};
8061
- // Functions to run when options are changed.
8062
- var optionHandlers = CodeMirror.optionHandlers = {};
 
 
 
 
8063
 
8064
- function option(name, deflt, handle, notOnInit) {
8065
- CodeMirror.defaults[name] = deflt;
8066
- if (handle) optionHandlers[name] =
8067
- notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8068
  }
 
8069
 
8070
- // Passed to option handlers when there is no old value.
8071
- var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}};
 
 
 
8072
 
8073
- // These two are, on init, called from the constructor because they
8074
- // have to be initialized before the editor can start at all.
8075
- option("value", "", function(cm, val) {
8076
- cm.setValue(val);
8077
- }, true);
8078
- option("mode", null, function(cm, val) {
8079
- cm.doc.modeOption = val;
8080
- loadMode(cm);
8081
- }, true);
8082
-
8083
- option("indentUnit", 2, loadMode, true);
8084
- option("indentWithTabs", false);
8085
- option("smartIndent", true);
8086
- option("tabSize", 4, function(cm) {
8087
- resetModeState(cm);
8088
- clearCaches(cm);
8089
- regChange(cm);
8090
- }, true);
8091
- option("lineSeparator", null, function(cm, val) {
8092
- cm.doc.lineSep = val;
8093
- if (!val) return;
8094
- var newBreaks = [], lineNo = cm.doc.first;
8095
- cm.doc.iter(function(line) {
8096
- for (var pos = 0;;) {
8097
- var found = line.text.indexOf(val, pos);
8098
- if (found == -1) break;
8099
- pos = found + val.length;
8100
- newBreaks.push(Pos(lineNo, found));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8101
  }
8102
- lineNo++;
8103
- });
8104
- for (var i = newBreaks.length - 1; i >= 0; i--)
8105
- replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length))
8106
- });
8107
- option("specialChars", /[\u0000-\u001f\u007f\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) {
8108
- cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
8109
- if (old != CodeMirror.Init) cm.refresh();
8110
- });
8111
- option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);
8112
- option("electricChars", true);
8113
- option("inputStyle", mobile ? "contenteditable" : "textarea", function() {
8114
- throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME
8115
- }, true);
8116
- option("spellcheck", false, function(cm, val) {
8117
- cm.getInputField().spellcheck = val
8118
- }, true);
8119
- option("rtlMoveVisually", !windows);
8120
- option("wholeLineUpdateBefore", true);
8121
-
8122
- option("theme", "default", function(cm) {
8123
- themeChanged(cm);
8124
- guttersChanged(cm);
8125
- }, true);
8126
- option("keyMap", "default", function(cm, val, old) {
8127
- var next = getKeyMap(val);
8128
- var prev = old != CodeMirror.Init && getKeyMap(old);
8129
- if (prev && prev.detach) prev.detach(cm, next);
8130
- if (next.attach) next.attach(cm, prev || null);
8131
- });
8132
- option("extraKeys", null);
8133
-
8134
- option("lineWrapping", false, wrappingChanged, true);
8135
- option("gutters", [], function(cm) {
8136
- setGuttersForLineNumbers(cm.options);
8137
- guttersChanged(cm);
8138
- }, true);
8139
- option("fixedGutter", true, function(cm, val) {
8140
- cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
8141
- cm.refresh();
8142
- }, true);
8143
- option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true);
8144
- option("scrollbarStyle", "native", function(cm) {
8145
- initScrollbars(cm);
8146
- updateScrollbars(cm);
8147
- cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
8148
- cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
8149
- }, true);
8150
- option("lineNumbers", false, function(cm) {
8151
- setGuttersForLineNumbers(cm.options);
8152
- guttersChanged(cm);
8153
- }, true);
8154
- option("firstLineNumber", 1, guttersChanged, true);
8155
- option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
8156
- option("showCursorWhenSelecting", false, updateSelection, true);
8157
-
8158
- option("resetSelectionOnContextMenu", true);
8159
- option("lineWiseCopyCut", true);
8160
-
8161
- option("readOnly", false, function(cm, val) {
8162
- if (val == "nocursor") {
8163
- onBlur(cm);
8164
- cm.display.input.blur();
8165
- cm.display.disabled = true;
8166
- } else {
8167
- cm.display.disabled = false;
8168
  }
8169
- cm.display.input.readOnlyChanged(val)
8170
- });
8171
- option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true);
8172
- option("dragDrop", true, dragDropChanged);
8173
- option("allowDropFileTypes", null);
8174
-
8175
- option("cursorBlinkRate", 530);
8176
- option("cursorScrollMargin", 0);
8177
- option("cursorHeight", 1, updateSelection, true);
8178
- option("singleCursorHeightPerLine", true, updateSelection, true);
8179
- option("workTime", 100);
8180
- option("workDelay", 100);
8181
- option("flattenSpans", true, resetModeState, true);
8182
- option("addModeClass", false, resetModeState, true);
8183
- option("pollInterval", 100);
8184
- option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;});
8185
- option("historyEventDelay", 1250);
8186
- option("viewportMargin", 10, function(cm){cm.refresh();}, true);
8187
- option("maxHighlightLength", 10000, resetModeState, true);
8188
- option("moveInputWithCursor", true, function(cm, val) {
8189
- if (!val) cm.display.input.resetPosition();
8190
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8191
 
8192
- option("tabindex", null, function(cm, val) {
8193
- cm.display.input.getField().tabIndex = val || "";
8194
- });
8195
- option("autofocus", null);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8196
 
8197
- // MODE DEFINITION AND QUERYING
8198
 
8199
- // Known modes, by name and by MIME
8200
- var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
 
 
 
8201
 
8202
- // Extra arguments are stored as the mode's dependencies, which is
8203
- // used by (legacy) mechanisms like loadmode.js to automatically
8204
- // load a mode. (Preferred mechanism is the require/define calls.)
8205
- CodeMirror.defineMode = function(name, mode) {
8206
- if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
8207
- if (arguments.length > 2)
8208
- mode.dependencies = Array.prototype.slice.call(arguments, 2);
8209
- modes[name] = mode;
8210
- };
8211
 
8212
- CodeMirror.defineMIME = function(mime, spec) {
8213
- mimeModes[mime] = spec;
8214
- };
8215
 
8216
- // Given a MIME type, a {name, ...options} config object, or a name
8217
- // string, return a mode config object.
8218
- CodeMirror.resolveMode = function(spec) {
8219
- if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
8220
- spec = mimeModes[spec];
8221
- } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
8222
- var found = mimeModes[spec.name];
8223
- if (typeof found == "string") found = {name: found};
8224
- spec = createObj(found, spec);
8225
- spec.name = found.name;
8226
- } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
8227
- return CodeMirror.resolveMode("application/xml");
8228
- } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
8229
- return CodeMirror.resolveMode("application/json");
8230
- }
8231
- if (typeof spec == "string") return {name: spec};
8232
- else return spec || {name: "null"};
8233
- };
8234
 
8235
- // Given a mode spec (anything that resolveMode accepts), find and
8236
- // initialize an actual mode object.
8237
- CodeMirror.getMode = function(options, spec) {
8238
- var spec = CodeMirror.resolveMode(spec);
8239
- var mfactory = modes[spec.name];
8240
- if (!mfactory) return CodeMirror.getMode(options, "text/plain");
8241
- var modeObj = mfactory(options, spec);
8242
- if (modeExtensions.hasOwnProperty(spec.name)) {
8243
- var exts = modeExtensions[spec.name];
8244
- for (var prop in exts) {
8245
- if (!exts.hasOwnProperty(prop)) continue;
8246
- if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
8247
- modeObj[prop] = exts[prop];
8248
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
8249
  }
8250
- modeObj.name = spec.name;
8251
- if (spec.helperType) modeObj.helperType = spec.helperType;
8252
- if (spec.modeProps) for (var prop in spec.modeProps)
8253
- modeObj[prop] = spec.modeProps[prop];
8254
 
8255
- return modeObj;
 
 
 
 
 
 
 
 
 
 
8256
  };
8257
 
8258
- // Minimal default mode.
8259
- CodeMirror.defineMode("null", function() {
8260
- return {token: function(stream) {stream.skipToEnd();}};
8261
- });
8262
- CodeMirror.defineMIME("text/plain", "null");
8263
-
8264
- // This can be used to attach properties to mode objects from
8265
- // outside the actual mode definition.
8266
- var modeExtensions = CodeMirror.modeExtensions = {};
8267
- CodeMirror.extendMode = function(mode, properties) {
8268
- var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
8269
- copyObj(properties, exts);
8270
- };
8271
 
8272
- // EXTENSIONS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8273
 
8274
- CodeMirror.defineExtension = function(name, func) {
8275
- CodeMirror.prototype[name] = func;
8276
- };
8277
- CodeMirror.defineDocExtension = function(name, func) {
8278
- Doc.prototype[name] = func;
8279
- };
8280
- CodeMirror.defineOption = option;
 
 
 
8281
 
8282
- var initHooks = [];
8283
- CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
 
 
 
 
 
8284
 
8285
- var helpers = CodeMirror.helpers = {};
8286
- CodeMirror.registerHelper = function(type, name, value) {
8287
- if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};
8288
- helpers[type][name] = value;
8289
- };
8290
- CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
8291
- CodeMirror.registerHelper(type, name, value);
8292
- helpers[type]._global.push({pred: predicate, val: value});
8293
- };
8294
 
8295
- // MODE STATE HANDLING
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8296
 
8297
- // Utility functions for working with state. Exported because nested
8298
- // modes need to do this for their inner modes.
8299
 
8300
- var copyState = CodeMirror.copyState = function(mode, state) {
8301
- if (state === true) return state;
8302
- if (mode.copyState) return mode.copyState(state);
8303
- var nstate = {};
8304
- for (var n in state) {
8305
- var val = state[n];
8306
- if (val instanceof Array) val = val.concat([]);
8307
- nstate[n] = val;
8308
- }
8309
- return nstate;
8310
- };
8311
 
8312
- var startState = CodeMirror.startState = function(mode, a1, a2) {
8313
- return mode.startState ? mode.startState(a1, a2) : true;
8314
- };
 
8315
 
8316
- // Given a mode and a state (for that mode), find the inner mode and
8317
- // state at the position that the state refers to.
8318
- CodeMirror.innerMode = function(mode, state) {
8319
- while (mode.innerMode) {
8320
- var info = mode.innerMode(state);
8321
- if (!info || info.mode == mode) break;
8322
- state = info.state;
8323
- mode = info.mode;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8324
  }
8325
- return info || {mode: mode, state: state};
8326
- };
 
 
 
8327
 
8328
- // STANDARD COMMANDS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8329
 
8330
- // Commands are parameter-less actions that can be performed on an
8331
- // editor, mostly used for keybindings.
8332
- var commands = CodeMirror.commands = {
8333
- selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);},
8334
- singleSelection: function(cm) {
8335
- cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll);
8336
- },
8337
- killLine: function(cm) {
8338
- deleteNearSelection(cm, function(range) {
8339
- if (range.empty()) {
8340
- var len = getLine(cm.doc, range.head.line).text.length;
8341
- if (range.head.ch == len && range.head.line < cm.lastLine())
8342
- return {from: range.head, to: Pos(range.head.line + 1, 0)};
8343
- else
8344
- return {from: range.head, to: Pos(range.head.line, len)};
8345
- } else {
8346
- return {from: range.from(), to: range.to()};
8347
- }
8348
- });
8349
- },
8350
- deleteLine: function(cm) {
8351
- deleteNearSelection(cm, function(range) {
8352
- return {from: Pos(range.from().line, 0),
8353
- to: clipPos(cm.doc, Pos(range.to().line + 1, 0))};
8354
- });
8355
- },
8356
- delLineLeft: function(cm) {
8357
- deleteNearSelection(cm, function(range) {
8358
- return {from: Pos(range.from().line, 0), to: range.from()};
8359
- });
8360
- },
8361
- delWrappedLineLeft: function(cm) {
8362
- deleteNearSelection(cm, function(range) {
8363
- var top = cm.charCoords(range.head, "div").top + 5;
8364
- var leftPos = cm.coordsChar({left: 0, top: top}, "div");
8365
- return {from: leftPos, to: range.from()};
8366
- });
8367
- },
8368
- delWrappedLineRight: function(cm) {
8369
- deleteNearSelection(cm, function(range) {
8370
- var top = cm.charCoords(range.head, "div").top + 5;
8371
- var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
8372
- return {from: range.from(), to: rightPos };
8373
- });
8374
- },
8375
- undo: function(cm) {cm.undo();},
8376
- redo: function(cm) {cm.redo();},
8377
- undoSelection: function(cm) {cm.undoSelection();},
8378
- redoSelection: function(cm) {cm.redoSelection();},
8379
- goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},
8380
- goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},
8381
- goLineStart: function(cm) {
8382
- cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); },
8383
- {origin: "+move", bias: 1});
8384
- },
8385
- goLineStartSmart: function(cm) {
8386
- cm.extendSelectionsBy(function(range) {
8387
- return lineStartSmart(cm, range.head);
8388
- }, {origin: "+move", bias: 1});
8389
- },
8390
- goLineEnd: function(cm) {
8391
- cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); },
8392
- {origin: "+move", bias: -1});
8393
- },
8394
- goLineRight: function(cm) {
8395
- cm.extendSelectionsBy(function(range) {
8396
- var top = cm.charCoords(range.head, "div").top + 5;
8397
- return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
8398
- }, sel_move);
8399
- },
8400
- goLineLeft: function(cm) {
8401
- cm.extendSelectionsBy(function(range) {
8402
- var top = cm.charCoords(range.head, "div").top + 5;
8403
- return cm.coordsChar({left: 0, top: top}, "div");
8404
- }, sel_move);
8405
- },
8406
- goLineLeftSmart: function(cm) {
8407
- cm.extendSelectionsBy(function(range) {
8408
- var top = cm.charCoords(range.head, "div").top + 5;
8409
- var pos = cm.coordsChar({left: 0, top: top}, "div");
8410
- if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head);
8411
- return pos;
8412
- }, sel_move);
8413
- },
8414
- goLineUp: function(cm) {cm.moveV(-1, "line");},
8415
- goLineDown: function(cm) {cm.moveV(1, "line");},
8416
- goPageUp: function(cm) {cm.moveV(-1, "page");},
8417
- goPageDown: function(cm) {cm.moveV(1, "page");},
8418
- goCharLeft: function(cm) {cm.moveH(-1, "char");},
8419
- goCharRight: function(cm) {cm.moveH(1, "char");},
8420
- goColumnLeft: function(cm) {cm.moveH(-1, "column");},
8421
- goColumnRight: function(cm) {cm.moveH(1, "column");},
8422
- goWordLeft: function(cm) {cm.moveH(-1, "word");},
8423
- goGroupRight: function(cm) {cm.moveH(1, "group");},
8424
- goGroupLeft: function(cm) {cm.moveH(-1, "group");},
8425
- goWordRight: function(cm) {cm.moveH(1, "word");},
8426
- delCharBefore: function(cm) {cm.deleteH(-1, "char");},
8427
- delCharAfter: function(cm) {cm.deleteH(1, "char");},
8428
- delWordBefore: function(cm) {cm.deleteH(-1, "word");},
8429
- delWordAfter: function(cm) {cm.deleteH(1, "word");},
8430
- delGroupBefore: function(cm) {cm.deleteH(-1, "group");},
8431
- delGroupAfter: function(cm) {cm.deleteH(1, "group");},
8432
- indentAuto: function(cm) {cm.indentSelection("smart");},
8433
- indentMore: function(cm) {cm.indentSelection("add");},
8434
- indentLess: function(cm) {cm.indentSelection("subtract");},
8435
- insertTab: function(cm) {cm.replaceSelection("\t");},
8436
- insertSoftTab: function(cm) {
8437
- var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
8438
- for (var i = 0; i < ranges.length; i++) {
8439
- var pos = ranges[i].from();
8440
- var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
8441
- spaces.push(spaceStr(tabSize - col % tabSize));
8442
- }
8443
- cm.replaceSelections(spaces);
8444
- },
8445
- defaultTab: function(cm) {
8446
- if (cm.somethingSelected()) cm.indentSelection("add");
8447
- else cm.execCommand("insertTab");
8448
- },
8449
- transposeChars: function(cm) {
8450
- runInOp(cm, function() {
8451
- var ranges = cm.listSelections(), newSel = [];
8452
- for (var i = 0; i < ranges.length; i++) {
8453
- var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
8454
- if (line) {
8455
- if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1);
8456
- if (cur.ch > 0) {
8457
- cur = new Pos(cur.line, cur.ch + 1);
8458
- cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
8459
- Pos(cur.line, cur.ch - 2), cur, "+transpose");
8460
- } else if (cur.line > cm.doc.first) {
8461
- var prev = getLine(cm.doc, cur.line - 1).text;
8462
- if (prev)
8463
- cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
8464
- prev.charAt(prev.length - 1),
8465
- Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose");
8466
- }
8467
- }
8468
- newSel.push(new Range(cur, cur));
8469
- }
8470
- cm.setSelections(newSel);
8471
- });
8472
- },
8473
- newlineAndIndent: function(cm) {
8474
- runInOp(cm, function() {
8475
- var len = cm.listSelections().length;
8476
- for (var i = 0; i < len; i++) {
8477
- var range = cm.listSelections()[i];
8478
- cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input");
8479
- cm.indentLine(range.from().line + 1, null, true);
8480
- }
8481
- ensureCursorVisible(cm);
8482
- });
8483
- },
8484
- openLine: function(cm) {cm.replaceSelection("\n", "start")},
8485
- toggleOverwrite: function(cm) {cm.toggleOverwrite();}
8486
- };
8487
 
 
 
 
 
 
 
 
 
 
 
 
8488
 
8489
- // STANDARD KEYMAPS
 
 
 
 
 
 
 
 
8490
 
8491
- var keyMap = CodeMirror.keyMap = {};
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8492
 
8493
- keyMap.basic = {
8494
- "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
8495
- "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
8496
- "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
8497
- "Tab": "defaultTab", "Shift-Tab": "indentAuto",
8498
- "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
8499
- "Esc": "singleSelection"
8500
- };
8501
- // Note that the save and find-related commands aren't defined by
8502
- // default. User code or addons can define them. Unknown commands
8503
- // are simply ignored.
8504
- keyMap.pcDefault = {
8505
- "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
8506
- "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
8507
- "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
8508
- "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
8509
- "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
8510
- "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
8511
- "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
8512
- fallthrough: "basic"
8513
- };
8514
- // Very basic readline/emacs-style bindings, which are standard on Mac.
8515
- keyMap.emacsy = {
8516
- "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
8517
- "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
8518
- "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
8519
- "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars",
8520
- "Ctrl-O": "openLine"
8521
- };
8522
- keyMap.macDefault = {
8523
- "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
8524
- "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
8525
- "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
8526
- "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
8527
- "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
8528
- "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
8529
- "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
8530
- fallthrough: ["basic", "emacsy"]
8531
- };
8532
- keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
8533
-
8534
- // KEYMAP DISPATCH
8535
-
8536
- function normalizeKeyName(name) {
8537
- var parts = name.split(/-(?!$)/), name = parts[parts.length - 1];
8538
- var alt, ctrl, shift, cmd;
8539
- for (var i = 0; i < parts.length - 1; i++) {
8540
- var mod = parts[i];
8541
- if (/^(cmd|meta|m)$/i.test(mod)) cmd = true;
8542
- else if (/^a(lt)?$/i.test(mod)) alt = true;
8543
- else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true;
8544
- else if (/^s(hift)$/i.test(mod)) shift = true;
8545
- else throw new Error("Unrecognized modifier name: " + mod);
8546
- }
8547
- if (alt) name = "Alt-" + name;
8548
- if (ctrl) name = "Ctrl-" + name;
8549
- if (cmd) name = "Cmd-" + name;
8550
- if (shift) name = "Shift-" + name;
8551
- return name;
8552
- }
8553
-
8554
- // This is a kludge to keep keymaps mostly working as raw objects
8555
- // (backwards compatibility) while at the same time support features
8556
- // like normalization and multi-stroke key bindings. It compiles a
8557
- // new normalized keymap, and then updates the old object to reflect
8558
- // this.
8559
- CodeMirror.normalizeKeyMap = function(keymap) {
8560
- var copy = {};
8561
- for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) {
8562
- var value = keymap[keyname];
8563
- if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue;
8564
- if (value == "...") { delete keymap[keyname]; continue; }
8565
-
8566
- var keys = map(keyname.split(" "), normalizeKeyName);
8567
- for (var i = 0; i < keys.length; i++) {
8568
- var val, name;
8569
- if (i == keys.length - 1) {
8570
- name = keys.join(" ");
8571
- val = value;
8572
- } else {
8573
- name = keys.slice(0, i + 1).join(" ");
8574
- val = "...";
8575
- }
8576
- var prev = copy[name];
8577
- if (!prev) copy[name] = val;
8578
- else if (prev != val) throw new Error("Inconsistent bindings for " + name);
8579
- }
8580
- delete keymap[keyname];
8581
  }
8582
- for (var prop in copy) keymap[prop] = copy[prop];
8583
- return keymap;
8584
- };
8585
 
8586
- var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) {
8587
- map = getKeyMap(map);
8588
- var found = map.call ? map.call(key, context) : map[key];
8589
- if (found === false) return "nothing";
8590
- if (found === "...") return "multi";
8591
- if (found != null && handle(found)) return "handled";
8592
-
8593
- if (map.fallthrough) {
8594
- if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
8595
- return lookupKey(key, map.fallthrough, handle, context);
8596
- for (var i = 0; i < map.fallthrough.length; i++) {
8597
- var result = lookupKey(key, map.fallthrough[i], handle, context);
8598
- if (result) return result;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8599
  }
8600
  }
8601
- };
 
 
8602
 
8603
- // Modifier key presses don't count as 'real' key presses for the
8604
- // purpose of keymap fallthrough.
8605
- var isModifierKey = CodeMirror.isModifierKey = function(value) {
8606
- var name = typeof value == "string" ? value : keyNames[value.keyCode];
8607
- return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
8608
- };
8609
 
8610
- // Look up the name of a key as indicated by an event object.
8611
- var keyName = CodeMirror.keyName = function(event, noShift) {
8612
- if (presto && event.keyCode == 34 && event["char"]) return false;
8613
- var base = keyNames[event.keyCode], name = base;
8614
- if (name == null || event.altGraphKey) return false;
8615
- if (event.altKey && base != "Alt") name = "Alt-" + name;
8616
- if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name;
8617
- if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name;
8618
- if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name;
8619
- return name;
8620
- };
8621
 
8622
- function getKeyMap(val) {
8623
- return typeof val == "string" ? keyMap[val] : val;
8624
- }
8625
-
8626
- // FROMTEXTAREA
8627
-
8628
- CodeMirror.fromTextArea = function(textarea, options) {
8629
- options = options ? copyObj(options) : {};
8630
- options.value = textarea.value;
8631
- if (!options.tabindex && textarea.tabIndex)
8632
- options.tabindex = textarea.tabIndex;
8633
- if (!options.placeholder && textarea.placeholder)
8634
- options.placeholder = textarea.placeholder;
8635
- // Set autofocus to true if this textarea is focused, or if it has
8636
- // autofocus and no other element is focused.
8637
- if (options.autofocus == null) {
8638
- var hasFocus = activeElt();
8639
- options.autofocus = hasFocus == textarea ||
8640
- textarea.getAttribute("autofocus") != null && hasFocus == document.body;
8641
- }
8642
-
8643
- function save() {textarea.value = cm.getValue();}
8644
- if (textarea.form) {
8645
- on(textarea.form, "submit", save);
8646
- // Deplorable hack to make the submit method do the right thing.
8647
- if (!options.leaveSubmitMethodAlone) {
8648
- var form = textarea.form, realSubmit = form.submit;
8649
- try {
8650
- var wrappedSubmit = form.submit = function() {
8651
- save();
8652
- form.submit = realSubmit;
8653
- form.submit();
8654
- form.submit = wrappedSubmit;
8655
- };
8656
- } catch(e) {}
8657
- }
8658
  }
 
 
 
 
8659
 
8660
- options.finishInit = function(cm) {
8661
- cm.save = save;
8662
- cm.getTextArea = function() { return textarea; };
8663
- cm.toTextArea = function() {
8664
- cm.toTextArea = isNaN; // Prevent this from being ran twice
8665
- save();
8666
- textarea.parentNode.removeChild(cm.getWrapperElement());
8667
- textarea.style.display = "";
8668
- if (textarea.form) {
8669
- off(textarea.form, "submit", save);
8670
- if (typeof textarea.form.submit == "function")
8671
- textarea.form.submit = realSubmit;
8672
- }
8673
- };
8674
- };
8675
 
8676
- textarea.style.display = "none";
8677
- var cm = CodeMirror(function(node) {
8678
- textarea.parentNode.insertBefore(node, textarea.nextSibling);
8679
- }, options);
8680
- return cm;
8681
- };
8682
 
8683
- // STRING STREAM
 
 
8684
 
8685
- // Fed to the mode parsers, provides helper functions to make
8686
- // parsers more succinct.
 
 
 
 
 
 
8687
 
8688
- var StringStream = CodeMirror.StringStream = function(string, tabSize) {
8689
- this.pos = this.start = 0;
8690
- this.string = string;
8691
- this.tabSize = tabSize || 8;
8692
- this.lastColumnPos = this.lastColumnValue = 0;
8693
- this.lineStart = 0;
8694
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8695
 
8696
- StringStream.prototype = {
8697
- eol: function() {return this.pos >= this.string.length;},
8698
- sol: function() {return this.pos == this.lineStart;},
8699
- peek: function() {return this.string.charAt(this.pos) || undefined;},
8700
- next: function() {
8701
- if (this.pos < this.string.length)
8702
- return this.string.charAt(this.pos++);
8703
- },
8704
- eat: function(match) {
8705
- var ch = this.string.charAt(this.pos);
8706
- if (typeof match == "string") var ok = ch == match;
8707
- else var ok = ch && (match.test ? match.test(ch) : match(ch));
8708
- if (ok) {++this.pos; return ch;}
8709
- },
8710
- eatWhile: function(match) {
8711
- var start = this.pos;
8712
- while (this.eat(match)){}
8713
- return this.pos > start;
8714
- },
8715
- eatSpace: function() {
8716
- var start = this.pos;
8717
- while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
8718
- return this.pos > start;
8719
- },
8720
- skipToEnd: function() {this.pos = this.string.length;},
8721
- skipTo: function(ch) {
8722
- var found = this.string.indexOf(ch, this.pos);
8723
- if (found > -1) {this.pos = found; return true;}
8724
- },
8725
- backUp: function(n) {this.pos -= n;},
8726
- column: function() {
8727
- if (this.lastColumnPos < this.start) {
8728
- this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
8729
- this.lastColumnPos = this.start;
8730
- }
8731
- return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
8732
- },
8733
- indentation: function() {
8734
- return countColumn(this.string, null, this.tabSize) -
8735
- (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
8736
- },
8737
- match: function(pattern, consume, caseInsensitive) {
8738
- if (typeof pattern == "string") {
8739
- var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
8740
- var substr = this.string.substr(this.pos, pattern.length);
8741
- if (cased(substr) == cased(pattern)) {
8742
- if (consume !== false) this.pos += pattern.length;
8743
- return true;
8744
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8745
  } else {
8746
- var match = this.string.slice(this.pos).match(pattern);
8747
- if (match && match.index > 0) return null;
8748
- if (match && consume !== false) this.pos += match[0].length;
8749
- return match;
8750
  }
8751
- },
8752
- current: function(){return this.string.slice(this.start, this.pos);},
8753
- hideFirstChars: function(n, inner) {
8754
- this.lineStart += n;
8755
- try { return inner(); }
8756
- finally { this.lineStart -= n; }
8757
  }
8758
- };
 
 
 
 
8759
 
8760
- // TEXTMARKERS
 
 
 
 
 
8761
 
8762
- // Created with markText and setBookmark methods. A TextMarker is a
8763
- // handle that can be used to clear or find a marked position in the
8764
- // document. Line objects hold arrays (markedSpans) containing
8765
- // {from, to, marker} object pointing to such marker objects, and
8766
- // indicating that such a marker is present on that line. Multiple
8767
- // lines may point to the same marker when it spans across lines.
8768
- // The spans will have null for their from/to properties when the
8769
- // marker continues beyond the start/end of the line. Markers have
8770
- // links back to the lines they currently touch.
8771
 
8772
- var nextMarkerId = 0;
 
 
 
 
 
8773
 
8774
- var TextMarker = CodeMirror.TextMarker = function(doc, type) {
8775
- this.lines = [];
8776
- this.type = type;
8777
- this.doc = doc;
8778
- this.id = ++nextMarkerId;
8779
- };
8780
- eventMixin(TextMarker);
8781
-
8782
- // Clear the marker.
8783
- TextMarker.prototype.clear = function() {
8784
- if (this.explicitlyCleared) return;
8785
- var cm = this.doc.cm, withOp = cm && !cm.curOp;
8786
- if (withOp) startOperation(cm);
8787
- if (hasHandler(this, "clear")) {
8788
- var found = this.find();
8789
- if (found) signalLater(this, "clear", found.from, found.to);
8790
- }
8791
- var min = null, max = null;
8792
- for (var i = 0; i < this.lines.length; ++i) {
8793
- var line = this.lines[i];
8794
- var span = getMarkedSpanFor(line.markedSpans, this);
8795
- if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text");
8796
- else if (cm) {
8797
- if (span.to != null) max = lineNo(line);
8798
- if (span.from != null) min = lineNo(line);
8799
- }
8800
- line.markedSpans = removeMarkedSpan(line.markedSpans, span);
8801
- if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
8802
- updateLineHeight(line, textHeight(cm.display));
8803
- }
8804
- if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {
8805
- var visual = visualLine(this.lines[i]), len = lineLength(visual);
8806
- if (len > cm.display.maxLineLength) {
8807
- cm.display.maxLine = visual;
8808
- cm.display.maxLineLength = len;
8809
- cm.display.maxLineChanged = true;
8810
- }
8811
- }
8812
 
8813
- if (min != null && cm && this.collapsed) regChange(cm, min, max + 1);
8814
- this.lines.length = 0;
8815
- this.explicitlyCleared = true;
8816
- if (this.atomic && this.doc.cantEdit) {
8817
- this.doc.cantEdit = false;
8818
- if (cm) reCheckSelection(cm.doc);
8819
- }
8820
- if (cm) signalLater(cm, "markerCleared", cm, this);
8821
- if (withOp) endOperation(cm);
8822
- if (this.parent) this.parent.clear();
8823
- };
8824
 
8825
- // Find the position of the marker in the document. Returns a {from,
8826
- // to} object by default. Side can be passed to get a specific side
8827
- // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
8828
- // Pos objects returned contain a line object, rather than a line
8829
- // number (used to prevent looking up the same line twice).
8830
- TextMarker.prototype.find = function(side, lineObj) {
8831
- if (side == null && this.type == "bookmark") side = 1;
8832
- var from, to;
8833
- for (var i = 0; i < this.lines.length; ++i) {
8834
- var line = this.lines[i];
8835
- var span = getMarkedSpanFor(line.markedSpans, this);
8836
- if (span.from != null) {
8837
- from = Pos(lineObj ? line : lineNo(line), span.from);
8838
- if (side == -1) return from;
8839
- }
8840
- if (span.to != null) {
8841
- to = Pos(lineObj ? line : lineNo(line), span.to);
8842
- if (side == 1) return to;
8843
- }
8844
- }
8845
- return from && {from: from, to: to};
8846
- };
 
 
8847
 
8848
- // Signals that the marker's widget changed, and surrounding layout
8849
- // should be recomputed.
8850
- TextMarker.prototype.changed = function() {
8851
- var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
8852
- if (!pos || !cm) return;
8853
- runInOp(cm, function() {
8854
- var line = pos.line, lineN = lineNo(pos.line);
8855
- var view = findViewForLine(cm, lineN);
8856
- if (view) {
8857
- clearLineMeasurementCacheFor(view);
8858
- cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
8859
- }
8860
- cm.curOp.updateMaxLine = true;
8861
- if (!lineIsHidden(widget.doc, line) && widget.height != null) {
8862
- var oldHeight = widget.height;
8863
- widget.height = null;
8864
- var dHeight = widgetHeight(widget) - oldHeight;
8865
- if (dHeight)
8866
- updateLineHeight(line, line.height + dHeight);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8867
  }
8868
- });
8869
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8870
 
8871
- TextMarker.prototype.attachLine = function(line) {
8872
- if (!this.lines.length && this.doc.cm) {
8873
- var op = this.doc.cm.curOp;
8874
- if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
8875
- (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);
8876
- }
8877
- this.lines.push(line);
8878
- };
8879
- TextMarker.prototype.detachLine = function(line) {
8880
- this.lines.splice(indexOf(this.lines, line), 1);
8881
- if (!this.lines.length && this.doc.cm) {
8882
- var op = this.doc.cm.curOp;
8883
- (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
8884
- }
8885
- };
8886
 
8887
- // Collapsed markers have unique ids, in order to be able to order
8888
- // them, which is needed for uniquely determining an outer marker
8889
- // when they overlap (they may nest, but not partially overlap).
8890
- var nextMarkerId = 0;
8891
-
8892
- // Create a marker, wire it up to the right lines, and
8893
- function markText(doc, from, to, options, type) {
8894
- // Shared markers (across linked documents) are handled separately
8895
- // (markTextShared will call out to this again, once per
8896
- // document).
8897
- if (options && options.shared) return markTextShared(doc, from, to, options, type);
8898
- // Ensure we are in an operation.
8899
- if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
8900
-
8901
- var marker = new TextMarker(doc, type), diff = cmp(from, to);
8902
- if (options) copyObj(options, marker, false);
8903
- // Don't connect empty markers unless clearWhenEmpty is false
8904
- if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
8905
- return marker;
8906
- if (marker.replacedWith) {
8907
- // Showing up as a widget implies collapsed (widget replaces text)
8908
- marker.collapsed = true;
8909
- marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget");
8910
- if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true");
8911
- if (options.insertLeft) marker.widgetNode.insertLeft = true;
8912
- }
8913
- if (marker.collapsed) {
8914
- if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
8915
- from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
8916
- throw new Error("Inserting collapsed marker partially overlapping an existing one");
8917
- sawCollapsedSpans = true;
8918
- }
8919
-
8920
- if (marker.addToHistory)
8921
- addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN);
8922
-
8923
- var curLine = from.line, cm = doc.cm, updateMaxLine;
8924
- doc.iter(curLine, to.line + 1, function(line) {
8925
- if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
8926
- updateMaxLine = true;
8927
- if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
8928
- addMarkedSpan(line, new MarkedSpan(marker,
8929
- curLine == from.line ? from.ch : null,
8930
- curLine == to.line ? to.ch : null));
8931
- ++curLine;
8932
- });
8933
- // lineIsHidden depends on the presence of the spans, so needs a second pass
8934
- if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {
8935
- if (lineIsHidden(doc, line)) updateLineHeight(line, 0);
8936
- });
8937
 
8938
- if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8939
 
8940
- if (marker.readOnly) {
8941
- sawReadOnlySpans = true;
8942
- if (doc.history.done.length || doc.history.undone.length)
8943
- doc.clearHistory();
8944
- }
8945
- if (marker.collapsed) {
8946
- marker.id = ++nextMarkerId;
8947
- marker.atomic = true;
8948
- }
8949
- if (cm) {
8950
- // Sync editor state
8951
- if (updateMaxLine) cm.curOp.updateMaxLine = true;
8952
- if (marker.collapsed)
8953
- regChange(cm, from.line, to.line + 1);
8954
- else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
8955
- for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text");
8956
- if (marker.atomic) reCheckSelection(cm.doc);
8957
- signalLater(cm, "markerAdded", cm, marker);
8958
- }
8959
- return marker;
8960
  }
 
 
 
8961
 
8962
- // SHARED TEXTMARKERS
 
 
 
 
 
 
 
 
 
 
 
 
 
8963
 
8964
- // A shared marker spans multiple linked documents. It is
8965
- // implemented as a meta-marker-object controlling multiple normal
8966
- // markers.
8967
- var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) {
8968
- this.markers = markers;
8969
- this.primary = primary;
8970
- for (var i = 0; i < markers.length; ++i)
8971
- markers[i].parent = this;
8972
- };
8973
- eventMixin(SharedTextMarker);
8974
-
8975
- SharedTextMarker.prototype.clear = function() {
8976
- if (this.explicitlyCleared) return;
8977
- this.explicitlyCleared = true;
8978
- for (var i = 0; i < this.markers.length; ++i)
8979
- this.markers[i].clear();
8980
- signalLater(this, "clear");
8981
- };
8982
- SharedTextMarker.prototype.find = function(side, lineObj) {
8983
- return this.primary.find(side, lineObj);
8984
- };
8985
 
8986
- function markTextShared(doc, from, to, options, type) {
8987
- options = copyObj(options);
8988
- options.shared = false;
8989
- var markers = [markText(doc, from, to, options, type)], primary = markers[0];
8990
- var widget = options.widgetNode;
8991
- linkedDocs(doc, function(doc) {
8992
- if (widget) options.widgetNode = widget.cloneNode(true);
8993
- markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
8994
- for (var i = 0; i < doc.linked.length; ++i)
8995
- if (doc.linked[i].isParent) return;
8996
- primary = lst(markers);
8997
- });
8998
- return new SharedTextMarker(markers, primary);
8999
  }
9000
 
9001
- function findSharedMarkers(doc) {
9002
- return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())),
9003
- function(m) { return m.parent; });
9004
  }
 
 
9005
 
9006
- function copySharedMarkers(doc, markers) {
9007
- for (var i = 0; i < markers.length; i++) {
9008
- var marker = markers[i], pos = marker.find();
9009
- var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
9010
- if (cmp(mFrom, mTo)) {
9011
- var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
9012
- marker.markers.push(subMark);
9013
- subMark.parent = marker;
9014
- }
9015
- }
 
 
 
 
 
 
9016
  }
 
9017
 
9018
- function detachSharedMarkers(markers) {
9019
- for (var i = 0; i < markers.length; i++) {
9020
- var marker = markers[i], linked = [marker.primary.doc];;
9021
- linkedDocs(marker.primary.doc, function(d) { linked.push(d); });
9022
- for (var j = 0; j < marker.markers.length; j++) {
9023
- var subMarker = marker.markers[j];
9024
- if (indexOf(linked, subMarker.doc) == -1) {
9025
- subMarker.parent = null;
9026
- marker.markers.splice(j--, 1);
9027
- }
9028
- }
9029
- }
9030
- }
9031
 
9032
- // TEXTMARKER SPANS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9033
 
9034
- function MarkedSpan(marker, from, to) {
9035
- this.marker = marker;
9036
- this.from = from; this.to = to;
9037
- }
9038
 
9039
- // Search an array of spans for a span matching the given marker.
9040
- function getMarkedSpanFor(spans, marker) {
9041
- if (spans) for (var i = 0; i < spans.length; ++i) {
9042
- var span = spans[i];
9043
- if (span.marker == marker) return span;
9044
  }
9045
  }
9046
- // Remove a span from an array, returning undefined if no spans are
9047
- // left (we don't store arrays for lines without spans).
9048
- function removeMarkedSpan(spans, span) {
9049
- for (var r, i = 0; i < spans.length; ++i)
9050
- if (spans[i] != span) (r || (r = [])).push(spans[i]);
9051
- return r;
9052
- }
9053
- // Add a span to a line.
9054
- function addMarkedSpan(line, span) {
9055
- line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
9056
- span.marker.attachLine(line);
9057
- }
9058
 
9059
- // Used for the algorithm that adjusts markers for a change in the
9060
- // document. These functions cut an array of spans at a given
9061
- // character position, returning an array of remaining chunks (or
9062
- // undefined if nothing remains).
9063
- function markedSpansBefore(old, startCh, isInsert) {
9064
- if (old) for (var i = 0, nw; i < old.length; ++i) {
9065
- var span = old[i], marker = span.marker;
9066
- var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
9067
- if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
9068
- var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
9069
- (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
9070
- }
9071
- }
9072
- return nw;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9073
  }
9074
- function markedSpansAfter(old, endCh, isInsert) {
9075
- if (old) for (var i = 0, nw; i < old.length; ++i) {
9076
- var span = old[i], marker = span.marker;
9077
- var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
9078
- if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
9079
- var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
9080
- (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
9081
- span.to == null ? null : span.to - endCh));
9082
- }
9083
- }
9084
- return nw;
9085
- }
9086
-
9087
- // Given a change object, compute the new set of marker spans that
9088
- // cover the line in which the change took place. Removes spans
9089
- // entirely within the change, reconnects spans belonging to the
9090
- // same marker that appear on both sides of the change, and cuts off
9091
- // spans partially within the change. Returns an array of span
9092
- // arrays with one element for each line in (after) the change.
9093
- function stretchSpansOverChange(doc, change) {
9094
- if (change.full) return null;
9095
- var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
9096
- var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
9097
- if (!oldFirst && !oldLast) return null;
9098
-
9099
- var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
9100
- // Get the spans that 'stick out' on both sides
9101
- var first = markedSpansBefore(oldFirst, startCh, isInsert);
9102
- var last = markedSpansAfter(oldLast, endCh, isInsert);
9103
-
9104
- // Next, merge those two ends
9105
- var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
9106
- if (first) {
9107
- // Fix up .to properties of first
9108
- for (var i = 0; i < first.length; ++i) {
9109
- var span = first[i];
9110
- if (span.to == null) {
9111
- var found = getMarkedSpanFor(last, span.marker);
9112
- if (!found) span.to = startCh;
9113
- else if (sameLine) span.to = found.to == null ? null : found.to + offset;
9114
- }
9115
- }
9116
- }
9117
- if (last) {
9118
- // Fix up .from in last (or move them into first in case of sameLine)
9119
- for (var i = 0; i < last.length; ++i) {
9120
- var span = last[i];
9121
- if (span.to != null) span.to += offset;
9122
- if (span.from == null) {
9123
- var found = getMarkedSpanFor(first, span.marker);
9124
- if (!found) {
9125
- span.from = offset;
9126
- if (sameLine) (first || (first = [])).push(span);
9127
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9128
  } else {
9129
- span.from += offset;
9130
- if (sameLine) (first || (first = [])).push(span);
9131
- }
9132
- }
9133
- }
9134
- // Make sure we didn't create any zero-length spans
9135
- if (first) first = clearEmptySpans(first);
9136
- if (last && last != first) last = clearEmptySpans(last);
9137
-
9138
- var newMarkers = [first];
9139
- if (!sameLine) {
9140
- // Fill gap with whole-line-spans
9141
- var gap = change.text.length - 2, gapMarkers;
9142
- if (gap > 0 && first)
9143
- for (var i = 0; i < first.length; ++i)
9144
- if (first[i].to == null)
9145
- (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null));
9146
- for (var i = 0; i < gap; ++i)
9147
- newMarkers.push(gapMarkers);
9148
- newMarkers.push(last);
9149
- }
9150
- return newMarkers;
9151
- }
9152
-
9153
- // Remove spans that are empty and don't have a clearWhenEmpty
9154
- // option of false.
9155
- function clearEmptySpans(spans) {
9156
- for (var i = 0; i < spans.length; ++i) {
9157
- var span = spans[i];
9158
- if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
9159
- spans.splice(i--, 1);
9160
- }
9161
- if (!spans.length) return null;
9162
- return spans;
9163
- }
9164
-
9165
- // Used for un/re-doing changes from the history. Combines the
9166
- // result of computing the existing spans with the set of spans that
9167
- // existed in the history (so that deleting around a span and then
9168
- // undoing brings back the span).
9169
- function mergeOldSpans(doc, change) {
9170
- var old = getOldSpans(doc, change);
9171
- var stretched = stretchSpansOverChange(doc, change);
9172
- if (!old) return stretched;
9173
- if (!stretched) return old;
9174
-
9175
- for (var i = 0; i < old.length; ++i) {
9176
- var oldCur = old[i], stretchCur = stretched[i];
9177
- if (oldCur && stretchCur) {
9178
- spans: for (var j = 0; j < stretchCur.length; ++j) {
9179
- var span = stretchCur[j];
9180
- for (var k = 0; k < oldCur.length; ++k)
9181
- if (oldCur[k].marker == span.marker) continue spans;
9182
- oldCur.push(span);
9183
  }
9184
- } else if (stretchCur) {
9185
- old[i] = stretchCur;
9186
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9187
  }
9188
- return old;
9189
  }
 
9190
 
9191
- // Used to 'clip' out readOnly ranges when making a change.
9192
- function removeReadOnlyRanges(doc, from, to) {
9193
- var markers = null;
9194
- doc.iter(from.line, to.line + 1, function(line) {
9195
- if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
9196
- var mark = line.markedSpans[i].marker;
9197
- if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
9198
- (markers || (markers = [])).push(mark);
9199
- }
9200
- });
9201
- if (!markers) return null;
9202
- var parts = [{from: from, to: to}];
9203
- for (var i = 0; i < markers.length; ++i) {
9204
- var mk = markers[i], m = mk.find(0);
9205
- for (var j = 0; j < parts.length; ++j) {
9206
- var p = parts[j];
9207
- if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue;
9208
- var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
9209
- if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
9210
- newParts.push({from: p.from, to: m.from});
9211
- if (dto > 0 || !mk.inclusiveRight && !dto)
9212
- newParts.push({from: m.to, to: p.to});
9213
- parts.splice.apply(parts, newParts);
9214
- j += newParts.length - 1;
9215
- }
9216
- }
9217
- return parts;
9218
- }
9219
-
9220
- // Connect or disconnect spans from a line.
9221
- function detachMarkedSpans(line) {
9222
- var spans = line.markedSpans;
9223
- if (!spans) return;
9224
- for (var i = 0; i < spans.length; ++i)
9225
- spans[i].marker.detachLine(line);
9226
- line.markedSpans = null;
9227
- }
9228
- function attachMarkedSpans(line, spans) {
9229
- if (!spans) return;
9230
- for (var i = 0; i < spans.length; ++i)
9231
- spans[i].marker.attachLine(line);
9232
- line.markedSpans = spans;
9233
- }
9234
-
9235
- // Helpers used when computing which overlapping collapsed span
9236
- // counts as the larger one.
9237
- function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
9238
- function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }
9239
-
9240
- // Returns a number indicating which of two overlapping collapsed
9241
- // spans is larger (and thus includes the other). Falls back to
9242
- // comparing ids when the spans cover exactly the same range.
9243
- function compareCollapsedMarkers(a, b) {
9244
- var lenDiff = a.lines.length - b.lines.length;
9245
- if (lenDiff != 0) return lenDiff;
9246
- var aPos = a.find(), bPos = b.find();
9247
- var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
9248
- if (fromCmp) return -fromCmp;
9249
- var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
9250
- if (toCmp) return toCmp;
9251
- return b.id - a.id;
9252
- }
9253
-
9254
- // Find out whether a line ends or starts in a collapsed span. If
9255
- // so, return the marker for that span.
9256
- function collapsedSpanAtSide(line, start) {
9257
- var sps = sawCollapsedSpans && line.markedSpans, found;
9258
- if (sps) for (var sp, i = 0; i < sps.length; ++i) {
9259
- sp = sps[i];
9260
- if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
9261
- (!found || compareCollapsedMarkers(found, sp.marker) < 0))
9262
- found = sp.marker;
9263
- }
9264
- return found;
9265
- }
9266
- function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
9267
- function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }
9268
-
9269
- // Test whether there exists a collapsed span that partially
9270
- // overlaps (covers the start or end, but not both) of a new span.
9271
- // Such overlap is not allowed.
9272
- function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
9273
- var line = getLine(doc, lineNo);
9274
- var sps = sawCollapsedSpans && line.markedSpans;
9275
- if (sps) for (var i = 0; i < sps.length; ++i) {
9276
- var sp = sps[i];
9277
- if (!sp.marker.collapsed) continue;
9278
- var found = sp.marker.find(0);
9279
- var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
9280
- var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
9281
- if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
9282
- if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
9283
- fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
9284
- return true;
9285
- }
9286
- }
9287
-
9288
- // A visual line is a line as drawn on the screen. Folding, for
9289
- // example, can cause multiple logical lines to appear on the same
9290
- // visual line. This finds the start of the visual line that the
9291
- // given line is part of (usually that is the line itself).
9292
- function visualLine(line) {
9293
- var merged;
9294
- while (merged = collapsedSpanAtStart(line))
9295
- line = merged.find(-1, true).line;
9296
- return line;
9297
- }
9298
-
9299
- // Returns an array of logical lines that continue the visual line
9300
- // started by the argument, or undefined if there are no such lines.
9301
- function visualLineContinued(line) {
9302
- var merged, lines;
9303
- while (merged = collapsedSpanAtEnd(line)) {
9304
- line = merged.find(1, true).line;
9305
- (lines || (lines = [])).push(line);
9306
- }
9307
- return lines;
9308
- }
9309
-
9310
- // Get the line number of the start of the visual line that the
9311
- // given line number is part of.
9312
- function visualLineNo(doc, lineN) {
9313
- var line = getLine(doc, lineN), vis = visualLine(line);
9314
- if (line == vis) return lineN;
9315
- return lineNo(vis);
9316
- }
9317
- // Get the line number of the start of the next visual line after
9318
- // the given line.
9319
- function visualLineEndNo(doc, lineN) {
9320
- if (lineN > doc.lastLine()) return lineN;
9321
- var line = getLine(doc, lineN), merged;
9322
- if (!lineIsHidden(doc, line)) return lineN;
9323
- while (merged = collapsedSpanAtEnd(line))
9324
- line = merged.find(1, true).line;
9325
- return lineNo(line) + 1;
9326
- }
9327
-
9328
- // Compute whether a line is hidden. Lines count as hidden when they
9329
- // are part of a visual line that starts with another line, or when
9330
- // they are entirely covered by collapsed, non-widget span.
9331
- function lineIsHidden(doc, line) {
9332
- var sps = sawCollapsedSpans && line.markedSpans;
9333
- if (sps) for (var sp, i = 0; i < sps.length; ++i) {
9334
- sp = sps[i];
9335
- if (!sp.marker.collapsed) continue;
9336
- if (sp.from == null) return true;
9337
- if (sp.marker.widgetNode) continue;
9338
- if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
9339
- return true;
9340
- }
9341
- }
9342
- function lineIsHiddenInner(doc, line, span) {
9343
- if (span.to == null) {
9344
- var end = span.marker.find(1, true);
9345
- return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker));
9346
- }
9347
- if (span.marker.inclusiveRight && span.to == line.text.length)
9348
- return true;
9349
- for (var sp, i = 0; i < line.markedSpans.length; ++i) {
9350
- sp = line.markedSpans[i];
9351
- if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
9352
- (sp.to == null || sp.to != span.from) &&
9353
- (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
9354
- lineIsHiddenInner(doc, line, sp)) return true;
9355
- }
9356
- }
9357
-
9358
- // LINE WIDGETS
9359
-
9360
- // Line widgets are block elements displayed above or below a line.
9361
-
9362
- var LineWidget = CodeMirror.LineWidget = function(doc, node, options) {
9363
- if (options) for (var opt in options) if (options.hasOwnProperty(opt))
9364
- this[opt] = options[opt];
9365
- this.doc = doc;
9366
- this.node = node;
9367
- };
9368
- eventMixin(LineWidget);
9369
-
9370
- function adjustScrollWhenAboveVisible(cm, line, diff) {
9371
- if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
9372
- addToScrollPos(cm, null, diff);
9373
- }
9374
-
9375
- LineWidget.prototype.clear = function() {
9376
- var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
9377
- if (no == null || !ws) return;
9378
- for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
9379
- if (!ws.length) line.widgets = null;
9380
- var height = widgetHeight(this);
9381
- updateLineHeight(line, Math.max(0, line.height - height));
9382
- if (cm) runInOp(cm, function() {
9383
- adjustScrollWhenAboveVisible(cm, line, -height);
9384
- regLineChange(cm, no, "widget");
9385
- });
9386
- };
9387
- LineWidget.prototype.changed = function() {
9388
- var oldH = this.height, cm = this.doc.cm, line = this.line;
9389
- this.height = null;
9390
- var diff = widgetHeight(this) - oldH;
9391
- if (!diff) return;
9392
- updateLineHeight(line, line.height + diff);
9393
- if (cm) runInOp(cm, function() {
9394
- cm.curOp.forceUpdate = true;
9395
- adjustScrollWhenAboveVisible(cm, line, diff);
9396
- });
9397
- };
9398
 
9399
- function widgetHeight(widget) {
9400
- if (widget.height != null) return widget.height;
9401
- var cm = widget.doc.cm;
9402
- if (!cm) return 0;
9403
- if (!contains(document.body, widget.node)) {
9404
- var parentStyle = "position: relative;";
9405
- if (widget.coverGutter)
9406
- parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;";
9407
- if (widget.noHScroll)
9408
- parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;";
9409
- removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
9410
- }
9411
- return widget.height = widget.node.parentNode.offsetHeight;
9412
- }
9413
-
9414
- function addLineWidget(doc, handle, node, options) {
9415
- var widget = new LineWidget(doc, node, options);
9416
- var cm = doc.cm;
9417
- if (cm && widget.noHScroll) cm.display.alignWidgets = true;
9418
- changeLine(doc, handle, "widget", function(line) {
9419
- var widgets = line.widgets || (line.widgets = []);
9420
- if (widget.insertAt == null) widgets.push(widget);
9421
- else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);
9422
- widget.line = line;
9423
- if (cm && !lineIsHidden(doc, line)) {
9424
- var aboveVisible = heightAtLine(line) < doc.scrollTop;
9425
- updateLineHeight(line, line.height + widgetHeight(widget));
9426
- if (aboveVisible) addToScrollPos(cm, null, widget.height);
9427
- cm.curOp.forceUpdate = true;
9428
- }
9429
- return true;
9430
- });
9431
- return widget;
9432
- }
9433
 
9434
- // LINE DATA STRUCTURE
 
 
 
9435
 
9436
- // Line objects. These hold state related to a line, including
9437
- // highlighting info (the styles array).
9438
- var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) {
9439
- this.text = text;
9440
- attachMarkedSpans(this, markedSpans);
9441
- this.height = estimateHeight ? estimateHeight(this) : 1;
9442
- };
9443
- eventMixin(Line);
9444
- Line.prototype.lineNo = function() { return lineNo(this); };
9445
-
9446
- // Change the content (text, markers) of a line. Automatically
9447
- // invalidates cached information and tries to re-estimate the
9448
- // line's height.
9449
- function updateLine(line, text, markedSpans, estimateHeight) {
9450
- line.text = text;
9451
- if (line.stateAfter) line.stateAfter = null;
9452
- if (line.styles) line.styles = null;
9453
- if (line.order != null) line.order = null;
9454
- detachMarkedSpans(line);
9455
- attachMarkedSpans(line, markedSpans);
9456
- var estHeight = estimateHeight ? estimateHeight(line) : 1;
9457
- if (estHeight != line.height) updateLineHeight(line, estHeight);
9458
- }
9459
-
9460
- // Detach a line from the document tree and its markers.
9461
- function cleanUpLine(line) {
9462
- line.parent = null;
9463
- detachMarkedSpans(line);
9464
- }
9465
-
9466
- function extractLineClasses(type, output) {
9467
- if (type) for (;;) {
9468
- var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
9469
- if (!lineClass) break;
9470
- type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
9471
- var prop = lineClass[1] ? "bgClass" : "textClass";
9472
- if (output[prop] == null)
9473
- output[prop] = lineClass[2];
9474
- else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
9475
- output[prop] += " " + lineClass[2];
9476
- }
9477
- return type;
9478
  }
9479
 
9480
- function callBlankLine(mode, state) {
9481
- if (mode.blankLine) return mode.blankLine(state);
9482
- if (!mode.innerMode) return;
9483
- var inner = CodeMirror.innerMode(mode, state);
9484
- if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
9485
- }
9486
-
9487
- function readToken(mode, stream, state, inner) {
9488
- for (var i = 0; i < 10; i++) {
9489
- if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode;
9490
- var style = mode.token(stream, state);
9491
- if (stream.pos > stream.start) return style;
9492
- }
9493
- throw new Error("Mode " + mode.name + " failed to advance stream.");
9494
- }
9495
-
9496
- // Utility for getTokenAt and getLineTokens
9497
- function takeToken(cm, pos, precise, asArray) {
9498
- function getObj(copy) {
9499
- return {start: stream.start, end: stream.pos,
9500
- string: stream.current(),
9501
- type: style || null,
9502
- state: copy ? copyState(doc.mode, state) : state};
9503
- }
9504
-
9505
- var doc = cm.doc, mode = doc.mode, style;
9506
- pos = clipPos(doc, pos);
9507
- var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise);
9508
- var stream = new StringStream(line.text, cm.options.tabSize), tokens;
9509
- if (asArray) tokens = [];
9510
- while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
9511
- stream.start = stream.pos;
9512
- style = readToken(mode, stream, state);
9513
- if (asArray) tokens.push(getObj(true));
9514
- }
9515
- return asArray ? tokens : getObj();
9516
- }
9517
-
9518
- // Run the given mode's parser over a line, calling f for each token.
9519
- function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
9520
- var flattenSpans = mode.flattenSpans;
9521
- if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
9522
- var curStart = 0, curStyle = null;
9523
- var stream = new StringStream(text, cm.options.tabSize), style;
9524
- var inner = cm.options.addModeClass && [null];
9525
- if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses);
9526
- while (!stream.eol()) {
9527
- if (stream.pos > cm.options.maxHighlightLength) {
9528
- flattenSpans = false;
9529
- if (forceToEnd) processLine(cm, text, state, stream.pos);
9530
- stream.pos = text.length;
9531
- style = null;
9532
- } else {
9533
- style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses);
9534
- }
9535
- if (inner) {
9536
- var mName = inner[0].name;
9537
- if (mName) style = "m-" + (style ? mName + " " + style : mName);
9538
- }
9539
- if (!flattenSpans || curStyle != style) {
9540
- while (curStart < stream.start) {
9541
- curStart = Math.min(stream.start, curStart + 50000);
9542
- f(curStart, curStyle);
9543
- }
9544
- curStyle = style;
9545
- }
9546
- stream.start = stream.pos;
9547
- }
9548
- while (curStart < stream.pos) {
9549
- // Webkit seems to refuse to render text nodes longer than 57444 characters
9550
- var pos = Math.min(stream.pos, curStart + 50000);
9551
- f(pos, curStyle);
9552
- curStart = pos;
9553
- }
9554
- }
9555
-
9556
- // Compute a style array (an array starting with a mode generation
9557
- // -- for invalidation -- followed by pairs of end positions and
9558
- // style strings), which is used to highlight the tokens on the
9559
- // line.
9560
- function highlightLine(cm, line, state, forceToEnd) {
9561
- // A styles array always starts with a number identifying the
9562
- // mode/overlays that it is based on (for easy invalidation).
9563
- var st = [cm.state.modeGen], lineClasses = {};
9564
- // Compute the base array of styles
9565
- runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
9566
- st.push(end, style);
9567
- }, lineClasses, forceToEnd);
9568
-
9569
- // Run overlays, adjust style array.
9570
- for (var o = 0; o < cm.state.overlays.length; ++o) {
9571
- var overlay = cm.state.overlays[o], i = 1, at = 0;
9572
- runMode(cm, line.text, overlay.mode, true, function(end, style) {
9573
- var start = i;
9574
- // Ensure there's a token end at the current position, and that i points at it
9575
- while (at < end) {
9576
- var i_end = st[i];
9577
- if (i_end > end)
9578
- st.splice(i, 1, end, st[i+1], i_end);
9579
- i += 2;
9580
- at = Math.min(end, i_end);
9581
- }
9582
- if (!style) return;
9583
- if (overlay.opaque) {
9584
- st.splice(start, i - start, end, "cm-overlay " + style);
9585
- i = start + 2;
9586
- } else {
9587
- for (; start < i; start += 2) {
9588
- var cur = st[start+1];
9589
- st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style;
9590
- }
9591
- }
9592
- }, lineClasses);
9593
- }
9594
-
9595
- return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};
9596
- }
9597
-
9598
- function getLineStyles(cm, line, updateFrontier) {
9599
- if (!line.styles || line.styles[0] != cm.state.modeGen) {
9600
- var state = getStateBefore(cm, lineNo(line));
9601
- var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state);
9602
- line.stateAfter = state;
9603
- line.styles = result.styles;
9604
- if (result.classes) line.styleClasses = result.classes;
9605
- else if (line.styleClasses) line.styleClasses = null;
9606
- if (updateFrontier === cm.doc.frontier) cm.doc.frontier++;
9607
- }
9608
- return line.styles;
9609
- }
9610
-
9611
- // Lightweight form of highlight -- proceed over this line and
9612
- // update state, but don't save a style array. Used for lines that
9613
- // aren't currently visible.
9614
- function processLine(cm, text, state, startAt) {
9615
- var mode = cm.doc.mode;
9616
- var stream = new StringStream(text, cm.options.tabSize);
9617
- stream.start = stream.pos = startAt || 0;
9618
- if (text == "") callBlankLine(mode, state);
9619
- while (!stream.eol()) {
9620
- readToken(mode, stream, state);
9621
- stream.start = stream.pos;
9622
- }
9623
- }
9624
-
9625
- // Convert a style as returned by a mode (either null, or a string
9626
- // containing one or more styles) to a CSS style. This is cached,
9627
- // and also looks for line-wide styles.
9628
- var styleToClassCache = {}, styleToClassCacheWithMode = {};
9629
- function interpretTokenStyle(style, options) {
9630
- if (!style || /^\s*$/.test(style)) return null;
9631
- var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
9632
- return cache[style] ||
9633
- (cache[style] = style.replace(/\S+/g, "cm-$&"));
9634
- }
9635
-
9636
- // Render the DOM representation of the text of a line. Also builds
9637
- // up a 'line map', which points at the DOM nodes that represent
9638
- // specific stretches of text, and is used by the measuring code.
9639
- // The returned object contains the DOM node, this map, and
9640
- // information about line-wide styles that were set by the mode.
9641
- function buildLineContent(cm, lineView) {
9642
- // The padding-right forces the element to have a 'border', which
9643
- // is needed on Webkit to be able to get line-level bounding
9644
- // rectangles for it (in measureChar).
9645
- var content = elt("span", null, null, webkit ? "padding-right: .1px" : null);
9646
- var builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content,
9647
- col: 0, pos: 0, cm: cm,
9648
- trailingSpace: false,
9649
- splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")};
9650
- lineView.measure = {};
9651
-
9652
- // Iterate over the logical lines that make up this visual line.
9653
- for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
9654
- var line = i ? lineView.rest[i - 1] : lineView.line, order;
9655
- builder.pos = 0;
9656
- builder.addToken = buildToken;
9657
- // Optionally wire in some hacks into the token-rendering
9658
- // algorithm, to deal with browser quirks.
9659
- if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))
9660
- builder.addToken = buildTokenBadBidi(builder.addToken, order);
9661
- builder.map = [];
9662
- var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
9663
- insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
9664
- if (line.styleClasses) {
9665
- if (line.styleClasses.bgClass)
9666
- builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "");
9667
- if (line.styleClasses.textClass)
9668
- builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "");
9669
- }
9670
 
9671
- // Ensure at least a single node is present, for measuring.
9672
- if (builder.map.length == 0)
9673
- builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure)));
9674
 
9675
- // Store the map and a cache object for the current logical line
9676
- if (i == 0) {
9677
- lineView.measure.map = builder.map;
9678
- lineView.measure.cache = {};
9679
- } else {
9680
- (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map);
9681
- (lineView.measure.caches || (lineView.measure.caches = [])).push({});
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9682
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9683
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9684
 
9685
- // See issue #2901
9686
- if (webkit) {
9687
- var last = builder.content.lastChild
9688
- if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
9689
- builder.content.className = "cm-tab-wrap-hack";
9690
- }
9691
-
9692
- signal(cm, "renderLine", cm, lineView.line, builder.pre);
9693
- if (builder.pre.className)
9694
- builder.textClass = joinClasses(builder.pre.className, builder.textClass || "");
9695
 
9696
- return builder;
 
 
 
 
 
 
 
 
 
9697
  }
 
9698
 
9699
- function defaultSpecialCharPlaceholder(ch) {
9700
- var token = elt("span", "\u2022", "cm-invalidchar");
9701
- token.title = "\\u" + ch.charCodeAt(0).toString(16);
9702
- token.setAttribute("aria-label", token.title);
9703
- return token;
9704
- }
 
 
 
 
 
 
 
 
9705
 
9706
- // Build up the DOM representation for a single token, and add it to
9707
- // the line map. Takes care to render special characters separately.
9708
- function buildToken(builder, text, style, startStyle, endStyle, title, css) {
9709
- if (!text) return;
9710
- var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text
9711
- var special = builder.cm.state.specialChars, mustWrap = false;
9712
- if (!special.test(text)) {
9713
- builder.col += text.length;
9714
- var content = document.createTextNode(displayText);
9715
- builder.map.push(builder.pos, builder.pos + text.length, content);
9716
- if (ie && ie_version < 9) mustWrap = true;
9717
- builder.pos += text.length;
9718
- } else {
9719
- var content = document.createDocumentFragment(), pos = 0;
9720
- while (true) {
9721
- special.lastIndex = pos;
9722
- var m = special.exec(text);
9723
- var skipped = m ? m.index - pos : text.length - pos;
9724
- if (skipped) {
9725
- var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
9726
- if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
9727
- else content.appendChild(txt);
9728
- builder.map.push(builder.pos, builder.pos + skipped, txt);
9729
- builder.col += skipped;
9730
- builder.pos += skipped;
9731
- }
9732
- if (!m) break;
9733
- pos += skipped + 1;
9734
- if (m[0] == "\t") {
9735
- var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
9736
- var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
9737
- txt.setAttribute("role", "presentation");
9738
- txt.setAttribute("cm-text", "\t");
9739
- builder.col += tabWidth;
9740
- } else if (m[0] == "\r" || m[0] == "\n") {
9741
- var txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
9742
- txt.setAttribute("cm-text", m[0]);
9743
- builder.col += 1;
9744
- } else {
9745
- var txt = builder.cm.options.specialCharPlaceholder(m[0]);
9746
- txt.setAttribute("cm-text", m[0]);
9747
- if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
9748
- else content.appendChild(txt);
9749
- builder.col += 1;
9750
- }
9751
- builder.map.push(builder.pos, builder.pos + 1, txt);
9752
- builder.pos++;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9753
  }
9754
  }
9755
- builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32
9756
- if (style || startStyle || endStyle || mustWrap || css) {
9757
- var fullStyle = style || "";
9758
- if (startStyle) fullStyle += startStyle;
9759
- if (endStyle) fullStyle += endStyle;
9760
- var token = elt("span", [content], fullStyle, css);
9761
- if (title) token.title = title;
9762
- return builder.content.appendChild(token);
9763
- }
9764
- builder.content.appendChild(content);
9765
  }
 
9766
 
9767
- function splitSpaces(text, trailingBefore) {
9768
- if (text.length > 1 && !/ /.test(text)) return text
9769
- var spaceBefore = trailingBefore, result = ""
9770
- for (var i = 0; i < text.length; i++) {
9771
- var ch = text.charAt(i)
9772
- if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))
9773
- ch = "\u00a0"
9774
- result += ch
9775
- spaceBefore = ch == " "
9776
- }
9777
- return result
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9778
  }
 
9779
 
9780
- // Work around nonsense dimensions being reported for stretches of
9781
- // right-to-left text.
9782
- function buildTokenBadBidi(inner, order) {
9783
- return function(builder, text, style, startStyle, endStyle, title, css) {
9784
- style = style ? style + " cm-force-border" : "cm-force-border";
9785
- var start = builder.pos, end = start + text.length;
9786
- for (;;) {
9787
- // Find the part that overlaps with the start of this text
9788
- for (var i = 0; i < order.length; i++) {
9789
- var part = order[i];
9790
- if (part.to > start && part.from <= start) break;
9791
- }
9792
- if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css);
9793
- inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);
9794
- startStyle = null;
9795
- text = text.slice(part.to - start);
9796
- start = part.to;
9797
- }
9798
- };
 
 
9799
  }
 
9800
 
9801
- function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
9802
- var widget = !ignoreWidget && marker.widgetNode;
9803
- if (widget) builder.map.push(builder.pos, builder.pos + size, widget);
9804
- if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
9805
- if (!widget)
9806
- widget = builder.content.appendChild(document.createElement("span"));
9807
- widget.setAttribute("cm-marker", marker.id);
9808
- }
9809
- if (widget) {
9810
- builder.cm.display.input.setUneditable(widget);
9811
- builder.content.appendChild(widget);
9812
- }
9813
- builder.pos += size;
9814
- builder.trailingSpace = false
9815
  }
 
 
9816
 
9817
- // Outputs a number of spans to make up a line, taking highlighting
9818
- // and marked text into account.
9819
- function insertLineContent(line, builder, styles) {
9820
- var spans = line.markedSpans, allText = line.text, at = 0;
9821
- if (!spans) {
9822
- for (var i = 1; i < styles.length; i+=2)
9823
- builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options));
9824
- return;
9825
- }
9826
 
9827
- var len = allText.length, pos = 0, i = 1, text = "", style, css;
9828
- var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
9829
- for (;;) {
9830
- if (nextChange == pos) { // Update current marker set
9831
- spanStyle = spanEndStyle = spanStartStyle = title = css = "";
9832
- collapsed = null; nextChange = Infinity;
9833
- var foundBookmarks = [], endStyles
9834
- for (var j = 0; j < spans.length; ++j) {
9835
- var sp = spans[j], m = sp.marker;
9836
- if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
9837
- foundBookmarks.push(m);
9838
- } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
9839
- if (sp.to != null && sp.to != pos && nextChange > sp.to) {
9840
- nextChange = sp.to;
9841
- spanEndStyle = "";
9842
- }
9843
- if (m.className) spanStyle += " " + m.className;
9844
- if (m.css) css = (css ? css + ";" : "") + m.css;
9845
- if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
9846
- if (m.endStyle && sp.to == nextChange) (endStyles || (endStyles = [])).push(m.endStyle, sp.to)
9847
- if (m.title && !title) title = m.title;
9848
- if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
9849
- collapsed = sp;
9850
- } else if (sp.from > pos && nextChange > sp.from) {
9851
- nextChange = sp.from;
9852
- }
9853
- }
9854
- if (endStyles) for (var j = 0; j < endStyles.length; j += 2)
9855
- if (endStyles[j + 1] == nextChange) spanEndStyle += " " + endStyles[j]
9856
-
9857
- if (!collapsed || collapsed.from == pos) for (var j = 0; j < foundBookmarks.length; ++j)
9858
- buildCollapsedSpan(builder, 0, foundBookmarks[j]);
9859
- if (collapsed && (collapsed.from || 0) == pos) {
9860
- buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
9861
- collapsed.marker, collapsed.from == null);
9862
- if (collapsed.to == null) return;
9863
- if (collapsed.to == pos) collapsed = false;
9864
- }
9865
- }
9866
- if (pos >= len) break;
9867
-
9868
- var upto = Math.min(len, nextChange);
9869
- while (true) {
9870
- if (text) {
9871
- var end = pos + text.length;
9872
- if (!collapsed) {
9873
- var tokenText = end > upto ? text.slice(0, upto - pos) : text;
9874
- builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
9875
- spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
9876
- }
9877
- if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
9878
- pos = end;
9879
- spanStartStyle = "";
9880
- }
9881
- text = allText.slice(at, at = styles[i++]);
9882
- style = interpretTokenStyle(styles[i++], builder.cm.options);
9883
- }
9884
- }
9885
- }
9886
 
9887
- // DOCUMENT DATA STRUCTURE
9888
-
9889
- // By default, updates that start and end at the beginning of a line
9890
- // are treated specially, in order to make the association of line
9891
- // widgets and marker elements with the text behave more intuitive.
9892
- function isWholeLineUpdate(doc, change) {
9893
- return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
9894
- (!doc.cm || doc.cm.options.wholeLineUpdateBefore);
9895
- }
9896
-
9897
- // Perform a change on the document data structure.
9898
- function updateDoc(doc, change, markedSpans, estimateHeight) {
9899
- function spansFor(n) {return markedSpans ? markedSpans[n] : null;}
9900
- function update(line, text, spans) {
9901
- updateLine(line, text, spans, estimateHeight);
9902
- signalLater(line, "change", line, change);
9903
- }
9904
- function linesFor(start, end) {
9905
- for (var i = start, result = []; i < end; ++i)
9906
- result.push(new Line(text[i], spansFor(i), estimateHeight));
9907
- return result;
9908
- }
9909
-
9910
- var from = change.from, to = change.to, text = change.text;
9911
- var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
9912
- var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
9913
-
9914
- // Adjust the line structure
9915
- if (change.full) {
9916
- doc.insert(0, linesFor(0, text.length));
9917
- doc.remove(text.length, doc.size - text.length);
9918
- } else if (isWholeLineUpdate(doc, change)) {
9919
- // This is a whole-line replace. Treated specially to make
9920
- // sure line objects move the way they are supposed to.
9921
- var added = linesFor(0, text.length - 1);
9922
- update(lastLine, lastLine.text, lastSpans);
9923
- if (nlines) doc.remove(from.line, nlines);
9924
- if (added.length) doc.insert(from.line, added);
9925
- } else if (firstLine == lastLine) {
9926
- if (text.length == 1) {
9927
- update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
9928
- } else {
9929
- var added = linesFor(1, text.length - 1);
9930
- added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
9931
- update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
9932
- doc.insert(from.line + 1, added);
9933
- }
9934
- } else if (text.length == 1) {
9935
- update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
9936
- doc.remove(from.line + 1, nlines);
9937
- } else {
9938
- update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
9939
- update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
9940
- var added = linesFor(1, text.length - 1);
9941
- if (nlines > 1) doc.remove(from.line + 1, nlines - 1);
9942
- doc.insert(from.line + 1, added);
9943
- }
9944
 
9945
- signalLater(doc, "change", doc, change);
9946
- }
 
 
9947
 
9948
- // The document is represented as a BTree consisting of leaves, with
9949
- // chunk of lines in them, and branches, with up to ten leaves or
9950
- // other branch nodes below them. The top node is always a branch
9951
- // node, and is the document object itself (meaning it has
9952
- // additional methods and properties).
9953
- //
9954
- // All nodes have parent links. The tree is used both to go from
9955
- // line numbers to line objects, and to go from objects to numbers.
9956
- // It also indexes by height, and is used to convert between height
9957
- // and line object, and to find the total height of the document.
9958
- //
9959
- // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
9960
-
9961
- function LeafChunk(lines) {
9962
- this.lines = lines;
9963
- this.parent = null;
9964
- for (var i = 0, height = 0; i < lines.length; ++i) {
9965
- lines[i].parent = this;
9966
- height += lines[i].height;
9967
- }
9968
- this.height = height;
9969
- }
9970
-
9971
- LeafChunk.prototype = {
9972
- chunkSize: function() { return this.lines.length; },
9973
- // Remove the n lines at offset 'at'.
9974
- removeInner: function(at, n) {
9975
- for (var i = at, e = at + n; i < e; ++i) {
9976
- var line = this.lines[i];
9977
- this.height -= line.height;
9978
- cleanUpLine(line);
9979
- signalLater(line, "delete");
9980
- }
9981
- this.lines.splice(at, n);
9982
  },
9983
- // Helper used to collapse a small branch into a single leaf.
9984
- collapse: function(lines) {
9985
- lines.push.apply(lines, this.lines);
 
 
 
9986
  },
9987
- // Insert the given array of lines at offset 'at', count them as
9988
- // having the given height.
9989
- insertInner: function(at, lines, height) {
9990
- this.height += height;
9991
- this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
9992
- for (var i = 0; i < lines.length; ++i) lines[i].parent = this;
 
9993
  },
9994
- // Used to iterate over a part of the tree.
9995
- iterN: function(at, n, op) {
9996
- for (var e = at + n; at < e; ++at)
9997
- if (op(this.lines[at])) return true;
9998
- }
9999
- };
10000
 
10001
- function BranchChunk(children) {
10002
- this.children = children;
10003
- var size = 0, height = 0;
10004
- for (var i = 0; i < children.length; ++i) {
10005
- var ch = children[i];
10006
- size += ch.chunkSize(); height += ch.height;
10007
- ch.parent = this;
10008
- }
10009
- this.size = size;
10010
- this.height = height;
10011
- this.parent = null;
10012
- }
10013
-
10014
- BranchChunk.prototype = {
10015
- chunkSize: function() { return this.size; },
10016
- removeInner: function(at, n) {
10017
- this.size -= n;
10018
- for (var i = 0; i < this.children.length; ++i) {
10019
- var child = this.children[i], sz = child.chunkSize();
10020
- if (at < sz) {
10021
- var rm = Math.min(n, sz - at), oldHeight = child.height;
10022
- child.removeInner(at, rm);
10023
- this.height -= oldHeight - child.height;
10024
- if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
10025
- if ((n -= rm) == 0) break;
10026
- at = 0;
10027
- } else at -= sz;
10028
  }
10029
- // If the result is smaller than 25 lines, ensure that it is a
10030
- // single leaf node.
10031
- if (this.size - n < 25 &&
10032
- (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
10033
- var lines = [];
10034
- this.collapse(lines);
10035
- this.children = [new LeafChunk(lines)];
10036
- this.children[0].parent = this;
10037
  }
10038
- },
10039
- collapse: function(lines) {
10040
- for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines);
10041
- },
10042
- insertInner: function(at, lines, height) {
10043
- this.size += lines.length;
10044
- this.height += height;
10045
- for (var i = 0; i < this.children.length; ++i) {
10046
- var child = this.children[i], sz = child.chunkSize();
10047
- if (at <= sz) {
10048
- child.insertInner(at, lines, height);
10049
- if (child.lines && child.lines.length > 50) {
10050
- // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.
10051
- // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.
10052
- var remaining = child.lines.length % 25 + 25
10053
- for (var pos = remaining; pos < child.lines.length;) {
10054
- var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));
10055
- child.height -= leaf.height;
10056
- this.children.splice(++i, 0, leaf);
10057
- leaf.parent = this;
10058
- }
10059
- child.lines = child.lines.slice(0, remaining);
10060
- this.maybeSpill();
10061
- }
10062
- break;
10063
  }
10064
- at -= sz;
10065
  }
 
 
 
 
 
 
10066
  },
10067
- // When a node has grown, check whether it should be split.
10068
- maybeSpill: function() {
10069
- if (this.children.length <= 10) return;
10070
- var me = this;
10071
- do {
10072
- var spilled = me.children.splice(me.children.length - 5, 5);
10073
- var sibling = new BranchChunk(spilled);
10074
- if (!me.parent) { // Become the parent node
10075
- var copy = new BranchChunk(me.children);
10076
- copy.parent = me;
10077
- me.children = [copy, sibling];
10078
- me = copy;
10079
- } else {
10080
- me.size -= sibling.size;
10081
- me.height -= sibling.height;
10082
- var myIndex = indexOf(me.parent.children, me);
10083
- me.parent.children.splice(myIndex + 1, 0, sibling);
10084
- }
10085
- sibling.parent = me.parent;
10086
- } while (me.children.length > 10);
10087
- me.parent.maybeSpill();
10088
  },
10089
- iterN: function(at, n, op) {
10090
- for (var i = 0; i < this.children.length; ++i) {
10091
- var child = this.children[i], sz = child.chunkSize();
10092
- if (at < sz) {
10093
- var used = Math.min(n, sz - at);
10094
- if (child.iterN(at, used, op)) return true;
10095
- if ((n -= used) == 0) break;
10096
- at = 0;
10097
- } else at -= sz;
10098
- }
10099
- }
10100
- };
10101
 
10102
- var nextDocId = 0;
10103
- var Doc = CodeMirror.Doc = function(text, mode, firstLine, lineSep) {
10104
- if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep);
10105
- if (firstLine == null) firstLine = 0;
10106
-
10107
- BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
10108
- this.first = firstLine;
10109
- this.scrollTop = this.scrollLeft = 0;
10110
- this.cantEdit = false;
10111
- this.cleanGeneration = 1;
10112
- this.frontier = firstLine;
10113
- var start = Pos(firstLine, 0);
10114
- this.sel = simpleSelection(start);
10115
- this.history = new History(null);
10116
- this.id = ++nextDocId;
10117
- this.modeOption = mode;
10118
- this.lineSep = lineSep;
10119
- this.extend = false;
10120
-
10121
- if (typeof text == "string") text = this.splitLines(text);
10122
- updateDoc(this, {from: start, to: start, text: text});
10123
- setSelection(this, simpleSelection(start), sel_dontScroll);
10124
- };
10125
 
10126
- Doc.prototype = createObj(BranchChunk.prototype, {
10127
- constructor: Doc,
10128
- // Iterate over the document. Supports two forms -- with only one
10129
- // argument, it calls that for each line in the document. With
10130
- // three, it iterates over the range given by the first two (with
10131
- // the second being non-inclusive).
10132
- iter: function(from, to, op) {
10133
- if (op) this.iterN(from - this.first, to - from, op);
10134
- else this.iterN(this.first, this.first + this.size, from);
10135
  },
10136
 
10137
- // Non-public interface for adding and removing lines.
10138
- insert: function(at, lines) {
10139
- var height = 0;
10140
- for (var i = 0; i < lines.length; ++i) height += lines[i].height;
10141
- this.insertInner(at - this.first, lines, height);
10142
  },
10143
- remove: function(at, n) { this.removeInner(at - this.first, n); },
10144
 
10145
- // From here, the methods are part of the public interface. Most
10146
- // are also available from CodeMirror (editor) instances.
10147
 
10148
- getValue: function(lineSep) {
10149
- var lines = getLines(this, this.first, this.first + this.size);
10150
- if (lineSep === false) return lines;
10151
- return lines.join(lineSep || this.lineSeparator());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10152
  },
10153
- setValue: docMethodOp(function(code) {
10154
- var top = Pos(this.first, 0), last = this.first + this.size - 1;
10155
- makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
10156
- text: this.splitLines(code), origin: "setValue", full: true}, true);
10157
- setSelection(this, simpleSelection(top));
10158
- }),
10159
- replaceRange: function(code, from, to, origin) {
10160
- from = clipPos(this, from);
10161
- to = to ? clipPos(this, to) : from;
10162
- replaceRange(this, code, from, to, origin);
10163
  },
10164
- getRange: function(from, to, lineSep) {
10165
- var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
10166
- if (lineSep === false) return lines;
10167
- return lines.join(lineSep || this.lineSeparator());
 
 
 
10168
  },
10169
 
10170
- getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
 
 
10171
 
10172
- getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);},
10173
- getLineNumber: function(line) {return lineNo(line);},
 
 
10174
 
10175
- getLineHandleVisualStart: function(line) {
10176
- if (typeof line == "number") line = getLine(this, line);
10177
- return visualLine(line);
 
 
 
 
 
 
 
 
 
 
 
 
 
10178
  },
10179
 
10180
- lineCount: function() {return this.size;},
10181
- firstLine: function() {return this.first;},
10182
- lastLine: function() {return this.first + this.size - 1;},
10183
 
10184
- clipPos: function(pos) {return clipPos(this, pos);},
 
 
 
 
 
 
 
10185
 
10186
- getCursor: function(start) {
10187
- var range = this.sel.primary(), pos;
10188
- if (start == null || start == "head") pos = range.head;
10189
- else if (start == "anchor") pos = range.anchor;
10190
- else if (start == "end" || start == "to" || start === false) pos = range.to();
10191
- else pos = range.from();
10192
- return pos;
10193
- },
10194
- listSelections: function() { return this.sel.ranges; },
10195
- somethingSelected: function() {return this.sel.somethingSelected();},
10196
 
10197
- setCursor: docMethodOp(function(line, ch, options) {
10198
- setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
10199
- }),
10200
- setSelection: docMethodOp(function(anchor, head, options) {
10201
- setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
10202
- }),
10203
- extendSelection: docMethodOp(function(head, other, options) {
10204
- extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
10205
- }),
10206
- extendSelections: docMethodOp(function(heads, options) {
10207
- extendSelections(this, clipPosArray(this, heads), options);
10208
- }),
10209
- extendSelectionsBy: docMethodOp(function(f, options) {
10210
- var heads = map(this.sel.ranges, f);
10211
- extendSelections(this, clipPosArray(this, heads), options);
10212
- }),
10213
- setSelections: docMethodOp(function(ranges, primary, options) {
10214
- if (!ranges.length) return;
10215
- for (var i = 0, out = []; i < ranges.length; i++)
10216
- out[i] = new Range(clipPos(this, ranges[i].anchor),
10217
- clipPos(this, ranges[i].head));
10218
- if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex);
10219
- setSelection(this, normalizeSelection(out, primary), options);
10220
- }),
10221
- addSelection: docMethodOp(function(anchor, head, options) {
10222
- var ranges = this.sel.ranges.slice(0);
10223
- ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
10224
- setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
10225
  }),
10226
 
10227
- getSelection: function(lineSep) {
10228
- var ranges = this.sel.ranges, lines;
10229
- for (var i = 0; i < ranges.length; i++) {
10230
- var sel = getBetween(this, ranges[i].from(), ranges[i].to());
10231
- lines = lines ? lines.concat(sel) : sel;
 
 
 
 
 
10232
  }
10233
- if (lineSep === false) return lines;
10234
- else return lines.join(lineSep || this.lineSeparator());
 
10235
  },
10236
- getSelections: function(lineSep) {
10237
- var parts = [], ranges = this.sel.ranges;
10238
- for (var i = 0; i < ranges.length; i++) {
10239
- var sel = getBetween(this, ranges[i].from(), ranges[i].to());
10240
- if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator());
10241
- parts[i] = sel;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10242
  }
10243
- return parts;
10244
- },
10245
- replaceSelection: function(code, collapse, origin) {
10246
- var dup = [];
10247
- for (var i = 0; i < this.sel.ranges.length; i++)
10248
- dup[i] = code;
10249
- this.replaceSelections(dup, collapse, origin || "+input");
10250
- },
10251
- replaceSelections: docMethodOp(function(code, collapse, origin) {
10252
- var changes = [], sel = this.sel;
10253
- for (var i = 0; i < sel.ranges.length; i++) {
10254
- var range = sel.ranges[i];
10255
- changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin};
10256
  }
10257
- var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
10258
- for (var i = changes.length - 1; i >= 0; i--)
10259
- makeChange(this, changes[i]);
10260
- if (newSel) setSelectionReplaceHistory(this, newSel);
10261
- else if (this.cm) ensureCursorVisible(this.cm);
10262
- }),
10263
- undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
10264
- redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
10265
- undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
10266
- redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
10267
-
10268
- setExtending: function(val) {this.extend = val;},
10269
- getExtending: function() {return this.extend;},
10270
-
10271
- historySize: function() {
10272
- var hist = this.history, done = 0, undone = 0;
10273
- for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done;
10274
- for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone;
10275
- return {undo: done, redo: undone};
10276
  },
10277
- clearHistory: function() {this.history = new History(this.history.maxGeneration);},
10278
 
10279
- markClean: function() {
10280
- this.cleanGeneration = this.changeGeneration(true);
10281
- },
10282
- changeGeneration: function(forceSplit) {
10283
- if (forceSplit)
10284
- this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null;
10285
- return this.history.generation;
10286
- },
10287
- isClean: function (gen) {
10288
- return this.history.generation == (gen || this.cleanGeneration);
10289
- },
10290
 
10291
- getHistory: function() {
10292
- return {done: copyHistoryArray(this.history.done),
10293
- undone: copyHistoryArray(this.history.undone)};
10294
  },
10295
- setHistory: function(histData) {
10296
- var hist = this.history = new History(this.history.maxGeneration);
10297
- hist.done = copyHistoryArray(histData.done.slice(0), null, true);
10298
- hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
 
 
 
 
 
 
 
 
 
 
10299
  },
10300
 
10301
- addLineClass: docMethodOp(function(handle, where, cls) {
10302
- return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
10303
- var prop = where == "text" ? "textClass"
10304
- : where == "background" ? "bgClass"
10305
- : where == "gutter" ? "gutterClass" : "wrapClass";
10306
- if (!line[prop]) line[prop] = cls;
10307
- else if (classTest(cls).test(line[prop])) return false;
10308
- else line[prop] += " " + cls;
10309
- return true;
10310
- });
10311
- }),
10312
- removeLineClass: docMethodOp(function(handle, where, cls) {
10313
- return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
10314
- var prop = where == "text" ? "textClass"
10315
- : where == "background" ? "bgClass"
10316
- : where == "gutter" ? "gutterClass" : "wrapClass";
10317
- var cur = line[prop];
10318
- if (!cur) return false;
10319
- else if (cls == null) line[prop] = null;
10320
- else {
10321
- var found = cur.match(classTest(cls));
10322
- if (!found) return false;
10323
- var end = found.index + found[0].length;
10324
- line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
10325
- }
10326
- return true;
10327
- });
10328
  }),
10329
 
10330
- addLineWidget: docMethodOp(function(handle, node, options) {
10331
- return addLineWidget(this, handle, node, options);
 
 
 
 
 
 
 
10332
  }),
10333
- removeLineWidget: function(widget) { widget.clear(); },
10334
 
10335
- markText: function(from, to, options) {
10336
- return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range");
10337
- },
10338
- setBookmark: function(pos, options) {
10339
- var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
10340
- insertLeft: options && options.insertLeft,
10341
- clearWhenEmpty: false, shared: options && options.shared,
10342
- handleMouseEvents: options && options.handleMouseEvents};
10343
- pos = clipPos(this, pos);
10344
- return markText(this, pos, pos, realOpts, "bookmark");
10345
- },
10346
- findMarksAt: function(pos) {
10347
- pos = clipPos(this, pos);
10348
- var markers = [], spans = getLine(this, pos.line).markedSpans;
10349
- if (spans) for (var i = 0; i < spans.length; ++i) {
10350
- var span = spans[i];
10351
- if ((span.from == null || span.from <= pos.ch) &&
10352
- (span.to == null || span.to >= pos.ch))
10353
- markers.push(span.marker.parent || span.marker);
10354
  }
10355
- return markers;
10356
- },
10357
- findMarks: function(from, to, filter) {
10358
- from = clipPos(this, from); to = clipPos(this, to);
10359
- var found = [], lineNo = from.line;
10360
- this.iter(from.line, to.line + 1, function(line) {
10361
- var spans = line.markedSpans;
10362
- if (spans) for (var i = 0; i < spans.length; i++) {
10363
- var span = spans[i];
10364
- if (!(span.to != null && lineNo == from.line && from.ch >= span.to ||
10365
- span.from == null && lineNo != from.line ||
10366
- span.from != null && lineNo == to.line && span.from >= to.ch) &&
10367
- (!filter || filter(span.marker)))
10368
- found.push(span.marker.parent || span.marker);
10369
- }
10370
- ++lineNo;
10371
- });
10372
- return found;
10373
- },
10374
- getAllMarks: function() {
10375
- var markers = [];
10376
- this.iter(function(line) {
10377
- var sps = line.markedSpans;
10378
- if (sps) for (var i = 0; i < sps.length; ++i)
10379
- if (sps[i].from != null) markers.push(sps[i].marker);
10380
- });
10381
- return markers;
10382
  },
10383
 
10384
- posFromIndex: function(off) {
10385
- var ch, lineNo = this.first, sepSize = this.lineSeparator().length;
10386
- this.iter(function(line) {
10387
- var sz = line.text.length + sepSize;
10388
- if (sz > off) { ch = off; return true; }
10389
- off -= sz;
10390
- ++lineNo;
10391
- });
10392
- return clipPos(this, Pos(lineNo, ch));
10393
- },
10394
- indexFromPos: function (coords) {
10395
- coords = clipPos(this, coords);
10396
- var index = coords.ch;
10397
- if (coords.line < this.first || coords.ch < 0) return 0;
10398
- var sepSize = this.lineSeparator().length;
10399
- this.iter(this.first, coords.line, function (line) {
10400
- index += line.text.length + sepSize;
10401
- });
10402
- return index;
10403
- },
10404
 
10405
- copy: function(copyHistory) {
10406
- var doc = new Doc(getLines(this, this.first, this.first + this.size),
10407
- this.modeOption, this.first, this.lineSep);
10408
- doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
10409
- doc.sel = this.sel;
10410
- doc.extend = false;
10411
- if (copyHistory) {
10412
- doc.history.undoDepth = this.history.undoDepth;
10413
- doc.setHistory(this.getHistory());
10414
- }
10415
- return doc;
10416
- },
 
 
 
 
10417
 
10418
- linkedDoc: function(options) {
10419
- if (!options) options = {};
10420
- var from = this.first, to = this.first + this.size;
10421
- if (options.from != null && options.from > from) from = options.from;
10422
- if (options.to != null && options.to < to) to = options.to;
10423
- var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep);
10424
- if (options.sharedHist) copy.history = this.history;
10425
- (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
10426
- copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
10427
- copySharedMarkers(copy, findSharedMarkers(this));
10428
- return copy;
10429
- },
10430
- unlinkDoc: function(other) {
10431
- if (other instanceof CodeMirror) other = other.doc;
10432
- if (this.linked) for (var i = 0; i < this.linked.length; ++i) {
10433
- var link = this.linked[i];
10434
- if (link.doc != other) continue;
10435
- this.linked.splice(i, 1);
10436
- other.unlinkDoc(this);
10437
- detachSharedMarkers(findSharedMarkers(this));
10438
- break;
10439
- }
10440
- // If the histories were shared, split them again
10441
- if (other.history == this.history) {
10442
- var splitIds = [other.id];
10443
- linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true);
10444
- other.history = new History(null);
10445
- other.history.done = copyHistoryArray(this.history.done, splitIds);
10446
- other.history.undone = copyHistoryArray(this.history.undone, splitIds);
10447
  }
 
10448
  },
10449
- iterLinkedDocs: function(f) {linkedDocs(this, f);},
10450
 
10451
- getMode: function() {return this.mode;},
10452
- getEditor: function() {return this.cm;},
 
 
 
 
10453
 
10454
- splitLines: function(str) {
10455
- if (this.lineSep) return str.split(this.lineSep);
10456
- return splitLinesAuto(str);
10457
  },
10458
- lineSeparator: function() { return this.lineSep || "\n"; }
10459
- });
10460
-
10461
- // Public alias.
10462
- Doc.prototype.eachLine = Doc.prototype.iter;
10463
-
10464
- // Set up methods on CodeMirror's prototype to redirect to the editor's document.
10465
- var dontDelegate = "iter insert remove copy getEditor constructor".split(" ");
10466
- for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
10467
- CodeMirror.prototype[prop] = (function(method) {
10468
- return function() {return method.apply(this.doc, arguments);};
10469
- })(Doc.prototype[prop]);
10470
-
10471
- eventMixin(Doc);
10472
-
10473
- // Call f for all linked documents.
10474
- function linkedDocs(doc, f, sharedHistOnly) {
10475
- function propagate(doc, skip, sharedHist) {
10476
- if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {
10477
- var rel = doc.linked[i];
10478
- if (rel.doc == skip) continue;
10479
- var shared = sharedHist && rel.sharedHist;
10480
- if (sharedHistOnly && !shared) continue;
10481
- f(rel.doc, shared);
10482
- propagate(rel.doc, doc, shared);
10483
- }
10484
- }
10485
- propagate(doc, null, true);
10486
- }
10487
-
10488
- // Attach a document to an editor.
10489
- function attachDoc(cm, doc) {
10490
- if (doc.cm) throw new Error("This document is already in use.");
10491
- cm.doc = doc;
10492
- doc.cm = cm;
10493
- estimateLineHeights(cm);
10494
- loadMode(cm);
10495
- if (!cm.options.lineWrapping) findMaxLine(cm);
10496
- cm.options.mode = doc.modeOption;
10497
- regChange(cm);
10498
- }
10499
 
10500
- // LINE UTILITIES
 
 
 
 
 
 
 
 
 
 
 
10501
 
10502
- // Find the line object corresponding to the given line number.
10503
- function getLine(doc, n) {
10504
- n -= doc.first;
10505
- if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document.");
10506
- for (var chunk = doc; !chunk.lines;) {
10507
- for (var i = 0;; ++i) {
10508
- var child = chunk.children[i], sz = child.chunkSize();
10509
- if (n < sz) { chunk = child; break; }
10510
- n -= sz;
10511
  }
10512
- }
10513
- return chunk.lines[n];
10514
- }
10515
 
10516
- // Get the part of a document between two positions, as an array of
10517
- // strings.
10518
- function getBetween(doc, start, end) {
10519
- var out = [], n = start.line;
10520
- doc.iter(start.line, end.line + 1, function(line) {
10521
- var text = line.text;
10522
- if (n == end.line) text = text.slice(0, end.ch);
10523
- if (n == start.line) text = text.slice(start.ch);
10524
- out.push(text);
10525
- ++n;
10526
- });
10527
- return out;
10528
- }
10529
- // Get the lines between from and to, as array of strings.
10530
- function getLines(doc, from, to) {
10531
- var out = [];
10532
- doc.iter(from, to, function(line) { out.push(line.text); });
10533
- return out;
10534
- }
10535
-
10536
- // Update the height of a line, propagating the height change
10537
- // upwards to parent nodes.
10538
- function updateLineHeight(line, height) {
10539
- var diff = height - line.height;
10540
- if (diff) for (var n = line; n; n = n.parent) n.height += diff;
10541
- }
10542
-
10543
- // Given a line object, find its line number by walking up through
10544
- // its parent links.
10545
- function lineNo(line) {
10546
- if (line.parent == null) return null;
10547
- var cur = line.parent, no = indexOf(cur.lines, line);
10548
- for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
10549
- for (var i = 0;; ++i) {
10550
- if (chunk.children[i] == cur) break;
10551
- no += chunk.children[i].chunkSize();
10552
  }
10553
- }
10554
- return no + cur.first;
10555
- }
10556
 
10557
- // Find the line at the given vertical position, using the height
10558
- // information in the document tree.
10559
- function lineAtHeight(chunk, h) {
10560
- var n = chunk.first;
10561
- outer: do {
10562
- for (var i = 0; i < chunk.children.length; ++i) {
10563
- var child = chunk.children[i], ch = child.height;
10564
- if (h < ch) { chunk = child; continue outer; }
10565
- h -= ch;
10566
- n += child.chunkSize();
10567
- }
10568
- return n;
10569
- } while (!chunk.lines);
10570
- for (var i = 0; i < chunk.lines.length; ++i) {
10571
- var line = chunk.lines[i], lh = line.height;
10572
- if (h < lh) break;
10573
- h -= lh;
10574
- }
10575
- return n + i;
10576
- }
10577
 
 
10578
 
10579
- // Find the height above the given line.
10580
- function heightAtLine(lineObj) {
10581
- lineObj = visualLine(lineObj);
 
 
 
 
 
 
 
 
10582
 
10583
- var h = 0, chunk = lineObj.parent;
10584
- for (var i = 0; i < chunk.lines.length; ++i) {
10585
- var line = chunk.lines[i];
10586
- if (line == lineObj) break;
10587
- else h += line.height;
10588
- }
10589
- for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
10590
- for (var i = 0; i < p.children.length; ++i) {
10591
- var cur = p.children[i];
10592
- if (cur == chunk) break;
10593
- else h += cur.height;
10594
- }
10595
- }
10596
- return h;
10597
- }
10598
-
10599
- // Get the bidi ordering for the given line (and cache it). Returns
10600
- // false for lines that are fully left-to-right, and an array of
10601
- // BidiSpan objects otherwise.
10602
- function getOrder(line) {
10603
- var order = line.order;
10604
- if (order == null) order = line.order = bidiOrdering(line.text);
10605
- return order;
10606
- }
10607
-
10608
- // HISTORY
10609
-
10610
- function History(startGen) {
10611
- // Arrays of change events and selections. Doing something adds an
10612
- // event to done and clears undo. Undoing moves events from done
10613
- // to undone, redoing moves them in the other direction.
10614
- this.done = []; this.undone = [];
10615
- this.undoDepth = Infinity;
10616
- // Used to track when changes can be merged into a single undo
10617
- // event
10618
- this.lastModTime = this.lastSelTime = 0;
10619
- this.lastOp = this.lastSelOp = null;
10620
- this.lastOrigin = this.lastSelOrigin = null;
10621
- // Used by the isClean() method
10622
- this.generation = this.maxGeneration = startGen || 1;
10623
- }
10624
-
10625
- // Create a history change event from an updateDoc-style change
10626
- // object.
10627
- function historyChangeFromChange(doc, change) {
10628
- var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
10629
- attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
10630
- linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true);
10631
- return histChange;
10632
- }
10633
-
10634
- // Pop all selection events off the end of a history array. Stop at
10635
- // a change event.
10636
- function clearSelectionEvents(array) {
10637
- while (array.length) {
10638
- var last = lst(array);
10639
- if (last.ranges) array.pop();
10640
- else break;
10641
- }
10642
- }
10643
-
10644
- // Find the top change event in the history. Pop off selection
10645
- // events that are in the way.
10646
- function lastChangeEvent(hist, force) {
10647
- if (force) {
10648
- clearSelectionEvents(hist.done);
10649
- return lst(hist.done);
10650
- } else if (hist.done.length && !lst(hist.done).ranges) {
10651
- return lst(hist.done);
10652
- } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
10653
- hist.done.pop();
10654
- return lst(hist.done);
10655
- }
10656
- }
10657
-
10658
- // Register a change in the history. Merges changes that are within
10659
- // a single operation, or are close together with an origin that
10660
- // allows merging (starting with "+") into a single event.
10661
- function addChangeToHistory(doc, change, selAfter, opId) {
10662
- var hist = doc.history;
10663
- hist.undone.length = 0;
10664
- var time = +new Date, cur;
10665
-
10666
- if ((hist.lastOp == opId ||
10667
- hist.lastOrigin == change.origin && change.origin &&
10668
- ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
10669
- change.origin.charAt(0) == "*")) &&
10670
- (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
10671
- // Merge this change into the last event
10672
- var last = lst(cur.changes);
10673
- if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
10674
- // Optimized case for simple insertion -- don't want to add
10675
- // new changesets for every character typed
10676
- last.to = changeEnd(change);
10677
- } else {
10678
- // Add new sub-event
10679
- cur.changes.push(historyChangeFromChange(doc, change));
10680
- }
10681
- } else {
10682
- // Can not be merged, start a new event.
10683
- var before = lst(hist.done);
10684
- if (!before || !before.ranges)
10685
- pushSelectionToHistory(doc.sel, hist.done);
10686
- cur = {changes: [historyChangeFromChange(doc, change)],
10687
- generation: hist.generation};
10688
- hist.done.push(cur);
10689
- while (hist.done.length > hist.undoDepth) {
10690
- hist.done.shift();
10691
- if (!hist.done[0].ranges) hist.done.shift();
10692
- }
10693
- }
10694
- hist.done.push(selAfter);
10695
- hist.generation = ++hist.maxGeneration;
10696
- hist.lastModTime = hist.lastSelTime = time;
10697
- hist.lastOp = hist.lastSelOp = opId;
10698
- hist.lastOrigin = hist.lastSelOrigin = change.origin;
10699
-
10700
- if (!last) signal(doc, "historyAdded");
10701
- }
10702
-
10703
- function selectionEventCanBeMerged(doc, origin, prev, sel) {
10704
- var ch = origin.charAt(0);
10705
- return ch == "*" ||
10706
- ch == "+" &&
10707
- prev.ranges.length == sel.ranges.length &&
10708
- prev.somethingSelected() == sel.somethingSelected() &&
10709
- new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500);
10710
- }
10711
-
10712
- // Called whenever the selection changes, sets the new selection as
10713
- // the pending selection in the history, and pushes the old pending
10714
- // selection into the 'done' array when it was significantly
10715
- // different (in number of selected ranges, emptiness, or time).
10716
- function addSelectionToHistory(doc, sel, opId, options) {
10717
- var hist = doc.history, origin = options && options.origin;
10718
-
10719
- // A new event is started when the previous origin does not match
10720
- // the current, or the origins don't allow matching. Origins
10721
- // starting with * are always merged, those starting with + are
10722
- // merged when similar and close together in time.
10723
- if (opId == hist.lastSelOp ||
10724
- (origin && hist.lastSelOrigin == origin &&
10725
- (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
10726
- selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
10727
- hist.done[hist.done.length - 1] = sel;
10728
- else
10729
- pushSelectionToHistory(sel, hist.done);
10730
 
10731
- hist.lastSelTime = +new Date;
10732
- hist.lastSelOrigin = origin;
10733
- hist.lastSelOp = opId;
10734
- if (options && options.clearRedo !== false)
10735
- clearSelectionEvents(hist.undone);
10736
  }
 
10737
 
10738
- function pushSelectionToHistory(sel, dest) {
10739
- var top = lst(dest);
10740
- if (!(top && top.ranges && top.equals(sel)))
10741
- dest.push(sel);
10742
  }
10743
-
10744
- // Used to store marked span information in the history.
10745
- function attachLocalSpans(doc, change, from, to) {
10746
- var existing = change["spans_" + doc.id], n = 0;
10747
- doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {
10748
- if (line.markedSpans)
10749
- (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans;
10750
- ++n;
10751
- });
10752
  }
 
10753
 
10754
- // When un/re-doing restores text containing marked spans, those
10755
- // that have been explicitly cleared should not be restored.
10756
- function removeClearedSpans(spans) {
10757
- if (!spans) return null;
10758
- for (var i = 0, out; i < spans.length; ++i) {
10759
- if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
10760
- else if (out) out.push(spans[i]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10761
  }
10762
- return !out ? spans : out.length ? out : null;
10763
  }
 
 
 
 
10764
 
10765
- // Retrieve and filter the old marked spans stored in a change event.
10766
- function getOldSpans(doc, change) {
10767
- var found = change["spans_" + doc.id];
10768
- if (!found) return null;
10769
- for (var i = 0, nw = []; i < change.text.length; ++i)
10770
- nw.push(removeClearedSpans(found[i]));
10771
- return nw;
10772
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10773
 
10774
- // Used both to provide a JSON-safe object in .getHistory, and, when
10775
- // detaching a document, to split the history in two
10776
- function copyHistoryArray(events, newGroup, instantiateSel) {
10777
- for (var i = 0, copy = []; i < events.length; ++i) {
10778
- var event = events[i];
10779
- if (event.ranges) {
10780
- copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
10781
- continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10782
  }
10783
- var changes = event.changes, newChanges = [];
10784
- copy.push({changes: newChanges});
10785
- for (var j = 0; j < changes.length; ++j) {
10786
- var change = changes[j], m;
10787
- newChanges.push({from: change.from, to: change.to, text: change.text});
10788
- if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) {
10789
- if (indexOf(newGroup, Number(m[1])) > -1) {
10790
- lst(newChanges)[prop] = change[prop];
10791
- delete change[prop];
10792
- }
10793
  }
10794
  }
10795
- }
10796
- return copy;
10797
- }
 
 
 
 
 
 
 
 
 
 
 
 
10798
 
10799
- // Rebasing/resetting history to deal with externally-sourced changes
 
 
 
 
10800
 
10801
- function rebaseHistSelSingle(pos, from, to, diff) {
10802
- if (to < pos.line) {
10803
- pos.line += diff;
10804
- } else if (from < pos.line) {
10805
- pos.line = from;
10806
- pos.ch = 0;
10807
- }
10808
- }
10809
 
10810
- // Tries to rebase an array of history events given a change in the
10811
- // document. If the change touches the same lines as the event, the
10812
- // event, and everything 'behind' it, is discarded. If the change is
10813
- // before the event, the event's positions are updated. Uses a
10814
- // copy-on-write scheme for the positions, to avoid having to
10815
- // reallocate them all on every rebase, but also avoid problems with
10816
- // shared position objects being unsafely updated.
10817
- function rebaseHistArray(array, from, to, diff) {
10818
- for (var i = 0; i < array.length; ++i) {
10819
- var sub = array[i], ok = true;
10820
- if (sub.ranges) {
10821
- if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
10822
- for (var j = 0; j < sub.ranges.length; j++) {
10823
- rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
10824
- rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
10825
- }
10826
- continue;
10827
- }
10828
- for (var j = 0; j < sub.changes.length; ++j) {
10829
- var cur = sub.changes[j];
10830
- if (to < cur.from.line) {
10831
- cur.from = Pos(cur.from.line + diff, cur.from.ch);
10832
- cur.to = Pos(cur.to.line + diff, cur.to.ch);
10833
- } else if (from <= cur.to.line) {
10834
- ok = false;
10835
- break;
 
 
 
 
 
 
10836
  }
 
 
 
10837
  }
10838
- if (!ok) {
10839
- array.splice(0, i + 1);
10840
- i = 0;
10841
- }
10842
  }
10843
- }
 
10844
 
10845
- function rebaseHist(hist, change) {
10846
- var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
10847
- rebaseHistArray(hist.done, from, to, diff);
10848
- rebaseHistArray(hist.undone, from, to, diff);
10849
- }
 
 
 
 
 
10850
 
10851
- // EVENT UTILITIES
 
 
 
10852
 
10853
- // Due to the fact that we still support jurassic IE versions, some
10854
- // compatibility wrappers are needed.
 
 
 
10855
 
10856
- var e_preventDefault = CodeMirror.e_preventDefault = function(e) {
10857
- if (e.preventDefault) e.preventDefault();
10858
- else e.returnValue = false;
10859
- };
10860
- var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) {
10861
- if (e.stopPropagation) e.stopPropagation();
10862
- else e.cancelBubble = true;
10863
- };
10864
- function e_defaultPrevented(e) {
10865
- return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;
10866
- }
10867
- var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);};
10868
 
10869
- function e_target(e) {return e.target || e.srcElement;}
10870
- function e_button(e) {
10871
- var b = e.which;
10872
- if (b == null) {
10873
- if (e.button & 1) b = 1;
10874
- else if (e.button & 2) b = 3;
10875
- else if (e.button & 4) b = 2;
10876
- }
10877
- if (mac && e.ctrlKey && b == 1) b = 3;
10878
- return b;
10879
- }
10880
 
10881
- // EVENT HANDLING
10882
 
10883
- // Lightweight event framework. on/off also work on DOM nodes,
10884
- // registering native DOM handlers.
 
 
 
 
10885
 
10886
- var on = CodeMirror.on = function(emitter, type, f) {
10887
- if (emitter.addEventListener)
10888
- emitter.addEventListener(type, f, false);
10889
- else if (emitter.attachEvent)
10890
- emitter.attachEvent("on" + type, f);
10891
- else {
10892
- var map = emitter._handlers || (emitter._handlers = {});
10893
- var arr = map[type] || (map[type] = []);
10894
- arr.push(f);
10895
  }
10896
- };
 
10897
 
10898
- var noHandlers = []
10899
- function getHandlers(emitter, type, copy) {
10900
- var arr = emitter._handlers && emitter._handlers[type]
10901
- if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers
10902
- else return arr || noHandlers
10903
- }
10904
 
10905
- var off = CodeMirror.off = function(emitter, type, f) {
10906
- if (emitter.removeEventListener)
10907
- emitter.removeEventListener(type, f, false);
10908
- else if (emitter.detachEvent)
10909
- emitter.detachEvent("on" + type, f);
10910
- else {
10911
- var handlers = getHandlers(emitter, type, false)
10912
- for (var i = 0; i < handlers.length; ++i)
10913
- if (handlers[i] == f) { handlers.splice(i, 1); break; }
 
10914
  }
10915
- };
10916
 
10917
- var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
10918
- var handlers = getHandlers(emitter, type, true)
10919
- if (!handlers.length) return;
10920
- var args = Array.prototype.slice.call(arguments, 2);
10921
- for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args);
10922
- };
10923
 
10924
- var orphanDelayedCallbacks = null;
10925
-
10926
- // Often, we want to signal events at a point where we are in the
10927
- // middle of some work, but don't want the handler to start calling
10928
- // other methods on the editor, which might be in an inconsistent
10929
- // state or simply not expect any other events to happen.
10930
- // signalLater looks whether there are any handlers, and schedules
10931
- // them to be executed when the last operation ends, or, if no
10932
- // operation is active, when a timeout fires.
10933
- function signalLater(emitter, type /*, values...*/) {
10934
- var arr = getHandlers(emitter, type, false)
10935
- if (!arr.length) return;
10936
- var args = Array.prototype.slice.call(arguments, 2), list;
10937
- if (operationGroup) {
10938
- list = operationGroup.delayedCallbacks;
10939
- } else if (orphanDelayedCallbacks) {
10940
- list = orphanDelayedCallbacks;
10941
  } else {
10942
- list = orphanDelayedCallbacks = [];
10943
- setTimeout(fireOrphanDelayed, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10944
  }
10945
- function bnd(f) {return function(){f.apply(null, args);};};
10946
- for (var i = 0; i < arr.length; ++i)
10947
- list.push(bnd(arr[i]));
10948
- }
10949
-
10950
- function fireOrphanDelayed() {
10951
- var delayed = orphanDelayedCallbacks;
10952
- orphanDelayedCallbacks = null;
10953
- for (var i = 0; i < delayed.length; ++i) delayed[i]();
10954
- }
10955
 
10956
- // The DOM events that CodeMirror handles can be overridden by
10957
- // registering a (non-DOM) handler on the editor for the event name,
10958
- // and preventDefault-ing the event in that handler.
10959
- function signalDOMEvent(cm, e, override) {
10960
- if (typeof e == "string")
10961
- e = {type: e, preventDefault: function() { this.defaultPrevented = true; }};
10962
- signal(cm, override || e.type, cm, e);
10963
- return e_defaultPrevented(e) || e.codemirrorIgnore;
10964
- }
 
 
 
 
 
 
 
 
 
 
10965
 
10966
- function signalCursorActivity(cm) {
10967
- var arr = cm._handlers && cm._handlers.cursorActivity;
10968
- if (!arr) return;
10969
- var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
10970
- for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)
10971
- set.push(arr[i]);
10972
- }
10973
 
10974
- function hasHandler(emitter, type) {
10975
- return getHandlers(emitter, type).length > 0
10976
- }
 
 
10977
 
10978
- // Add on and off methods to a constructor's prototype, to make
10979
- // registering events on such objects more convenient.
10980
- function eventMixin(ctor) {
10981
- ctor.prototype.on = function(type, f) {on(this, type, f);};
10982
- ctor.prototype.off = function(type, f) {off(this, type, f);};
10983
- }
10984
 
10985
- // MISC UTILITIES
 
10986
 
10987
- // Number of pixels added to scroller and sizer to hide scrollbar
10988
- var scrollerGap = 30;
10989
 
10990
- // Returned or thrown by various protocols to signal 'I'm not
10991
- // handling this'.
10992
- var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
 
 
10993
 
10994
- // Reused option objects for setSelection & friends
10995
- var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
 
 
 
 
 
 
 
10996
 
10997
- function Delayed() {this.id = null;}
10998
- Delayed.prototype.set = function(ms, f) {
10999
- clearTimeout(this.id);
11000
- this.id = setTimeout(f, ms);
11001
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11002
 
11003
- // Counts the column offset in a string, taking tabs into account.
11004
- // Used mostly to find indentation.
11005
- var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) {
11006
- if (end == null) {
11007
- end = string.search(/[^\s\u00a0]/);
11008
- if (end == -1) end = string.length;
11009
- }
11010
- for (var i = startIndex || 0, n = startValue || 0;;) {
11011
- var nextTab = string.indexOf("\t", i);
11012
- if (nextTab < 0 || nextTab >= end)
11013
- return n + (end - i);
11014
- n += nextTab - i;
11015
- n += tabSize - (n % tabSize);
11016
- i = nextTab + 1;
11017
  }
11018
- };
 
 
 
 
 
 
11019
 
11020
- // The inverse of countColumn -- find the offset that corresponds to
11021
- // a particular column.
11022
- var findColumn = CodeMirror.findColumn = function(string, goal, tabSize) {
11023
- for (var pos = 0, col = 0;;) {
11024
- var nextTab = string.indexOf("\t", pos);
11025
- if (nextTab == -1) nextTab = string.length;
11026
- var skipped = nextTab - pos;
11027
- if (nextTab == string.length || col + skipped >= goal)
11028
- return pos + Math.min(skipped, goal - col);
11029
- col += nextTab - pos;
11030
- col += tabSize - (col % tabSize);
11031
- pos = nextTab + 1;
11032
- if (col >= goal) return pos;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11033
  }
11034
  }
 
 
11035
 
11036
- var spaceStrs = [""];
11037
- function spaceStr(n) {
11038
- while (spaceStrs.length <= n)
11039
- spaceStrs.push(lst(spaceStrs) + " ");
11040
- return spaceStrs[n];
 
 
 
 
 
 
 
 
 
11041
  }
 
11042
 
11043
- function lst(arr) { return arr[arr.length-1]; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11044
 
11045
- var selectInput = function(node) { node.select(); };
11046
- if (ios) // Mobile Safari apparently has a bug where select() is broken.
11047
- selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; };
11048
- else if (ie) // Suppress mysterious IE10 errors
11049
- selectInput = function(node) { try { node.select(); } catch(_e) {} };
11050
 
11051
- function indexOf(array, elt) {
11052
- for (var i = 0; i < array.length; ++i)
11053
- if (array[i] == elt) return i;
11054
- return -1;
11055
- }
11056
- function map(array, f) {
11057
- var out = [];
11058
- for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
11059
- return out;
11060
- }
11061
 
11062
- function insertSorted(array, value, score) {
11063
- var pos = 0, priority = score(value)
11064
- while (pos < array.length && score(array[pos]) <= priority) pos++
11065
- array.splice(pos, 0, value)
11066
- }
 
11067
 
11068
- function nothing() {}
 
11069
 
11070
- function createObj(base, props) {
11071
- var inst;
11072
- if (Object.create) {
11073
- inst = Object.create(base);
11074
- } else {
11075
- nothing.prototype = base;
11076
- inst = new nothing();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11077
  }
11078
- if (props) copyObj(props, inst);
11079
- return inst;
11080
- };
11081
 
11082
- function copyObj(obj, target, overwrite) {
11083
- if (!target) target = {};
11084
- for (var prop in obj)
11085
- if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
11086
- target[prop] = obj[prop];
11087
- return target;
11088
- }
11089
 
11090
- function bind(f) {
11091
- var args = Array.prototype.slice.call(arguments, 1);
11092
- return function(){return f.apply(null, args);};
11093
- }
 
 
 
 
 
11094
 
11095
- var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
11096
- var isWordCharBasic = CodeMirror.isWordChar = function(ch) {
11097
- return /\w/.test(ch) || ch > "\x80" &&
11098
- (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
11099
- };
11100
- function isWordChar(ch, helper) {
11101
- if (!helper) return isWordCharBasic(ch);
11102
- if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true;
11103
- return helper.test(ch);
11104
- }
 
 
 
 
 
 
 
 
 
 
11105
 
11106
- function isEmpty(obj) {
11107
- for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;
11108
- return true;
11109
- }
11110
 
11111
- // Extending unicode characters. A series of a non-extending char +
11112
- // any number of extending chars is treated as a single unit as far
11113
- // as editing and measuring is concerned. This is not fully correct,
11114
- // since some scripts/fonts/browsers also treat other configurations
11115
- // of code points as a group.
11116
- var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
11117
- function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }
11118
 
11119
- // DOM UTILITIES
 
 
 
 
 
11120
 
11121
- function elt(tag, content, className, style) {
11122
- var e = document.createElement(tag);
11123
- if (className) e.className = className;
11124
- if (style) e.style.cssText = style;
11125
- if (typeof content == "string") e.appendChild(document.createTextNode(content));
11126
- else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
11127
- return e;
11128
- }
11129
 
11130
- var range;
11131
- if (document.createRange) range = function(node, start, end, endNode) {
11132
- var r = document.createRange();
11133
- r.setEnd(endNode || node, end);
11134
- r.setStart(node, start);
11135
- return r;
11136
- };
11137
- else range = function(node, start, end) {
11138
- var r = document.body.createTextRange();
11139
- try { r.moveToElementText(node.parentNode); }
11140
- catch(e) { return r; }
11141
- r.collapse(true);
11142
- r.moveEnd("character", end);
11143
- r.moveStart("character", start);
11144
- return r;
11145
- };
11146
 
11147
- function removeChildren(e) {
11148
- for (var count = e.childNodes.length; count > 0; --count)
11149
- e.removeChild(e.firstChild);
11150
- return e;
11151
- }
11152
 
11153
- function removeChildrenAndAdd(parent, e) {
11154
- return removeChildren(parent).appendChild(e);
11155
- }
 
11156
 
11157
- var contains = CodeMirror.contains = function(parent, child) {
11158
- if (child.nodeType == 3) // Android browser always returns false when child is a textnode
11159
- child = child.parentNode;
11160
- if (parent.contains)
11161
- return parent.contains(child);
11162
- do {
11163
- if (child.nodeType == 11) child = child.host;
11164
- if (child == parent) return true;
11165
- } while (child = child.parentNode);
11166
- };
11167
 
11168
- function activeElt() {
11169
- var activeElement = document.activeElement;
11170
- while (activeElement && activeElement.root && activeElement.root.activeElement)
11171
- activeElement = activeElement.root.activeElement;
11172
- return activeElement;
11173
- }
11174
- // Older versions of IE throws unspecified error when touching
11175
- // document.activeElement in some cases (during loading, in iframe)
11176
- if (ie && ie_version < 11) activeElt = function() {
11177
- try { return document.activeElement; }
11178
- catch(e) { return document.body; }
11179
- };
 
11180
 
11181
- function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); }
11182
- var rmClass = CodeMirror.rmClass = function(node, cls) {
11183
- var current = node.className;
11184
- var match = classTest(cls).exec(current);
11185
- if (match) {
11186
- var after = current.slice(match.index + match[0].length);
11187
- node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
11188
- }
11189
- };
11190
- var addClass = CodeMirror.addClass = function(node, cls) {
11191
- var current = node.className;
11192
- if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls;
11193
- };
11194
- function joinClasses(a, b) {
11195
- var as = a.split(" ");
11196
- for (var i = 0; i < as.length; i++)
11197
- if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i];
11198
- return b;
11199
- }
11200
-
11201
- // WINDOW-WIDE EVENTS
11202
-
11203
- // These must be handled carefully, because naively registering a
11204
- // handler for each editor will cause the editors to never be
11205
- // garbage collected.
11206
-
11207
- function forEachCodeMirror(f) {
11208
- if (!document.body.getElementsByClassName) return;
11209
- var byClass = document.body.getElementsByClassName("CodeMirror");
11210
- for (var i = 0; i < byClass.length; i++) {
11211
- var cm = byClass[i].CodeMirror;
11212
- if (cm) f(cm);
11213
- }
11214
- }
11215
-
11216
- var globalsRegistered = false;
11217
- function ensureGlobalHandlers() {
11218
- if (globalsRegistered) return;
11219
- registerGlobalHandlers();
11220
- globalsRegistered = true;
11221
- }
11222
- function registerGlobalHandlers() {
11223
- // When the window resizes, we need to refresh active editors.
11224
- var resizeTimer;
11225
- on(window, "resize", function() {
11226
- if (resizeTimer == null) resizeTimer = setTimeout(function() {
11227
- resizeTimer = null;
11228
- forEachCodeMirror(onResize);
11229
- }, 100);
11230
- });
11231
- // When the window loses focus, we want to show the editor as blurred
11232
- on(window, "blur", function() {
11233
- forEachCodeMirror(onBlur);
11234
- });
11235
- }
 
11236
 
11237
- // FEATURE DETECTION
 
 
11238
 
11239
- // Detect drag-and-drop
11240
- var dragAndDrop = function() {
11241
- // There is *some* kind of drag-and-drop support in IE6-8, but I
11242
- // couldn't get it to work yet.
11243
- if (ie && ie_version < 9) return false;
11244
- var div = elt('div');
11245
- return "draggable" in div || "dragDrop" in div;
11246
- }();
11247
 
11248
- var zwspSupported;
11249
- function zeroWidthElement(measure) {
11250
- if (zwspSupported == null) {
11251
- var test = elt("span", "\u200b");
11252
- removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
11253
- if (measure.firstChild.offsetHeight != 0)
11254
- zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8);
11255
- }
11256
- var node = zwspSupported ? elt("span", "\u200b") :
11257
- elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
11258
- node.setAttribute("cm-text", "");
11259
- return node;
11260
- }
11261
-
11262
- // Feature-detect IE's crummy client rect reporting for bidi text
11263
- var badBidiRects;
11264
- function hasBadBidiRects(measure) {
11265
- if (badBidiRects != null) return badBidiRects;
11266
- var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
11267
- var r0 = range(txt, 0, 1).getBoundingClientRect();
11268
- var r1 = range(txt, 1, 2).getBoundingClientRect();
11269
- removeChildren(measure);
11270
- if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780)
11271
- return badBidiRects = (r1.right - r0.right < 3);
11272
- }
11273
-
11274
- // See if "".split is the broken IE version, if so, provide an
11275
- // alternative way to split lines.
11276
- var splitLinesAuto = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
11277
- var pos = 0, result = [], l = string.length;
11278
- while (pos <= l) {
11279
- var nl = string.indexOf("\n", pos);
11280
- if (nl == -1) nl = string.length;
11281
- var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
11282
- var rt = line.indexOf("\r");
11283
- if (rt != -1) {
11284
- result.push(line.slice(0, rt));
11285
- pos += rt + 1;
11286
- } else {
11287
- result.push(line);
11288
- pos = nl + 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11289
  }
11290
  }
11291
- return result;
11292
- } : function(string){return string.split(/\r\n?|\n/);};
11293
-
11294
- var hasSelection = window.getSelection ? function(te) {
11295
- try { return te.selectionStart != te.selectionEnd; }
11296
- catch(e) { return false; }
11297
- } : function(te) {
11298
- try {var range = te.ownerDocument.selection.createRange();}
11299
- catch(e) {}
11300
- if (!range || range.parentElement() != te) return false;
11301
- return range.compareEndPoints("StartToEnd", range) != 0;
11302
- };
11303
 
11304
- var hasCopyEvent = (function() {
11305
- var e = elt("div");
11306
- if ("oncopy" in e) return true;
11307
- e.setAttribute("oncopy", "return;");
11308
- return typeof e.oncopy == "function";
11309
- })();
11310
-
11311
- var badZoomedRects = null;
11312
- function hasBadZoomedRects(measure) {
11313
- if (badZoomedRects != null) return badZoomedRects;
11314
- var node = removeChildrenAndAdd(measure, elt("span", "x"));
11315
- var normal = node.getBoundingClientRect();
11316
- var fromRange = range(node, 0, 1).getBoundingClientRect();
11317
- return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1;
11318
- }
11319
-
11320
- // KEY NAMES
11321
-
11322
- var keyNames = CodeMirror.keyNames = {
11323
- 3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
11324
- 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
11325
- 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
11326
- 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
11327
- 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete",
11328
- 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
11329
- 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
11330
- 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
11331
- };
11332
- (function() {
11333
- // Number keys
11334
- for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
11335
- // Alphabetic keys
11336
- for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
11337
- // Function keys
11338
- for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
11339
- })();
11340
-
11341
- // BIDI HELPERS
11342
-
11343
- function iterateBidiSections(order, from, to, f) {
11344
- if (!order) return f(from, to, "ltr");
11345
- var found = false;
11346
- for (var i = 0; i < order.length; ++i) {
11347
- var part = order[i];
11348
- if (part.from < to && part.to > from || from == to && part.to == from) {
11349
- f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
11350
- found = true;
11351
  }
 
 
 
11352
  }
11353
- if (!found) f(from, to, "ltr");
11354
- }
11355
-
11356
- function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
11357
- function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
11358
-
11359
- function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
11360
- function lineRight(line) {
11361
- var order = getOrder(line);
11362
- if (!order) return line.text.length;
11363
- return bidiRight(lst(order));
11364
- }
11365
-
11366
- function lineStart(cm, lineN) {
11367
- var line = getLine(cm.doc, lineN);
11368
- var visual = visualLine(line);
11369
- if (visual != line) lineN = lineNo(visual);
11370
- var order = getOrder(visual);
11371
- var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
11372
- return Pos(lineN, ch);
11373
- }
11374
- function lineEnd(cm, lineN) {
11375
- var merged, line = getLine(cm.doc, lineN);
11376
- while (merged = collapsedSpanAtEnd(line)) {
11377
- line = merged.find(1, true).line;
11378
- lineN = null;
11379
- }
11380
- var order = getOrder(line);
11381
- var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
11382
- return Pos(lineN == null ? lineNo(line) : lineN, ch);
11383
- }
11384
- function lineStartSmart(cm, pos) {
11385
- var start = lineStart(cm, pos.line);
11386
- var line = getLine(cm.doc, start.line);
11387
- var order = getOrder(line);
11388
- if (!order || order[0].level == 0) {
11389
- var firstNonWS = Math.max(0, line.text.search(/\S/));
11390
- var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
11391
- return Pos(start.line, inWS ? 0 : firstNonWS);
11392
- }
11393
- return start;
11394
- }
11395
-
11396
- function compareBidiLevel(order, a, b) {
11397
- var linedir = order[0].level;
11398
- if (a == linedir) return true;
11399
- if (b == linedir) return false;
11400
- return a < b;
11401
- }
11402
- var bidiOther;
11403
- function getBidiPartAt(order, pos) {
11404
- bidiOther = null;
11405
- for (var i = 0, found; i < order.length; ++i) {
11406
- var cur = order[i];
11407
- if (cur.from < pos && cur.to > pos) return i;
11408
- if ((cur.from == pos || cur.to == pos)) {
11409
- if (found == null) {
11410
- found = i;
11411
- } else if (compareBidiLevel(order, cur.level, order[found].level)) {
11412
- if (cur.from != cur.to) bidiOther = found;
11413
- return i;
11414
- } else {
11415
- if (cur.from != cur.to) bidiOther = i;
11416
- return found;
11417
  }
11418
- }
11419
  }
11420
- return found;
11421
- }
11422
-
11423
- function moveInLine(line, pos, dir, byUnit) {
11424
- if (!byUnit) return pos + dir;
11425
- do pos += dir;
11426
- while (pos > 0 && isExtendingChar(line.text.charAt(pos)));
11427
- return pos;
11428
  }
11429
 
11430
- // This is needed in order to move 'visually' through bi-directional
11431
- // text -- i.e., pressing left should make the cursor go left, even
11432
- // when in RTL text. The tricky part is the 'jumps', where RTL and
11433
- // LTR text touch each other. This often requires the cursor offset
11434
- // to move more than one unit, in order to visually move one unit.
11435
- function moveVisually(line, start, dir, byUnit) {
11436
- var bidi = getOrder(line);
11437
- if (!bidi) return moveLogically(line, start, dir, byUnit);
11438
- var pos = getBidiPartAt(bidi, start), part = bidi[pos];
11439
- var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);
11440
-
11441
- for (;;) {
11442
- if (target > part.from && target < part.to) return target;
11443
- if (target == part.from || target == part.to) {
11444
- if (getBidiPartAt(bidi, target) == pos) return target;
11445
- part = bidi[pos += dir];
11446
- return (dir > 0) == part.level % 2 ? part.to : part.from;
11447
- } else {
11448
- part = bidi[pos += dir];
11449
- if (!part) return null;
11450
- if ((dir > 0) == part.level % 2)
11451
- target = moveInLine(line, part.to, -1, byUnit);
11452
- else
11453
- target = moveInLine(line, part.from, 1, byUnit);
11454
  }
11455
  }
11456
  }
11457
 
11458
- function moveLogically(line, start, dir, byUnit) {
11459
- var target = start + dir;
11460
- if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;
11461
- return target < 0 || target > line.text.length ? null : target;
11462
- }
11463
-
11464
- // Bidirectional ordering algorithm
11465
- // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
11466
- // that this (partially) implements.
11467
-
11468
- // One-char codes used for character types:
11469
- // L (L): Left-to-Right
11470
- // R (R): Right-to-Left
11471
- // r (AL): Right-to-Left Arabic
11472
- // 1 (EN): European Number
11473
- // + (ES): European Number Separator
11474
- // % (ET): European Number Terminator
11475
- // n (AN): Arabic Number
11476
- // , (CS): Common Number Separator
11477
- // m (NSM): Non-Spacing Mark
11478
- // b (BN): Boundary Neutral
11479
- // s (B): Paragraph Separator
11480
- // t (S): Segment Separator
11481
- // w (WS): Whitespace
11482
- // N (ON): Other Neutrals
11483
-
11484
- // Returns null if characters are ordered as they appear
11485
- // (left-to-right), or an array of sections ({from, to, level}
11486
- // objects) in the order in which they occur visually.
11487
- var bidiOrdering = (function() {
11488
- // Character types for codepoints 0 to 0xff
11489
- var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
11490
- // Character types for codepoints 0x600 to 0x6ff
11491
- var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm";
11492
- function charType(code) {
11493
- if (code <= 0xf7) return lowTypes.charAt(code);
11494
- else if (0x590 <= code && code <= 0x5f4) return "R";
11495
- else if (0x600 <= code && code <= 0x6ed) r
2515
  function Iter(cm, line, ch, range) {
2516
  this.line = line; this.ch = ch;
2517
  this.cm = cm; this.text = cm.getLine(line);
2518
+ this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine();
2519
+ this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine();
2520
  }
2521
 
2522
  function tagAt(iter, ch) {
2685
  // You can find some technical background for some of the code below
2686
  // at http://marijnhaverbeke.nl/blog/#cm-internals .
2687
 
2688
+ (function (global, factory) {
2689
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
2690
+ typeof define === 'function' && define.amd ? define(factory) :
2691
+ (global.CodeMirror = factory());
2692
+ }(this, (function () { 'use strict';
2693
+
2694
+ // Kludges for bugs and behavior differences that can't be feature
2695
+ // detected are enabled based on userAgent etc sniffing.
2696
+ var userAgent = navigator.userAgent
2697
+ var platform = navigator.platform
2698
+
2699
+ var gecko = /gecko\/\d/i.test(userAgent)
2700
+ var ie_upto10 = /MSIE \d/.test(userAgent)
2701
+ var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent)
2702
+ var ie = ie_upto10 || ie_11up
2703
+ var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1])
2704
+ var webkit = /WebKit\//.test(userAgent)
2705
+ var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent)
2706
+ var chrome = /Chrome\//.test(userAgent)
2707
+ var presto = /Opera\//.test(userAgent)
2708
+ var safari = /Apple Computer/.test(navigator.vendor)
2709
+ var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent)
2710
+ var phantom = /PhantomJS/.test(userAgent)
2711
+
2712
+ var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent)
2713
+ // This is woefully incomplete. Suggestions for alternative methods welcome.
2714
+ var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent)
2715
+ var mac = ios || /Mac/.test(platform)
2716
+ var chromeOS = /\bCrOS\b/.test(userAgent)
2717
+ var windows = /win/i.test(platform)
2718
+
2719
+ var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/)
2720
+ if (presto_version) { presto_version = Number(presto_version[1]) }
2721
+ if (presto_version && presto_version >= 15) { presto = false; webkit = true }
2722
+ // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
2723
+ var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11))
2724
+ var captureRightClick = gecko || (ie && ie_version >= 9)
2725
+
2726
+ function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
2727
+
2728
+ var rmClass = function(node, cls) {
2729
+ var current = node.className
2730
+ var match = classTest(cls).exec(current)
2731
+ if (match) {
2732
+ var after = current.slice(match.index + match[0].length)
2733
+ node.className = current.slice(0, match.index) + (after ? match[1] + after : "")
2734
+ }
2735
+ }
2736
 
2737
+ function removeChildren(e) {
2738
+ for (var count = e.childNodes.length; count > 0; --count)
2739
+ { e.removeChild(e.firstChild) }
2740
+ return e
2741
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2742
 
2743
+ function removeChildrenAndAdd(parent, e) {
2744
+ return removeChildren(parent).appendChild(e)
2745
+ }
2746
 
2747
+ function elt(tag, content, className, style) {
2748
+ var e = document.createElement(tag)
2749
+ if (className) { e.className = className }
2750
+ if (style) { e.style.cssText = style }
2751
+ if (typeof content == "string") { e.appendChild(document.createTextNode(content)) }
2752
+ else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]) } }
2753
+ return e
2754
+ }
2755
 
2756
+ var range
2757
+ if (document.createRange) { range = function(node, start, end, endNode) {
2758
+ var r = document.createRange()
2759
+ r.setEnd(endNode || node, end)
2760
+ r.setStart(node, start)
2761
+ return r
2762
+ } }
2763
+ else { range = function(node, start, end) {
2764
+ var r = document.body.createTextRange()
2765
+ try { r.moveToElementText(node.parentNode) }
2766
+ catch(e) { return r }
2767
+ r.collapse(true)
2768
+ r.moveEnd("character", end)
2769
+ r.moveStart("character", start)
2770
+ return r
2771
+ } }
2772
+
2773
+ function contains(parent, child) {
2774
+ if (child.nodeType == 3) // Android browser always returns false when child is a textnode
2775
+ { child = child.parentNode }
2776
+ if (parent.contains)
2777
+ { return parent.contains(child) }
2778
+ do {
2779
+ if (child.nodeType == 11) { child = child.host }
2780
+ if (child == parent) { return true }
2781
+ } while (child = child.parentNode)
2782
+ }
2783
 
2784
+ var activeElt = function() {
2785
+ var activeElement = document.activeElement
2786
+ while (activeElement && activeElement.root && activeElement.root.activeElement)
2787
+ { activeElement = activeElement.root.activeElement }
2788
+ return activeElement
2789
+ }
2790
+ // Older versions of IE throws unspecified error when touching
2791
+ // document.activeElement in some cases (during loading, in iframe)
2792
+ if (ie && ie_version < 11) { activeElt = function() {
2793
+ try { return document.activeElement }
2794
+ catch(e) { return document.body }
2795
+ } }
2796
+
2797
+ function addClass(node, cls) {
2798
+ var current = node.className
2799
+ if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls }
2800
+ }
2801
+ function joinClasses(a, b) {
2802
+ var as = a.split(" ")
2803
+ for (var i = 0; i < as.length; i++)
2804
+ { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i] } }
2805
+ return b
2806
+ }
2807
 
2808
+ var selectInput = function(node) { node.select() }
2809
+ if (ios) // Mobile Safari apparently has a bug where select() is broken.
2810
+ { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length } }
2811
+ else if (ie) // Suppress mysterious IE10 errors
2812
+ { selectInput = function(node) { try { node.select() } catch(_e) {} } }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2813
 
2814
+ function bind(f) {
2815
+ var args = Array.prototype.slice.call(arguments, 1)
2816
+ return function(){return f.apply(null, args)}
2817
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2818
 
2819
+ function copyObj(obj, target, overwrite) {
2820
+ if (!target) { target = {} }
2821
+ for (var prop in obj)
2822
+ { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
2823
+ { target[prop] = obj[prop] } }
2824
+ return target
2825
+ }
2826
 
2827
+ // Counts the column offset in a string, taking tabs into account.
2828
+ // Used mostly to find indentation.
2829
+ function countColumn(string, end, tabSize, startIndex, startValue) {
2830
+ if (end == null) {
2831
+ end = string.search(/[^\s\u00a0]/)
2832
+ if (end == -1) { end = string.length }
2833
+ }
2834
+ for (var i = startIndex || 0, n = startValue || 0;;) {
2835
+ var nextTab = string.indexOf("\t", i)
2836
+ if (nextTab < 0 || nextTab >= end)
2837
+ { return n + (end - i) }
2838
+ n += nextTab - i
2839
+ n += tabSize - (n % tabSize)
2840
+ i = nextTab + 1
2841
  }
2842
+ }
2843
 
2844
+ function Delayed() {this.id = null}
2845
+ Delayed.prototype.set = function(ms, f) {
2846
+ clearTimeout(this.id)
2847
+ this.id = setTimeout(f, ms)
2848
+ }
2849
 
2850
+ function indexOf(array, elt) {
2851
+ for (var i = 0; i < array.length; ++i)
2852
+ { if (array[i] == elt) { return i } }
2853
+ return -1
2854
+ }
2855
 
2856
+ // Number of pixels added to scroller and sizer to hide scrollbar
2857
+ var scrollerGap = 30
2858
+
2859
+ // Returned or thrown by various protocols to signal 'I'm not
2860
+ // handling this'.
2861
+ var Pass = {toString: function(){return "CodeMirror.Pass"}}
2862
+
2863
+ // Reused option objects for setSelection & friends
2864
+ var sel_dontScroll = {scroll: false};
2865
+ var sel_mouse = {origin: "*mouse"};
2866
+ var sel_move = {origin: "+move"};
2867
+ // The inverse of countColumn -- find the offset that corresponds to
2868
+ // a particular column.
2869
+ function findColumn(string, goal, tabSize) {
2870
+ for (var pos = 0, col = 0;;) {
2871
+ var nextTab = string.indexOf("\t", pos)
2872
+ if (nextTab == -1) { nextTab = string.length }
2873
+ var skipped = nextTab - pos
2874
+ if (nextTab == string.length || col + skipped >= goal)
2875
+ { return pos + Math.min(skipped, goal - col) }
2876
+ col += nextTab - pos
2877
+ col += tabSize - (col % tabSize)
2878
+ pos = nextTab + 1
2879
+ if (col >= goal) { return pos }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2880
  }
2881
+ }
2882
 
2883
+ var spaceStrs = [""]
2884
+ function spaceStr(n) {
2885
+ while (spaceStrs.length <= n)
2886
+ { spaceStrs.push(lst(spaceStrs) + " ") }
2887
+ return spaceStrs[n]
2888
+ }
 
 
 
 
 
2889
 
2890
+ function lst(arr) { return arr[arr.length-1] }
2891
 
2892
+ function map(array, f) {
2893
+ var out = []
2894
+ for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i) }
2895
+ return out
2896
+ }
 
 
 
 
 
 
 
 
 
 
 
 
2897
 
2898
+ function insertSorted(array, value, score) {
2899
+ var pos = 0, priority = score(value)
2900
+ while (pos < array.length && score(array[pos]) <= priority) { pos++ }
2901
+ array.splice(pos, 0, value)
2902
+ }
2903
 
2904
+ function nothing() {}
 
 
 
 
 
2905
 
2906
+ function createObj(base, props) {
2907
+ var inst
2908
+ if (Object.create) {
2909
+ inst = Object.create(base)
2910
+ } else {
2911
+ nothing.prototype = base
2912
+ inst = new nothing()
2913
  }
2914
+ if (props) { copyObj(props, inst) }
2915
+ return inst
2916
+ }
2917
 
2918
+ var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/
2919
+ function isWordCharBasic(ch) {
2920
+ return /\w/.test(ch) || ch > "\x80" &&
2921
+ (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))
2922
+ }
2923
+ function isWordChar(ch, helper) {
2924
+ if (!helper) { return isWordCharBasic(ch) }
2925
+ if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true }
2926
+ return helper.test(ch)
2927
+ }
 
 
 
 
 
 
 
2928
 
2929
+ function isEmpty(obj) {
2930
+ for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }
2931
+ return true
2932
+ }
 
 
 
 
 
 
 
2933
 
2934
+ // Extending unicode characters. A series of a non-extending char +
2935
+ // any number of extending chars is treated as a single unit as far
2936
+ // as editing and measuring is concerned. This is not fully correct,
2937
+ // since some scripts/fonts/browsers also treat other configurations
2938
+ // of code points as a group.
2939
+ var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/
2940
+ function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }
2941
+
2942
+ // The display handles the DOM integration, both for input reading
2943
+ // and content drawing. It holds references to DOM nodes and
2944
+ // display-related state.
2945
+
2946
+ function Display(place, doc, input) {
2947
+ var d = this
2948
+ this.input = input
2949
+
2950
+ // Covers bottom-right square when both scrollbars are present.
2951
+ d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler")
2952
+ d.scrollbarFiller.setAttribute("cm-not-content", "true")
2953
+ // Covers bottom of gutter when coverGutterNextToScrollbar is on
2954
+ // and h scrollbar is present.
2955
+ d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler")
2956
+ d.gutterFiller.setAttribute("cm-not-content", "true")
2957
+ // Will contain the actual code, positioned to cover the viewport.
2958
+ d.lineDiv = elt("div", null, "CodeMirror-code")
2959
+ // Elements are added to these to represent selection and cursors.
2960
+ d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1")
2961
+ d.cursorDiv = elt("div", null, "CodeMirror-cursors")
2962
+ // A visibility: hidden element used to find the size of things.
2963
+ d.measure = elt("div", null, "CodeMirror-measure")
2964
+ // When lines outside of the viewport are measured, they are drawn in this.
2965
+ d.lineMeasure = elt("div", null, "CodeMirror-measure")
2966
+ // Wraps everything that needs to exist inside the vertically-padded coordinate system
2967
+ d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
2968
+ null, "position: relative; outline: none")
2969
+ // Moved around its parent to cover visible view.
2970
+ d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative")
2971
+ // Set to the height of the document, allowing scrolling.
2972
+ d.sizer = elt("div", [d.mover], "CodeMirror-sizer")
2973
+ d.sizerWidth = null
2974
+ // Behavior of elts with overflow: auto and padding is
2975
+ // inconsistent across browsers. This is used to ensure the
2976
+ // scrollable area is big enough.
2977
+ d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;")
2978
+ // Will contain the gutters, if any.
2979
+ d.gutters = elt("div", null, "CodeMirror-gutters")
2980
+ d.lineGutter = null
2981
+ // Actual scrollable element.
2982
+ d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll")
2983
+ d.scroller.setAttribute("tabIndex", "-1")
2984
+ // The element in which the editor lives.
2985
+ d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror")
2986
+
2987
+ // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
2988
+ if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0 }
2989
+ if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true }
2990
+
2991
+ if (place) {
2992
+ if (place.appendChild) { place.appendChild(d.wrapper) }
2993
+ else { place(d.wrapper) }
2994
+ }
2995
+
2996
+ // Current rendered range (may be bigger than the view window).
2997
+ d.viewFrom = d.viewTo = doc.first
2998
+ d.reportedViewFrom = d.reportedViewTo = doc.first
2999
+ // Information about the rendered lines.
3000
+ d.view = []
3001
+ d.renderedView = null
3002
+ // Holds info about a single rendered line when it was rendered
3003
+ // for measurement, while not in view.
3004
+ d.externalMeasured = null
3005
+ // Empty space (in pixels) above the view
3006
+ d.viewOffset = 0
3007
+ d.lastWrapHeight = d.lastWrapWidth = 0
3008
+ d.updateLineNumbers = null
3009
+
3010
+ d.nativeBarWidth = d.barHeight = d.barWidth = 0
3011
+ d.scrollbarsClipped = false
3012
+
3013
+ // Used to only resize the line number gutter when necessary (when
3014
+ // the amount of lines crosses a boundary that makes its width change)
3015
+ d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null
3016
+ // Set to true when a non-horizontal-scrolling line widget is
3017
+ // added. As an optimization, line widget aligning is skipped when
3018
+ // this is false.
3019
+ d.alignWidgets = false
3020
+
3021
+ d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null
3022
+
3023
+ // Tracks the maximum line length so that the horizontal scrollbar
3024
+ // can be kept static when scrolling.
3025
+ d.maxLine = null
3026
+ d.maxLineLength = 0
3027
+ d.maxLineChanged = false
3028
+
3029
+ // Used for measuring wheel scrolling granularity
3030
+ d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null
3031
+
3032
+ // True when shift is held down.
3033
+ d.shift = false
3034
+
3035
+ // Used to track whether anything happened since the context menu
3036
+ // was opened.
3037
+ d.selForContextMenu = null
3038
+
3039
+ d.activeTouch = null
3040
+
3041
+ input.init(d)
3042
+ }
3043
 
3044
+ // Find the line object corresponding to the given line number.
3045
+ function getLine(doc, n) {
3046
+ n -= doc.first
3047
+ if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
3048
+ var chunk = doc
3049
+ while (!chunk.lines) {
3050
+ for (var i = 0;; ++i) {
3051
+ var child = chunk.children[i], sz = child.chunkSize()
3052
+ if (n < sz) { chunk = child; break }
3053
+ n -= sz
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3054
  }
 
3055
  }
3056
+ return chunk.lines[n]
3057
+ }
3058
 
3059
+ // Get the part of a document between two positions, as an array of
3060
+ // strings.
3061
+ function getBetween(doc, start, end) {
3062
+ var out = [], n = start.line
3063
+ doc.iter(start.line, end.line + 1, function (line) {
3064
+ var text = line.text
3065
+ if (n == end.line) { text = text.slice(0, end.ch) }
3066
+ if (n == start.line) { text = text.slice(start.ch) }
3067
+ out.push(text)
3068
+ ++n
3069
+ })
3070
+ return out
3071
+ }
3072
+ // Get the lines between from and to, as array of strings.
3073
+ function getLines(doc, from, to) {
3074
+ var out = []
3075
+ doc.iter(from, to, function (line) { out.push(line.text) }) // iter aborts when callback returns truthy value
3076
+ return out
3077
+ }
3078
 
3079
+ // Update the height of a line, propagating the height change
3080
+ // upwards to parent nodes.
3081
+ function updateLineHeight(line, height) {
3082
+ var diff = height - line.height
3083
+ if (diff) { for (var n = line; n; n = n.parent) { n.height += diff } }
3084
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3085
 
3086
+ // Given a line object, find its line number by walking up through
3087
+ // its parent links.
3088
+ function lineNo(line) {
3089
+ if (line.parent == null) { return null }
3090
+ var cur = line.parent, no = indexOf(cur.lines, line)
3091
+ for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
3092
+ for (var i = 0;; ++i) {
3093
+ if (chunk.children[i] == cur) { break }
3094
+ no += chunk.children[i].chunkSize()
3095
  }
3096
  }
3097
+ return no + cur.first
3098
+ }
3099
 
3100
+ // Find the line at the given vertical position, using the height
3101
+ // information in the document tree.
3102
+ function lineAtHeight(chunk, h) {
3103
+ var n = chunk.first
3104
+ outer: do {
3105
+ for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
3106
+ var child = chunk.children[i$1], ch = child.height
3107
+ if (h < ch) { chunk = child; continue outer }
3108
+ h -= ch
3109
+ n += child.chunkSize()
3110
+ }
3111
+ return n
3112
+ } while (!chunk.lines)
3113
+ var i = 0
3114
+ for (; i < chunk.lines.length; ++i) {
3115
+ var line = chunk.lines[i], lh = line.height
3116
+ if (h < lh) { break }
3117
+ h -= lh
3118
+ }
3119
+ return n + i
3120
+ }
 
3121
 
3122
+ function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
 
 
 
 
 
 
 
 
 
3123
 
3124
+ function lineNumberFor(options, i) {
3125
+ return String(options.lineNumberFormatter(i + options.firstLineNumber))
3126
+ }
3127
 
3128
+ // A Pos instance represents a position within the text.
3129
+ function Pos (line, ch) {
3130
+ if (!(this instanceof Pos)) { return new Pos(line, ch) }
3131
+ this.line = line; this.ch = ch
3132
+ }
3133
 
3134
+ // Compare two positions, return 0 if they are the same, a negative
3135
+ // number when a is less, and a positive number otherwise.
3136
+ function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
3137
+
3138
+ function copyPos(x) {return Pos(x.line, x.ch)}
3139
+ function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
3140
+ function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
3141
+
3142
+ // Most of the external API clips given positions to make sure they
3143
+ // actually exist within the document.
3144
+ function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
3145
+ function clipPos(doc, pos) {
3146
+ if (pos.line < doc.first) { return Pos(doc.first, 0) }
3147
+ var last = doc.first + doc.size - 1
3148
+ if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
3149
+ return clipToLen(pos, getLine(doc, pos.line).text.length)
3150
+ }
3151
+ function clipToLen(pos, linelen) {
3152
+ var ch = pos.ch
3153
+ if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
3154
+ else if (ch < 0) { return Pos(pos.line, 0) }
3155
+ else { return pos }
3156
+ }
3157
+ function clipPosArray(doc, array) {
3158
+ var out = []
3159
+ for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]) }
3160
+ return out
3161
+ }
3162
 
3163
+ // Optimize some code when these features are not used.
3164
+ var sawReadOnlySpans = false;
3165
+ var sawCollapsedSpans = false;
3166
+ function seeReadOnlySpans() {
3167
+ sawReadOnlySpans = true
3168
+ }
 
 
 
 
3169
 
3170
+ function seeCollapsedSpans() {
3171
+ sawCollapsedSpans = true
3172
+ }
 
 
3173
 
3174
+ // TEXTMARKER SPANS
 
 
 
 
3175
 
3176
+ function MarkedSpan(marker, from, to) {
3177
+ this.marker = marker
3178
+ this.from = from; this.to = to
3179
+ }
3180
 
3181
+ // Search an array of spans for a span matching the given marker.
3182
+ function getMarkedSpanFor(spans, marker) {
3183
+ if (spans) { for (var i = 0; i < spans.length; ++i) {
3184
+ var span = spans[i]
3185
+ if (span.marker == marker) { return span }
3186
+ } }
3187
+ }
3188
+ // Remove a span from an array, returning undefined if no spans are
3189
+ // left (we don't store arrays for lines without spans).
3190
+ function removeMarkedSpan(spans, span) {
3191
+ var r
3192
+ for (var i = 0; i < spans.length; ++i)
3193
+ { if (spans[i] != span) { (r || (r = [])).push(spans[i]) } }
3194
+ return r
3195
+ }
3196
+ // Add a span to a line.
3197
+ function addMarkedSpan(line, span) {
3198
+ line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]
3199
+ span.marker.attachLine(line)
3200
+ }
3201
 
3202
+ // Used for the algorithm that adjusts markers for a change in the
3203
+ // document. These functions cut an array of spans at a given
3204
+ // character position, returning an array of remaining chunks (or
3205
+ // undefined if nothing remains).
3206
+ function markedSpansBefore(old, startCh, isInsert) {
3207
+ var nw
3208
+ if (old) { for (var i = 0; i < old.length; ++i) {
3209
+ var span = old[i], marker = span.marker
3210
+ var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh)
3211
+ if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
3212
+ var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh)
3213
+ ;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to))
3214
+ }
3215
+ } }
3216
+ return nw
3217
+ }
3218
+ function markedSpansAfter(old, endCh, isInsert) {
3219
+ var nw
3220
+ if (old) { for (var i = 0; i < old.length; ++i) {
3221
+ var span = old[i], marker = span.marker
3222
+ var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh)
3223
+ if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
3224
+ var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh)
3225
+ ;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
3226
+ span.to == null ? null : span.to - endCh))
3227
+ }
3228
+ } }
3229
+ return nw
3230
+ }
3231
 
3232
+ // Given a change object, compute the new set of marker spans that
3233
+ // cover the line in which the change took place. Removes spans
3234
+ // entirely within the change, reconnects spans belonging to the
3235
+ // same marker that appear on both sides of the change, and cuts off
3236
+ // spans partially within the change. Returns an array of span
3237
+ // arrays with one element for each line in (after) the change.
3238
+ function stretchSpansOverChange(doc, change) {
3239
+ if (change.full) { return null }
3240
+ var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans
3241
+ var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans
3242
+ if (!oldFirst && !oldLast) { return null }
3243
+
3244
+ var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0
3245
+ // Get the spans that 'stick out' on both sides
3246
+ var first = markedSpansBefore(oldFirst, startCh, isInsert)
3247
+ var last = markedSpansAfter(oldLast, endCh, isInsert)
3248
+
3249
+ // Next, merge those two ends
3250
+ var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0)
3251
+ if (first) {
3252
+ // Fix up .to properties of first
3253
+ for (var i = 0; i < first.length; ++i) {
3254
+ var span = first[i]
3255
+ if (span.to == null) {
3256
+ var found = getMarkedSpanFor(last, span.marker)
3257
+ if (!found) { span.to = startCh }
3258
+ else if (sameLine) { span.to = found.to == null ? null : found.to + offset }
3259
+ }
3260
+ }
3261
+ }
3262
+ if (last) {
3263
+ // Fix up .from in last (or move them into first in case of sameLine)
3264
+ for (var i$1 = 0; i$1 < last.length; ++i$1) {
3265
+ var span$1 = last[i$1]
3266
+ if (span$1.to != null) { span$1.to += offset }
3267
+ if (span$1.from == null) {
3268
+ var found$1 = getMarkedSpanFor(first, span$1.marker)
3269
+ if (!found$1) {
3270
+ span$1.from = offset
3271
+ if (sameLine) { (first || (first = [])).push(span$1) }
3272
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3273
  } else {
3274
+ span$1.from += offset
3275
+ if (sameLine) { (first || (first = [])).push(span$1) }
 
 
 
 
 
 
 
 
3276
  }
3277
  }
3278
  }
3279
+ // Make sure we didn't create any zero-length spans
3280
+ if (first) { first = clearEmptySpans(first) }
3281
+ if (last && last != first) { last = clearEmptySpans(last) }
3282
 
3283
+ var newMarkers = [first]
3284
+ if (!sameLine) {
3285
+ // Fill gap with whole-line-spans
3286
+ var gap = change.text.length - 2, gapMarkers
3287
+ if (gap > 0 && first)
3288
+ { for (var i$2 = 0; i$2 < first.length; ++i$2)
3289
+ { if (first[i$2].to == null)
3290
+ { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)) } } }
3291
+ for (var i$3 = 0; i$3 < gap; ++i$3)
3292
+ { newMarkers.push(gapMarkers) }
3293
+ newMarkers.push(last)
3294
  }
3295
+ return newMarkers
3296
+ }
3297
 
3298
+ // Remove spans that are empty and don't have a clearWhenEmpty
3299
+ // option of false.
3300
+ function clearEmptySpans(spans) {
3301
+ for (var i = 0; i < spans.length; ++i) {
3302
+ var span = spans[i]
3303
+ if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
3304
+ { spans.splice(i--, 1) }
 
 
 
 
 
 
 
3305
  }
3306
+ if (!spans.length) { return null }
3307
+ return spans
3308
+ }
3309
 
3310
+ // Used to 'clip' out readOnly ranges when making a change.
3311
+ function removeReadOnlyRanges(doc, from, to) {
3312
+ var markers = null
3313
+ doc.iter(from.line, to.line + 1, function (line) {
3314
+ if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
3315
+ var mark = line.markedSpans[i].marker
3316
+ if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
3317
+ { (markers || (markers = [])).push(mark) }
3318
+ } }
3319
+ })
3320
+ if (!markers) { return null }
3321
+ var parts = [{from: from, to: to}]
3322
+ for (var i = 0; i < markers.length; ++i) {
3323
+ var mk = markers[i], m = mk.find(0)
3324
+ for (var j = 0; j < parts.length; ++j) {
3325
+ var p = parts[j]
3326
+ if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
3327
+ var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to)
3328
+ if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
3329
+ { newParts.push({from: p.from, to: m.from}) }
3330
+ if (dto > 0 || !mk.inclusiveRight && !dto)
3331
+ { newParts.push({from: m.to, to: p.to}) }
3332
+ parts.splice.apply(parts, newParts)
3333
+ j += newParts.length - 1
3334
+ }
3335
+ }
3336
+ return parts
3337
+ }
3338
 
3339
+ // Connect or disconnect spans from a line.
3340
+ function detachMarkedSpans(line) {
3341
+ var spans = line.markedSpans
3342
+ if (!spans) { return }
3343
+ for (var i = 0; i < spans.length; ++i)
3344
+ { spans[i].marker.detachLine(line) }
3345
+ line.markedSpans = null
3346
+ }
3347
+ function attachMarkedSpans(line, spans) {
3348
+ if (!spans) { return }
3349
+ for (var i = 0; i < spans.length; ++i)
3350
+ { spans[i].marker.attachLine(line) }
3351
+ line.markedSpans = spans
3352
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3353
 
3354
+ // Helpers used when computing which overlapping collapsed span
3355
+ // counts as the larger one.
3356
+ function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
3357
+ function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
3358
+
3359
+ // Returns a number indicating which of two overlapping collapsed
3360
+ // spans is larger (and thus includes the other). Falls back to
3361
+ // comparing ids when the spans cover exactly the same range.
3362
+ function compareCollapsedMarkers(a, b) {
3363
+ var lenDiff = a.lines.length - b.lines.length
3364
+ if (lenDiff != 0) { return lenDiff }
3365
+ var aPos = a.find(), bPos = b.find()
3366
+ var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b)
3367
+ if (fromCmp) { return -fromCmp }
3368
+ var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b)
3369
+ if (toCmp) { return toCmp }
3370
+ return b.id - a.id
3371
+ }
3372
 
3373
+ // Find out whether a line ends or starts in a collapsed span. If
3374
+ // so, return the marker for that span.
3375
+ function collapsedSpanAtSide(line, start) {
3376
+ var sps = sawCollapsedSpans && line.markedSpans, found
3377
+ if (sps) { for (var sp = void 0, i = 0; i < sps.length; ++i) {
3378
+ sp = sps[i]
3379
+ if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
3380
+ (!found || compareCollapsedMarkers(found, sp.marker) < 0))
3381
+ { found = sp.marker }
3382
+ } }
3383
+ return found
3384
+ }
3385
+ function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
3386
+ function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
3387
+
3388
+ // Test whether there exists a collapsed span that partially
3389
+ // overlaps (covers the start or end, but not both) of a new span.
3390
+ // Such overlap is not allowed.
3391
+ function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
3392
+ var line = getLine(doc, lineNo)
3393
+ var sps = sawCollapsedSpans && line.markedSpans
3394
+ if (sps) { for (var i = 0; i < sps.length; ++i) {
3395
+ var sp = sps[i]
3396
+ if (!sp.marker.collapsed) { continue }
3397
+ var found = sp.marker.find(0)
3398
+ var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker)
3399
+ var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker)
3400
+ if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
3401
+ if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
3402
+ fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
3403
+ { return true }
3404
+ } }
3405
+ }
3406
 
3407
+ // A visual line is a line as drawn on the screen. Folding, for
3408
+ // example, can cause multiple logical lines to appear on the same
3409
+ // visual line. This finds the start of the visual line that the
3410
+ // given line is part of (usually that is the line itself).
3411
+ function visualLine(line) {
3412
+ var merged
3413
+ while (merged = collapsedSpanAtStart(line))
3414
+ { line = merged.find(-1, true).line }
3415
+ return line
3416
+ }
3417
 
3418
+ // Returns an array of logical lines that continue the visual line
3419
+ // started by the argument, or undefined if there are no such lines.
3420
+ function visualLineContinued(line) {
3421
+ var merged, lines
3422
+ while (merged = collapsedSpanAtEnd(line)) {
3423
+ line = merged.find(1, true).line
3424
+ ;(lines || (lines = [])).push(line)
3425
  }
3426
+ return lines
3427
+ }
3428
 
3429
+ // Get the line number of the start of the visual line that the
3430
+ // given line number is part of.
3431
+ function visualLineNo(doc, lineN) {
3432
+ var line = getLine(doc, lineN), vis = visualLine(line)
3433
+ if (line == vis) { return lineN }
3434
+ return lineNo(vis)
3435
+ }
 
 
 
 
 
 
 
 
3436
 
3437
+ // Get the line number of the start of the next visual line after
3438
+ // the given line.
3439
+ function visualLineEndNo(doc, lineN) {
3440
+ if (lineN > doc.lastLine()) { return lineN }
3441
+ var line = getLine(doc, lineN), merged
3442
+ if (!lineIsHidden(doc, line)) { return lineN }
3443
+ while (merged = collapsedSpanAtEnd(line))
3444
+ { line = merged.find(1, true).line }
3445
+ return lineNo(line) + 1
3446
+ }
3447
+
3448
+ // Compute whether a line is hidden. Lines count as hidden when they
3449
+ // are part of a visual line that starts with another line, or when
3450
+ // they are entirely covered by collapsed, non-widget span.
3451
+ function lineIsHidden(doc, line) {
3452
+ var sps = sawCollapsedSpans && line.markedSpans
3453
+ if (sps) { for (var sp = void 0, i = 0; i < sps.length; ++i) {
3454
+ sp = sps[i]
3455
+ if (!sp.marker.collapsed) { continue }
3456
+ if (sp.from == null) { return true }
3457
+ if (sp.marker.widgetNode) { continue }
3458
+ if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
3459
+ { return true }
3460
+ } }
3461
+ }
3462
+ function lineIsHiddenInner(doc, line, span) {
3463
+ if (span.to == null) {
3464
+ var end = span.marker.find(1, true)
3465
+ return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
3466
+ }
3467
+ if (span.marker.inclusiveRight && span.to == line.text.length)
3468
+ { return true }
3469
+ for (var sp = void 0, i = 0; i < line.markedSpans.length; ++i) {
3470
+ sp = line.markedSpans[i]
3471
+ if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
3472
+ (sp.to == null || sp.to != span.from) &&
3473
+ (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
3474
+ lineIsHiddenInner(doc, line, sp)) { return true }
3475
  }
3476
+ }
3477
 
3478
+ // Find the height above the given line.
3479
+ function heightAtLine(lineObj) {
3480
+ lineObj = visualLine(lineObj)
3481
 
3482
+ var h = 0, chunk = lineObj.parent
3483
+ for (var i = 0; i < chunk.lines.length; ++i) {
3484
+ var line = chunk.lines[i]
3485
+ if (line == lineObj) { break }
3486
+ else { h += line.height }
3487
+ }
3488
+ for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
3489
+ for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
3490
+ var cur = p.children[i$1]
3491
+ if (cur == chunk) { break }
3492
+ else { h += cur.height }
3493
+ }
3494
+ }
3495
+ return h
3496
+ }
3497
 
3498
+ // Compute the character length of a line, taking into account
3499
+ // collapsed ranges (see markText) that might hide parts, and join
3500
+ // other lines onto it.
3501
+ function lineLength(line) {
3502
+ if (line.height == 0) { return 0 }
3503
+ var len = line.text.length, merged, cur = line
3504
+ while (merged = collapsedSpanAtStart(cur)) {
3505
+ var found = merged.find(0, true)
3506
+ cur = found.from.line
3507
+ len += found.from.ch - found.to.ch
3508
+ }
3509
+ cur = line
3510
+ while (merged = collapsedSpanAtEnd(cur)) {
3511
+ var found$1 = merged.find(0, true)
3512
+ len -= cur.text.length - found$1.from.ch
3513
+ cur = found$1.to.line
3514
+ len += cur.text.length - found$1.to.ch
3515
+ }
3516
+ return len
3517
+ }
3518
 
3519
+ // Find the longest line in the document.
3520
+ function findMaxLine(cm) {
3521
+ var d = cm.display, doc = cm.doc
3522
+ d.maxLine = getLine(doc, doc.first)
3523
+ d.maxLineLength = lineLength(d.maxLine)
3524
+ d.maxLineChanged = true
3525
+ doc.iter(function (line) {
3526
+ var len = lineLength(line)
3527
+ if (len > d.maxLineLength) {
3528
+ d.maxLineLength = len
3529
+ d.maxLine = line
3530
+ }
3531
+ })
3532
+ }
3533
 
3534
+ // BIDI HELPERS
3535
 
3536
+ function iterateBidiSections(order, from, to, f) {
3537
+ if (!order) { return f(from, to, "ltr") }
3538
+ var found = false
3539
+ for (var i = 0; i < order.length; ++i) {
3540
+ var part = order[i]
3541
+ if (part.from < to && part.to > from || from == to && part.to == from) {
3542
+ f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr")
3543
+ found = true
3544
+ }
3545
  }
3546
+ if (!found) { f(from, to, "ltr") }
3547
+ }
3548
 
3549
+ function bidiLeft(part) { return part.level % 2 ? part.to : part.from }
3550
+ function bidiRight(part) { return part.level % 2 ? part.from : part.to }
 
 
3551
 
3552
+ function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0 }
3553
+ function lineRight(line) {
3554
+ var order = getOrder(line)
3555
+ if (!order) { return line.text.length }
3556
+ return bidiRight(lst(order))
3557
+ }
3558
 
3559
+ function compareBidiLevel(order, a, b) {
3560
+ var linedir = order[0].level
3561
+ if (a == linedir) { return true }
3562
+ if (b == linedir) { return false }
3563
+ return a < b
3564
+ }
 
 
 
 
 
 
 
 
3565
 
3566
+ var bidiOther = null
3567
+ function getBidiPartAt(order, pos) {
3568
+ var found
3569
+ bidiOther = null
3570
+ for (var i = 0; i < order.length; ++i) {
3571
+ var cur = order[i]
3572
+ if (cur.from < pos && cur.to > pos) { return i }
3573
+ if ((cur.from == pos || cur.to == pos)) {
3574
+ if (found == null) {
3575
+ found = i
3576
+ } else if (compareBidiLevel(order, cur.level, order[found].level)) {
3577
+ if (cur.from != cur.to) { bidiOther = found }
3578
+ return i
3579
+ } else {
3580
+ if (cur.from != cur.to) { bidiOther = i }
3581
+ return found
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3582
  }
 
3583
  }
3584
  }
3585
+ return found
3586
+ }
3587
 
3588
+ function moveInLine(line, pos, dir, byUnit) {
3589
+ if (!byUnit) { return pos + dir }
3590
+ do { pos += dir }
3591
+ while (pos > 0 && isExtendingChar(line.text.charAt(pos)))
3592
+ return pos
3593
+ }
 
 
 
 
3594
 
3595
+ // This is needed in order to move 'visually' through bi-directional
3596
+ // text -- i.e., pressing left should make the cursor go left, even
3597
+ // when in RTL text. The tricky part is the 'jumps', where RTL and
3598
+ // LTR text touch each other. This often requires the cursor offset
3599
+ // to move more than one unit, in order to visually move one unit.
3600
+ function moveVisually(line, start, dir, byUnit) {
3601
+ var bidi = getOrder(line)
3602
+ if (!bidi) { return moveLogically(line, start, dir, byUnit) }
3603
+ var pos = getBidiPartAt(bidi, start), part = bidi[pos]
3604
+ var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit)
3605
+
3606
+ for (;;) {
3607
+ if (target > part.from && target < part.to) { return target }
3608
+ if (target == part.from || target == part.to) {
3609
+ if (getBidiPartAt(bidi, target) == pos) { return target }
3610
+ part = bidi[pos += dir]
3611
+ return (dir > 0) == part.level % 2 ? part.to : part.from
3612
+ } else {
3613
+ part = bidi[pos += dir]
3614
+ if (!part) { return null }
3615
+ if ((dir > 0) == part.level % 2)
3616
+ { target = moveInLine(line, part.to, -1, byUnit) }
3617
+ else
3618
+ { target = moveInLine(line, part.from, 1, byUnit) }
3619
+ }
3620
  }
3621
+ }
3622
 
3623
+ function moveLogically(line, start, dir, byUnit) {
3624
+ var target = start + dir
3625
+ if (byUnit) { while (target > 0 && isExtendingChar(line.text.charAt(target))) { target += dir } }
3626
+ return target < 0 || target > line.text.length ? null : target
3627
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3628
 
3629
+ // Bidirectional ordering algorithm
3630
+ // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
3631
+ // that this (partially) implements.
3632
+
3633
+ // One-char codes used for character types:
3634
+ // L (L): Left-to-Right
3635
+ // R (R): Right-to-Left
3636
+ // r (AL): Right-to-Left Arabic
3637
+ // 1 (EN): European Number
3638
+ // + (ES): European Number Separator
3639
+ // % (ET): European Number Terminator
3640
+ // n (AN): Arabic Number
3641
+ // , (CS): Common Number Separator
3642
+ // m (NSM): Non-Spacing Mark
3643
+ // b (BN): Boundary Neutral
3644
+ // s (B): Paragraph Separator
3645
+ // t (S): Segment Separator
3646
+ // w (WS): Whitespace
3647
+ // N (ON): Other Neutrals
3648
+
3649
+ // Returns null if characters are ordered as they appear
3650
+ // (left-to-right), or an array of sections ({from, to, level}
3651
+ // objects) in the order in which they occur visually.
3652
+ var bidiOrdering = (function() {
3653
+ // Character types for codepoints 0 to 0xff
3654
+ var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"
3655
+ // Character types for codepoints 0x600 to 0x6ff
3656
+ var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm"
3657
+ function charType(code) {
3658
+ if (code <= 0xf7) { return lowTypes.charAt(code) }
3659
+ else if (0x590 <= code && code <= 0x5f4) { return "R" }
3660
+ else if (0x600 <= code && code <= 0x6ed) { return arabicTypes.charAt(code - 0x600) }
3661
+ else if (0x6ee <= code && code <= 0x8ac) { return "r" }
3662
+ else if (0x2000 <= code && code <= 0x200b) { return "w" }
3663
+ else if (code == 0x200c) { return "b" }
3664
+ else { return "L" }
3665
+ }
3666
+
3667
+ var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/
3668
+ var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/
3669
+ // Browsers seem to always treat the boundaries of block elements as being L.
3670
+ var outerType = "L"
3671
+
3672
+ function BidiSpan(level, from, to) {
3673
+ this.level = level
3674
+ this.from = from; this.to = to
3675
+ }
3676
+
3677
+ return function(str) {
3678
+ if (!bidiRE.test(str)) { return false }
3679
+ var len = str.length, types = []
3680
+ for (var i = 0; i < len; ++i)
3681
+ { types.push(charType(str.charCodeAt(i))) }
3682
+
3683
+ // W1. Examine each non-spacing mark (NSM) in the level run, and
3684
+ // change the type of the NSM to the type of the previous
3685
+ // character. If the NSM is at the start of the level run, it will
3686
+ // get the type of sor.
3687
+ for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
3688
+ var type = types[i$1]
3689
+ if (type == "m") { types[i$1] = prev }
3690
+ else { prev = type }
3691
+ }
3692
+
3693
+ // W2. Search backwards from each instance of a European number
3694
+ // until the first strong type (R, L, AL, or sor) is found. If an
3695
+ // AL is found, change the type of the European number to Arabic
3696
+ // number.
3697
+ // W3. Change all ALs to R.
3698
+ for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
3699
+ var type$1 = types[i$2]
3700
+ if (type$1 == "1" && cur == "r") { types[i$2] = "n" }
3701
+ else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R" } }
3702
+ }
3703
+
3704
+ // W4. A single European separator between two European numbers
3705
+ // changes to a European number. A single common separator between
3706
+ // two numbers of the same type changes to that type.
3707
+ for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
3708
+ var type$2 = types[i$3]
3709
+ if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1" }
3710
+ else if (type$2 == "," && prev$1 == types[i$3+1] &&
3711
+ (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1 }
3712
+ prev$1 = type$2
3713
+ }
3714
+
3715
+ // W5. A sequence of European terminators adjacent to European
3716
+ // numbers changes to all European numbers.
3717
+ // W6. Otherwise, separators and terminators change to Other
3718
+ // Neutral.
3719
+ for (var i$4 = 0; i$4 < len; ++i$4) {
3720
+ var type$3 = types[i$4]
3721
+ if (type$3 == ",") { types[i$4] = "N" }
3722
+ else if (type$3 == "%") {
3723
+ var end = void 0
3724
+ for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
3725
+ var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"
3726
+ for (var j = i$4; j < end; ++j) { types[j] = replace }
3727
+ i$4 = end - 1
3728
+ }
3729
+ }
3730
+
3731
+ // W7. Search backwards from each instance of a European number
3732
+ // until the first strong type (R, L, or sor) is found. If an L is
3733
+ // found, then change the type of the European number to L.
3734
+ for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
3735
+ var type$4 = types[i$5]
3736
+ if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L" }
3737
+ else if (isStrong.test(type$4)) { cur$1 = type$4 }
3738
+ }
3739
+
3740
+ // N1. A sequence of neutrals takes the direction of the
3741
+ // surrounding strong text if the text on both sides has the same
3742
+ // direction. European and Arabic numbers act as if they were R in
3743
+ // terms of their influence on neutrals. Start-of-level-run (sor)
3744
+ // and end-of-level-run (eor) are used at level run boundaries.
3745
+ // N2. Any remaining neutrals take the embedding direction.
3746
+ for (var i$6 = 0; i$6 < len; ++i$6) {
3747
+ if (isNeutral.test(types[i$6])) {
3748
+ var end$1 = void 0
3749
+ for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
3750
+ var before = (i$6 ? types[i$6-1] : outerType) == "L"
3751
+ var after = (end$1 < len ? types[end$1] : outerType) == "L"
3752
+ var replace$1 = before || after ? "L" : "R"
3753
+ for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1 }
3754
+ i$6 = end$1 - 1
3755
+ }
3756
+ }
3757
+
3758
+ // Here we depart from the documented algorithm, in order to avoid
3759
+ // building up an actual levels array. Since there are only three
3760
+ // levels (0, 1, 2) in an implementation that doesn't take
3761
+ // explicit embedding into account, we can build up the order on
3762
+ // the fly, without following the level-based algorithm.
3763
+ var order = [], m
3764
+ for (var i$7 = 0; i$7 < len;) {
3765
+ if (countsAsLeft.test(types[i$7])) {
3766
+ var start = i$7
3767
+ for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
3768
+ order.push(new BidiSpan(0, start, i$7))
3769
+ } else {
3770
+ var pos = i$7, at = order.length
3771
+ for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
3772
+ for (var j$2 = pos; j$2 < i$7;) {
3773
+ if (countsAsNum.test(types[j$2])) {
3774
+ if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)) }
3775
+ var nstart = j$2
3776
+ for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
3777
+ order.splice(at, 0, new BidiSpan(2, nstart, j$2))
3778
+ pos = j$2
3779
+ } else { ++j$2 }
3780
  }
3781
+ if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)) }
3782
  }
3783
+ }
3784
+ if (order[0].level == 1 && (m = str.match(/^\s+/))) {
3785
+ order[0].from = m[0].length
3786
+ order.unshift(new BidiSpan(0, 0, m[0].length))
3787
+ }
3788
+ if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
3789
+ lst(order).to -= m[0].length
3790
+ order.push(new BidiSpan(0, len - m[0].length, len))
3791
+ }
3792
+ if (order[0].level == 2)
3793
+ { order.unshift(new BidiSpan(1, order[0].to, order[0].to)) }
3794
+ if (order[0].level != lst(order).level)
3795
+ { order.push(new BidiSpan(order[0].level, len, len)) }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3796
 
3797
+ return order
3798
+ }
3799
+ })()
 
 
 
 
 
 
 
 
 
 
 
3800
 
3801
+ // Get the bidi ordering for the given line (and cache it). Returns
3802
+ // false for lines that are fully left-to-right, and an array of
3803
+ // BidiSpan objects otherwise.
3804
+ function getOrder(line) {
3805
+ var order = line.order
3806
+ if (order == null) { order = line.order = bidiOrdering(line.text) }
3807
+ return order
3808
+ }
3809
 
3810
+ // EVENT HANDLING
 
 
 
 
 
 
 
 
3811
 
3812
+ // Lightweight event framework. on/off also work on DOM nodes,
3813
+ // registering native DOM handlers.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3814
 
3815
+ var on = function(emitter, type, f) {
3816
+ if (emitter.addEventListener)
3817
+ { emitter.addEventListener(type, f, false) }
3818
+ else if (emitter.attachEvent)
3819
+ { emitter.attachEvent("on" + type, f) }
3820
+ else {
3821
+ var map = emitter._handlers || (emitter._handlers = {})
3822
+ var arr = map[type] || (map[type] = [])
3823
+ arr.push(f)
3824
+ }
3825
+ }
3826
 
3827
+ var noHandlers = []
3828
+ function getHandlers(emitter, type, copy) {
3829
+ var arr = emitter._handlers && emitter._handlers[type]
3830
+ if (copy) { return arr && arr.length > 0 ? arr.slice() : noHandlers }
3831
+ else { return arr || noHandlers }
3832
+ }
3833
 
3834
+ function off(emitter, type, f) {
3835
+ if (emitter.removeEventListener)
3836
+ { emitter.removeEventListener(type, f, false) }
3837
+ else if (emitter.detachEvent)
3838
+ { emitter.detachEvent("on" + type, f) }
3839
+ else {
3840
+ var handlers = getHandlers(emitter, type, false)
3841
+ for (var i = 0; i < handlers.length; ++i)
3842
+ { if (handlers[i] == f) { handlers.splice(i, 1); break } }
3843
+ }
3844
+ }
3845
 
3846
+ function signal(emitter, type /*, values...*/) {
3847
+ var handlers = getHandlers(emitter, type, true)
3848
+ if (!handlers.length) { return }
3849
+ var args = Array.prototype.slice.call(arguments, 2)
3850
+ for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args) }
3851
+ }
3852
 
3853
+ // The DOM events that CodeMirror handles can be overridden by
3854
+ // registering a (non-DOM) handler on the editor for the event name,
3855
+ // and preventDefault-ing the event in that handler.
3856
+ function signalDOMEvent(cm, e, override) {
3857
+ if (typeof e == "string")
3858
+ { e = {type: e, preventDefault: function() { this.defaultPrevented = true }} }
3859
+ signal(cm, override || e.type, cm, e)
3860
+ return e_defaultPrevented(e) || e.codemirrorIgnore
3861
+ }
3862
 
3863
+ function signalCursorActivity(cm) {
3864
+ var arr = cm._handlers && cm._handlers.cursorActivity
3865
+ if (!arr) { return }
3866
+ var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = [])
3867
+ for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
3868
+ { set.push(arr[i]) } }
3869
+ }
 
 
 
 
 
3870
 
3871
+ function hasHandler(emitter, type) {
3872
+ return getHandlers(emitter, type).length > 0
3873
+ }
 
 
 
 
 
 
 
 
 
 
3874
 
3875
+ // Add on and off methods to a constructor's prototype, to make
3876
+ // registering events on such objects more convenient.
3877
+ function eventMixin(ctor) {
3878
+ ctor.prototype.on = function(type, f) {on(this, type, f)}
3879
+ ctor.prototype.off = function(type, f) {off(this, type, f)}
3880
+ }
 
 
 
 
 
 
 
 
 
 
3881
 
3882
+ // Due to the fact that we still support jurassic IE versions, some
3883
+ // compatibility wrappers are needed.
 
 
 
 
 
 
 
 
 
3884
 
3885
+ function e_preventDefault(e) {
3886
+ if (e.preventDefault) { e.preventDefault() }
3887
+ else { e.returnValue = false }
3888
+ }
3889
+ function e_stopPropagation(e) {
3890
+ if (e.stopPropagation) { e.stopPropagation() }
3891
+ else { e.cancelBubble = true }
3892
+ }
3893
+ function e_defaultPrevented(e) {
3894
+ return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
3895
+ }
3896
+ function e_stop(e) {e_preventDefault(e); e_stopPropagation(e)}
3897
+
3898
+ function e_target(e) {return e.target || e.srcElement}
3899
+ function e_button(e) {
3900
+ var b = e.which
3901
+ if (b == null) {
3902
+ if (e.button & 1) { b = 1 }
3903
+ else if (e.button & 2) { b = 3 }
3904
+ else if (e.button & 4) { b = 2 }
3905
+ }
3906
+ if (mac && e.ctrlKey && b == 1) { b = 3 }
3907
+ return b
3908
+ }
 
 
3909
 
3910
+ // Detect drag-and-drop
3911
+ var dragAndDrop = function() {
3912
+ // There is *some* kind of drag-and-drop support in IE6-8, but I
3913
+ // couldn't get it to work yet.
3914
+ if (ie && ie_version < 9) { return false }
3915
+ var div = elt('div')
3916
+ return "draggable" in div || "dragDrop" in div
3917
+ }()
3918
+
3919
+ var zwspSupported
3920
+ function zeroWidthElement(measure) {
3921
+ if (zwspSupported == null) {
3922
+ var test = elt("span", "\u200b")
3923
+ removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]))
3924
+ if (measure.firstChild.offsetHeight != 0)
3925
+ { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8) }
3926
+ }
3927
+ var node = zwspSupported ? elt("span", "\u200b") :
3928
+ elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px")
3929
+ node.setAttribute("cm-text", "")
3930
+ return node
3931
+ }
3932
 
3933
+ // Feature-detect IE's crummy client rect reporting for bidi text
3934
+ var badBidiRects
3935
+ function hasBadBidiRects(measure) {
3936
+ if (badBidiRects != null) { return badBidiRects }
3937
+ var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"))
3938
+ var r0 = range(txt, 0, 1).getBoundingClientRect()
3939
+ var r1 = range(txt, 1, 2).getBoundingClientRect()
3940
+ removeChildren(measure)
3941
+ if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)
3942
+ return badBidiRects = (r1.right - r0.right < 3)
3943
+ }
3944
 
3945
+ // See if "".split is the broken IE version, if so, provide an
3946
+ // alternative way to split lines.
3947
+ var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) {
3948
+ var pos = 0, result = [], l = string.length
3949
+ while (pos <= l) {
3950
+ var nl = string.indexOf("\n", pos)
3951
+ if (nl == -1) { nl = string.length }
3952
+ var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl)
3953
+ var rt = line.indexOf("\r")
3954
+ if (rt != -1) {
3955
+ result.push(line.slice(0, rt))
3956
+ pos += rt + 1
3957
+ } else {
3958
+ result.push(line)
3959
+ pos = nl + 1
3960
+ }
3961
+ }
3962
+ return result
3963
+ } : function (string) { return string.split(/\r\n?|\n/); }
3964
+
3965
+ var hasSelection = window.getSelection ? function (te) {
3966
+ try { return te.selectionStart != te.selectionEnd }
3967
+ catch(e) { return false }
3968
+ } : function (te) {
3969
+ var range
3970
+ try {range = te.ownerDocument.selection.createRange()}
3971
+ catch(e) {}
3972
+ if (!range || range.parentElement() != te) { return false }
3973
+ return range.compareEndPoints("StartToEnd", range) != 0
3974
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3975
 
3976
+ var hasCopyEvent = (function () {
3977
+ var e = elt("div")
3978
+ if ("oncopy" in e) { return true }
3979
+ e.setAttribute("oncopy", "return;")
3980
+ return typeof e.oncopy == "function"
3981
+ })()
3982
+
3983
+ var badZoomedRects = null
3984
+ function hasBadZoomedRects(measure) {
3985
+ if (badZoomedRects != null) { return badZoomedRects }
3986
+ var node = removeChildrenAndAdd(measure, elt("span", "x"))
3987
+ var normal = node.getBoundingClientRect()
3988
+ var fromRange = range(node, 0, 1).getBoundingClientRect()
3989
+ return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
3990
+ }
3991
 
3992
+ var modes = {};
3993
+ var mimeModes = {};
3994
+ // Extra arguments are stored as the mode's dependencies, which is
3995
+ // used by (legacy) mechanisms like loadmode.js to automatically
3996
+ // load a mode. (Preferred mechanism is the require/define calls.)
3997
+ function defineMode(name, mode) {
3998
+ if (arguments.length > 2)
3999
+ { mode.dependencies = Array.prototype.slice.call(arguments, 2) }
4000
+ modes[name] = mode
4001
+ }
4002
+
4003
+ function defineMIME(mime, spec) {
4004
+ mimeModes[mime] = spec
4005
+ }
4006
 
4007
+ // Given a MIME type, a {name, ...options} config object, or a name
4008
+ // string, return a mode config object.
4009
+ function resolveMode(spec) {
4010
+ if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
4011
+ spec = mimeModes[spec]
4012
+ } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
4013
+ var found = mimeModes[spec.name]
4014
+ if (typeof found == "string") { found = {name: found} }
4015
+ spec = createObj(found, spec)
4016
+ spec.name = found.name
4017
+ } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
4018
+ return resolveMode("application/xml")
4019
+ } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
4020
+ return resolveMode("application/json")
4021
+ }
4022
+ if (typeof spec == "string") { return {name: spec} }
4023
+ else { return spec || {name: "null"} }
4024
+ }
4025
 
4026
+ // Given a mode spec (anything that resolveMode accepts), find and
4027
+ // initialize an actual mode object.
4028
+ function getMode(options, spec) {
4029
+ spec = resolveMode(spec)
4030
+ var mfactory = modes[spec.name]
4031
+ if (!mfactory) { return getMode(options, "text/plain") }
4032
+ var modeObj = mfactory(options, spec)
4033
+ if (modeExtensions.hasOwnProperty(spec.name)) {
4034
+ var exts = modeExtensions[spec.name]
4035
+ for (var prop in exts) {
4036
+ if (!exts.hasOwnProperty(prop)) { continue }
4037
+ if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop] }
4038
+ modeObj[prop] = exts[prop]
4039
+ }
4040
+ }
4041
+ modeObj.name = spec.name
4042
+ if (spec.helperType) { modeObj.helperType = spec.helperType }
4043
+ if (spec.modeProps) { for (var prop$1 in spec.modeProps)
4044
+ { modeObj[prop$1] = spec.modeProps[prop$1] } }
4045
+
4046
+ return modeObj
4047
+ }
4048
 
4049
+ // This can be used to attach properties to mode objects from
4050
+ // outside the actual mode definition.
4051
+ var modeExtensions = {}
4052
+ function extendMode(mode, properties) {
4053
+ var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {})
4054
+ copyObj(properties, exts)
4055
+ }
4056
 
4057
+ function copyState(mode, state) {
4058
+ if (state === true) { return state }
4059
+ if (mode.copyState) { return mode.copyState(state) }
4060
+ var nstate = {}
4061
+ for (var n in state) {
4062
+ var val = state[n]
4063
+ if (val instanceof Array) { val = val.concat([]) }
4064
+ nstate[n] = val
4065
  }
4066
+ return nstate
4067
+ }
4068
 
4069
+ // Given a mode and a state (for that mode), find the inner mode and
4070
+ // state at the position that the state refers to.
4071
+ function innerMode(mode, state) {
4072
+ var info
4073
+ while (mode.innerMode) {
4074
+ info = mode.innerMode(state)
4075
+ if (!info || info.mode == mode) { break }
4076
+ state = info.state
4077
+ mode = info.mode
4078
+ }
4079
+ return info || {mode: mode, state: state}
4080
+ }
 
4081
 
4082
+ function startState(mode, a1, a2) {
4083
+ return mode.startState ? mode.startState(a1, a2) : true
4084
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4085
 
4086
+ // STRING STREAM
 
 
 
 
4087
 
4088
+ // Fed to the mode parsers, provides helper functions to make
4089
+ // parsers more succinct.
 
 
 
4090
 
4091
+ var StringStream = function(string, tabSize) {
4092
+ this.pos = this.start = 0
4093
+ this.string = string
4094
+ this.tabSize = tabSize || 8
4095
+ this.lastColumnPos = this.lastColumnValue = 0
4096
+ this.lineStart = 0
4097
+ }
 
4098
 
4099
+ StringStream.prototype = {
4100
+ eol: function() {return this.pos >= this.string.length},
4101
+ sol: function() {return this.pos == this.lineStart},
4102
+ peek: function() {return this.string.charAt(this.pos) || undefined},
4103
+ next: function() {
4104
+ if (this.pos < this.string.length)
4105
+ { return this.string.charAt(this.pos++) }
4106
+ },
4107
+ eat: function(match) {
4108
+ var ch = this.string.charAt(this.pos)
4109
+ var ok
4110
+ if (typeof match == "string") { ok = ch == match }
4111
+ else { ok = ch && (match.test ? match.test(ch) : match(ch)) }
4112
+ if (ok) {++this.pos; return ch}
4113
+ },
4114
+ eatWhile: function(match) {
4115
+ var start = this.pos
4116
+ while (this.eat(match)){}
4117
+ return this.pos > start
4118
+ },
4119
+ eatSpace: function() {
4120
+ var this$1 = this;
4121
 
4122
+ var start = this.pos
4123
+ while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos }
4124
+ return this.pos > start
4125
+ },
4126
+ skipToEnd: function() {this.pos = this.string.length},
4127
+ skipTo: function(ch) {
4128
+ var found = this.string.indexOf(ch, this.pos)
4129
+ if (found > -1) {this.pos = found; return true}
4130
+ },
4131
+ backUp: function(n) {this.pos -= n},
4132
+ column: function() {
4133
+ if (this.lastColumnPos < this.start) {
4134
+ this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue)
4135
+ this.lastColumnPos = this.start
4136
+ }
4137
+ return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
4138
+ },
4139
+ indentation: function() {
4140
+ return countColumn(this.string, null, this.tabSize) -
4141
+ (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
4142
+ },
4143
+ match: function(pattern, consume, caseInsensitive) {
4144
+ if (typeof pattern == "string") {
4145
+ var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; }
4146
+ var substr = this.string.substr(this.pos, pattern.length)
4147
+ if (cased(substr) == cased(pattern)) {
4148
+ if (consume !== false) { this.pos += pattern.length }
4149
+ return true
4150
+ }
4151
+ } else {
4152
+ var match = this.string.slice(this.pos).match(pattern)
4153
+ if (match && match.index > 0) { return null }
4154
+ if (match && consume !== false) { this.pos += match[0].length }
4155
+ return match
4156
+ }
4157
+ },
4158
+ current: function(){return this.string.slice(this.start, this.pos)},
4159
+ hideFirstChars: function(n, inner) {
4160
+ this.lineStart += n
4161
+ try { return inner() }
4162
+ finally { this.lineStart -= n }
4163
+ }
4164
+ }
4165
+
4166
+ // Compute a style array (an array starting with a mode generation
4167
+ // -- for invalidation -- followed by pairs of end positions and
4168
+ // style strings), which is used to highlight the tokens on the
4169
+ // line.
4170
+ function highlightLine(cm, line, state, forceToEnd) {
4171
+ // A styles array always starts with a number identifying the
4172
+ // mode/overlays that it is based on (for easy invalidation).
4173
+ var st = [cm.state.modeGen], lineClasses = {}
4174
+ // Compute the base array of styles
4175
+ runMode(cm, line.text, cm.doc.mode, state, function (end, style) { return st.push(end, style); },
4176
+ lineClasses, forceToEnd)
4177
+
4178
+ // Run overlays, adjust style array.
4179
+ var loop = function ( o ) {
4180
+ var overlay = cm.state.overlays[o], i = 1, at = 0
4181
+ runMode(cm, line.text, overlay.mode, true, function (end, style) {
4182
+ var start = i
4183
+ // Ensure there's a token end at the current position, and that i points at it
4184
+ while (at < end) {
4185
+ var i_end = st[i]
4186
+ if (i_end > end)
4187
+ { st.splice(i, 1, end, st[i+1], i_end) }
4188
+ i += 2
4189
+ at = Math.min(end, i_end)
4190
+ }
4191
+ if (!style) { return }
4192
+ if (overlay.opaque) {
4193
+ st.splice(start, i - start, end, "overlay " + style)
4194
+ i = start + 2
4195
+ } else {
4196
+ for (; start < i; start += 2) {
4197
+ var cur = st[start+1]
4198
+ st[start+1] = (cur ? cur + " " : "") + "overlay " + style
4199
  }
 
 
4200
  }
4201
+ }, lineClasses)
4202
+ };
4203
 
4204
+ for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );
 
 
 
 
 
 
 
 
4205
 
4206
+ return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
4207
+ }
 
 
4208
 
4209
+ function getLineStyles(cm, line, updateFrontier) {
4210
+ if (!line.styles || line.styles[0] != cm.state.modeGen) {
4211
+ var state = getStateBefore(cm, lineNo(line))
4212
+ var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state)
4213
+ line.stateAfter = state
4214
+ line.styles = result.styles
4215
+ if (result.classes) { line.styleClasses = result.classes }
4216
+ else if (line.styleClasses) { line.styleClasses = null }
4217
+ if (updateFrontier === cm.doc.frontier) { cm.doc.frontier++ }
4218
+ }
4219
+ return line.styles
4220
+ }
4221
 
4222
+ function getStateBefore(cm, n, precise) {
4223
+ var doc = cm.doc, display = cm.display
4224
+ if (!doc.mode.startState) { return true }
4225
+ var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter
4226
+ if (!state) { state = startState(doc.mode) }
4227
+ else { state = copyState(doc.mode, state) }
4228
+ doc.iter(pos, n, function (line) {
4229
+ processLine(cm, line.text, state)
4230
+ var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo
4231
+ line.stateAfter = save ? copyState(doc.mode, state) : null
4232
+ ++pos
4233
+ })
4234
+ if (precise) { doc.frontier = pos }
4235
+ return state
4236
+ }
4237
 
4238
+ // Lightweight form of highlight -- proceed over this line and
4239
+ // update state, but don't save a style array. Used for lines that
4240
+ // aren't currently visible.
4241
+ function processLine(cm, text, state, startAt) {
4242
+ var mode = cm.doc.mode
4243
+ var stream = new StringStream(text, cm.options.tabSize)
4244
+ stream.start = stream.pos = startAt || 0
4245
+ if (text == "") { callBlankLine(mode, state) }
4246
+ while (!stream.eol()) {
4247
+ readToken(mode, stream, state)
4248
+ stream.start = stream.pos
4249
+ }
4250
+ }
4251
 
4252
+ function callBlankLine(mode, state) {
4253
+ if (mode.blankLine) { return mode.blankLine(state) }
4254
+ if (!mode.innerMode) { return }
4255
+ var inner = innerMode(mode, state)
4256
+ if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
4257
+ }
4258
 
4259
+ function readToken(mode, stream, state, inner) {
4260
+ for (var i = 0; i < 10; i++) {
4261
+ if (inner) { inner[0] = innerMode(mode, state).mode }
4262
+ var style = mode.token(stream, state)
4263
+ if (stream.pos > stream.start) { return style }
4264
+ }
4265
+ throw new Error("Mode " + mode.name + " failed to advance stream.")
4266
+ }
4267
 
4268
+ // Utility for getTokenAt and getLineTokens
4269
+ function takeToken(cm, pos, precise, asArray) {
4270
+ var getObj = function (copy) { return ({
4271
+ start: stream.start, end: stream.pos,
4272
+ string: stream.current(),
4273
+ type: style || null,
4274
+ state: copy ? copyState(doc.mode, state) : state
4275
+ }); }
4276
+
4277
+ var doc = cm.doc, mode = doc.mode, style
4278
+ pos = clipPos(doc, pos)
4279
+ var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise)
4280
+ var stream = new StringStream(line.text, cm.options.tabSize), tokens
4281
+ if (asArray) { tokens = [] }
4282
+ while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
4283
+ stream.start = stream.pos
4284
+ style = readToken(mode, stream, state)
4285
+ if (asArray) { tokens.push(getObj(true)) }
4286
+ }
4287
+ return asArray ? tokens : getObj()
4288
+ }
4289
 
4290
+ function extractLineClasses(type, output) {
4291
+ if (type) { for (;;) {
4292
+ var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/)
4293
+ if (!lineClass) { break }
4294
+ type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length)
4295
+ var prop = lineClass[1] ? "bgClass" : "textClass"
4296
+ if (output[prop] == null)
4297
+ { output[prop] = lineClass[2] }
4298
+ else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
4299
+ { output[prop] += " " + lineClass[2] }
4300
+ } }
4301
+ return type
4302
+ }
4303
 
4304
+ // Run the given mode's parser over a line, calling f for each token.
4305
+ function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
4306
+ var flattenSpans = mode.flattenSpans
4307
+ if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans }
4308
+ var curStart = 0, curStyle = null
4309
+ var stream = new StringStream(text, cm.options.tabSize), style
4310
+ var inner = cm.options.addModeClass && [null]
4311
+ if (text == "") { extractLineClasses(callBlankLine(mode, state), lineClasses) }
4312
+ while (!stream.eol()) {
4313
+ if (stream.pos > cm.options.maxHighlightLength) {
4314
+ flattenSpans = false
4315
+ if (forceToEnd) { processLine(cm, text, state, stream.pos) }
4316
+ stream.pos = text.length
4317
+ style = null
4318
+ } else {
4319
+ style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses)
4320
+ }
4321
+ if (inner) {
4322
+ var mName = inner[0].name
4323
+ if (mName) { style = "m-" + (style ? mName + " " + style : mName) }
4324
+ }
4325
+ if (!flattenSpans || curStyle != style) {
4326
+ while (curStart < stream.start) {
4327
+ curStart = Math.min(stream.start, curStart + 5000)
4328
+ f(curStart, curStyle)
4329
  }
4330
+ curStyle = style
4331
+ }
4332
+ stream.start = stream.pos
4333
+ }
4334
+ while (curStart < stream.pos) {
4335
+ // Webkit seems to refuse to render text nodes longer than 57444
4336
+ // characters, and returns inaccurate measurements in nodes
4337
+ // starting around 5000 chars.
4338
+ var pos = Math.min(stream.pos, curStart + 5000)
4339
+ f(pos, curStyle)
4340
+ curStart = pos
4341
+ }
4342
+ }
4343
 
4344
+ // Finds the line to start with when starting a parse. Tries to
4345
+ // find a line with a stateAfter, so that it can start with a
4346
+ // valid state. If that fails, it returns the line with the
4347
+ // smallest indentation, which tends to need the least context to
4348
+ // parse correctly.
4349
+ function findStartLine(cm, n, precise) {
4350
+ var minindent, minline, doc = cm.doc
4351
+ var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100)
4352
+ for (var search = n; search > lim; --search) {
4353
+ if (search <= doc.first) { return doc.first }
4354
+ var line = getLine(doc, search - 1)
4355
+ if (line.stateAfter && (!precise || search <= doc.frontier)) { return search }
4356
+ var indented = countColumn(line.text, null, cm.options.tabSize)
4357
+ if (minline == null || minindent > indented) {
4358
+ minline = search - 1
4359
+ minindent = indented
4360
+ }
4361
+ }
4362
+ return minline
4363
+ }
4364
 
4365
+ // LINE DATA STRUCTURE
 
 
 
 
 
 
4366
 
4367
+ // Line objects. These hold state related to a line, including
4368
+ // highlighting info (the styles array).
4369
+ function Line(text, markedSpans, estimateHeight) {
4370
+ this.text = text
4371
+ attachMarkedSpans(this, markedSpans)
4372
+ this.height = estimateHeight ? estimateHeight(this) : 1
4373
+ }
4374
+ eventMixin(Line)
4375
+ Line.prototype.lineNo = function() { return lineNo(this) }
4376
+
4377
+ // Change the content (text, markers) of a line. Automatically
4378
+ // invalidates cached information and tries to re-estimate the
4379
+ // line's height.
4380
+ function updateLine(line, text, markedSpans, estimateHeight) {
4381
+ line.text = text
4382
+ if (line.stateAfter) { line.stateAfter = null }
4383
+ if (line.styles) { line.styles = null }
4384
+ if (line.order != null) { line.order = null }
4385
+ detachMarkedSpans(line)
4386
+ attachMarkedSpans(line, markedSpans)
4387
+ var estHeight = estimateHeight ? estimateHeight(line) : 1
4388
+ if (estHeight != line.height) { updateLineHeight(line, estHeight) }
4389
+ }
4390
 
4391
+ // Detach a line from the document tree and its markers.
4392
+ function cleanUpLine(line) {
4393
+ line.parent = null
4394
+ detachMarkedSpans(line)
4395
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4396
 
4397
+ // Convert a style as returned by a mode (either null, or a string
4398
+ // containing one or more styles) to a CSS style. This is cached,
4399
+ // and also looks for line-wide styles.
4400
+ var styleToClassCache = {};
4401
+ var styleToClassCacheWithMode = {};
4402
+ function interpretTokenStyle(style, options) {
4403
+ if (!style || /^\s*$/.test(style)) { return null }
4404
+ var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache
4405
+ return cache[style] ||
4406
+ (cache[style] = style.replace(/\S+/g, "cm-$&"))
4407
+ }
4408
 
4409
+ // Render the DOM representation of the text of a line. Also builds
4410
+ // up a 'line map', which points at the DOM nodes that represent
4411
+ // specific stretches of text, and is used by the measuring code.
4412
+ // The returned object contains the DOM node, this map, and
4413
+ // information about line-wide styles that were set by the mode.
4414
+ function buildLineContent(cm, lineView) {
4415
+ // The padding-right forces the element to have a 'border', which
4416
+ // is needed on Webkit to be able to get line-level bounding
4417
+ // rectangles for it (in measureChar).
4418
+ var content = elt("span", null, null, webkit ? "padding-right: .1px" : null)
4419
+ var builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content,
4420
+ col: 0, pos: 0, cm: cm,
4421
+ trailingSpace: false,
4422
+ splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")}
4423
+ lineView.measure = {}
4424
+
4425
+ // Iterate over the logical lines that make up this visual line.
4426
+ for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
4427
+ var line = i ? lineView.rest[i - 1] : lineView.line, order = void 0
4428
+ builder.pos = 0
4429
+ builder.addToken = buildToken
4430
+ // Optionally wire in some hacks into the token-rendering
4431
+ // algorithm, to deal with browser quirks.
4432
+ if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))
4433
+ { builder.addToken = buildTokenBadBidi(builder.addToken, order) }
4434
+ builder.map = []
4435
+ var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line)
4436
+ insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate))
4437
+ if (line.styleClasses) {
4438
+ if (line.styleClasses.bgClass)
4439
+ { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "") }
4440
+ if (line.styleClasses.textClass)
4441
+ { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "") }
4442
+ }
4443
+
4444
+ // Ensure at least a single node is present, for measuring.
4445
+ if (builder.map.length == 0)
4446
+ { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))) }
4447
+
4448
+ // Store the map and a cache object for the current logical line
4449
+ if (i == 0) {
4450
+ lineView.measure.map = builder.map
4451
+ lineView.measure.cache = {}
4452
+ } else {
4453
+ ;(lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)
4454
+ ;(lineView.measure.caches || (lineView.measure.caches = [])).push({})
4455
+ }
4456
+ }
4457
 
4458
+ // See issue #2901
4459
+ if (webkit) {
4460
+ var last = builder.content.lastChild
4461
+ if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
4462
+ { builder.content.className = "cm-tab-wrap-hack" }
4463
+ }
4464
 
4465
+ signal(cm, "renderLine", cm, lineView.line, builder.pre)
4466
+ if (builder.pre.className)
4467
+ { builder.textClass = joinClasses(builder.pre.className, builder.textClass || "") }
4468
 
4469
+ return builder
4470
+ }
4471
 
4472
+ function defaultSpecialCharPlaceholder(ch) {
4473
+ var token = elt("span", "\u2022", "cm-invalidchar")
4474
+ token.title = "\\u" + ch.charCodeAt(0).toString(16)
4475
+ token.setAttribute("aria-label", token.title)
4476
+ return token
4477
+ }
4478
 
4479
+ // Build up the DOM representation for a single token, and add it to
4480
+ // the line map. Takes care to render special characters separately.
4481
+ function buildToken(builder, text, style, startStyle, endStyle, title, css) {
4482
+ if (!text) { return }
4483
+ var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text
4484
+ var special = builder.cm.state.specialChars, mustWrap = false
4485
+ var content
4486
+ if (!special.test(text)) {
4487
+ builder.col += text.length
4488
+ content = document.createTextNode(displayText)
4489
+ builder.map.push(builder.pos, builder.pos + text.length, content)
4490
+ if (ie && ie_version < 9) { mustWrap = true }
4491
+ builder.pos += text.length
4492
+ } else {
4493
+ content = document.createDocumentFragment()
4494
+ var pos = 0
4495
+ while (true) {
4496
+ special.lastIndex = pos
4497
+ var m = special.exec(text)
4498
+ var skipped = m ? m.index - pos : text.length - pos
4499
+ if (skipped) {
4500
+ var txt = document.createTextNode(displayText.slice(pos, pos + skipped))
4501
+ if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])) }
4502
+ else { content.appendChild(txt) }
4503
+ builder.map.push(builder.pos, builder.pos + skipped, txt)
4504
+ builder.col += skipped
4505
+ builder.pos += skipped
4506
+ }
4507
+ if (!m) { break }
4508
+ pos += skipped + 1
4509
+ var txt$1 = void 0
4510
+ if (m[0] == "\t") {
4511
+ var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize
4512
+ txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"))
4513
+ txt$1.setAttribute("role", "presentation")
4514
+ txt$1.setAttribute("cm-text", "\t")
4515
+ builder.col += tabWidth
4516
+ } else if (m[0] == "\r" || m[0] == "\n") {
4517
+ txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"))
4518
+ txt$1.setAttribute("cm-text", m[0])
4519
+ builder.col += 1
4520
+ } else {
4521
+ txt$1 = builder.cm.options.specialCharPlaceholder(m[0])
4522
+ txt$1.setAttribute("cm-text", m[0])
4523
+ if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])) }
4524
+ else { content.appendChild(txt$1) }
4525
+ builder.col += 1
4526
+ }
4527
+ builder.map.push(builder.pos, builder.pos + 1, txt$1)
4528
+ builder.pos++
4529
+ }
4530
+ }
4531
+ builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32
4532
+ if (style || startStyle || endStyle || mustWrap || css) {
4533
+ var fullStyle = style || ""
4534
+ if (startStyle) { fullStyle += startStyle }
4535
+ if (endStyle) { fullStyle += endStyle }
4536
+ var token = elt("span", [content], fullStyle, css)
4537
+ if (title) { token.title = title }
4538
+ return builder.content.appendChild(token)
4539
+ }
4540
+ builder.content.appendChild(content)
4541
+ }
4542
 
4543
+ function splitSpaces(text, trailingBefore) {
4544
+ if (text.length > 1 && !/ /.test(text)) { return text }
4545
+ var spaceBefore = trailingBefore, result = ""
4546
+ for (var i = 0; i < text.length; i++) {
4547
+ var ch = text.charAt(i)
4548
+ if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))
4549
+ { ch = "\u00a0" }
4550
+ result += ch
4551
+ spaceBefore = ch == " "
4552
+ }
4553
+ return result
4554
+ }
4555
 
4556
+ // Work around nonsense dimensions being reported for stretches of
4557
+ // right-to-left text.
4558
+ function buildTokenBadBidi(inner, order) {
4559
+ return function (builder, text, style, startStyle, endStyle, title, css) {
4560
+ style = style ? style + " cm-force-border" : "cm-force-border"
4561
+ var start = builder.pos, end = start + text.length
4562
+ for (;;) {
4563
+ // Find the part that overlaps with the start of this text
4564
+ var part = void 0
4565
+ for (var i = 0; i < order.length; i++) {
4566
+ part = order[i]
4567
+ if (part.to > start && part.from <= start) { break }
4568
  }
4569
+ if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) }
4570
+ inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css)
4571
+ startStyle = null
4572
+ text = text.slice(part.to - start)
4573
+ start = part.to
4574
  }
4575
  }
4576
+ }
4577
 
4578
+ function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
4579
+ var widget = !ignoreWidget && marker.widgetNode
4580
+ if (widget) { builder.map.push(builder.pos, builder.pos + size, widget) }
4581
+ if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
4582
+ if (!widget)
4583
+ { widget = builder.content.appendChild(document.createElement("span")) }
4584
+ widget.setAttribute("cm-marker", marker.id)
4585
+ }
4586
+ if (widget) {
4587
+ builder.cm.display.input.setUneditable(widget)
4588
+ builder.content.appendChild(widget)
4589
+ }
4590
+ builder.pos += size
4591
+ builder.trailingSpace = false
4592
+ }
4593
 
4594
+ // Outputs a number of spans to make up a line, taking highlighting
4595
+ // and marked text into account.
4596
+ function insertLineContent(line, builder, styles) {
4597
+ var spans = line.markedSpans, allText = line.text, at = 0
4598
+ if (!spans) {
4599
+ for (var i$1 = 1; i$1 < styles.length; i$1+=2)
4600
+ { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)) }
4601
+ return
4602
+ }
4603
+
4604
+ var len = allText.length, pos = 0, i = 1, text = "", style, css
4605
+ var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed
4606
+ for (;;) {
4607
+ if (nextChange == pos) { // Update current marker set
4608
+ spanStyle = spanEndStyle = spanStartStyle = title = css = ""
4609
+ collapsed = null; nextChange = Infinity
4610
+ var foundBookmarks = [], endStyles = void 0
4611
+ for (var j = 0; j < spans.length; ++j) {
4612
+ var sp = spans[j], m = sp.marker
4613
+ if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
4614
+ foundBookmarks.push(m)
4615
+ } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
4616
+ if (sp.to != null && sp.to != pos && nextChange > sp.to) {
4617
+ nextChange = sp.to
4618
+ spanEndStyle = ""
4619
  }
4620
+ if (m.className) { spanStyle += " " + m.className }
4621
+ if (m.css) { css = (css ? css + ";" : "") + m.css }
4622
+ if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle }
4623
+ if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to) }
4624
+ if (m.title && !title) { title = m.title }
4625
+ if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
4626
+ { collapsed = sp }
4627
+ } else if (sp.from > pos && nextChange > sp.from) {
4628
+ nextChange = sp.from
4629
  }
4630
  }
4631
+ if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)
4632
+ { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1] } } }
 
4633
 
4634
+ if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)
4635
+ { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]) } }
4636
+ if (collapsed && (collapsed.from || 0) == pos) {
4637
+ buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
4638
+ collapsed.marker, collapsed.from == null)
4639
+ if (collapsed.to == null) { return }
4640
+ if (collapsed.to == pos) { collapsed = false }
4641
+ }
 
 
 
 
 
 
4642
  }
4643
+ if (pos >= len) { break }
4644
 
4645
+ var upto = Math.min(len, nextChange)
4646
+ while (true) {
4647
+ if (text) {
4648
+ var end = pos + text.length
4649
+ if (!collapsed) {
4650
+ var tokenText = end > upto ? text.slice(0, upto - pos) : text
4651
+ builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
4652
+ spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4653
  }
4654
+ if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
4655
+ pos = end
4656
+ spanStartStyle = ""
4657
  }
4658
+ text = allText.slice(at, at = styles[i++])
4659
+ style = interpretTokenStyle(styles[i++], builder.cm.options)
4660
  }
 
 
 
 
 
 
4661
  }
4662
+ }
4663
 
 
4664
 
4665
+ // These objects are used to represent the visible (currently drawn)
4666
+ // part of the document. A LineView may correspond to multiple
4667
+ // logical lines, if those are connected by collapsed ranges.
4668
+ function LineView(doc, line, lineN) {
4669
+ // The starting line
4670
+ this.line = line
4671
+ // Continuing lines, if any
4672
+ this.rest = visualLineContinued(line)
4673
+ // Number of logical lines in this visual line
4674
+ this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1
4675
+ this.node = this.text = null
4676
+ this.hidden = lineIsHidden(doc, line)
4677
+ }
4678
 
4679
+ // Create a range of LineView objects for the given lines.
4680
+ function buildViewArray(cm, from, to) {
4681
+ var array = [], nextPos
4682
+ for (var pos = from; pos < to; pos = nextPos) {
4683
+ var view = new LineView(cm.doc, getLine(cm.doc, pos), pos)
4684
+ nextPos = pos + view.size
4685
+ array.push(view)
 
4686
  }
4687
+ return array
4688
+ }
4689
 
4690
+ var operationGroup = null
4691
+
4692
+ function pushOperation(op) {
4693
+ if (operationGroup) {
4694
+ operationGroup.ops.push(op)
4695
+ } else {
4696
+ op.ownsGroup = operationGroup = {
4697
+ ops: [op],
4698
+ delayedCallbacks: []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4699
  }
4700
+ }
4701
+ }
4702
+
4703
+ function fireCallbacksForOps(group) {
4704
+ // Calls delayed callbacks and cursorActivity handlers until no
4705
+ // new ones appear
4706
+ var callbacks = group.delayedCallbacks, i = 0
4707
+ do {
4708
+ for (; i < callbacks.length; i++)
4709
+ { callbacks[i].call(null) }
4710
+ for (var j = 0; j < group.ops.length; j++) {
4711
+ var op = group.ops[j]
4712
+ if (op.cursorActivityHandlers)
4713
+ { while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
4714
+ { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm) } }
4715
+ }
4716
+ } while (i < callbacks.length)
4717
+ }
4718
+
4719
+ function finishOperation(op, endCb) {
4720
+ var group = op.ownsGroup
4721
+ if (!group) { return }
4722
 
4723
+ try { fireCallbacksForOps(group) }
4724
+ finally {
4725
+ operationGroup = null
4726
+ endCb(group)
4727
  }
4728
+ }
4729
 
4730
+ var orphanDelayedCallbacks = null
4731
+
4732
+ // Often, we want to signal events at a point where we are in the
4733
+ // middle of some work, but don't want the handler to start calling
4734
+ // other methods on the editor, which might be in an inconsistent
4735
+ // state or simply not expect any other events to happen.
4736
+ // signalLater looks whether there are any handlers, and schedules
4737
+ // them to be executed when the last operation ends, or, if no
4738
+ // operation is active, when a timeout fires.
4739
+ function signalLater(emitter, type /*, values...*/) {
4740
+ var arr = getHandlers(emitter, type, false)
4741
+ if (!arr.length) { return }
4742
+ var args = Array.prototype.slice.call(arguments, 2), list
4743
+ if (operationGroup) {
4744
+ list = operationGroup.delayedCallbacks
4745
+ } else if (orphanDelayedCallbacks) {
4746
+ list = orphanDelayedCallbacks
4747
+ } else {
4748
+ list = orphanDelayedCallbacks = []
4749
+ setTimeout(fireOrphanDelayed, 0)
4750
+ }
4751
+ var loop = function ( i ) {
4752
+ list.push(function () { return arr[i].apply(null, args); })
4753
  };
4754
 
4755
+ for (var i = 0; i < arr.length; ++i)
4756
+ loop( i );
4757
+ }
4758
+
4759
+ function fireOrphanDelayed() {
4760
+ var delayed = orphanDelayedCallbacks
4761
+ orphanDelayedCallbacks = null
4762
+ for (var i = 0; i < delayed.length; ++i) { delayed[i]() }
4763
+ }
4764
+
4765
+ // When an aspect of a line changes, a string is added to
4766
+ // lineView.changes. This updates the relevant part of the line's
4767
+ // DOM structure.
4768
+ function updateLineForChanges(cm, lineView, lineN, dims) {
4769
+ for (var j = 0; j < lineView.changes.length; j++) {
4770
+ var type = lineView.changes[j]
4771
+ if (type == "text") { updateLineText(cm, lineView) }
4772
+ else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims) }
4773
+ else if (type == "class") { updateLineClasses(lineView) }
4774
+ else if (type == "widget") { updateLineWidgets(cm, lineView, dims) }
4775
+ }
4776
+ lineView.changes = null
4777
+ }
4778
+
4779
+ // Lines with gutter elements, widgets or a background class need to
4780
+ // be wrapped, and have the extra elements added to the wrapper div
4781
+ function ensureLineWrapped(lineView) {
4782
+ if (lineView.node == lineView.text) {
4783
+ lineView.node = elt("div", null, null, "position: relative")
4784
+ if (lineView.text.parentNode)
4785
+ { lineView.text.parentNode.replaceChild(lineView.node, lineView.text) }
4786
+ lineView.node.appendChild(lineView.text)
4787
+ if (ie && ie_version < 8) { lineView.node.style.zIndex = 2 }
4788
+ }
4789
+ return lineView.node
4790
+ }
4791
+
4792
+ function updateLineBackground(lineView) {
4793
+ var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass
4794
+ if (cls) { cls += " CodeMirror-linebackground" }
4795
+ if (lineView.background) {
4796
+ if (cls) { lineView.background.className = cls }
4797
+ else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null }
4798
+ } else if (cls) {
4799
+ var wrap = ensureLineWrapped(lineView)
4800
+ lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4801
  }
4802
+ }
4803
 
4804
+ // Wrapper around buildLineContent which will reuse the structure
4805
+ // in display.externalMeasured when possible.
4806
+ function getLineContent(cm, lineView) {
4807
+ var ext = cm.display.externalMeasured
4808
+ if (ext && ext.line == lineView.line) {
4809
+ cm.display.externalMeasured = null
4810
+ lineView.measure = ext.measure
4811
+ return ext.built
4812
  }
4813
+ return buildLineContent(cm, lineView)
4814
+ }
4815
 
4816
+ // Redraw the line's text. Interacts with the background and text
4817
+ // classes because the mode may output tokens that influence these
4818
+ // classes.
4819
+ function updateLineText(cm, lineView) {
4820
+ var cls = lineView.text.className
4821
+ var built = getLineContent(cm, lineView)
4822
+ if (lineView.text == lineView.node) { lineView.node = built.pre }
4823
+ lineView.text.parentNode.replaceChild(built.pre, lineView.text)
4824
+ lineView.text = built.pre
4825
+ if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
4826
+ lineView.bgClass = built.bgClass
4827
+ lineView.textClass = built.textClass
4828
+ updateLineClasses(lineView)
4829
+ } else if (cls) {
4830
+ lineView.text.className = cls
4831
  }
4832
+ }
4833
+
4834
+ function updateLineClasses(lineView) {
4835
+ updateLineBackground(lineView)
4836
+ if (lineView.line.wrapClass)
4837
+ { ensureLineWrapped(lineView).className = lineView.line.wrapClass }
4838
+ else if (lineView.node != lineView.text)
4839
+ { lineView.node.className = "" }
4840
+ var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass
4841
+ lineView.text.className = textClass || ""
4842
+ }
4843
 
4844
+ function updateLineGutter(cm, lineView, lineN, dims) {
4845
+ if (lineView.gutter) {
4846
+ lineView.node.removeChild(lineView.gutter)
4847
+ lineView.gutter = null
4848
+ }
4849
+ if (lineView.gutterBackground) {
4850
+ lineView.node.removeChild(lineView.gutterBackground)
4851
+ lineView.gutterBackground = null
4852
+ }
4853
+ if (lineView.line.gutterClass) {
4854
+ var wrap = ensureLineWrapped(lineView)
4855
+ lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
4856
+ ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px"))
4857
+ wrap.insertBefore(lineView.gutterBackground, lineView.text)
4858
+ }
4859
+ var markers = lineView.line.gutterMarkers
4860
+ if (cm.options.lineNumbers || markers) {
4861
+ var wrap$1 = ensureLineWrapped(lineView)
4862
+ var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"))
4863
+ cm.display.input.setUneditable(gutterWrap)
4864
+ wrap$1.insertBefore(gutterWrap, lineView.text)
4865
+ if (lineView.line.gutterClass)
4866
+ { gutterWrap.className += " " + lineView.line.gutterClass }
4867
+ if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
4868
+ { lineView.lineNumber = gutterWrap.appendChild(
4869
+ elt("div", lineNumberFor(cm.options, lineN),
4870
+ "CodeMirror-linenumber CodeMirror-gutter-elt",
4871
+ ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))) }
4872
+ if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) {
4873
+ var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]
4874
+ if (found)
4875
+ { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
4876
+ ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))) }
4877
+ } }
4878
  }
4879
+ }
4880
 
4881
+ function updateLineWidgets(cm, lineView, dims) {
4882
+ if (lineView.alignable) { lineView.alignable = null }
4883
+ for (var node = lineView.node.firstChild, next = void 0; node; node = next) {
4884
+ next = node.nextSibling
4885
+ if (node.className == "CodeMirror-linewidget")
4886
+ { lineView.node.removeChild(node) }
4887
  }
4888
+ insertLineWidgets(cm, lineView, dims)
4889
+ }
4890
 
4891
+ // Build a line's DOM representation from scratch
4892
+ function buildLineElement(cm, lineView, lineN, dims) {
4893
+ var built = getLineContent(cm, lineView)
4894
+ lineView.text = lineView.node = built.pre
4895
+ if (built.bgClass) { lineView.bgClass = built.bgClass }
4896
+ if (built.textClass) { lineView.textClass = built.textClass }
4897
+
4898
+ updateLineClasses(lineView)
4899
+ updateLineGutter(cm, lineView, lineN, dims)
4900
+ insertLineWidgets(cm, lineView, dims)
4901
+ return lineView.node
4902
+ }
4903
+
4904
+ // A lineView may contain multiple logical lines (when merged by
4905
+ // collapsed spans). The widgets for all of them need to be drawn.
4906
+ function insertLineWidgets(cm, lineView, dims) {
4907
+ insertLineWidgetsFor(cm, lineView.line, lineView, dims, true)
4908
+ if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
4909
+ { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false) } }
4910
+ }
4911
+
4912
+ function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
4913
+ if (!line.widgets) { return }
4914
+ var wrap = ensureLineWrapped(lineView)
4915
+ for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
4916
+ var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget")
4917
+ if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true") }
4918
+ positionLineWidget(widget, node, lineView, dims)
4919
+ cm.display.input.setUneditable(node)
4920
+ if (allowAbove && widget.above)
4921
+ { wrap.insertBefore(node, lineView.gutter || lineView.text) }
4922
+ else
4923
+ { wrap.appendChild(node) }
4924
+ signalLater(widget, "redraw")
4925
  }
4926
+ }
4927
 
4928
+ function positionLineWidget(widget, node, lineView, dims) {
4929
+ if (widget.noHScroll) {
4930
+ ;(lineView.alignable || (lineView.alignable = [])).push(node)
4931
+ var width = dims.wrapperWidth
4932
+ node.style.left = dims.fixedPos + "px"
4933
+ if (!widget.coverGutter) {
4934
+ width -= dims.gutterTotalWidth
4935
+ node.style.paddingLeft = dims.gutterTotalWidth + "px"
4936
  }
4937
+ node.style.width = width + "px"
4938
  }
4939
+ if (widget.coverGutter) {
4940
+ node.style.zIndex = 5
4941
+ node.style.position = "relative"
4942
+ if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px" }
 
4943
  }
4944
+ }
4945
 
4946
+ function widgetHeight(widget) {
4947
+ if (widget.height != null) { return widget.height }
4948
+ var cm = widget.doc.cm
4949
+ if (!cm) { return 0 }
4950
+ if (!contains(document.body, widget.node)) {
4951
+ var parentStyle = "position: relative;"
4952
+ if (widget.coverGutter)
4953
+ { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;" }
4954
+ if (widget.noHScroll)
4955
+ { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;" }
4956
+ removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle))
4957
+ }
4958
+ return widget.height = widget.node.parentNode.offsetHeight
4959
+ }
4960
 
4961
+ // Return true when the given mouse event happened in a widget
4962
+ function eventInWidget(display, e) {
4963
+ for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
4964
+ if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
4965
+ (n.parentNode == display.sizer && n != display.mover))
4966
+ { return true }
4967
  }
4968
+ }
4969
 
4970
+ // POSITION MEASUREMENT
4971
+
4972
+ function paddingTop(display) {return display.lineSpace.offsetTop}
4973
+ function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}
4974
+ function paddingH(display) {
4975
+ if (display.cachedPaddingH) { return display.cachedPaddingH }
4976
+ var e = removeChildrenAndAdd(display.measure, elt("pre", "x"))
4977
+ var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle
4978
+ var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}
4979
+ if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data }
4980
+ return data
4981
+ }
4982
 
4983
+ function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
4984
+ function displayWidth(cm) {
4985
+ return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth
4986
+ }
4987
+ function displayHeight(cm) {
4988
+ return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight
4989
+ }
4990
 
4991
+ // Ensure the lineView.wrapping.heights array is populated. This is
4992
+ // an array of bottom offsets for the lines that make up a drawn
4993
+ // line. When lineWrapping is on, there might be more than one
4994
+ // height.
4995
+ function ensureLineHeights(cm, lineView, rect) {
4996
+ var wrapping = cm.options.lineWrapping
4997
+ var curWidth = wrapping && displayWidth(cm)
4998
+ if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
4999
+ var heights = lineView.measure.heights = []
5000
+ if (wrapping) {
5001
+ lineView.measure.width = curWidth
5002
+ var rects = lineView.text.firstChild.getClientRects()
5003
+ for (var i = 0; i < rects.length - 1; i++) {
5004
+ var cur = rects[i], next = rects[i + 1]
5005
+ if (Math.abs(cur.bottom - next.bottom) > 2)
5006
+ { heights.push((cur.bottom + next.top) / 2 - rect.top) }
5007
+ }
5008
+ }
5009
+ heights.push(rect.bottom - rect.top)
5010
  }
5011
+ }
5012
 
5013
+ // Find a line map (mapping character offsets to text nodes) and a
5014
+ // measurement cache for the given line number. (A line view might
5015
+ // contain multiple lines when collapsed ranges are present.)
5016
+ function mapFromLineView(lineView, line, lineN) {
5017
+ if (lineView.line == line)
5018
+ { return {map: lineView.measure.map, cache: lineView.measure.cache} }
5019
+ for (var i = 0; i < lineView.rest.length; i++)
5020
+ { if (lineView.rest[i] == line)
5021
+ { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
5022
+ for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
5023
+ { if (lineNo(lineView.rest[i$1]) > lineN)
5024
+ { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
5025
+ }
5026
 
5027
+ // Render a line into the hidden node display.externalMeasured. Used
5028
+ // when measurement is needed for a line that's not in the viewport.
5029
+ function updateExternalMeasurement(cm, line) {
5030
+ line = visualLine(line)
5031
+ var lineN = lineNo(line)
5032
+ var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN)
5033
+ view.lineN = lineN
5034
+ var built = view.built = buildLineContent(cm, view)
5035
+ view.text = built.pre
5036
+ removeChildrenAndAdd(cm.display.lineMeasure, built.pre)
5037
+ return view
5038
+ }
 
 
 
 
5039
 
5040
+ // Get a {top, bottom, left, right} box (in line-local coordinates)
5041
+ // for a given character.
5042
+ function measureChar(cm, line, ch, bias) {
5043
+ return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)
5044
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5045
 
5046
+ // Find a line view that corresponds to the given line number.
5047
+ function findViewForLine(cm, lineN) {
5048
+ if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
5049
+ { return cm.display.view[findViewIndex(cm, lineN)] }
5050
+ var ext = cm.display.externalMeasured
5051
+ if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
5052
+ { return ext }
5053
+ }
5054
 
5055
+ // Measurement can be split in two steps, the set-up work that
5056
+ // applies to the whole line, and the measurement of the actual
5057
+ // character. Functions like coordsChar, that need to do a lot of
5058
+ // measurements in a row, can thus ensure that the set-up work is
5059
+ // only done once.
5060
+ function prepareMeasureForLine(cm, line) {
5061
+ var lineN = lineNo(line)
5062
+ var view = findViewForLine(cm, lineN)
5063
+ if (view && !view.text) {
5064
+ view = null
5065
+ } else if (view && view.changes) {
5066
+ updateLineForChanges(cm, view, lineN, getDimensions(cm))
5067
+ cm.curOp.forceUpdate = true
5068
+ }
5069
+ if (!view)
5070
+ { view = updateExternalMeasurement(cm, line) }
5071
+
5072
+ var info = mapFromLineView(view, line, lineN)
5073
+ return {
5074
+ line: line, view: view, rect: null,
5075
+ map: info.map, cache: info.cache, before: info.before,
5076
+ hasHeights: false
5077
  }
5078
+ }
5079
 
5080
+ // Given a prepared measurement object, measures the position of an
5081
+ // actual character (or fetches it from the cache).
5082
+ function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
5083
+ if (prepared.before) { ch = -1 }
5084
+ var key = ch + (bias || ""), found
5085
+ if (prepared.cache.hasOwnProperty(key)) {
5086
+ found = prepared.cache[key]
5087
+ } else {
5088
+ if (!prepared.rect)
5089
+ { prepared.rect = prepared.view.text.getBoundingClientRect() }
5090
+ if (!prepared.hasHeights) {
5091
+ ensureLineHeights(cm, prepared.view, prepared.rect)
5092
+ prepared.hasHeights = true
5093
+ }
5094
+ found = measureCharInner(cm, prepared, ch, bias)
5095
+ if (!found.bogus) { prepared.cache[key] = found }
5096
+ }
5097
+ return {left: found.left, right: found.right,
5098
+ top: varHeight ? found.rtop : found.top,
5099
+ bottom: varHeight ? found.rbottom : found.bottom}
5100
+ }
5101
+
5102
+ var nullRect = {left: 0, right: 0, top: 0, bottom: 0}
5103
+
5104
+ function nodeAndOffsetInLineMap(map, ch, bias) {
5105
+ var node, start, end, collapse, mStart, mEnd
5106
+ // First, search the line map for the text node corresponding to,
5107
+ // or closest to, the target character.
5108
+ for (var i = 0; i < map.length; i += 3) {
5109
+ mStart = map[i]
5110
+ mEnd = map[i + 1]
5111
+ if (ch < mStart) {
5112
+ start = 0; end = 1
5113
+ collapse = "left"
5114
+ } else if (ch < mEnd) {
5115
+ start = ch - mStart
5116
+ end = start + 1
5117
+ } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
5118
+ end = mEnd - mStart
5119
+ start = end - 1
5120
+ if (ch >= mEnd) { collapse = "right" }
5121
+ }
5122
+ if (start != null) {
5123
+ node = map[i + 2]
5124
+ if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
5125
+ { collapse = bias }
5126
+ if (bias == "left" && start == 0)
5127
+ { while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
5128
+ node = map[(i -= 3) + 2]
5129
+ collapse = "left"
5130
+ } }
5131
+ if (bias == "right" && start == mEnd - mStart)
5132
+ { while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
5133
+ node = map[(i += 3) + 2]
5134
+ collapse = "right"
5135
+ } }
5136
+ break
5137
+ }
5138
+ }
5139
+ return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}
5140
+ }
5141
 
5142
+ function getUsefulRect(rects, bias) {
5143
+ var rect = nullRect
5144
+ if (bias == "left") { for (var i = 0; i < rects.length; i++) {
5145
+ if ((rect = rects[i]).left != rect.right) { break }
5146
+ } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {
5147
+ if ((rect = rects[i$1]).left != rect.right) { break }
5148
+ } }
5149
+ return rect
5150
+ }
5151
 
5152
+ function measureCharInner(cm, prepared, ch, bias) {
5153
+ var place = nodeAndOffsetInLineMap(prepared.map, ch, bias)
5154
+ var node = place.node, start = place.start, end = place.end, collapse = place.collapse
5155
+
5156
+ var rect
5157
+ if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
5158
+ for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned
5159
+ while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start }
5160
+ while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end }
5161
+ if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)
5162
+ { rect = node.parentNode.getBoundingClientRect() }
5163
+ else
5164
+ { rect = getUsefulRect(range(node, start, end).getClientRects(), bias) }
5165
+ if (rect.left || rect.right || start == 0) { break }
5166
+ end = start
5167
+ start = start - 1
5168
+ collapse = "right"
5169
+ }
5170
+ if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect) }
5171
+ } else { // If it is a widget, simply get the box for the whole widget.
5172
+ if (start > 0) { collapse = bias = "right" }
5173
+ var rects
5174
+ if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
5175
+ { rect = rects[bias == "right" ? rects.length - 1 : 0] }
5176
+ else
5177
+ { rect = node.getBoundingClientRect() }
5178
  }
5179
+ if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
5180
+ var rSpan = node.parentNode.getClientRects()[0]
5181
+ if (rSpan)
5182
+ { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom} }
5183
+ else
5184
+ { rect = nullRect }
5185
+ }
5186
+
5187
+ var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top
5188
+ var mid = (rtop + rbot) / 2
5189
+ var heights = prepared.view.measure.heights
5190
+ var i = 0
5191
+ for (; i < heights.length - 1; i++)
5192
+ { if (mid < heights[i]) { break } }
5193
+ var top = i ? heights[i - 1] : 0, bot = heights[i]
5194
+ var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
5195
+ right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
5196
+ top: top, bottom: bot}
5197
+ if (!rect.left && !rect.right) { result.bogus = true }
5198
+ if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot }
5199
+
5200
+ return result
5201
+ }
5202
 
5203
+ // Work around problem with bounding client rects on ranges being
5204
+ // returned incorrectly when zoomed on IE10 and below.
5205
+ function maybeUpdateRectForZooming(measure, rect) {
5206
+ if (!window.screen || screen.logicalXDPI == null ||
5207
+ screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
5208
+ { return rect }
5209
+ var scaleX = screen.logicalXDPI / screen.deviceXDPI
5210
+ var scaleY = screen.logicalYDPI / screen.deviceYDPI
5211
+ return {left: rect.left * scaleX, right: rect.right * scaleX,
5212
+ top: rect.top * scaleY, bottom: rect.bottom * scaleY}
5213
+ }
5214
 
5215
+ function clearLineMeasurementCacheFor(lineView) {
5216
+ if (lineView.measure) {
5217
+ lineView.measure.cache = {}
5218
+ lineView.measure.heights = null
5219
+ if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
5220
+ { lineView.measure.caches[i] = {} } }
 
 
 
 
 
5221
  }
5222
+ }
5223
 
5224
+ function clearLineMeasurementCache(cm) {
5225
+ cm.display.externalMeasure = null
5226
+ removeChildren(cm.display.lineMeasure)
5227
+ for (var i = 0; i < cm.display.view.length; i++)
5228
+ { clearLineMeasurementCacheFor(cm.display.view[i]) }
5229
+ }
5230
 
5231
+ function clearCaches(cm) {
5232
+ clearLineMeasurementCache(cm)
5233
+ cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null
5234
+ if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true }
5235
+ cm.display.lineNumChars = null
5236
+ }
5237
 
5238
+ function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft }
5239
+ function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop }
5240
+
5241
+ // Converts a {top, bottom, left, right} box from line-local
5242
+ // coordinates into another coordinate system. Context may be one of
5243
+ // "line", "div" (display.lineDiv), "local"./null (editor), "window",
5244
+ // or "page".
5245
+ function intoCoordSystem(cm, lineObj, rect, context) {
5246
+ if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) {
5247
+ var size = widgetHeight(lineObj.widgets[i])
5248
+ rect.top += size; rect.bottom += size
5249
+ } } }
5250
+ if (context == "line") { return rect }
5251
+ if (!context) { context = "local" }
5252
+ var yOff = heightAtLine(lineObj)
5253
+ if (context == "local") { yOff += paddingTop(cm.display) }
5254
+ else { yOff -= cm.display.viewOffset }
5255
+ if (context == "page" || context == "window") {
5256
+ var lOff = cm.display.lineSpace.getBoundingClientRect()
5257
+ yOff += lOff.top + (context == "window" ? 0 : pageScrollY())
5258
+ var xOff = lOff.left + (context == "window" ? 0 : pageScrollX())
5259
+ rect.left += xOff; rect.right += xOff
5260
+ }
5261
+ rect.top += yOff; rect.bottom += yOff
5262
+ return rect
5263
+ }
5264
 
5265
+ // Coverts a box from "div" coords to another coordinate system.
5266
+ // Context may be "window", "page", "div", or "local"./null.
5267
+ function fromCoordSystem(cm, coords, context) {
5268
+ if (context == "div") { return coords }
5269
+ var left = coords.left, top = coords.top
5270
+ // First move into "page" coordinate system
5271
+ if (context == "page") {
5272
+ left -= pageScrollX()
5273
+ top -= pageScrollY()
5274
+ } else if (context == "local" || !context) {
5275
+ var localBox = cm.display.sizer.getBoundingClientRect()
5276
+ left += localBox.left
5277
+ top += localBox.top
5278
+ }
5279
+
5280
+ var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect()
5281
+ return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}
5282
+ }
5283
 
5284
+ function charCoords(cm, pos, context, lineObj, bias) {
5285
+ if (!lineObj) { lineObj = getLine(cm.doc, pos.line) }
5286
+ return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)
5287
+ }
 
 
 
 
5288
 
5289
+ // Returns a box for a given cursor position, which may have an
5290
+ // 'other' property containing the position of the secondary cursor
5291
+ // on a bidi boundary.
5292
+ function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
5293
+ lineObj = lineObj || getLine(cm.doc, pos.line)
5294
+ if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj) }
5295
+ function get(ch, right) {
5296
+ var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight)
5297
+ if (right) { m.left = m.right; } else { m.right = m.left }
5298
+ return intoCoordSystem(cm, lineObj, m, context)
5299
+ }
5300
+ function getBidi(ch, partPos) {
5301
+ var part = order[partPos], right = part.level % 2
5302
+ if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
5303
+ part = order[--partPos]
5304
+ ch = bidiRight(part) - (part.level % 2 ? 0 : 1)
5305
+ right = true
5306
+ } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
5307
+ part = order[++partPos]
5308
+ ch = bidiLeft(part) - part.level % 2
5309
+ right = false
5310
+ }
5311
+ if (right && ch == part.to && ch > part.from) { return get(ch - 1) }
5312
+ return get(ch, right)
5313
+ }
5314
+ var order = getOrder(lineObj), ch = pos.ch
5315
+ if (!order) { return get(ch) }
5316
+ var partPos = getBidiPartAt(order, ch)
5317
+ var val = getBidi(ch, partPos)
5318
+ if (bidiOther != null) { val.other = getBidi(ch, bidiOther) }
5319
+ return val
5320
+ }
5321
 
5322
+ // Used to cheaply estimate the coordinates for a position. Used for
5323
+ // intermediate scroll updates.
5324
+ function estimateCoords(cm, pos) {
5325
+ var left = 0
5326
+ pos = clipPos(cm.doc, pos)
5327
+ if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch }
5328
+ var lineObj = getLine(cm.doc, pos.line)
5329
+ var top = heightAtLine(lineObj) + paddingTop(cm.display)
5330
+ return {left: left, right: left, top: top, bottom: top + lineObj.height}
5331
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5332
 
5333
+ // Positions returned by coordsChar contain some extra information.
5334
+ // xRel is the relative x position of the input coordinates compared
5335
+ // to the found position (so xRel > 0 means the coordinates are to
5336
+ // the right of the character position, for example). When outside
5337
+ // is true, that means the coordinates lie outside the line's
5338
+ // vertical range.
5339
+ function PosWithInfo(line, ch, outside, xRel) {
5340
+ var pos = Pos(line, ch)
5341
+ pos.xRel = xRel
5342
+ if (outside) { pos.outside = true }
5343
+ return pos
5344
+ }
 
 
 
 
 
 
 
 
5345
 
5346
+ // Compute the character position closest to the given coordinates.
5347
+ // Input must be lineSpace-local ("div" coordinate system).
5348
+ function coordsChar(cm, x, y) {
5349
+ var doc = cm.doc
5350
+ y += cm.display.viewOffset
5351
+ if (y < 0) { return PosWithInfo(doc.first, 0, true, -1) }
5352
+ var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1
5353
+ if (lineN > last)
5354
+ { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1) }
5355
+ if (x < 0) { x = 0 }
5356
+
5357
+ var lineObj = getLine(doc, lineN)
5358
+ for (;;) {
5359
+ var found = coordsCharInner(cm, lineObj, lineN, x, y)
5360
+ var merged = collapsedSpanAtEnd(lineObj)
5361
+ var mergedPos = merged && merged.find(0, true)
5362
+ if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
5363
+ { lineN = lineNo(lineObj = mergedPos.to.line) }
5364
+ else
5365
+ { return found }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5366
  }
5367
+ }
5368
 
5369
+ function coordsCharInner(cm, lineObj, lineNo, x, y) {
5370
+ var innerOff = y - heightAtLine(lineObj)
5371
+ var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth
5372
+ var preparedMeasure = prepareMeasureForLine(cm, lineObj)
5373
+
5374
+ function getX(ch) {
5375
+ var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure)
5376
+ wrongLine = true
5377
+ if (innerOff > sp.bottom) { return sp.left - adjust }
5378
+ else if (innerOff < sp.top) { return sp.left + adjust }
5379
+ else { wrongLine = false }
5380
+ return sp.left
5381
+ }
5382
+
5383
+ var bidi = getOrder(lineObj), dist = lineObj.text.length
5384
+ var from = lineLeft(lineObj), to = lineRight(lineObj)
5385
+ var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine
5386
+
5387
+ if (x > toX) { return PosWithInfo(lineNo, to, toOutside, 1) }
5388
+ // Do a binary search between these bounds.
5389
+ for (;;) {
5390
+ if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
5391
+ var ch = x < fromX || x - fromX <= toX - x ? from : to
5392
+ var outside = ch == from ? fromOutside : toOutside
5393
+ var xDiff = x - (ch == from ? fromX : toX)
5394
+ // This is a kludge to handle the case where the coordinates
5395
+ // are after a line-wrapped line. We should replace it with a
5396
+ // more general handling of cursor positions around line
5397
+ // breaks. (Issue #4078)
5398
+ if (toOutside && !bidi && !/\s/.test(lineObj.text.charAt(ch)) && xDiff > 0 &&
5399
+ ch < lineObj.text.length && preparedMeasure.view.measure.heights.length > 1) {
5400
+ var charSize = measureCharPrepared(cm, preparedMeasure, ch, "right")
5401
+ if (innerOff <= charSize.bottom && innerOff >= charSize.top && Math.abs(x - charSize.right) < xDiff) {
5402
+ outside = false
5403
+ ch++
5404
+ xDiff = x - charSize.right
5405
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5406
  }
5407
+ while (isExtendingChar(lineObj.text.charAt(ch))) { ++ch }
5408
+ var pos = PosWithInfo(lineNo, ch, outside, xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0)
5409
+ return pos
5410
  }
5411
+ var step = Math.ceil(dist / 2), middle = from + step
5412
+ if (bidi) {
5413
+ middle = from
5414
+ for (var i = 0; i < step; ++i) { middle = moveVisually(lineObj, middle, 1) }
 
 
 
 
 
5415
  }
5416
+ var middleX = getX(middle)
5417
+ if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) { toX += 1000; } dist = step}
5418
+ else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step}
5419
  }
5420
+ }
5421
 
5422
+ var measureText
5423
+ // Compute the default text height.
5424
+ function textHeight(display) {
5425
+ if (display.cachedTextHeight != null) { return display.cachedTextHeight }
5426
+ if (measureText == null) {
5427
+ measureText = elt("pre")
5428
+ // Measure a bunch of lines, for browsers that compute
5429
+ // fractional heights.
5430
+ for (var i = 0; i < 49; ++i) {
5431
+ measureText.appendChild(document.createTextNode("x"))
5432
+ measureText.appendChild(elt("br"))
5433
+ }
5434
+ measureText.appendChild(document.createTextNode("x"))
5435
+ }
5436
+ removeChildrenAndAdd(display.measure, measureText)
5437
+ var height = measureText.offsetHeight / 50
5438
+ if (height > 3) { display.cachedTextHeight = height }
5439
+ removeChildren(display.measure)
5440
+ return height || 1
5441
+ }
5442
 
5443
+ // Compute the default character width.
5444
+ function charWidth(display) {
5445
+ if (display.cachedCharWidth != null) { return display.cachedCharWidth }
5446
+ var anchor = elt("span", "xxxxxxxxxx")
5447
+ var pre = elt("pre", [anchor])
5448
+ removeChildrenAndAdd(display.measure, pre)
5449
+ var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10
5450
+ if (width > 2) { display.cachedCharWidth = width }
5451
+ return width || 10
5452
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5453
 
5454
+ // Do a bulk-read of the DOM positions and sizes needed to draw the
5455
+ // view, so that we don't interleave reading and writing to the DOM.
5456
+ function getDimensions(cm) {
5457
+ var d = cm.display, left = {}, width = {}
5458
+ var gutterLeft = d.gutters.clientLeft
5459
+ for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
5460
+ left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft
5461
+ width[cm.options.gutters[i]] = n.clientWidth
5462
+ }
5463
+ return {fixedPos: compensateForHScroll(d),
5464
+ gutterTotalWidth: d.gutters.offsetWidth,
5465
+ gutterLeft: left,
5466
+ gutterWidth: width,
5467
+ wrapperWidth: d.wrapper.clientWidth}
5468
+ }
5469
 
5470
+ // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
5471
+ // but using getBoundingClientRect to get a sub-pixel-accurate
5472
+ // result.
5473
+ function compensateForHScroll(display) {
5474
+ return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left
5475
+ }
5476
 
5477
+ // Returns a function that estimates the height of a line, to use as
5478
+ // first approximation until the line becomes visible (and is thus
5479
+ // properly measurable).
5480
+ function estimateHeight(cm) {
5481
+ var th = textHeight(cm.display), wrapping = cm.options.lineWrapping
5482
+ var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3)
5483
+ return function (line) {
5484
+ if (lineIsHidden(cm.doc, line)) { return 0 }
5485
+
5486
+ var widgetsHeight = 0
5487
+ if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {
5488
+ if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height }
5489
+ } }
5490
+
5491
+ if (wrapping)
5492
+ { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }
5493
+ else
5494
+ { return widgetsHeight + th }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5495
  }
5496
+ }
5497
 
5498
+ function estimateLineHeights(cm) {
5499
+ var doc = cm.doc, est = estimateHeight(cm)
5500
+ doc.iter(function (line) {
5501
+ var estHeight = est(line)
5502
+ if (estHeight != line.height) { updateLineHeight(line, estHeight) }
5503
+ })
5504
+ }
5505
 
5506
+ // Given a mouse event, find the corresponding position. If liberal
5507
+ // is false, it checks whether a gutter or scrollbar was clicked,
5508
+ // and returns null if it was. forRect is used by rectangular
5509
+ // selections, and tries to estimate a character position even for
5510
+ // coordinates beyond the right of the text.
5511
+ function posFromMouse(cm, e, liberal, forRect) {
5512
+ var display = cm.display
5513
+ if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null }
5514
+
5515
+ var x, y, space = display.lineSpace.getBoundingClientRect()
5516
+ // Fails unpredictably on IE[67] when mouse is dragged around quickly.
5517
+ try { x = e.clientX - space.left; y = e.clientY - space.top }
5518
+ catch (e) { return null }
5519
+ var coords = coordsChar(cm, x, y), line
5520
+ if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
5521
+ var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length
5522
+ coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff))
5523
+ }
5524
+ return coords
5525
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5526
 
5527
+ // Find the view element corresponding to a given line. Return null
5528
+ // when the line isn't visible.
5529
+ function findViewIndex(cm, n) {
5530
+ if (n >= cm.display.viewTo) { return null }
5531
+ n -= cm.display.viewFrom
5532
+ if (n < 0) { return null }
5533
+ var view = cm.display.view
5534
+ for (var i = 0; i < view.length; i++) {
5535
+ n -= view[i].size
5536
+ if (n < 0) { return i }
 
 
 
 
5537
  }
5538
+ }
5539
 
5540
+ function updateSelection(cm) {
5541
+ cm.display.input.showSelection(cm.display.input.prepareSelection())
5542
+ }
 
5543
 
5544
+ function prepareSelection(cm, primary) {
5545
+ var doc = cm.doc, result = {}
5546
+ var curFragment = result.cursors = document.createDocumentFragment()
5547
+ var selFragment = result.selection = document.createDocumentFragment()
5548
+
5549
+ for (var i = 0; i < doc.sel.ranges.length; i++) {
5550
+ if (primary === false && i == doc.sel.primIndex) { continue }
5551
+ var range = doc.sel.ranges[i]
5552
+ if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue }
5553
+ var collapsed = range.empty()
5554
+ if (collapsed || cm.options.showCursorWhenSelecting)
5555
+ { drawSelectionCursor(cm, range.head, curFragment) }
5556
+ if (!collapsed)
5557
+ { drawSelectionRange(cm, range, selFragment) }
5558
+ }
5559
+ return result
5560
+ }
5561
 
5562
+ // Draws a cursor for the given range
5563
+ function drawSelectionCursor(cm, head, output) {
5564
+ var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine)
 
 
 
 
 
 
 
 
 
 
 
 
5565
 
5566
+ var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"))
5567
+ cursor.style.left = pos.left + "px"
5568
+ cursor.style.top = pos.top + "px"
5569
+ cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"
5570
 
5571
+ if (pos.other) {
5572
+ // Secondary cursor, shown when on a 'jump' in bi-directional text
5573
+ var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"))
5574
+ otherCursor.style.display = ""
5575
+ otherCursor.style.left = pos.other.left + "px"
5576
+ otherCursor.style.top = pos.other.top + "px"
5577
+ otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"
5578
  }
5579
+ }
5580
 
5581
+ // Draws the given range as a highlighted selection
5582
+ function drawSelectionRange(cm, range, output) {
5583
+ var display = cm.display, doc = cm.doc
5584
+ var fragment = document.createDocumentFragment()
5585
+ var padding = paddingH(cm.display), leftSide = padding.left
5586
+ var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right
5587
+
5588
+ function add(left, top, width, bottom) {
5589
+ if (top < 0) { top = 0 }
5590
+ top = Math.round(top)
5591
+ bottom = Math.round(bottom)
5592
+ fragment.appendChild(elt("div", null, "CodeMirror-selected", ("position: absolute; left: " + left + "px;\n top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px;\n height: " + (bottom - top) + "px")))
5593
+ }
5594
+
5595
+ function drawForLine(line, fromArg, toArg) {
5596
+ var lineObj = getLine(doc, line)
5597
+ var lineLen = lineObj.text.length
5598
+ var start, end
5599
+ function coords(ch, bias) {
5600
+ return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
5601
+ }
5602
+
5603
+ iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir) {
5604
+ var leftPos = coords(from, "left"), rightPos, left, right
5605
+ if (from == to) {
5606
+ rightPos = leftPos
5607
+ left = right = leftPos.left
5608
+ } else {
5609
+ rightPos = coords(to - 1, "right")
5610
+ if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp }
5611
+ left = leftPos.left
5612
+ right = rightPos.right
5613
+ }
5614
+ if (fromArg == null && from == 0) { left = leftSide }
5615
+ if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
5616
+ add(left, leftPos.top, null, leftPos.bottom)
5617
+ left = leftSide
5618
+ if (leftPos.bottom < rightPos.top) { add(left, leftPos.bottom, null, rightPos.top) }
5619
+ }
5620
+ if (toArg == null && to == lineLen) { right = rightSide }
5621
+ if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
5622
+ { start = leftPos }
5623
+ if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
5624
+ { end = rightPos }
5625
+ if (left < leftSide + 1) { left = leftSide }
5626
+ add(left, rightPos.top, right - left, rightPos.bottom)
5627
+ })
5628
+ return {start: start, end: end}
5629
+ }
5630
+
5631
+ var sFrom = range.from(), sTo = range.to()
5632
+ if (sFrom.line == sTo.line) {
5633
+ drawForLine(sFrom.line, sFrom.ch, sTo.ch)
5634
+ } else {
5635
+ var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line)
5636
+ var singleVLine = visualLine(fromLine) == visualLine(toLine)
5637
+ var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end
5638
+ var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start
5639
+ if (singleVLine) {
5640
+ if (leftEnd.top < rightStart.top - 2) {
5641
+ add(leftEnd.right, leftEnd.top, null, leftEnd.bottom)
5642
+ add(leftSide, rightStart.top, rightStart.left, rightStart.bottom)
5643
+ } else {
5644
+ add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom)
5645
+ }
5646
+ }
5647
+ if (leftEnd.bottom < rightStart.top)
5648
+ { add(leftSide, leftEnd.bottom, null, rightStart.top) }
5649
  }
5650
 
5651
+ output.appendChild(fragment)
5652
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5653
 
5654
+ // Cursor-blinking
5655
+ function restartBlink(cm) {
5656
+ if (!cm.state.focused) { return }
5657
+ var display = cm.display
5658
+ clearInterval(display.blinker)
5659
+ var on = true
5660
+ display.cursorDiv.style.visibility = ""
5661
+ if (cm.options.cursorBlinkRate > 0)
5662
+ { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; },
5663
+ cm.options.cursorBlinkRate) }
5664
+ else if (cm.options.cursorBlinkRate < 0)
5665
+ { display.cursorDiv.style.visibility = "hidden" }
5666
+ }
5667
 
5668
+ function ensureFocus(cm) {
5669
+ if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm) }
5670
+ }
 
 
 
5671
 
5672
+ function delayBlurEvent(cm) {
5673
+ cm.state.delayingBlurEvent = true
5674
+ setTimeout(function () { if (cm.state.delayingBlurEvent) {
5675
+ cm.state.delayingBlurEvent = false
5676
+ onBlur(cm)
5677
+ } }, 100)
5678
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5679
 
5680
+ function onFocus(cm, e) {
5681
+ if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5682
 
5683
+ if (cm.options.readOnly == "nocursor") { return }
5684
+ if (!cm.state.focused) {
5685
+ signal(cm, "focus", cm, e)
5686
+ cm.state.focused = true
5687
+ addClass(cm.display.wrapper, "CodeMirror-focused")
5688
+ // This test prevents this from firing when a context
5689
+ // menu is closed (since the input reset would kill the
5690
+ // select-all detection hack)
5691
+ if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
5692
+ cm.display.input.reset()
5693
+ if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20) } // Issue #1730
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5694
  }
5695
+ cm.display.input.receivedFocus()
 
 
 
 
 
5696
  }
5697
+ restartBlink(cm)
5698
+ }
5699
+ function onBlur(cm, e) {
5700
+ if (cm.state.delayingBlurEvent) { return }
5701
 
5702
+ if (cm.state.focused) {
5703
+ signal(cm, "blur", cm, e)
5704
+ cm.state.focused = false
5705
+ rmClass(cm.display.wrapper, "CodeMirror-focused")
5706
+ }
5707
+ clearInterval(cm.display.blinker)
5708
+ setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false } }, 150)
5709
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5710
 
5711
+ // Re-align line numbers and gutter marks to compensate for
5712
+ // horizontal scrolling.
5713
+ function alignHorizontally(cm) {
5714
+ var display = cm.display, view = display.view
5715
+ if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
5716
+ var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft
5717
+ var gutterW = display.gutters.offsetWidth, left = comp + "px"
5718
+ for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {
5719
+ if (cm.options.fixedGutter) {
5720
+ if (view[i].gutter)
5721
+ { view[i].gutter.style.left = left }
5722
+ if (view[i].gutterBackground)
5723
+ { view[i].gutterBackground.style.left = left }
5724
+ }
5725
+ var align = view[i].alignable
5726
+ if (align) { for (var j = 0; j < align.length; j++)
5727
+ { align[j].style.left = left } }
5728
+ } }
5729
+ if (cm.options.fixedGutter)
5730
+ { display.gutters.style.left = (comp + gutterW) + "px" }
5731
+ }
5732
 
5733
+ // Used to ensure that the line number gutter is still the right
5734
+ // size for the current document size. Returns true when an update
5735
+ // is needed.
5736
+ function maybeUpdateLineNumberWidth(cm) {
5737
+ if (!cm.options.lineNumbers) { return false }
5738
+ var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display
5739
+ if (last.length != display.lineNumChars) {
5740
+ var test = display.measure.appendChild(elt("div", [elt("div", last)],
5741
+ "CodeMirror-linenumber CodeMirror-gutter-elt"))
5742
+ var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW
5743
+ display.lineGutter.style.width = ""
5744
+ display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1
5745
+ display.lineNumWidth = display.lineNumInnerWidth + padding
5746
+ display.lineNumChars = display.lineNumInnerWidth ? last.length : -1
5747
+ display.lineGutter.style.width = display.lineNumWidth + "px"
5748
+ updateGutterSpace(cm)
5749
+ return true
5750
+ }
5751
+ return false
5752
+ }
5753
 
5754
+ // Read the actual heights of the rendered lines, and update their
5755
+ // stored heights to match.
5756
+ function updateHeightsInViewport(cm) {
5757
+ var display = cm.display
5758
+ var prevBottom = display.lineDiv.offsetTop
5759
+ for (var i = 0; i < display.view.length; i++) {
5760
+ var cur = display.view[i], height = void 0
5761
+ if (cur.hidden) { continue }
5762
+ if (ie && ie_version < 8) {
5763
+ var bot = cur.node.offsetTop + cur.node.offsetHeight
5764
+ height = bot - prevBottom
5765
+ prevBottom = bot
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5766
  } else {
5767
+ var box = cur.node.getBoundingClientRect()
5768
+ height = box.bottom - box.top
5769
  }
5770
+ var diff = cur.line.height - height
5771
+ if (height < 2) { height = textHeight(display) }
5772
+ if (diff > .001 || diff < -.001) {
5773
+ updateLineHeight(cur.line, height)
5774
+ updateWidgetHeight(cur.line)
5775
+ if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
5776
+ { updateWidgetHeight(cur.rest[j]) } }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5777
  }
5778
+ }
5779
+ }
5780
 
5781
+ // Read and store the height of line widgets associated with the
5782
+ // given line.
5783
+ function updateWidgetHeight(line) {
5784
+ if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i)
5785
+ { line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight } }
5786
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5787
 
5788
+ // Compute the lines that are visible in a given viewport (defaults
5789
+ // the the current scroll position). viewport may contain top,
5790
+ // height, and ensure (see op.scrollToPos) properties.
5791
+ function visibleLines(display, doc, viewport) {
5792
+ var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop
5793
+ top = Math.floor(top - paddingTop(display))
5794
+ var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight
5795
+
5796
+ var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom)
5797
+ // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
5798
+ // forces those lines into the viewport (if possible).
5799
+ if (viewport && viewport.ensure) {
5800
+ var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line
5801
+ if (ensureFrom < from) {
5802
+ from = ensureFrom
5803
+ to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight)
5804
+ } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
5805
+ from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight)
5806
+ to = ensureTo
5807
+ }
5808
+ }
5809
+ return {from: from, to: Math.max(to, from + 1)}
5810
+ }
5811
 
5812
+ // Sync the scrollable area and scrollbars, ensure the viewport
5813
+ // covers the visible area.
5814
+ function setScrollTop(cm, val) {
5815
+ if (Math.abs(cm.doc.scrollTop - val) < 2) { return }
5816
+ cm.doc.scrollTop = val
5817
+ if (!gecko) { updateDisplaySimple(cm, {top: val}) }
5818
+ if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val }
5819
+ cm.display.scrollbars.setScrollTop(val)
5820
+ if (gecko) { updateDisplaySimple(cm) }
5821
+ startWorker(cm, 100)
5822
+ }
5823
+ // Sync scroller and scrollbar, ensure the gutter elements are
5824
+ // aligned.
5825
+ function setScrollLeft(cm, val, isScroller) {
5826
+ if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) { return }
5827
+ val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth)
5828
+ cm.doc.scrollLeft = val
5829
+ alignHorizontally(cm)
5830
+ if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val }
5831
+ cm.display.scrollbars.setScrollLeft(val)
5832
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
5833
 
5834
+ // Since the delta values reported on mouse wheel events are
5835
+ // unstandardized between browsers and even browser versions, and
5836
+ // generally horribly unpredictable, this code starts by measuring
5837
+ // the scroll effect that the first few mouse wheel events have,
5838
+ // and, from that, detects the way it can convert deltas to pixel
5839
+ // offsets afterwards.
5840
+ //
5841
+ // The reason we want to know the amount a wheel event will scroll
5842
+ // is that it gives us a chance to update the display before the
5843
+ // actual scrolling happens, reducing flickering.
5844
+
5845
+ var wheelSamples = 0;
5846
+ var wheelPixelsPerUnit = null;
5847
+ // Fill in a browser-detected starting value on browsers where we
5848
+ // know one. These don't have to be accurate -- the result of them
5849
+ // being wrong would just be a slight flicker on the first wheel
5850
+ // scroll (if it is large enough).
5851
+ if (ie) { wheelPixelsPerUnit = -.53 }
5852
+ else if (gecko) { wheelPixelsPerUnit = 15 }
5853
+ else if (chrome) { wheelPixelsPerUnit = -.7 }
5854
+ else if (safari) { wheelPixelsPerUnit = -1/3 }
5855
+
5856
+ function wheelEventDelta(e) {
5857
+ var dx = e.wheelDeltaX, dy = e.wheelDeltaY
5858
+ if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail }
5859
+ if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail }
5860
+ else if (dy == null) { dy = e.wheelDelta }
5861
+ return {x: dx, y: dy}
5862
+ }
5863
+ function wheelEventPixels(e) {
5864
+ var delta = wheelEventDelta(e)
5865
+ delta.x *= wheelPixelsPerUnit
5866
+ delta.y *= wheelPixelsPerUnit
5867
+ return delta
5868
+ }
5869
+
5870
+ function onScrollWheel(cm, e) {
5871
+ var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y
5872
+
5873
+ var display = cm.display, scroll = display.scroller
5874
+ // Quit if there's nothing to scroll here
5875
+ var canScrollX = scroll.scrollWidth > scroll.clientWidth
5876
+ var canScrollY = scroll.scrollHeight > scroll.clientHeight
5877
+ if (!(dx && canScrollX || dy && canScrollY)) { return }
5878
+
5879
+ // Webkit browsers on OS X abort momentum scrolls when the target
5880
+ // of the scroll event is removed from the scrollable element.
5881
+ // This hack (see related code in patchDisplay) makes sure the
5882
+ // element is kept around.
5883
+ if (dy && mac && webkit) {
5884
+ outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
5885
+ for (var i = 0; i < view.length; i++) {
5886
+ if (view[i].node == cur) {
5887
+ cm.display.currentWheelTarget = cur
5888
+ break outer
 
 
 
 
 
 
5889
  }
5890
  }
 
5891
  }
5892
  }
5893
 
5894
+ // On some browsers, horizontal scrolling will cause redraws to
5895
+ // happen before the gutter has been realigned, causing it to
5896
+ // wriggle around in a most unseemly way. When we have an
5897
+ // estimated pixels/delta value, we just handle horizontal
5898
+ // scrolling entirely here. It'll be slightly off from native, but
5899
+ // better than glitching out.
5900
+ if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
5901
+ if (dy && canScrollY)
5902
+ { setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))) }
5903
+ setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)))
5904
+ // Only prevent default scrolling if vertical scrolling is
5905
+ // actually possible. Otherwise, it causes vertical scroll
5906
+ // jitter on OSX trackpads when deltaX is small and deltaY
5907
+ // is large (issue #3579)
5908
+ if (!dy || (dy && canScrollY))
5909
+ { e_preventDefault(e) }
5910
+ display.wheelStartX = null // Abort measurement, if in progress
5911
+ return
5912
+ }
5913
+
5914
+ // 'Project' the visible viewport to cover the area that is being
5915
+ // scrolled into view (if we know enough to estimate it).
5916
+ if (dy && wheelPixelsPerUnit != null) {
5917
+ var pixels = dy * wheelPixelsPerUnit
5918
+ var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight
5919
+ if (pixels < 0) { top = Math.max(0, top + pixels - 50) }
5920
+ else { bot = Math.min(cm.doc.height, bot + pixels + 50) }
5921
+ updateDisplaySimple(cm, {top: top, bottom: bot})
5922
+ }
5923
+
5924
+ if (wheelSamples < 20) {
5925
+ if (display.wheelStartX == null) {
5926
+ display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop
5927
+ display.wheelDX = dx; display.wheelDY = dy
5928
+ setTimeout(function () {
5929
+ if (display.wheelStartX == null) { return }
5930
+ var movedX = scroll.scrollLeft - display.wheelStartX
5931
+ var movedY = scroll.scrollTop - display.wheelStartY
5932
+ var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
5933
+ (movedX && display.wheelDX && movedX / display.wheelDX)
5934
+ display.wheelStartX = display.wheelStartY = null
5935
+ if (!sample) { return }
5936
+ wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1)
5937
+ ++wheelSamples
5938
+ }, 200)
5939
+ } else {
5940
+ display.wheelDX += dx; display.wheelDY += dy
5941
  }
5942
  }
5943
+ }
5944
 
5945
+ // SCROLLBARS
 
 
 
 
 
 
 
 
 
 
5946
 
5947
+ // Prepare DOM reads needed to update the scrollbars. Done in one
5948
+ // shot to minimize update/measure roundtrips.
5949
+ function measureForScrollbars(cm) {
5950
+ var d = cm.display, gutterW = d.gutters.offsetWidth
5951
+ var docH = Math.round(cm.doc.height + paddingVert(cm.display))
5952
+ return {
5953
+ clientHeight: d.scroller.clientHeight,
5954
+ viewHeight: d.wrapper.clientHeight,
5955
+ scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
5956
+ viewWidth: d.wrapper.clientWidth,
5957
+ barLeft: cm.options.fixedGutter ? gutterW : 0,
5958
+ docHeight: docH,
5959
+ scrollHeight: docH + scrollGap(cm) + d.barHeight,
5960
+ nativeBarWidth: d.nativeBarWidth,
5961
+ gutterWidth: gutterW
5962
  }
5963
+ }
5964
 
5965
+ function NativeScrollbars(place, scroll, cm) {
5966
+ this.cm = cm
5967
+ var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar")
5968
+ var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar")
5969
+ place(vert); place(horiz)
5970
+
5971
+ on(vert, "scroll", function () {
5972
+ if (vert.clientHeight) { scroll(vert.scrollTop, "vertical") }
5973
+ })
5974
+ on(horiz, "scroll", function () {
5975
+ if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal") }
5976
+ })
5977
+
5978
+ this.checkedZeroWidth = false
5979
+ // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
5980
+ if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px" }
5981
+ }
 
 
 
 
 
 
5982
 
5983
+ NativeScrollbars.prototype = copyObj({
5984
+ update: function(measure) {
5985
+ var needsH = measure.scrollWidth > measure.clientWidth + 1
5986
+ var needsV = measure.scrollHeight > measure.clientHeight + 1
5987
+ var sWidth = measure.nativeBarWidth
5988
+
5989
+ if (needsV) {
5990
+ this.vert.style.display = "block"
5991
+ this.vert.style.bottom = needsH ? sWidth + "px" : "0"
5992
+ var totalHeight = measure.viewHeight - (needsH ? sWidth : 0)
5993
+ // A bug in IE8 can cause this value to be negative, so guard it.
5994
+ this.vert.firstChild.style.height =
5995
+ Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"
5996
+ } else {
5997
+ this.vert.style.display = ""
5998
+ this.vert.firstChild.style.height = "0"
5999
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6000
 
6001
+ if (needsH) {
6002
+ this.horiz.style.display = "block"
6003
+ this.horiz.style.right = needsV ? sWidth + "px" : "0"
6004
+ this.horiz.style.left = measure.barLeft + "px"
6005
+ var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0)
6006
+ this.horiz.firstChild.style.width =
6007
+ (measure.scrollWidth - measure.clientWidth + totalWidth) + "px"
6008
+ } else {
6009
+ this.horiz.style.display = ""
6010
+ this.horiz.firstChild.style.width = "0"
 
 
 
 
 
 
 
 
 
 
 
 
6011
  }
6012
 
6013
+ if (!this.checkedZeroWidth && measure.clientHeight > 0) {
6014
+ if (sWidth == 0) { this.zeroWidthHack() }
6015
+ this.checkedZeroWidth = true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6016
  }
6017
+
6018
+ return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
6019
+ },
6020
+ setScrollLeft: function(pos) {
6021
+ if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos }
6022
+ if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz) }
6023
+ },
6024
+ setScrollTop: function(pos) {
6025
+ if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos }
6026
+ if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert) }
6027
+ },
6028
+ zeroWidthHack: function() {
6029
+ var w = mac && !mac_geMountainLion ? "12px" : "18px"
6030
+ this.horiz.style.height = this.vert.style.width = w
6031
+ this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"
6032
+ this.disableHoriz = new Delayed
6033
+ this.disableVert = new Delayed
6034
+ },
6035
+ enableZeroWidthBar: function(bar, delay) {
6036
+ bar.style.pointerEvents = "auto"
6037
+ function maybeDisable() {
6038
+ // To find out whether the scrollbar is still visible, we
6039
+ // check whether the element under the pixel in the bottom
6040
+ // left corner of the scrollbar box is the scrollbar box
6041
+ // itself (when the bar is still visible) or its filler child
6042
+ // (when the bar is hidden). If it is still visible, we keep
6043
+ // it enabled, if it's hidden, we disable pointer events.
6044
+ var box = bar.getBoundingClientRect()
6045
+ var elt = document.elementFromPoint(box.left + 1, box.bottom - 1)
6046
+ if (elt != bar) { bar.style.pointerEvents = "none" }
6047
+ else { delay.set(1000, maybeDisable) }
6048
+ }
6049
+ delay.set(1000, maybeDisable)
6050
+ },
6051
+ clear: function() {
6052
+ var parent = this.horiz.parentNode
6053
+ parent.removeChild(this.horiz)
6054
+ parent.removeChild(this.vert)
6055
+ }
6056
+ }, NativeScrollbars.prototype)
6057
+
6058
+ function NullScrollbars() {}
6059
+
6060
+ NullScrollbars.prototype = copyObj({
6061
+ update: function() { return {bottom: 0, right: 0} },
6062
+ setScrollLeft: function() {},
6063
+ setScrollTop: function() {},
6064
+ clear: function() {}
6065
+ }, NullScrollbars.prototype)
6066
+
6067
+ function updateScrollbars(cm, measure) {
6068
+ if (!measure) { measure = measureForScrollbars(cm) }
6069
+ var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight
6070
+ updateScrollbarsInner(cm, measure)
6071
+ for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
6072
+ if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
6073
+ { updateHeightsInViewport(cm) }
6074
+ updateScrollbarsInner(cm, measureForScrollbars(cm))
6075
+ startWidth = cm.display.barWidth; startHeight = cm.display.barHeight
6076
  }
6077
+ }
6078
 
6079
+ // Re-synchronize the fake scrollbars with the actual size of the
6080
+ // content.
6081
+ function updateScrollbarsInner(cm, measure) {
6082
+ var d = cm.display
6083
+ var sizes = d.scrollbars.update(measure)
6084
+
6085
+ d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"
6086
+ d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"
6087
+ d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent"
6088
+
6089
+ if (sizes.right && sizes.bottom) {
6090
+ d.scrollbarFiller.style.display = "block"
6091
+ d.scrollbarFiller.style.height = sizes.bottom + "px"
6092
+ d.scrollbarFiller.style.width = sizes.right + "px"
6093
+ } else { d.scrollbarFiller.style.display = "" }
6094
+ if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
6095
+ d.gutterFiller.style.display = "block"
6096
+ d.gutterFiller.style.height = sizes.bottom + "px"
6097
+ d.gutterFiller.style.width = measure.gutterWidth + "px"
6098
+ } else { d.gutterFiller.style.display = "" }
6099
+ }
6100
 
6101
+ var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}
6102
+
6103
+ function initScrollbars(cm) {
6104
+ if (cm.display.scrollbars) {
6105
+ cm.display.scrollbars.clear()
6106
+ if (cm.display.scrollbars.addClass)
6107
+ { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass) }
6108
+ }
6109
+
6110
+ cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {
6111
+ cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller)
6112
+ // Prevent clicks in the scrollbars from killing focus
6113
+ on(node, "mousedown", function () {
6114
+ if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0) }
6115
+ })
6116
+ node.setAttribute("cm-not-content", "true")
6117
+ }, function (pos, axis) {
6118
+ if (axis == "horizontal") { setScrollLeft(cm, pos) }
6119
+ else { setScrollTop(cm, pos) }
6120
+ }, cm)
6121
+ if (cm.display.scrollbars.addClass)
6122
+ { addClass(cm.display.wrapper, cm.display.scrollbars.addClass) }
6123
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6124
 
6125
+ // SCROLLING THINGS INTO VIEW
 
 
 
6126
 
6127
+ // If an editor sits on the top or bottom of the window, partially
6128
+ // scrolled out of view, this ensures that the cursor is visible.
6129
+ function maybeScrollWindow(cm, coords) {
6130
+ if (signalDOMEvent(cm, "scrollCursorIntoView")) { return }
6131
 
6132
+ var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null
6133
+ if (coords.top + box.top < 0) { doScroll = true }
6134
+ else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false }
6135
+ if (doScroll != null && !phantom) {
6136
+ var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n top: " + (coords.top - display.viewOffset - paddingTop(cm.display)) + "px;\n height: " + (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px;\n left: " + (coords.left) + "px; width: 2px;"))
6137
+ cm.display.lineSpace.appendChild(scrollNode)
6138
+ scrollNode.scrollIntoView(doScroll)
6139
+ cm.display.lineSpace.removeChild(scrollNode)
6140
  }
6141
+ }
6142
 
6143
+ // Scroll a given position into view (immediately), verifying that
6144
+ // it actually became visible (as line heights are accurately
6145
+ // measured, the position of something may 'drift' during drawing).
6146
+ function scrollPosIntoView(cm, pos, end, margin) {
6147
+ if (margin == null) { margin = 0 }
6148
+ var coords
6149
+ for (var limit = 0; limit < 5; limit++) {
6150
+ var changed = false
6151
+ coords = cursorCoords(cm, pos)
6152
+ var endCoords = !end || end == pos ? coords : cursorCoords(cm, end)
6153
+ var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
6154
+ Math.min(coords.top, endCoords.top) - margin,
6155
+ Math.max(coords.left, endCoords.left),
6156
+ Math.max(coords.bottom, endCoords.bottom) + margin)
6157
+ var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft
6158
+ if (scrollPos.scrollTop != null) {
6159
+ setScrollTop(cm, scrollPos.scrollTop)
6160
+ if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true }
6161
+ }
6162
+ if (scrollPos.scrollLeft != null) {
6163
+ setScrollLeft(cm, scrollPos.scrollLeft)
6164
+ if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true }
6165
+ }
6166
+ if (!changed) { break }
6167
+ }
6168
+ return coords
6169
+ }
6170
 
6171
+ // Scroll a given set of coordinates into view (immediately).
6172
+ function scrollIntoView(cm, x1, y1, x2, y2) {
6173
+ var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2)
6174
+ if (scrollPos.scrollTop != null) { setScrollTop(cm, scrollPos.scrollTop) }
6175
+ if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft) }
6176
+ }
6177
+
6178
+ // Calculate a new scroll position needed to scroll the given
6179
+ // rectangle into view. Returns an object with scrollTop and
6180
+ // scrollLeft properties. When these are undefined, the
6181
+ // vertical/horizontal position does not need to be adjusted.
6182
+ function calculateScrollPos(cm, x1, y1, x2, y2) {
6183
+ var display = cm.display, snapMargin = textHeight(cm.display)
6184
+ if (y1 < 0) { y1 = 0 }
6185
+ var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop
6186
+ var screen = displayHeight(cm), result = {}
6187
+ if (y2 - y1 > screen) { y2 = y1 + screen }
6188
+ var docBottom = cm.doc.height + paddingVert(display)
6189
+ var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin
6190
+ if (y1 < screentop) {
6191
+ result.scrollTop = atTop ? 0 : y1
6192
+ } else if (y2 > screentop + screen) {
6193
+ var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen)
6194
+ if (newTop != screentop) { result.scrollTop = newTop }
6195
+ }
6196
+
6197
+ var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft
6198
+ var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0)
6199
+ var tooWide = x2 - x1 > screenw
6200
+ if (tooWide) { x2 = x1 + screenw }
6201
+ if (x1 < 10)
6202
+ { result.scrollLeft = 0 }
6203
+ else if (x1 < screenleft)
6204
+ { result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10)) }
6205
+ else if (x2 > screenw + screenleft - 3)
6206
+ { result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw }
6207
+ return result
6208
+ }
6209
+
6210
+ // Store a relative adjustment to the scroll position in the current
6211
+ // operation (to be applied when the operation finishes).
6212
+ function addToScrollPos(cm, left, top) {
6213
+ if (left != null || top != null) { resolveScrollToPos(cm) }
6214
+ if (left != null)
6215
+ { cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left }
6216
+ if (top != null)
6217
+ { cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top }
6218
+ }
6219
+
6220
+ // Make sure that at the end of the operation the current cursor is
6221
+ // shown.
6222
+ function ensureCursorVisible(cm) {
6223
+ resolveScrollToPos(cm)
6224
+ var cur = cm.getCursor(), from = cur, to = cur
6225
+ if (!cm.options.lineWrapping) {
6226
+ from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur
6227
+ to = Pos(cur.line, cur.ch + 1)
6228
  }
6229
+ cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true}
6230
+ }
6231
 
6232
+ // When an operation has its scrollToPos property set, and another
6233
+ // scroll action is applied before the end of the operation, this
6234
+ // 'simulates' scrolling that position into view in a cheap way, so
6235
+ // that the effect of intermediate scroll commands is not ignored.
6236
+ function resolveScrollToPos(cm) {
6237
+ var range = cm.curOp.scrollToPos
6238
+ if (range) {
6239
+ cm.curOp.scrollToPos = null
6240
+ var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to)
6241
+ var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),
6242
+ Math.min(from.top, to.top) - range.margin,
6243
+ Math.max(from.right, to.right),
6244
+ Math.max(from.bottom, to.bottom) + range.margin)
6245
+ cm.scrollTo(sPos.scrollLeft, sPos.scrollTop)
6246
  }
6247
+ }
6248
 
6249
+ // Operations are used to wrap a series of changes to the editor
6250
+ // state in such a way that each change won't have to update the
6251
+ // cursor and display (which would be awkward, slow, and
6252
+ // error-prone). Instead, display updates are batched and then all
6253
+ // combined and executed at once.
6254
+
6255
+ var nextOpId = 0
6256
+ // Start a new operation.
6257
+ function startOperation(cm) {
6258
+ cm.curOp = {
6259
+ cm: cm,
6260
+ viewChanged: false, // Flag that indicates that lines might need to be redrawn
6261
+ startHeight: cm.doc.height, // Used to detect need to update scrollbar
6262
+ forceUpdate: false, // Used to force a redraw
6263
+ updateInput: null, // Whether to reset the input textarea
6264
+ typing: false, // Whether this reset should be careful to leave existing text (for compositing)
6265
+ changeObjs: null, // Accumulated changes, for firing change events
6266
+ cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
6267
+ cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
6268
+ selectionChanged: false, // Whether the selection needs to be redrawn
6269
+ updateMaxLine: false, // Set when the widest line needs to be determined anew
6270
+ scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
6271
+ scrollToPos: null, // Used to scroll to a specific position
6272
+ focus: false,
6273
+ id: ++nextOpId // Unique ID
6274
+ }
6275
+ pushOperation(cm.curOp)
6276
+ }
6277
 
6278
+ // Finish an operation, updating the display and signalling delayed events
6279
+ function endOperation(cm) {
6280
+ var op = cm.curOp
6281
+ finishOperation(op, function (group) {
6282
+ for (var i = 0; i < group.ops.length; i++)
6283
+ { group.ops[i].cm.curOp = null }
6284
+ endOperations(group)
6285
+ })
6286
+ }
6287
 
6288
+ // The DOM updates done when an operation finishes are batched so
6289
+ // that the minimum number of relayouts are required.
6290
+ function endOperations(group) {
6291
+ var ops = group.ops
6292
+ for (var i = 0; i < ops.length; i++) // Read DOM
6293
+ { endOperation_R1(ops[i]) }
6294
+ for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)
6295
+ { endOperation_W1(ops[i$1]) }
6296
+ for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM
6297
+ { endOperation_R2(ops[i$2]) }
6298
+ for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)
6299
+ { endOperation_W2(ops[i$3]) }
6300
+ for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM
6301
+ { endOperation_finish(ops[i$4]) }
6302
+ }
6303
 
6304
+ function endOperation_R1(op) {
6305
+ var cm = op.cm, display = cm.display
6306
+ maybeClipScrollbars(cm)
6307
+ if (op.updateMaxLine) { findMaxLine(cm) }
6308
+
6309
+ op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
6310
+ op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
6311
+ op.scrollToPos.to.line >= display.viewTo) ||
6312
+ display.maxLineChanged && cm.options.lineWrapping
6313
+ op.update = op.mustUpdate &&
6314
+ new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate)
6315
+ }
6316
 
6317
+ function endOperation_W1(op) {
6318
+ op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update)
6319
+ }
 
6320
 
6321
+ function endOperation_R2(op) {
6322
+ var cm = op.cm, display = cm.display
6323
+ if (op.updatedDisplay) { updateHeightsInViewport(cm) }
 
 
 
 
 
 
 
6324
 
6325
+ op.barMeasure = measureForScrollbars(cm)
6326
 
6327
+ // If the max line changed since it was last measured, measure it,
6328
+ // and ensure the document's width matches it.
6329
+ // updateDisplay_W2 will use these properties to do the actual resizing
6330
+ if (display.maxLineChanged && !cm.options.lineWrapping) {
6331
+ op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3
6332
+ cm.display.sizerWidth = op.adjustWidthTo
6333
+ op.barMeasure.scrollWidth =
6334
+ Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth)
6335
+ op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6336
  }
 
 
6337
 
6338
+ if (op.updatedDisplay || op.selectionChanged)
6339
+ { op.preparedSelection = display.input.prepareSelection(op.focus) }
6340
+ }
 
 
 
 
 
6341
 
6342
+ function endOperation_W2(op) {
6343
+ var cm = op.cm
6344
 
6345
+ if (op.adjustWidthTo != null) {
6346
+ cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"
6347
+ if (op.maxScrollLeft < cm.doc.scrollLeft)
6348
+ { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true) }
6349
+ cm.display.maxLineChanged = false
 
 
6350
  }
6351
 
6352
+ var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus())
6353
+ if (op.preparedSelection)
6354
+ { cm.display.input.showSelection(op.preparedSelection, takeFocus) }
6355
+ if (op.updatedDisplay || op.startHeight != cm.doc.height)
6356
+ { updateScrollbars(cm, op.barMeasure) }
6357
+ if (op.updatedDisplay)
6358
+ { setDocumentHeight(cm, op.barMeasure) }
6359
 
6360
+ if (op.selectionChanged) { restartBlink(cm) }
6361
 
6362
+ if (cm.state.focused && op.updateInput)
6363
+ { cm.display.input.reset(op.typing) }
6364
+ if (takeFocus) { ensureFocus(op.cm) }
6365
+ }
 
 
 
6366
 
6367
+ function endOperation_finish(op) {
6368
+ var cm = op.cm, display = cm.display, doc = cm.doc
6369
+
6370
+ if (op.updatedDisplay) { postUpdateDisplay(cm, op.update) }
6371
+
6372
+ // Abort mouse wheel delta measurement, when scrolling explicitly
6373
+ if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
6374
+ { display.wheelStartX = display.wheelStartY = null }
6375
+
6376
+ // Propagate the scroll position to the actual DOM scroller
6377
+ if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
6378
+ doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop))
6379
+ display.scrollbars.setScrollTop(doc.scrollTop)
6380
+ display.scroller.scrollTop = doc.scrollTop
6381
+ }
6382
+ if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
6383
+ doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - display.scroller.clientWidth, op.scrollLeft))
6384
+ display.scrollbars.setScrollLeft(doc.scrollLeft)
6385
+ display.scroller.scrollLeft = doc.scrollLeft
6386
+ alignHorizontally(cm)
6387
+ }
6388
+ // If we need to scroll a specific position into view, do so.
6389
+ if (op.scrollToPos) {
6390
+ var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
6391
+ clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin)
6392
+ if (op.scrollToPos.isCursor && cm.state.focused) { maybeScrollWindow(cm, coords) }
6393
+ }
6394
+
6395
+ // Fire events for markers that are hidden/unidden by editing or
6396
+ // undoing
6397
+ var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers
6398
+ if (hidden) { for (var i = 0; i < hidden.length; ++i)
6399
+ { if (!hidden[i].lines.length) { signal(hidden[i], "hide") } } }
6400
+ if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1)
6401
+ { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide") } } }
6402
+
6403
+ if (display.wrapper.offsetHeight)
6404
+ { doc.scrollTop = cm.display.scroller.scrollTop }
6405
+
6406
+ // Fire change events, and delayed event handlers
6407
+ if (op.changeObjs)
6408
+ { signal(cm, "changes", cm, op.changeObjs) }
6409
+ if (op.update)
6410
+ { op.update.finish() }
6411
+ }
6412
 
6413
+ // Run the given function in an operation
6414
+ function runInOp(cm, f) {
6415
+ if (cm.curOp) { return f() }
6416
+ startOperation(cm)
6417
+ try { return f() }
6418
+ finally { endOperation(cm) }
6419
+ }
6420
+ // Wraps a function in an operation. Returns the wrapped function.
6421
+ function operation(cm, f) {
6422
+ return function() {
6423
+ if (cm.curOp) { return f.apply(cm, arguments) }
6424
+ startOperation(cm)
6425
+ try { return f.apply(cm, arguments) }
6426
+ finally { endOperation(cm) }
6427
  }
6428
+ }
6429
+ // Used to add methods to editor and doc instances, wrapping them in
6430
+ // operations.
6431
+ function methodOp(f) {
6432
+ return function() {
6433
+ if (this.curOp) { return f.apply(this, arguments) }
6434
+ startOperation(this)
6435
+ try { return f.apply(this, arguments) }
6436
+ finally { endOperation(this) }
6437
+ }
6438
+ }
6439
+ function docMethodOp(f) {
6440
+ return function() {
6441
+ var cm = this.cm
6442
+ if (!cm || cm.curOp) { return f.apply(this, arguments) }
6443
+ startOperation(cm)
6444
+ try { return f.apply(this, arguments) }
6445
+ finally { endOperation(cm) }
6446
  }
6447
+ }
6448
 
6449
+ // Updates the display.view data structure for a given change to the
6450
+ // document. From and to are in pre-change coordinates. Lendiff is
6451
+ // the amount of lines added or subtracted by the change. This is
6452
+ // used for changes that span multiple lines, or change the way
6453
+ // lines are divided into visual lines. regLineChange (below)
6454
+ // registers single-line changes.
6455
+ function regChange(cm, from, to, lendiff) {
6456
+ if (from == null) { from = cm.doc.first }
6457
+ if (to == null) { to = cm.doc.first + cm.doc.size }
6458
+ if (!lendiff) { lendiff = 0 }
6459
+
6460
+ var display = cm.display
6461
+ if (lendiff && to < display.viewTo &&
6462
+ (display.updateLineNumbers == null || display.updateLineNumbers > from))
6463
+ { display.updateLineNumbers = from }
6464
+
6465
+ cm.curOp.viewChanged = true
6466
+
6467
+ if (from >= display.viewTo) { // Change after
6468
+ if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
6469
+ { resetView(cm) }
6470
+ } else if (to <= display.viewFrom) { // Change before
6471
+ if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
6472
+ resetView(cm)
6473
+ } else {
6474
+ display.viewFrom += lendiff
6475
+ display.viewTo += lendiff
6476
+ }
6477
+ } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
6478
+ resetView(cm)
6479
+ } else if (from <= display.viewFrom) { // Top overlap
6480
+ var cut = viewCuttingPoint(cm, to, to + lendiff, 1)
6481
+ if (cut) {
6482
+ display.view = display.view.slice(cut.index)
6483
+ display.viewFrom = cut.lineN
6484
+ display.viewTo += lendiff
6485
+ } else {
6486
+ resetView(cm)
6487
+ }
6488
+ } else if (to >= display.viewTo) { // Bottom overlap
6489
+ var cut$1 = viewCuttingPoint(cm, from, from, -1)
6490
+ if (cut$1) {
6491
+ display.view = display.view.slice(0, cut$1.index)
6492
+ display.viewTo = cut$1.lineN
6493
+ } else {
6494
+ resetView(cm)
6495
+ }
6496
+ } else { // Gap in the middle
6497
+ var cutTop = viewCuttingPoint(cm, from, from, -1)
6498
+ var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1)
6499
+ if (cutTop && cutBot) {
6500
+ display.view = display.view.slice(0, cutTop.index)
6501
+ .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
6502
+ .concat(display.view.slice(cutBot.index))
6503
+ display.viewTo += lendiff
6504
+ } else {
6505
+ resetView(cm)
6506
  }
 
6507
  }
6508
 
6509
+ var ext = display.externalMeasured
6510
+ if (ext) {
6511
+ if (to < ext.lineN)
6512
+ { ext.lineN += lendiff }
6513
+ else if (from < ext.lineN + ext.size)
6514
+ { display.externalMeasured = null }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6515
  }
6516
+ }
6517
 
6518
+ // Register a change to a single line. Type must be one of "text",
6519
+ // "gutter", "class", "widget"
6520
+ function regLineChange(cm, line, type) {
6521
+ cm.curOp.viewChanged = true
6522
+ var display = cm.display, ext = cm.display.externalMeasured
6523
+ if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
6524
+ { display.externalMeasured = null }
6525
+
6526
+ if (line < display.viewFrom || line >= display.viewTo) { return }
6527
+ var lineView = display.view[findViewIndex(cm, line)]
6528
+ if (lineView.node == null) { return }
6529
+ var arr = lineView.changes || (lineView.changes = [])
6530
+ if (indexOf(arr, type) == -1) { arr.push(type) }
6531
+ }
6532
 
6533
+ // Clear the view.
6534
+ function resetView(cm) {
6535
+ cm.display.viewFrom = cm.display.viewTo = cm.doc.first
6536
+ cm.display.view = []
6537
+ cm.display.viewOffset = 0
6538
+ }
6539
 
6540
+ function viewCuttingPoint(cm, oldN, newN, dir) {
6541
+ var index = findViewIndex(cm, oldN), diff, view = cm.display.view
6542
+ if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
6543
+ { return {index: index, lineN: newN} }
6544
+ var n = cm.display.viewFrom
6545
+ for (var i = 0; i < index; i++)
6546
+ { n += view[i].size }
6547
+ if (n != oldN) {
6548
+ if (dir > 0) {
6549
+ if (index == view.length - 1) { return null }
6550
+ diff = (n + view[index].size) - oldN
6551
+ index++
6552
  } else {
6553
+ diff = n - oldN
6554
  }
6555
+ oldN += diff; newN += diff
6556
  }
6557
+ while (visualLineNo(cm.doc, newN) != newN) {
6558
+ if (index == (dir < 0 ? 0 : view.length - 1)) { return null }
6559
+ newN += dir * view[index - (dir < 0 ? 1 : 0)].size
6560
+ index += dir
6561
+ }
6562
+ return {index: index, lineN: newN}
6563
+ }
6564
 
6565
+ // Force the view to cover a given range, adding empty view element
6566
+ // or clipping off existing ones as needed.
6567
+ function adjustView(cm, from, to) {
6568
+ var display = cm.display, view = display.view
6569
+ if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
6570
+ display.view = buildViewArray(cm, from, to)
6571
+ display.viewFrom = from
6572
+ } else {
6573
+ if (display.viewFrom > from)
6574
+ { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view) }
6575
+ else if (display.viewFrom < from)
6576
+ { display.view = display.view.slice(findViewIndex(cm, from)) }
6577
+ display.viewFrom = from
6578
+ if (display.viewTo < to)
6579
+ { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)) }
6580
+ else if (display.viewTo > to)
6581
+ { display.view = display.view.slice(0, findViewIndex(cm, to)) }
6582
+ }
6583
+ display.viewTo = to
6584
+ }
6585
 
6586
+ // Count the number of lines in the view whose DOM representation is
6587
+ // out of date (or nonexistent).
6588
+ function countDirtyView(cm) {
6589
+ var view = cm.display.view, dirty = 0
6590
+ for (var i = 0; i < view.length; i++) {
6591
+ var lineView = view[i]
6592
+ if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty }
6593
  }
6594
+ return dirty
6595
+ }
6596
 
6597
+ // HIGHLIGHT WORKER
 
 
 
 
 
6598
 
6599
+ function startWorker(cm, time) {
6600
+ if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)
6601
+ { cm.state.highlight.set(time, bind(highlightWorker, cm)) }
6602
+ }
 
 
 
 
 
6603
 
6604
+ function highlightWorker(cm) {
6605
+ var doc = cm.doc
6606
+ if (doc.frontier < doc.first) { doc.frontier = doc.first }
6607
+ if (doc.frontier >= cm.display.viewTo) { return }
6608
+ var end = +new Date + cm.options.workTime
6609
+ var state = copyState(doc.mode, getStateBefore(cm, doc.frontier))
6610
+ var changedLines = []
6611
+
6612
+ doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {
6613
+ if (doc.frontier >= cm.display.viewFrom) { // Visible
6614
+ var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength
6615
+ var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true)
6616
+ line.styles = highlighted.styles
6617
+ var oldCls = line.styleClasses, newCls = highlighted.classes
6618
+ if (newCls) { line.styleClasses = newCls }
6619
+ else if (oldCls) { line.styleClasses = null }
6620
+ var ischange = !oldStyles || oldStyles.length != line.styles.length ||
6621
+ oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass)
6622
+ for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i] }
6623
+ if (ischange) { changedLines.push(doc.frontier) }
6624
+ line.stateAfter = tooLong ? state : copyState(doc.mode, state)
6625
+ } else {
6626
+ if (line.text.length <= cm.options.maxHighlightLength)
6627
+ { processLine(cm, line.text, state) }
6628
+ line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null
6629
+ }
6630
+ ++doc.frontier
6631
+ if (+new Date > end) {
6632
+ startWorker(cm, cm.options.workDelay)
6633
+ return true
6634
+ }
6635
+ })
6636
+ if (changedLines.length) { runInOp(cm, function () {
6637
+ for (var i = 0; i < changedLines.length; i++)
6638
+ { regLineChange(cm, changedLines[i], "text") }
6639
+ }) }
6640
+ }
6641
 
6642
+ // DISPLAY DRAWING
6643
+
6644
+ function DisplayUpdate(cm, viewport, force) {
6645
+ var display = cm.display
6646
+
6647
+ this.viewport = viewport
6648
+ // Store some values that we'll need later (but don't want to force a relayout for)
6649
+ this.visible = visibleLines(display, cm.doc, viewport)
6650
+ this.editorIsHidden = !display.wrapper.offsetWidth
6651
+ this.wrapperHeight = display.wrapper.clientHeight
6652
+ this.wrapperWidth = display.wrapper.clientWidth
6653
+ this.oldDisplayWidth = displayWidth(cm)
6654
+ this.force = force
6655
+ this.dims = getDimensions(cm)
6656
+ this.events = []
6657
+ }
6658
 
6659
+ DisplayUpdate.prototype.signal = function(emitter, type) {
6660
+ if (hasHandler(emitter, type))
6661
+ { this.events.push(arguments) }
6662
+ }
6663
+ DisplayUpdate.prototype.finish = function() {
6664
+ var this$1 = this;
6665
 
6666
+ for (var i = 0; i < this.events.length; i++)
6667
+ { signal.apply(null, this$1.events[i]) }
6668
+ }
 
 
 
 
6669
 
6670
+ function maybeClipScrollbars(cm) {
6671
+ var display = cm.display
6672
+ if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
6673
+ display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth
6674
+ display.heightForcer.style.height = scrollGap(cm) + "px"
6675
+ display.sizer.style.marginBottom = -display.nativeBarWidth + "px"
6676
+ display.sizer.style.borderRightWidth = scrollGap(cm) + "px"
6677
+ display.scrollbarsClipped = true
6678
+ }
6679
+ }
6680
 
6681
+ // Does the actual updating of the line display. Bails out
6682
+ // (returning false) when there is nothing to be done and forced is
6683
+ // false.
6684
+ function updateDisplayIfNeeded(cm, update) {
6685
+ var display = cm.display, doc = cm.doc
6686
+
6687
+ if (update.editorIsHidden) {
6688
+ resetView(cm)
6689
+ return false
6690
+ }
6691
+
6692
+ // Bail out if the visible area is already rendered and nothing changed.
6693
+ if (!update.force &&
6694
+ update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
6695
+ (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
6696
+ display.renderedView == display.view && countDirtyView(cm) == 0)
6697
+ { return false }
6698
+
6699
+ if (maybeUpdateLineNumberWidth(cm)) {
6700
+ resetView(cm)
6701
+ update.dims = getDimensions(cm)
6702
+ }
6703
+
6704
+ // Compute a suitable new viewport (from & to)
6705
+ var end = doc.first + doc.size
6706
+ var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first)
6707
+ var to = Math.min(end, update.visible.to + cm.options.viewportMargin)
6708
+ if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom) }
6709
+ if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo) }
6710
+ if (sawCollapsedSpans) {
6711
+ from = visualLineNo(cm.doc, from)
6712
+ to = visualLineEndNo(cm.doc, to)
6713
+ }
6714
+
6715
+ var different = from != display.viewFrom || to != display.viewTo ||
6716
+ display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth
6717
+ adjustView(cm, from, to)
6718
+
6719
+ display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom))
6720
+ // Position the mover div to align with the current scroll position
6721
+ cm.display.mover.style.top = display.viewOffset + "px"
6722
+
6723
+ var toUpdate = countDirtyView(cm)
6724
+ if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
6725
+ (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
6726
+ { return false }
6727
+
6728
+ // For big changes, we hide the enclosing element during the
6729
+ // update, since that speeds up the operations on most browsers.
6730
+ var focused = activeElt()
6731
+ if (toUpdate > 4) { display.lineDiv.style.display = "none" }
6732
+ patchDisplay(cm, display.updateLineNumbers, update.dims)
6733
+ if (toUpdate > 4) { display.lineDiv.style.display = "" }
6734
+ display.renderedView = display.view
6735
+ // There might have been a widget with a focused element that got
6736
+ // hidden or updated, if so re-focus it.
6737
+ if (focused && activeElt() != focused && focused.offsetHeight) { focused.focus() }
6738
+
6739
+ // Prevent selection and cursors from interfering with the scroll
6740
+ // width and height.
6741
+ removeChildren(display.cursorDiv)
6742
+ removeChildren(display.selectionDiv)
6743
+ display.gutters.style.height = display.sizer.style.minHeight = 0
6744
+
6745
+ if (different) {
6746
+ display.lastWrapHeight = update.wrapperHeight
6747
+ display.lastWrapWidth = update.wrapperWidth
6748
+ startWorker(cm, 400)
6749
+ }
6750
+
6751
+ display.updateLineNumbers = null
6752
+
6753
+ return true
6754
+ }
6755
 
6756
+ function postUpdateDisplay(cm, update) {
6757
+ var viewport = update.viewport
6758
+
6759
+ for (var first = true;; first = false) {
6760
+ if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
6761
+ // Clip forced viewport to actual scrollable area.
6762
+ if (viewport && viewport.top != null)
6763
+ { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)} }
6764
+ // Updated line heights might result in the drawn area not
6765
+ // actually covering the viewport. Keep looping until it does.
6766
+ update.visible = visibleLines(cm.display, cm.doc, viewport)
6767
+ if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
6768
+ { break }
6769
+ }
6770
+ if (!updateDisplayIfNeeded(cm, update)) { break }
6771
+ updateHeightsInViewport(cm)
6772
+ var barMeasure = measureForScrollbars(cm)
6773
+ updateSelection(cm)
6774
+ updateScrollbars(cm, barMeasure)
6775
+ setDocumentHeight(cm, barMeasure)
6776
+ }
6777
+
6778
+ update.signal(cm, "update", cm)
6779
+ if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
6780
+ update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo)
6781
+ cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo
6782
  }
6783
+ }
6784
 
6785
+ function updateDisplaySimple(cm, viewport) {
6786
+ var update = new DisplayUpdate(cm, viewport)
6787
+ if (updateDisplayIfNeeded(cm, update)) {
6788
+ updateHeightsInViewport(cm)
6789
+ postUpdateDisplay(cm, update)
6790
+ var barMeasure = measureForScrollbars(cm)
6791
+ updateSelection(cm)
6792
+ updateScrollbars(cm, barMeasure)
6793
+ setDocumentHeight(cm, barMeasure)
6794
+ update.finish()
 
 
 
 
6795
  }
6796
+ }
6797
 
6798
+ // Sync the actual display DOM structure with display.view, removing
6799
+ // nodes for lines that are no longer in view, and creating the ones
6800
+ // that are not there yet, and updating the ones that are out of
6801
+ // date.
6802
+ function patchDisplay(cm, updateNumbersFrom, dims) {
6803
+ var display = cm.display, lineNumbers = cm.options.lineNumbers
6804
+ var container = display.lineDiv, cur = container.firstChild
6805
+
6806
+ function rm(node) {
6807
+ var next = node.nextSibling
6808
+ // Works around a throw-scroll bug in OS X Webkit
6809
+ if (webkit && mac && cm.display.currentWheelTarget == node)
6810
+ { node.style.display = "none" }
6811
+ else
6812
+ { node.parentNode.removeChild(node) }
6813
+ return next
6814
+ }
6815
+
6816
+ var view = display.view, lineN = display.viewFrom
6817
+ // Loop over the elements in the view, syncing cur (the DOM nodes
6818
+ // in display.lineDiv) with the view as we go.
6819
+ for (var i = 0; i < view.length; i++) {
6820
+ var lineView = view[i]
6821
+ if (lineView.hidden) {
6822
+ } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
6823
+ var node = buildLineElement(cm, lineView, lineN, dims)
6824
+ container.insertBefore(node, cur)
6825
+ } else { // Already drawn
6826
+ while (cur != lineView.node) { cur = rm(cur) }
6827
+ var updateNumber = lineNumbers && updateNumbersFrom != null &&
6828
+ updateNumbersFrom <= lineN && lineView.lineNumber
6829
+ if (lineView.changes) {
6830
+ if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false }
6831
+ updateLineForChanges(cm, lineView, lineN, dims)
6832
+ }
6833
+ if (updateNumber) {
6834
+ removeChildren(lineView.lineNumber)
6835
+ lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)))
6836
+ }
6837
+ cur = lineView.node.nextSibling
6838
+ }
6839
+ lineN += lineView.size
6840
+ }
6841
+ while (cur) { cur = rm(cur) }
6842
+ }
6843
 
6844
+ function updateGutterSpace(cm) {
6845
+ var width = cm.display.gutters.offsetWidth
6846
+ cm.display.sizer.style.marginLeft = width + "px"
6847
+ }
 
6848
 
6849
+ function setDocumentHeight(cm, measure) {
6850
+ cm.display.sizer.style.minHeight = measure.docHeight + "px"
6851
+ cm.display.heightForcer.style.top = measure.docHeight + "px"
6852
+ cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px"
6853
+ }
 
 
 
 
 
 
 
6854
 
6855
+ // Rebuild the gutter elements, ensure the margin to the left of the
6856
+ // code matches their width.
6857
+ function updateGutters(cm) {
6858
+ var gutters = cm.display.gutters, specs = cm.options.gutters
6859
+ removeChildren(gutters)
6860
+ var i = 0
6861
+ for (; i < specs.length; ++i) {
6862
+ var gutterClass = specs[i]
6863
+ var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass))
6864
+ if (gutterClass == "CodeMirror-linenumbers") {
6865
+ cm.display.lineGutter = gElt
6866
+ gElt.style.width = (cm.display.lineNumWidth || 1) + "px"
6867
+ }
6868
+ }
6869
+ gutters.style.display = i ? "" : "none"
6870
+ updateGutterSpace(cm)
6871
+ }
6872
 
6873
+ // Make sure the gutters options contains the element
6874
+ // "CodeMirror-linenumbers" when the lineNumbers option is true.
6875
+ function setGuttersForLineNumbers(options) {
6876
+ var found = indexOf(options.gutters, "CodeMirror-linenumbers")
6877
+ if (found == -1 && options.lineNumbers) {
6878
+ options.gutters = options.gutters.concat(["CodeMirror-linenumbers"])
6879
+ } else if (found > -1 && !options.lineNumbers) {
6880
+ options.gutters = options.gutters.slice(0)
6881
+ options.gutters.splice(found, 1)
6882
  }
6883
+ }
6884
 
6885
+ // Selection objects are immutable. A new one is created every time
6886
+ // the selection changes. A selection is one or more non-overlapping
6887
+ // (and non-touching) ranges, sorted, and an integer that indicates
6888
+ // which one is the primary selection (the one that's scrolled into
6889
+ // view, that getCursor returns, etc).
6890
+ function Selection(ranges, primIndex) {
6891
+ this.ranges = ranges
6892
+ this.primIndex = primIndex
6893
+ }
6894
 
6895
+ Selection.prototype = {
6896
+ primary: function() { return this.ranges[this.primIndex] },
6897
+ equals: function(other) {
6898
+ var this$1 = this;
6899
+
6900
+ if (other == this) { return true }
6901
+ if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }
6902
+ for (var i = 0; i < this.ranges.length; i++) {
6903
+ var here = this$1.ranges[i], there = other.ranges[i]
6904
+ if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) { return false }
6905
  }
6906
+ return true
6907
+ },
6908
+ deepCopy: function() {
6909
+ var this$1 = this;
6910
 
6911
+ var out = []
6912
+ for (var i = 0; i < this.ranges.length; i++)
6913
+ { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)) }
6914
+ return new Selection(out, this.primIndex)
6915
+ },
6916
+ somethingSelected: function() {
6917
+ var this$1 = this;
6918
 
6919
+ for (var i = 0; i < this.ranges.length; i++)
6920
+ { if (!this$1.ranges[i].empty()) { return true } }
6921
+ return false
6922
+ },
6923
+ contains: function(pos, end) {
6924
+ var this$1 = this;
6925
 
6926
+ if (!end) { end = pos }
6927
+ for (var i = 0; i < this.ranges.length; i++) {
6928
+ var range = this$1.ranges[i]
6929
+ if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
6930
+ { return i }
 
 
 
 
 
 
6931
  }
6932
+ return -1
6933
+ }
6934
+ }
6935
 
6936
+ function Range(anchor, head) {
6937
+ this.anchor = anchor; this.head = head
6938
+ }
6939
 
6940
+ Range.prototype = {
6941
+ from: function() { return minPos(this.anchor, this.head) },
6942
+ to: function() { return maxPos(this.anchor, this.head) },
6943
+ empty: function() {
6944
+ return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6945
  }
6946
+ }
6947
 
6948
+ // Take an unsorted, potentially overlapping set of ranges, and
6949
+ // build a selection out of it. 'Consumes' ranges array (modifying
6950
+ // it).
6951
+ function normalizeSelection(ranges, primIndex) {
6952
+ var prim = ranges[primIndex]
6953
+ ranges.sort(function (a, b) { return cmp(a.from(), b.from()); })
6954
+ primIndex = indexOf(ranges, prim)
6955
+ for (var i = 1; i < ranges.length; i++) {
6956
+ var cur = ranges[i], prev = ranges[i - 1]
6957
+ if (cmp(prev.to(), cur.from()) >= 0) {
6958
+ var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to())
6959
+ var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head
6960
+ if (i <= primIndex) { --primIndex }
6961
+ ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to))
6962
+ }
6963
+ }
6964
+ return new Selection(ranges, primIndex)
6965
+ }
6966
+
6967
+ function simpleSelection(anchor, head) {
6968
+ return new Selection([new Range(anchor, head || anchor)], 0)
6969
+ }
6970
+
6971
+ // Compute the position of the end of a change (its 'to' property
6972
+ // refers to the pre-change end).
6973
+ function changeEnd(change) {
6974
+ if (!change.text) { return change.to }
6975
+ return Pos(change.from.line + change.text.length - 1,
6976
+ lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0))
6977
+ }
6978
+
6979
+ // Adjust a position to refer to the post-change position of the
6980
+ // same text, or the end of the change if the change covers it.
6981
+ function adjustForChange(pos, change) {
6982
+ if (cmp(pos, change.from) < 0) { return pos }
6983
+ if (cmp(pos, change.to) <= 0) { return changeEnd(change) }
6984
+
6985
+ var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch
6986
+ if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch }
6987
+ return Pos(line, ch)
6988
+ }
6989
+
6990
+ function computeSelAfterChange(doc, change) {
6991
+ var out = []
6992
+ for (var i = 0; i < doc.sel.ranges.length; i++) {
6993
+ var range = doc.sel.ranges[i]
6994
+ out.push(new Range(adjustForChange(range.anchor, change),
6995
+ adjustForChange(range.head, change)))
6996
+ }
6997
+ return normalizeSelection(out, doc.sel.primIndex)
6998
+ }
6999
+
7000
+ function offsetPos(pos, old, nw) {
7001
+ if (pos.line == old.line)
7002
+ { return Pos(nw.line, pos.ch - old.ch + nw.ch) }
7003
+ else
7004
+ { return Pos(nw.line + (pos.line - old.line), pos.ch) }
7005
+ }
7006
+
7007
+ // Used by replaceSelections to allow moving the selection to the
7008
+ // start or around the replaced test. Hint may be "start" or "around".
7009
+ function computeReplacedSel(doc, changes, hint) {
7010
+ var out = []
7011
+ var oldPrev = Pos(doc.first, 0), newPrev = oldPrev
7012
+ for (var i = 0; i < changes.length; i++) {
7013
+ var change = changes[i]
7014
+ var from = offsetPos(change.from, oldPrev, newPrev)
7015
+ var to = offsetPos(changeEnd(change), oldPrev, newPrev)
7016
+ oldPrev = change.to
7017
+ newPrev = to
7018
+ if (hint == "around") {
7019
+ var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0
7020
+ out[i] = new Range(inv ? to : from, inv ? from : to)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7021
  } else {
7022
+ out[i] = new Range(from, from)
 
 
 
 
 
 
 
 
 
7023
  }
7024
  }
7025
+ return new Selection(out, doc.sel.primIndex)
7026
+ }
7027
 
7028
+ // Used to get the editor into a consistent state again when options change.
7029
+
7030
+ function loadMode(cm) {
7031
+ cm.doc.mode = getMode(cm.options, cm.doc.modeOption)
7032
+ resetModeState(cm)
7033
+ }
7034
+
7035
+ function resetModeState(cm) {
7036
+ cm.doc.iter(function (line) {
7037
+ if (line.stateAfter) { line.stateAfter = null }
7038
+ if (line.styles) { line.styles = null }
7039
+ })
7040
+ cm.doc.frontier = cm.doc.first
7041
+ startWorker(cm, 100)
7042
+ cm.state.modeGen++
7043
+ if (cm.curOp) { regChange(cm) }
7044
+ }
7045
+
7046
+ // DOCUMENT DATA STRUCTURE
7047
+
7048
+ // By default, updates that start and end at the beginning of a line
7049
+ // are treated specially, in order to make the association of line
7050
+ // widgets and marker elements with the text behave more intuitive.
7051
+ function isWholeLineUpdate(doc, change) {
7052
+ return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
7053
+ (!doc.cm || doc.cm.options.wholeLineUpdateBefore)
7054
+ }
7055
+
7056
+ // Perform a change on the document data structure.
7057
+ function updateDoc(doc, change, markedSpans, estimateHeight) {
7058
+ function spansFor(n) {return markedSpans ? markedSpans[n] : null}
7059
+ function update(line, text, spans) {
7060
+ updateLine(line, text, spans, estimateHeight)
7061
+ signalLater(line, "change", line, change)
7062
+ }
7063
+ function linesFor(start, end) {
7064
+ var result = []
7065
+ for (var i = start; i < end; ++i)
7066
+ { result.push(new Line(text[i], spansFor(i), estimateHeight)) }
7067
+ return result
7068
  }
7069
 
7070
+ var from = change.from, to = change.to, text = change.text
7071
+ var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line)
7072
+ var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line
7073
+
7074
+ // Adjust the line structure
7075
+ if (change.full) {
7076
+ doc.insert(0, linesFor(0, text.length))
7077
+ doc.remove(text.length, doc.size - text.length)
7078
+ } else if (isWholeLineUpdate(doc, change)) {
7079
+ // This is a whole-line replace. Treated specially to make
7080
+ // sure line objects move the way they are supposed to.
7081
+ var added = linesFor(0, text.length - 1)
7082
+ update(lastLine, lastLine.text, lastSpans)
7083
+ if (nlines) { doc.remove(from.line, nlines) }
7084
+ if (added.length) { doc.insert(from.line, added) }
7085
+ } else if (firstLine == lastLine) {
7086
+ if (text.length == 1) {
7087
+ update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans)
7088
+ } else {
7089
+ var added$1 = linesFor(1, text.length - 1)
7090
+ added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight))
7091
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0))
7092
+ doc.insert(from.line + 1, added$1)
7093
+ }
7094
+ } else if (text.length == 1) {
7095
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0))
7096
+ doc.remove(from.line + 1, nlines)
7097
+ } else {
7098
+ update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0))
7099
+ update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans)
7100
+ var added$2 = linesFor(1, text.length - 1)
7101
+ if (nlines > 1) { doc.remove(from.line + 1, nlines - 1) }
7102
+ doc.insert(from.line + 1, added$2)
7103
+ }
7104
+
7105
+ signalLater(doc, "change", doc, change)
7106
+ }
7107
+
7108
+ // Call f for all linked documents.
7109
+ function linkedDocs(doc, f, sharedHistOnly) {
7110
+ function propagate(doc, skip, sharedHist) {
7111
+ if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) {
7112
+ var rel = doc.linked[i]
7113
+ if (rel.doc == skip) { continue }
7114
+ var shared = sharedHist && rel.sharedHist
7115
+ if (sharedHistOnly && !shared) { continue }
7116
+ f(rel.doc, shared)
7117
+ propagate(rel.doc, doc, shared)
7118
+ } }
7119
+ }
7120
+ propagate(doc, null, true)
7121
+ }
7122
+
7123
+ // Attach a document to an editor.
7124
+ function attachDoc(cm, doc) {
7125
+ if (doc.cm) { throw new Error("This document is already in use.") }
7126
+ cm.doc = doc
7127
+ doc.cm = cm
7128
+ estimateLineHeights(cm)
7129
+ loadMode(cm)
7130
+ if (!cm.options.lineWrapping) { findMaxLine(cm) }
7131
+ cm.options.mode = doc.modeOption
7132
+ regChange(cm)
7133
+ }
7134
+
7135
+ function History(startGen) {
7136
+ // Arrays of change events and selections. Doing something adds an
7137
+ // event to done and clears undo. Undoing moves events from done
7138
+ // to undone, redoing moves them in the other direction.
7139
+ this.done = []; this.undone = []
7140
+ this.undoDepth = Infinity
7141
+ // Used to track when changes can be merged into a single undo
7142
+ // event
7143
+ this.lastModTime = this.lastSelTime = 0
7144
+ this.lastOp = this.lastSelOp = null
7145
+ this.lastOrigin = this.lastSelOrigin = null
7146
+ // Used by the isClean() method
7147
+ this.generation = this.maxGeneration = startGen || 1
7148
+ }
7149
+
7150
+ // Create a history change event from an updateDoc-style change
7151
+ // object.
7152
+ function historyChangeFromChange(doc, change) {
7153
+ var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)}
7154
+ attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1)
7155
+ linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true)
7156
+ return histChange
7157
+ }
7158
+
7159
+ // Pop all selection events off the end of a history array. Stop at
7160
+ // a change event.
7161
+ function clearSelectionEvents(array) {
7162
+ while (array.length) {
7163
+ var last = lst(array)
7164
+ if (last.ranges) { array.pop() }
7165
+ else { break }
7166
  }
7167
+ }
7168
 
7169
+ // Find the top change event in the history. Pop off selection
7170
+ // events that are in the way.
7171
+ function lastChangeEvent(hist, force) {
7172
+ if (force) {
7173
+ clearSelectionEvents(hist.done)
7174
+ return lst(hist.done)
7175
+ } else if (hist.done.length && !lst(hist.done).ranges) {
7176
+ return lst(hist.done)
7177
+ } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
7178
+ hist.done.pop()
7179
+ return lst(hist.done)
7180
+ }
7181
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7182
 
7183
+ // Register a change in the history. Merges changes that are within
7184
+ // a single operation, or are close together with an origin that
7185
+ // allows merging (starting with "+") into a single event.
7186
+ function addChangeToHistory(doc, change, selAfter, opId) {
7187
+ var hist = doc.history
7188
+ hist.undone.length = 0
7189
+ var time = +new Date, cur
7190
+ var last
7191
+
7192
+ if ((hist.lastOp == opId ||
7193
+ hist.lastOrigin == change.origin && change.origin &&
7194
+ ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
7195
+ change.origin.charAt(0) == "*")) &&
7196
+ (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
7197
+ // Merge this change into the last event
7198
+ last = lst(cur.changes)
7199
+ if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
7200
+ // Optimized case for simple insertion -- don't want to add
7201
+ // new changesets for every character typed
7202
+ last.to = changeEnd(change)
7203
+ } else {
7204
+ // Add new sub-event
7205
+ cur.changes.push(historyChangeFromChange(doc, change))
7206
+ }
7207
+ } else {
7208
+ // Can not be merged, start a new event.
7209
+ var before = lst(hist.done)
7210
+ if (!before || !before.ranges)
7211
+ { pushSelectionToHistory(doc.sel, hist.done) }
7212
+ cur = {changes: [historyChangeFromChange(doc, change)],
7213
+ generation: hist.generation}
7214
+ hist.done.push(cur)
7215
+ while (hist.done.length > hist.undoDepth) {
7216
+ hist.done.shift()
7217
+ if (!hist.done[0].ranges) { hist.done.shift() }
7218
+ }
7219
+ }
7220
+ hist.done.push(selAfter)
7221
+ hist.generation = ++hist.maxGeneration
7222
+ hist.lastModTime = hist.lastSelTime = time
7223
+ hist.lastOp = hist.lastSelOp = opId
7224
+ hist.lastOrigin = hist.lastSelOrigin = change.origin
7225
+
7226
+ if (!last) { signal(doc, "historyAdded") }
7227
+ }
7228
+
7229
+ function selectionEventCanBeMerged(doc, origin, prev, sel) {
7230
+ var ch = origin.charAt(0)
7231
+ return ch == "*" ||
7232
+ ch == "+" &&
7233
+ prev.ranges.length == sel.ranges.length &&
7234
+ prev.somethingSelected() == sel.somethingSelected() &&
7235
+ new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500)
7236
+ }
7237
+
7238
+ // Called whenever the selection changes, sets the new selection as
7239
+ // the pending selection in the history, and pushes the old pending
7240
+ // selection into the 'done' array when it was significantly
7241
+ // different (in number of selected ranges, emptiness, or time).
7242
+ function addSelectionToHistory(doc, sel, opId, options) {
7243
+ var hist = doc.history, origin = options && options.origin
7244
+
7245
+ // A new event is started when the previous origin does not match
7246
+ // the current, or the origins don't allow matching. Origins
7247
+ // starting with * are always merged, those starting with + are
7248
+ // merged when similar and close together in time.
7249
+ if (opId == hist.lastSelOp ||
7250
+ (origin && hist.lastSelOrigin == origin &&
7251
+ (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
7252
+ selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
7253
+ { hist.done[hist.done.length - 1] = sel }
7254
+ else
7255
+ { pushSelectionToHistory(sel, hist.done) }
7256
+
7257
+ hist.lastSelTime = +new Date
7258
+ hist.lastSelOrigin = origin
7259
+ hist.lastSelOp = opId
7260
+ if (options && options.clearRedo !== false)
7261
+ { clearSelectionEvents(hist.undone) }
7262
+ }
7263
+
7264
+ function pushSelectionToHistory(sel, dest) {
7265
+ var top = lst(dest)
7266
+ if (!(top && top.ranges && top.equals(sel)))
7267
+ { dest.push(sel) }
7268
+ }
7269
+
7270
+ // Used to store marked span information in the history.
7271
+ function attachLocalSpans(doc, change, from, to) {
7272
+ var existing = change["spans_" + doc.id], n = 0
7273
+ doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) {
7274
+ if (line.markedSpans)
7275
+ { (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans }
7276
+ ++n
7277
+ })
7278
+ }
7279
+
7280
+ // When un/re-doing restores text containing marked spans, those
7281
+ // that have been explicitly cleared should not be restored.
7282
+ function removeClearedSpans(spans) {
7283
+ if (!spans) { return null }
7284
+ var out
7285
+ for (var i = 0; i < spans.length; ++i) {
7286
+ if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i) } }
7287
+ else if (out) { out.push(spans[i]) }
7288
  }
7289
+ return !out ? spans : out.length ? out : null
7290
+ }
7291
 
7292
+ // Retrieve and filter the old marked spans stored in a change event.
7293
+ function getOldSpans(doc, change) {
7294
+ var found = change["spans_" + doc.id]
7295
+ if (!found) { return null }
7296
+ var nw = []
7297
+ for (var i = 0; i < change.text.length; ++i)
7298
+ { nw.push(removeClearedSpans(found[i])) }
7299
+ return nw
7300
+ }
7301
+
7302
+ // Used for un/re-doing changes from the history. Combines the
7303
+ // result of computing the existing spans with the set of spans that
7304
+ // existed in the history (so that deleting around a span and then
7305
+ // undoing brings back the span).
7306
+ function mergeOldSpans(doc, change) {
7307
+ var old = getOldSpans(doc, change)
7308
+ var stretched = stretchSpansOverChange(doc, change)
7309
+ if (!old) { return stretched }
7310
+ if (!stretched) { return old }
7311
+
7312
+ for (var i = 0; i < old.length; ++i) {
7313
+ var oldCur = old[i], stretchCur = stretched[i]
7314
+ if (oldCur && stretchCur) {
7315
+ spans: for (var j = 0; j < stretchCur.length; ++j) {
7316
+ var span = stretchCur[j]
7317
+ for (var k = 0; k < oldCur.length; ++k)
7318
+ { if (oldCur[k].marker == span.marker) { continue spans } }
7319
+ oldCur.push(span)
7320
+ }
7321
+ } else if (stretchCur) {
7322
+ old[i] = stretchCur
7323
+ }
7324
+ }
7325
+ return old
7326
+ }
7327
+
7328
+ // Used both to provide a JSON-safe object in .getHistory, and, when
7329
+ // detaching a document, to split the history in two
7330
+ function copyHistoryArray(events, newGroup, instantiateSel) {
7331
+ var copy = []
7332
+ for (var i = 0; i < events.length; ++i) {
7333
+ var event = events[i]
7334
+ if (event.ranges) {
7335
+ copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event)
7336
+ continue
7337
+ }
7338
+ var changes = event.changes, newChanges = []
7339
+ copy.push({changes: newChanges})
7340
+ for (var j = 0; j < changes.length; ++j) {
7341
+ var change = changes[j], m = void 0
7342
+ newChanges.push({from: change.from, to: change.to, text: change.text})
7343
+ if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) {
7344
+ if (indexOf(newGroup, Number(m[1])) > -1) {
7345
+ lst(newChanges)[prop] = change[prop]
7346
+ delete change[prop]
7347
+ }
7348
+ } } }
7349
  }
 
7350
  }
7351
+ return copy
7352
+ }
7353
 
7354
+ // The 'scroll' parameter given to many of these indicated whether
7355
+ // the new cursor position should be scrolled into view after
7356
+ // modifying the selection.
7357
+
7358
+ // If shift is held or the extend flag is set, extends a range to
7359
+ // include a given position (and optionally a second position).
7360
+ // Otherwise, simply returns the range between the given positions.
7361
+ // Used for cursor motion and such.
7362
+ function extendRange(doc, range, head, other) {
7363
+ if (doc.cm && doc.cm.display.shift || doc.extend) {
7364
+ var anchor = range.anchor
7365
+ if (other) {
7366
+ var posBefore = cmp(head, anchor) < 0
7367
+ if (posBefore != (cmp(other, anchor) < 0)) {
7368
+ anchor = head
7369
+ head = other
7370
+ } else if (posBefore != (cmp(head, other) < 0)) {
7371
+ head = other
7372
+ }
7373
+ }
7374
+ return new Range(anchor, head)
7375
+ } else {
7376
+ return new Range(other || head, head)
7377
+ }
7378
+ }
7379
 
7380
+ // Extend the primary selection range, discard the rest.
7381
+ function extendSelection(doc, head, other, options) {
7382
+ setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options)
7383
+ }
7384
 
7385
+ // Extend all selections (pos is an array of selections with length
7386
+ // equal the number of selections)
7387
+ function extendSelections(doc, heads, options) {
7388
+ var out = []
7389
+ for (var i = 0; i < doc.sel.ranges.length; i++)
7390
+ { out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null) }
7391
+ var newSel = normalizeSelection(out, doc.sel.primIndex)
7392
+ setSelection(doc, newSel, options)
7393
+ }
7394
 
7395
+ // Updates a single range in the selection.
7396
+ function replaceOneSelection(doc, i, range, options) {
7397
+ var ranges = doc.sel.ranges.slice(0)
7398
+ ranges[i] = range
7399
+ setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options)
7400
+ }
7401
 
7402
+ // Reset the selection to a single range.
7403
+ function setSimpleSelection(doc, anchor, head, options) {
7404
+ setSelection(doc, simpleSelection(anchor, head), options)
7405
+ }
 
 
 
7406
 
7407
+ // Give beforeSelectionChange handlers a change to influence a
7408
+ // selection update.
7409
+ function filterSelectionChange(doc, sel, options) {
7410
+ var obj = {
7411
+ ranges: sel.ranges,
7412
+ update: function(ranges) {
7413
+ var this$1 = this;
7414
+
7415
+ this.ranges = []
7416
+ for (var i = 0; i < ranges.length; i++)
7417
+ { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
7418
+ clipPos(doc, ranges[i].head)) }
7419
+ },
7420
+ origin: options && options.origin
7421
+ }
7422
+ signal(doc, "beforeSelectionChange", doc, obj)
7423
+ if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj) }
7424
+ if (obj.ranges != sel.ranges) { return normalizeSelection(obj.ranges, obj.ranges.length - 1) }
7425
+ else { return sel }
7426
+ }
7427
 
7428
+ function setSelectionReplaceHistory(doc, sel, options) {
7429
+ var done = doc.history.done, last = lst(done)
7430
+ if (last && last.ranges) {
7431
+ done[done.length - 1] = sel
7432
+ setSelectionNoUndo(doc, sel, options)
7433
+ } else {
7434
+ setSelection(doc, sel, options)
7435
+ }
7436
+ }
 
 
7437
 
7438
+ // Set a new selection.
7439
+ function setSelection(doc, sel, options) {
7440
+ setSelectionNoUndo(doc, sel, options)
7441
+ addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options)
7442
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7443
 
7444
+ function setSelectionNoUndo(doc, sel, options) {
7445
+ if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
7446
+ { sel = filterSelectionChange(doc, sel, options) }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7447
 
7448
+ var bias = options && options.bias ||
7449
+ (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1)
7450
+ setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true))
 
 
7451
 
7452
+ if (!(options && options.scroll === false) && doc.cm)
7453
+ { ensureCursorVisible(doc.cm) }
7454
+ }
7455
 
7456
+ function setSelectionInner(doc, sel) {
7457
+ if (sel.equals(doc.sel)) { return }
 
 
 
 
 
 
 
 
 
 
 
 
 
7458
 
7459
+ doc.sel = sel
 
 
 
 
7460
 
7461
+ if (doc.cm) {
7462
+ doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true
7463
+ signalCursorActivity(doc.cm)
7464
+ }
7465
+ signalLater(doc, "cursorActivity", doc)
7466
+ }
7467
 
7468
+ // Verify that the selection does not partially select any atomic
7469
+ // marked ranges.
7470
+ function reCheckSelection(doc) {
7471
+ setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll)
7472
+ }
7473
+
7474
+ // Return a selection that does not partially select any atomic
7475
+ // ranges.
7476
+ function skipAtomicInSelection(doc, sel, bias, mayClear) {
7477
+ var out
7478
+ for (var i = 0; i < sel.ranges.length; i++) {
7479
+ var range = sel.ranges[i]
7480
+ var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i]
7481
+ var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear)
7482
+ var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear)
7483
+ if (out || newAnchor != range.anchor || newHead != range.head) {
7484
+ if (!out) { out = sel.ranges.slice(0, i) }
7485
+ out[i] = new Range(newAnchor, newHead)
7486
+ }
7487
+ }
7488
+ return out ? normalizeSelection(out, sel.primIndex) : sel
7489
+ }
7490
+
7491
+ function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
7492
+ var line = getLine(doc, pos.line)
7493
+ if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
7494
+ var sp = line.markedSpans[i], m = sp.marker
7495
+ if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
7496
+ (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
7497
+ if (mayClear) {
7498
+ signal(m, "beforeCursorEnter")
7499
+ if (m.explicitlyCleared) {
7500
+ if (!line.markedSpans) { break }
7501
+ else {--i; continue}
7502
  }
 
 
 
 
7503
  }
7504
+ if (!m.atomic) { continue }
7505
+
7506
+ if (oldPos) {
7507
+ var near = m.find(dir < 0 ? 1 : -1), diff = void 0
7508
+ if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)
7509
+ { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null) }
7510
+ if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
7511
+ { return skipAtomicInner(doc, near, pos, dir, mayClear) }
7512
  }
 
 
7513
 
7514
+ var far = m.find(dir < 0 ? -1 : 1)
7515
+ if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)
7516
+ { far = movePos(doc, far, dir, far.line == pos.line ? line : null) }
7517
+ return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null
7518
+ }
7519
+ } }
7520
+ return pos
7521
+ }
7522
 
7523
+ // Ensure a given position is not inside an atomic range.
7524
+ function skipAtomic(doc, pos, oldPos, bias, mayClear) {
7525
+ var dir = bias || 1
7526
+ var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
7527
+ (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
7528
+ skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
7529
+ (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true))
7530
+ if (!found) {
7531
+ doc.cantEdit = true
7532
+ return Pos(doc.first, 0)
7533
+ }
7534
+ return found
7535
+ }
7536
 
7537
+ function movePos(doc, pos, dir, line) {
7538
+ if (dir < 0 && pos.ch == 0) {
7539
+ if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) }
7540
+ else { return null }
7541
+ } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
7542
+ if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) }
7543
+ else { return null }
7544
+ } else {
7545
+ return new Pos(pos.line, pos.ch + dir)
7546
+ }
7547
+ }
7548
 
7549
+ function selectAll(cm) {
7550
+ cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll)
7551
+ }
 
7552
 
7553
+ // UPDATING
7554
+
7555
+ // Allow "beforeChange" event handlers to influence a change
7556
+ function filterChange(doc, change, update) {
7557
+ var obj = {
7558
+ canceled: false,
7559
+ from: change.from,
7560
+ to: change.to,
7561
+ text: change.text,
7562
+ origin: change.origin,
7563
+ cancel: function () { return obj.canceled = true; }
7564
+ }
7565
+ if (update) { obj.update = function (from, to, text, origin) {
7566
+ if (from) { obj.from = clipPos(doc, from) }
7567
+ if (to) { obj.to = clipPos(doc, to) }
7568
+ if (text) { obj.text = text }
7569
+ if (origin !== undefined) { obj.origin = origin }
7570
+ } }
7571
+ signal(doc, "beforeChange", doc, obj)
7572
+ if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj) }
7573
+
7574
+ if (obj.canceled) { return null }
7575
+ return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}
7576
+ }
7577
 
7578
+ // Apply a change to a document, and add it to the document's
7579
+ // history, and propagating it to all linked documents.
7580
+ function makeChange(doc, change, ignoreReadOnly) {
7581
+ if (doc.cm) {
7582
+ if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) }
7583
+ if (doc.cm.state.suppressEdits) { return }
7584
+ }
7585
 
7586
+ if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
7587
+ change = filterChange(doc, change, true)
7588
+ if (!change) { return }
7589
+ }
 
 
 
 
7590
 
7591
+ // Possibly split or suppress the update based on the presence
7592
+ // of read-only spans in its range.
7593
+ var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to)
7594
+ if (split) {
7595
+ for (var i = split.length - 1; i >= 0; --i)
7596
+ { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}) }
7597
+ } else {
7598
+ makeChangeInner(doc, change)
7599
+ }
7600
+ }
 
7601
 
7602
+ function makeChangeInner(doc, change) {
7603
+ if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return }
7604
+ var selAfter = computeSelAfterChange(doc, change)
7605
+ addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN)
 
 
 
 
 
 
 
 
 
 
7606
 
7607
+ makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change))
7608
+ var rebased = []
7609
 
7610
+ linkedDocs(doc, function (doc, sharedHist) {
7611
+ if (!sharedHist && indexOf(rebased, doc.history) == -1) {
7612
+ rebaseHist(doc.history, change)
7613
+ rebased.push(doc.history)
7614
+ }
7615
+ makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change))
7616
+ })
7617
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7618
 
7619
+ // Revert a change stored in a document's history.
7620
+ function makeChangeFromHistory(doc, type, allowSelectionOnly) {
7621
+ if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) { return }
7622
 
7623
+ var hist = doc.history, event, selAfter = doc.sel
7624
+ var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done
 
 
7625
 
7626
+ // Verify that there is a useable event (so that ctrl-z won't
7627
+ // needlessly clear selection events)
7628
+ var i = 0
7629
+ for (; i < source.length; i++) {
7630
+ event = source[i]
7631
+ if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
7632
+ { break }
7633
+ }
7634
+ if (i == source.length) { return }
7635
+ hist.lastOrigin = hist.lastSelOrigin = null
7636
 
7637
+ for (;;) {
7638
+ event = source.pop()
7639
+ if (event.ranges) {
7640
+ pushSelectionToHistory(event, dest)
7641
+ if (allowSelectionOnly && !event.equals(doc.sel)) {
7642
+ setSelection(doc, event, {clearRedo: false})
7643
+ return
7644
  }
7645
+ selAfter = event
7646
+ }
7647
+ else { break }
7648
+ }
7649
 
7650
+ // Build up a reverse change object to add to the opposite history
7651
+ // stack (redo when undoing, and vice versa).
7652
+ var antiChanges = []
7653
+ pushSelectionToHistory(selAfter, dest)
7654
+ dest.push({changes: antiChanges, generation: hist.generation})
7655
+ hist.generation = event.generation || ++hist.maxGeneration
 
 
 
7656
 
7657
+ var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")
 
 
 
 
 
 
 
 
 
7658
 
7659
+ var loop = function ( i ) {
7660
+ var change = event.changes[i]
7661
+ change.origin = type
7662
+ if (filter && !filterChange(doc, change, false)) {
7663
+ source.length = 0
7664
+ return {}
7665
+ }
 
 
 
 
 
7666
 
7667
+ antiChanges.push(historyChangeFromChange(doc, change))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7668
 
7669
+ var after = i ? computeSelAfterChange(doc, change) : lst(source)
7670
+ makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change))
7671
+ if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}) }
7672
+ var rebased = []
7673
+
7674
+ // Propagate to the linked documents
7675
+ linkedDocs(doc, function (doc, sharedHist) {
7676
+ if (!sharedHist && indexOf(rebased, doc.history) == -1) {
7677
+ rebaseHist(doc.history, change)
7678
+ rebased.push(doc.history)
 
 
 
 
7679
  }
7680
+ makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change))
7681
+ })
7682
+ };
7683
 
7684
+ for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) {
7685
+ var returned = loop( i$1 );
 
 
 
 
7686
 
7687
+ if ( returned ) return returned.v;
7688
+ }
7689
+ }
 
7690
 
7691
+ // Sub-views need their line numbers shifted when text is added
7692
+ // above or below them in the parent document.
7693
+ function shiftDoc(doc, distance) {
7694
+ if (distance == 0) { return }
7695
+ doc.first += distance
7696
+ doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range(
7697
+ Pos(range.anchor.line + distance, range.anchor.ch),
7698
+ Pos(range.head.line + distance, range.head.ch)
7699
+ ); }), doc.sel.primIndex)
7700
+ if (doc.cm) {
7701
+ regChange(doc.cm, doc.first, doc.first - distance, distance)
7702
+ for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
7703
+ { regLineChange(doc.cm, l, "gutter") }
7704
+ }
7705
+ }
7706
 
7707
+ // More lower-level change function, handling only a single document
7708
+ // (not linked ones).
7709
+ function makeChangeSingleDoc(doc, change, selAfter, spans) {
7710
+ if (doc.cm && !doc.cm.curOp)
7711
+ { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) }
 
 
 
 
 
 
7712
 
7713
+ if (change.to.line < doc.first) {
7714
+ shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line))
7715
+ return
7716
+ }
7717
+ if (change.from.line > doc.lastLine()) { return }
7718
+
7719
+ // Clip the change to the size of this doc
7720
+ if (change.from.line < doc.first) {
7721
+ var shift = change.text.length - 1 - (doc.first - change.from.line)
7722
+ shiftDoc(doc, shift)
7723
+ change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
7724
+ text: [lst(change.text)], origin: change.origin}
7725
+ }
7726
+ var last = doc.lastLine()
7727
+ if (change.to.line > last) {
7728
+ change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
7729
+ text: [change.text[0]], origin: change.origin}
7730
+ }
7731
+
7732
+ change.removed = getBetween(doc, change.from, change.to)
7733
+
7734
+ if (!selAfter) { selAfter = computeSelAfterChange(doc, change) }
7735
+ if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans) }
7736
+ else { updateDoc(doc, change, spans) }
7737
+ setSelectionNoUndo(doc, selAfter, sel_dontScroll)
7738
+ }
7739
+
7740
+ // Handle the interaction of a change to a document with the editor
7741
+ // that this document is part of.
7742
+ function makeChangeSingleDocInEditor(cm, change, spans) {
7743
+ var doc = cm.doc, display = cm.display, from = change.from, to = change.to
7744
+
7745
+ var recomputeMaxLength = false, checkWidthStart = from.line
7746
+ if (!cm.options.lineWrapping) {
7747
+ checkWidthStart = lineNo(visualLine(getLine(doc, from.line)))
7748
+ doc.iter(checkWidthStart, to.line + 1, function (line) {
7749
+ if (line == display.maxLine) {
7750
+ recomputeMaxLength = true
7751
+ return true
7752
  }
7753
+ })
7754
+ }
7755
 
7756
+ if (doc.sel.contains(change.from, change.to) > -1)
7757
+ { signalCursorActivity(cm) }
7758
+
7759
+ updateDoc(doc, change, spans, estimateHeight(cm))
7760
+
7761
+ if (!cm.options.lineWrapping) {
7762
+ doc.iter(checkWidthStart, from.line + change.text.length, function (line) {
7763
+ var len = lineLength(line)
7764
+ if (len > display.maxLineLength) {
7765
+ display.maxLine = line
7766
+ display.maxLineLength = len
7767
+ display.maxLineChanged = true
7768
+ recomputeMaxLength = false
7769
  }
7770
+ })
7771
+ if (recomputeMaxLength) { cm.curOp.updateMaxLine = true }
7772
+ }
 
 
 
 
 
 
 
 
 
7773
 
7774
+ // Adjust frontier, schedule worker
7775
+ doc.frontier = Math.min(doc.frontier, from.line)
7776
+ startWorker(cm, 400)
7777
 
7778
+ var lendiff = change.text.length - (to.line - from.line) - 1
7779
+ // Remember that these lines changed, for updating the display
7780
+ if (change.full)
7781
+ { regChange(cm) }
7782
+ else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
7783
+ { regLineChange(cm, from.line, "text") }
7784
+ else
7785
+ { regChange(cm, from.line, to.line + 1, lendiff) }
 
 
 
7786
 
7787
+ var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change")
7788
+ if (changeHandler || changesHandler) {
7789
+ var obj = {
7790
+ from: from, to: to,
7791
+ text: change.text,
7792
+ removed: change.removed,
7793
+ origin: change.origin
7794
+ }
7795
+ if (changeHandler) { signalLater(cm, "change", cm, obj) }
7796
+ if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj) }
7797
+ }
7798
+ cm.display.selForContextMenu = null
7799
+ }
7800
 
7801
+ function replaceRange(doc, code, from, to, origin) {
7802
+ if (!to) { to = from }
7803
+ if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp }
7804
+ if (typeof code == "string") { code = doc.splitLines(code) }
7805
+ makeChange(doc, {from: from, to: to, text: code, origin: origin})
7806
+ }
7807
 
7808
+ // Rebasing/resetting history to deal with externally-sourced changes
7809
 
7810
+ function rebaseHistSelSingle(pos, from, to, diff) {
7811
+ if (to < pos.line) {
7812
+ pos.line += diff
7813
+ } else if (from < pos.line) {
7814
+ pos.line = from
7815
+ pos.ch = 0
7816
+ }
7817
+ }
7818
 
7819
+ // Tries to rebase an array of history events given a change in the
7820
+ // document. If the change touches the same lines as the event, the
7821
+ // event, and everything 'behind' it, is discarded. If the change is
7822
+ // before the event, the event's positions are updated. Uses a
7823
+ // copy-on-write scheme for the positions, to avoid having to
7824
+ // reallocate them all on every rebase, but also avoid problems with
7825
+ // shared position objects being unsafely updated.
7826
+ function rebaseHistArray(array, from, to, diff) {
7827
+ for (var i = 0; i < array.length; ++i) {
7828
+ var sub = array[i], ok = true
7829
+ if (sub.ranges) {
7830
+ if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true }
7831
+ for (var j = 0; j < sub.ranges.length; j++) {
7832
+ rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff)
7833
+ rebaseHistSelSingle(sub.ranges[j].head, from, to, diff)
7834
+ }
7835
+ continue
7836
+ }
7837
+ for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) {
7838
+ var cur = sub.changes[j$1]
7839
+ if (to < cur.from.line) {
7840
+ cur.from = Pos(cur.from.line + diff, cur.from.ch)
7841
+ cur.to = Pos(cur.to.line + diff, cur.to.ch)
7842
+ } else if (from <= cur.to.line) {
7843
+ ok = false
7844
+ break
7845
+ }
7846
+ }
7847
+ if (!ok) {
7848
+ array.splice(0, i + 1)
7849
+ i = 0
7850
+ }
7851
  }
7852
+ }
7853
 
7854
+ function rebaseHist(hist, change) {
7855
+ var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1
7856
+ rebaseHistArray(hist.done, from, to, diff)
7857
+ rebaseHistArray(hist.undone, from, to, diff)
7858
+ }
7859
 
7860
+ // Utility for applying a change to a line by handle or number,
7861
+ // returning the number and optionally registering the line as
7862
+ // changed.
7863
+ function changeLine(doc, handle, changeType, op) {
7864
+ var no = handle, line = handle
7865
+ if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)) }
7866
+ else { no = lineNo(handle) }
7867
+ if (no == null) { return null }
7868
+ if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType) }
7869
+ return line
7870
+ }
7871
+
7872
+ // The document is represented as a BTree consisting of leaves, with
7873
+ // chunk of lines in them, and branches, with up to ten leaves or
7874
+ // other branch nodes below them. The top node is always a branch
7875
+ // node, and is the document object itself (meaning it has
7876
+ // additional methods and properties).
7877
+ //
7878
+ // All nodes have parent links. The tree is used both to go from
7879
+ // line numbers to line objects, and to go from objects to numbers.
7880
+ // It also indexes by height, and is used to convert between height
7881
+ // and line object, and to find the total height of the document.
7882
+ //
7883
+ // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
7884
+
7885
+ function LeafChunk(lines) {
7886
+ var this$1 = this;
7887
+
7888
+ this.lines = lines
7889
+ this.parent = null
7890
+ var height = 0
7891
+ for (var i = 0; i < lines.length; ++i) {
7892
+ lines[i].parent = this$1
7893
+ height += lines[i].height
7894
+ }
7895
+ this.height = height
7896
+ }
7897
+
7898
+ LeafChunk.prototype = {
7899
+ chunkSize: function() { return this.lines.length },
7900
+ // Remove the n lines at offset 'at'.
7901
+ removeInner: function(at, n) {
7902
+ var this$1 = this;
7903
+
7904
+ for (var i = at, e = at + n; i < e; ++i) {
7905
+ var line = this$1.lines[i]
7906
+ this$1.height -= line.height
7907
+ cleanUpLine(line)
7908
+ signalLater(line, "delete")
7909
+ }
7910
+ this.lines.splice(at, n)
7911
+ },
7912
+ // Helper used to collapse a small branch into a single leaf.
7913
+ collapse: function(lines) {
7914
+ lines.push.apply(lines, this.lines)
7915
+ },
7916
+ // Insert the given array of lines at offset 'at', count them as
7917
+ // having the given height.
7918
+ insertInner: function(at, lines, height) {
7919
+ var this$1 = this;
7920
+
7921
+ this.height += height
7922
+ this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at))
7923
+ for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1 }
7924
+ },
7925
+ // Used to iterate over a part of the tree.
7926
+ iterN: function(at, n, op) {
7927
+ var this$1 = this;
7928
+
7929
+ for (var e = at + n; at < e; ++at)
7930
+ { if (op(this$1.lines[at])) { return true } }
7931
+ }
7932
+ }
7933
+
7934
+ function BranchChunk(children) {
7935
+ var this$1 = this;
7936
+
7937
+ this.children = children
7938
+ var size = 0, height = 0
7939
+ for (var i = 0; i < children.length; ++i) {
7940
+ var ch = children[i]
7941
+ size += ch.chunkSize(); height += ch.height
7942
+ ch.parent = this$1
7943
+ }
7944
+ this.size = size
7945
+ this.height = height
7946
+ this.parent = null
7947
+ }
7948
+
7949
+ BranchChunk.prototype = {
7950
+ chunkSize: function() { return this.size },
7951
+ removeInner: function(at, n) {
7952
+ var this$1 = this;
7953
+
7954
+ this.size -= n
7955
+ for (var i = 0; i < this.children.length; ++i) {
7956
+ var child = this$1.children[i], sz = child.chunkSize()
7957
+ if (at < sz) {
7958
+ var rm = Math.min(n, sz - at), oldHeight = child.height
7959
+ child.removeInner(at, rm)
7960
+ this$1.height -= oldHeight - child.height
7961
+ if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null }
7962
+ if ((n -= rm) == 0) { break }
7963
+ at = 0
7964
+ } else { at -= sz }
7965
+ }
7966
+ // If the result is smaller than 25 lines, ensure that it is a
7967
+ // single leaf node.
7968
+ if (this.size - n < 25 &&
7969
+ (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
7970
+ var lines = []
7971
+ this.collapse(lines)
7972
+ this.children = [new LeafChunk(lines)]
7973
+ this.children[0].parent = this
7974
+ }
7975
+ },
7976
+ collapse: function(lines) {
7977
+ var this$1 = this;
7978
+
7979
+ for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines) }
7980
+ },
7981
+ insertInner: function(at, lines, height) {
7982
+ var this$1 = this;
7983
+
7984
+ this.size += lines.length
7985
+ this.height += height
7986
+ for (var i = 0; i < this.children.length; ++i) {
7987
+ var child = this$1.children[i], sz = child.chunkSize()
7988
+ if (at <= sz) {
7989
+ child.insertInner(at, lines, height)
7990
+ if (child.lines && child.lines.length > 50) {
7991
+ // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.
7992
+ // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.
7993
+ var remaining = child.lines.length % 25 + 25
7994
+ for (var pos = remaining; pos < child.lines.length;) {
7995
+ var leaf = new LeafChunk(child.lines.slice(pos, pos += 25))
7996
+ child.height -= leaf.height
7997
+ this$1.children.splice(++i, 0, leaf)
7998
+ leaf.parent = this$1
7999
+ }
8000
+ child.lines = child.lines.slice(0, remaining)
8001
+ this$1.maybeSpill()
8002
+ }
8003
+ break
8004
  }
8005
+ at -= sz
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8006
  }
8007
+ },
8008
+ // When a node has grown, check whether it should be split.
8009
+ maybeSpill: function() {
8010
+ if (this.children.length <= 10) { return }
8011
+ var me = this
8012
+ do {
8013
+ var spilled = me.children.splice(me.children.length - 5, 5)
8014
+ var sibling = new BranchChunk(spilled)
8015
+ if (!me.parent) { // Become the parent node
8016
+ var copy = new BranchChunk(me.children)
8017
+ copy.parent = me
8018
+ me.children = [copy, sibling]
8019
+ me = copy
8020
+ } else {
8021
+ me.size -= sibling.size
8022
+ me.height -= sibling.height
8023
+ var myIndex = indexOf(me.parent.children, me)
8024
+ me.parent.children.splice(myIndex + 1, 0, sibling)
8025
+ }
8026
+ sibling.parent = me.parent
8027
+ } while (me.children.length > 10)
8028
+ me.parent.maybeSpill()
8029
+ },
8030
+ iterN: function(at, n, op) {
8031
+ var this$1 = this;
8032
+
8033
+ for (var i = 0; i < this.children.length; ++i) {
8034
+ var child = this$1.children[i], sz = child.chunkSize()
8035
+ if (at < sz) {
8036
+ var used = Math.min(n, sz - at)
8037
+ if (child.iterN(at, used, op)) { return true }
8038
+ if ((n -= used) == 0) { break }
8039
+ at = 0
8040
+ } else { at -= sz }
8041
+ }
8042
+ }
8043
+ }
8044
+
8045
+ // Line widgets are block elements displayed above or below a line.
8046
+
8047
+ function LineWidget(doc, node, options) {
8048
+ var this$1 = this;
8049
+
8050
+ if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))
8051
+ { this$1[opt] = options[opt] } } }
8052
+ this.doc = doc
8053
+ this.node = node
8054
+ }
8055
+ eventMixin(LineWidget)
8056
+
8057
+ function adjustScrollWhenAboveVisible(cm, line, diff) {
8058
+ if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
8059
+ { addToScrollPos(cm, null, diff) }
8060
+ }
8061
+
8062
+ LineWidget.prototype.clear = function() {
8063
+ var this$1 = this;
8064
+
8065
+ var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line)
8066
+ if (no == null || !ws) { return }
8067
+ for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1) } }
8068
+ if (!ws.length) { line.widgets = null }
8069
+ var height = widgetHeight(this)
8070
+ updateLineHeight(line, Math.max(0, line.height - height))
8071
+ if (cm) { runInOp(cm, function () {
8072
+ adjustScrollWhenAboveVisible(cm, line, -height)
8073
+ regLineChange(cm, no, "widget")
8074
+ }) }
8075
+ }
8076
+ LineWidget.prototype.changed = function() {
8077
+ var oldH = this.height, cm = this.doc.cm, line = this.line
8078
+ this.height = null
8079
+ var diff = widgetHeight(this) - oldH
8080
+ if (!diff) { return }
8081
+ updateLineHeight(line, line.height + diff)
8082
+ if (cm) { runInOp(cm, function () {
8083
+ cm.curOp.forceUpdate = true
8084
+ adjustScrollWhenAboveVisible(cm, line, diff)
8085
+ }) }
8086
+ }
8087
+
8088
+ function addLineWidget(doc, handle, node, options) {
8089
+ var widget = new LineWidget(doc, node, options)
8090
+ var cm = doc.cm
8091
+ if (cm && widget.noHScroll) { cm.display.alignWidgets = true }
8092
+ changeLine(doc, handle, "widget", function (line) {
8093
+ var widgets = line.widgets || (line.widgets = [])
8094
+ if (widget.insertAt == null) { widgets.push(widget) }
8095
+ else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget) }
8096
+ widget.line = line
8097
+ if (cm && !lineIsHidden(doc, line)) {
8098
+ var aboveVisible = heightAtLine(line) < doc.scrollTop
8099
+ updateLineHeight(line, line.height + widgetHeight(widget))
8100
+ if (aboveVisible) { addToScrollPos(cm, null, widget.height) }
8101
+ cm.curOp.forceUpdate = true
8102
+ }
8103
+ return true
8104
+ })
8105
+ return widget
8106
+ }
8107
+
8108
+ // TEXTMARKERS
8109
+
8110
+ // Created with markText and setBookmark methods. A TextMarker is a
8111
+ // handle that can be used to clear or find a marked position in the
8112
+ // document. Line objects hold arrays (markedSpans) containing
8113
+ // {from, to, marker} object pointing to such marker objects, and
8114
+ // indicating that such a marker is present on that line. Multiple
8115
+ // lines may point to the same marker when it spans across lines.
8116
+ // The spans will have null for their from/to properties when the
8117
+ // marker continues beyond the start/end of the line. Markers have
8118
+ // links back to the lines they currently touch.
8119
+
8120
+ // Collapsed markers have unique ids, in order to be able to order
8121
+ // them, which is needed for uniquely determining an outer marker
8122
+ // when they overlap (they may nest, but not partially overlap).
8123
+ var nextMarkerId = 0
8124
+
8125
+ function TextMarker(doc, type) {
8126
+ this.lines = []
8127
+ this.type = type
8128
+ this.doc = doc
8129
+ this.id = ++nextMarkerId
8130
+ }
8131
+ eventMixin(TextMarker)
8132
+
8133
+ // Clear the marker.
8134
+ TextMarker.prototype.clear = function() {
8135
+ var this$1 = this;
8136
+
8137
+ if (this.explicitlyCleared) { return }
8138
+ var cm = this.doc.cm, withOp = cm && !cm.curOp
8139
+ if (withOp) { startOperation(cm) }
8140
+ if (hasHandler(this, "clear")) {
8141
+ var found = this.find()
8142
+ if (found) { signalLater(this, "clear", found.from, found.to) }
8143
+ }
8144
+ var min = null, max = null
8145
+ for (var i = 0; i < this.lines.length; ++i) {
8146
+ var line = this$1.lines[i]
8147
+ var span = getMarkedSpanFor(line.markedSpans, this$1)
8148
+ if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text") }
8149
+ else if (cm) {
8150
+ if (span.to != null) { max = lineNo(line) }
8151
+ if (span.from != null) { min = lineNo(line) }
8152
+ }
8153
+ line.markedSpans = removeMarkedSpan(line.markedSpans, span)
8154
+ if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm)
8155
+ { updateLineHeight(line, textHeight(cm.display)) }
8156
+ }
8157
+ if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {
8158
+ var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual)
8159
+ if (len > cm.display.maxLineLength) {
8160
+ cm.display.maxLine = visual
8161
+ cm.display.maxLineLength = len
8162
+ cm.display.maxLineChanged = true
8163
+ }
8164
+ } }
8165
+
8166
+ if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1) }
8167
+ this.lines.length = 0
8168
+ this.explicitlyCleared = true
8169
+ if (this.atomic && this.doc.cantEdit) {
8170
+ this.doc.cantEdit = false
8171
+ if (cm) { reCheckSelection(cm.doc) }
8172
+ }
8173
+ if (cm) { signalLater(cm, "markerCleared", cm, this) }
8174
+ if (withOp) { endOperation(cm) }
8175
+ if (this.parent) { this.parent.clear() }
8176
+ }
8177
+
8178
+ // Find the position of the marker in the document. Returns a {from,
8179
+ // to} object by default. Side can be passed to get a specific side
8180
+ // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
8181
+ // Pos objects returned contain a line object, rather than a line
8182
+ // number (used to prevent looking up the same line twice).
8183
+ TextMarker.prototype.find = function(side, lineObj) {
8184
+ var this$1 = this;
8185
+
8186
+ if (side == null && this.type == "bookmark") { side = 1 }
8187
+ var from, to
8188
+ for (var i = 0; i < this.lines.length; ++i) {
8189
+ var line = this$1.lines[i]
8190
+ var span = getMarkedSpanFor(line.markedSpans, this$1)
8191
+ if (span.from != null) {
8192
+ from = Pos(lineObj ? line : lineNo(line), span.from)
8193
+ if (side == -1) { return from }
8194
+ }
8195
+ if (span.to != null) {
8196
+ to = Pos(lineObj ? line : lineNo(line), span.to)
8197
+ if (side == 1) { return to }
8198
+ }
8199
+ }
8200
+ return from && {from: from, to: to}
8201
+ }
8202
+
8203
+ // Signals that the marker's widget changed, and surrounding layout
8204
+ // should be recomputed.
8205
+ TextMarker.prototype.changed = function() {
8206
+ var pos = this.find(-1, true), widget = this, cm = this.doc.cm
8207
+ if (!pos || !cm) { return }
8208
+ runInOp(cm, function () {
8209
+ var line = pos.line, lineN = lineNo(pos.line)
8210
+ var view = findViewForLine(cm, lineN)
8211
+ if (view) {
8212
+ clearLineMeasurementCacheFor(view)
8213
+ cm.curOp.selectionChanged = cm.curOp.forceUpdate = true
8214
+ }
8215
+ cm.curOp.updateMaxLine = true
8216
+ if (!lineIsHidden(widget.doc, line) && widget.height != null) {
8217
+ var oldHeight = widget.height
8218
+ widget.height = null
8219
+ var dHeight = widgetHeight(widget) - oldHeight
8220
+ if (dHeight)
8221
+ { updateLineHeight(line, line.height + dHeight) }
8222
+ }
8223
+ })
8224
+ }
8225
+
8226
+ TextMarker.prototype.attachLine = function(line) {
8227
+ if (!this.lines.length && this.doc.cm) {
8228
+ var op = this.doc.cm.curOp
8229
+ if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
8230
+ { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this) }
8231
+ }
8232
+ this.lines.push(line)
8233
+ }
8234
+ TextMarker.prototype.detachLine = function(line) {
8235
+ this.lines.splice(indexOf(this.lines, line), 1)
8236
+ if (!this.lines.length && this.doc.cm) {
8237
+ var op = this.doc.cm.curOp
8238
+ ;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this)
8239
+ }
8240
+ }
8241
 
8242
+ // Create a marker, wire it up to the right lines, and
8243
+ function markText(doc, from, to, options, type) {
8244
+ // Shared markers (across linked documents) are handled separately
8245
+ // (markTextShared will call out to this again, once per
8246
+ // document).
8247
+ if (options && options.shared) { return markTextShared(doc, from, to, options, type) }
8248
+ // Ensure we are in an operation.
8249
+ if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) }
8250
+
8251
+ var marker = new TextMarker(doc, type), diff = cmp(from, to)
8252
+ if (options) { copyObj(options, marker, false) }
8253
+ // Don't connect empty markers unless clearWhenEmpty is false
8254
+ if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
8255
+ { return marker }
8256
+ if (marker.replacedWith) {
8257
+ // Showing up as a widget implies collapsed (widget replaces text)
8258
+ marker.collapsed = true
8259
+ marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget")
8260
+ if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true") }
8261
+ if (options.insertLeft) { marker.widgetNode.insertLeft = true }
8262
+ }
8263
+ if (marker.collapsed) {
8264
+ if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
8265
+ from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
8266
+ { throw new Error("Inserting collapsed marker partially overlapping an existing one") }
8267
+ seeCollapsedSpans()
8268
+ }
8269
+
8270
+ if (marker.addToHistory)
8271
+ { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN) }
8272
+
8273
+ var curLine = from.line, cm = doc.cm, updateMaxLine
8274
+ doc.iter(curLine, to.line + 1, function (line) {
8275
+ if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
8276
+ { updateMaxLine = true }
8277
+ if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0) }
8278
+ addMarkedSpan(line, new MarkedSpan(marker,
8279
+ curLine == from.line ? from.ch : null,
8280
+ curLine == to.line ? to.ch : null))
8281
+ ++curLine
8282
+ })
8283
+ // lineIsHidden depends on the presence of the spans, so needs a second pass
8284
+ if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) {
8285
+ if (lineIsHidden(doc, line)) { updateLineHeight(line, 0) }
8286
+ }) }
8287
+
8288
+ if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }) }
8289
+
8290
+ if (marker.readOnly) {
8291
+ seeReadOnlySpans()
8292
+ if (doc.history.done.length || doc.history.undone.length)
8293
+ { doc.clearHistory() }
8294
+ }
8295
+ if (marker.collapsed) {
8296
+ marker.id = ++nextMarkerId
8297
+ marker.atomic = true
8298
+ }
8299
+ if (cm) {
8300
+ // Sync editor state
8301
+ if (updateMaxLine) { cm.curOp.updateMaxLine = true }
8302
+ if (marker.collapsed)
8303
+ { regChange(cm, from.line, to.line + 1) }
8304
+ else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
8305
+ { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text") } }
8306
+ if (marker.atomic) { reCheckSelection(cm.doc) }
8307
+ signalLater(cm, "markerAdded", cm, marker)
8308
+ }
8309
+ return marker
8310
+ }
8311
 
8312
+ // SHARED TEXTMARKERS
8313
 
8314
+ // A shared marker spans multiple linked documents. It is
8315
+ // implemented as a meta-marker-object controlling multiple normal
8316
+ // markers.
8317
+ function SharedTextMarker(markers, primary) {
8318
+ var this$1 = this;
8319
 
8320
+ this.markers = markers
8321
+ this.primary = primary
8322
+ for (var i = 0; i < markers.length; ++i)
8323
+ { markers[i].parent = this$1 }
8324
+ }
8325
+ eventMixin(SharedTextMarker)
 
 
 
8326
 
8327
+ SharedTextMarker.prototype.clear = function() {
8328
+ var this$1 = this;
 
8329
 
8330
+ if (this.explicitlyCleared) { return }
8331
+ this.explicitlyCleared = true
8332
+ for (var i = 0; i < this.markers.length; ++i)
8333
+ { this$1.markers[i].clear() }
8334
+ signalLater(this, "clear")
8335
+ }
8336
+ SharedTextMarker.prototype.find = function(side, lineObj) {
8337
+ return this.primary.find(side, lineObj)
8338
+ }
 
 
 
 
 
 
 
 
 
8339
 
8340
+ function markTextShared(doc, from, to, options, type) {
8341
+ options = copyObj(options)
8342
+ options.shared = false
8343
+ var markers = [markText(doc, from, to, options, type)], primary = markers[0]
8344
+ var widget = options.widgetNode
8345
+ linkedDocs(doc, function (doc) {
8346
+ if (widget) { options.widgetNode = widget.cloneNode(true) }
8347
+ markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type))
8348
+ for (var i = 0; i < doc.linked.length; ++i)
8349
+ { if (doc.linked[i].isParent) { return } }
8350
+ primary = lst(markers)
8351
+ })
8352
+ return new SharedTextMarker(markers, primary)
8353
+ }
8354
+
8355
+ function findSharedMarkers(doc) {
8356
+ return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; })
8357
+ }
8358
+
8359
+ function copySharedMarkers(doc, markers) {
8360
+ for (var i = 0; i < markers.length; i++) {
8361
+ var marker = markers[i], pos = marker.find()
8362
+ var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to)
8363
+ if (cmp(mFrom, mTo)) {
8364
+ var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type)
8365
+ marker.markers.push(subMark)
8366
+ subMark.parent = marker
8367
  }
8368
+ }
8369
+ }
 
 
8370
 
8371
+ function detachSharedMarkers(markers) {
8372
+ var loop = function ( i ) {
8373
+ var marker = markers[i], linked = [marker.primary.doc]
8374
+ linkedDocs(marker.primary.doc, function (d) { return linked.push(d); })
8375
+ for (var j = 0; j < marker.markers.length; j++) {
8376
+ var subMarker = marker.markers[j]
8377
+ if (indexOf(linked, subMarker.doc) == -1) {
8378
+ subMarker.parent = null
8379
+ marker.markers.splice(j--, 1)
8380
+ }
8381
+ }
8382
  };
8383
 
8384
+ for (var i = 0; i < markers.length; i++) loop( i );
8385
+ }
 
 
 
 
 
 
 
 
 
 
 
8386
 
8387
+ var nextDocId = 0
8388
+ var Doc = function(text, mode, firstLine, lineSep) {
8389
+ if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep) }
8390
+ if (firstLine == null) { firstLine = 0 }
8391
+
8392
+ BranchChunk.call(this, [new LeafChunk([new Line("", null)])])
8393
+ this.first = firstLine
8394
+ this.scrollTop = this.scrollLeft = 0
8395
+ this.cantEdit = false
8396
+ this.cleanGeneration = 1
8397
+ this.frontier = firstLine
8398
+ var start = Pos(firstLine, 0)
8399
+ this.sel = simpleSelection(start)
8400
+ this.history = new History(null)
8401
+ this.id = ++nextDocId
8402
+ this.modeOption = mode
8403
+ this.lineSep = lineSep
8404
+ this.extend = false
8405
+
8406
+ if (typeof text == "string") { text = this.splitLines(text) }
8407
+ updateDoc(this, {from: start, to: start, text: text})
8408
+ setSelection(this, simpleSelection(start), sel_dontScroll)
8409
+ }
8410
 
8411
+ Doc.prototype = createObj(BranchChunk.prototype, {
8412
+ constructor: Doc,
8413
+ // Iterate over the document. Supports two forms -- with only one
8414
+ // argument, it calls that for each line in the document. With
8415
+ // three, it iterates over the range given by the first two (with
8416
+ // the second being non-inclusive).
8417
+ iter: function(from, to, op) {
8418
+ if (op) { this.iterN(from - this.first, to - from, op) }
8419
+ else { this.iterN(this.first, this.first + this.size, from) }
8420
+ },
8421
 
8422
+ // Non-public interface for adding and removing lines.
8423
+ insert: function(at, lines) {
8424
+ var height = 0
8425
+ for (var i = 0; i < lines.length; ++i) { height += lines[i].height }
8426
+ this.insertInner(at - this.first, lines, height)
8427
+ },
8428
+ remove: function(at, n) { this.removeInner(at - this.first, n) },
8429
 
8430
+ // From here, the methods are part of the public interface. Most
8431
+ // are also available from CodeMirror (editor) instances.
 
 
 
 
 
 
 
8432
 
8433
+ getValue: function(lineSep) {
8434
+ var lines = getLines(this, this.first, this.first + this.size)
8435
+ if (lineSep === false) { return lines }
8436
+ return lines.join(lineSep || this.lineSeparator())
8437
+ },
8438
+ setValue: docMethodOp(function(code) {
8439
+ var top = Pos(this.first, 0), last = this.first + this.size - 1
8440
+ makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
8441
+ text: this.splitLines(code), origin: "setValue", full: true}, true)
8442
+ setSelection(this, simpleSelection(top))
8443
+ }),
8444
+ replaceRange: function(code, from, to, origin) {
8445
+ from = clipPos(this, from)
8446
+ to = to ? clipPos(this, to) : from
8447
+ replaceRange(this, code, from, to, origin)
8448
+ },
8449
+ getRange: function(from, to, lineSep) {
8450
+ var lines = getBetween(this, clipPos(this, from), clipPos(this, to))
8451
+ if (lineSep === false) { return lines }
8452
+ return lines.join(lineSep || this.lineSeparator())
8453
+ },
8454
 
8455
+ getLine: function(line) {var l = this.getLineHandle(line); return l && l.text},
 
8456
 
8457
+ getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }},
8458
+ getLineNumber: function(line) {return lineNo(line)},
 
 
 
 
 
 
 
 
 
8459
 
8460
+ getLineHandleVisualStart: function(line) {
8461
+ if (typeof line == "number") { line = getLine(this, line) }
8462
+ return visualLine(line)
8463
+ },
8464
 
8465
+ lineCount: function() {return this.size},
8466
+ firstLine: function() {return this.first},
8467
+ lastLine: function() {return this.first + this.size - 1},
8468
+
8469
+ clipPos: function(pos) {return clipPos(this, pos)},
8470
+
8471
+ getCursor: function(start) {
8472
+ var range = this.sel.primary(), pos
8473
+ if (start == null || start == "head") { pos = range.head }
8474
+ else if (start == "anchor") { pos = range.anchor }
8475
+ else if (start == "end" || start == "to" || start === false) { pos = range.to() }
8476
+ else { pos = range.from() }
8477
+ return pos
8478
+ },
8479
+ listSelections: function() { return this.sel.ranges },
8480
+ somethingSelected: function() {return this.sel.somethingSelected()},
8481
+
8482
+ setCursor: docMethodOp(function(line, ch, options) {
8483
+ setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options)
8484
+ }),
8485
+ setSelection: docMethodOp(function(anchor, head, options) {
8486
+ setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options)
8487
+ }),
8488
+ extendSelection: docMethodOp(function(head, other, options) {
8489
+ extendSelection(this, clipPos(this, head), other && clipPos(this, other), options)
8490
+ }),
8491
+ extendSelections: docMethodOp(function(heads, options) {
8492
+ extendSelections(this, clipPosArray(this, heads), options)
8493
+ }),
8494
+ extendSelectionsBy: docMethodOp(function(f, options) {
8495
+ var heads = map(this.sel.ranges, f)
8496
+ extendSelections(this, clipPosArray(this, heads), options)
8497
+ }),
8498
+ setSelections: docMethodOp(function(ranges, primary, options) {
8499
+ var this$1 = this;
8500
+
8501
+ if (!ranges.length) { return }
8502
+ var out = []
8503
+ for (var i = 0; i < ranges.length; i++)
8504
+ { out[i] = new Range(clipPos(this$1, ranges[i].anchor),
8505
+ clipPos(this$1, ranges[i].head)) }
8506
+ if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex) }
8507
+ setSelection(this, normalizeSelection(out, primary), options)
8508
+ }),
8509
+ addSelection: docMethodOp(function(anchor, head, options) {
8510
+ var ranges = this.sel.ranges.slice(0)
8511
+ ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)))
8512
+ setSelection(this, normalizeSelection(ranges, ranges.length - 1), options)
8513
+ }),
8514
+
8515
+ getSelection: function(lineSep) {
8516
+ var this$1 = this;
8517
+
8518
+ var ranges = this.sel.ranges, lines
8519
+ for (var i = 0; i < ranges.length; i++) {
8520
+ var sel = getBetween(this$1, ranges[i].from(), ranges[i].to())
8521
+ lines = lines ? lines.concat(sel) : sel
8522
  }
8523
+ if (lineSep === false) { return lines }
8524
+ else { return lines.join(lineSep || this.lineSeparator()) }
8525
+ },
8526
+ getSelections: function(lineSep) {
8527
+ var this$1 = this;
8528
 
8529
+ var parts = [], ranges = this.sel.ranges
8530
+ for (var i = 0; i < ranges.length; i++) {
8531
+ var sel = getBetween(this$1, ranges[i].from(), ranges[i].to())
8532
+ if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()) }
8533
+ parts[i] = sel
8534
+ }
8535
+ return parts
8536
+ },
8537
+ replaceSelection: function(code, collapse, origin) {
8538
+ var dup = []
8539
+ for (var i = 0; i < this.sel.ranges.length; i++)
8540
+ { dup[i] = code }
8541
+ this.replaceSelections(dup, collapse, origin || "+input")
8542
+ },
8543
+ replaceSelections: docMethodOp(function(code, collapse, origin) {
8544
+ var this$1 = this;
8545
 
8546
+ var changes = [], sel = this.sel
8547
+ for (var i = 0; i < sel.ranges.length; i++) {
8548
+ var range = sel.ranges[i]
8549
+ changes[i] = {from: range.from(), to: range.to(), text: this$1.splitLines(code[i]), origin: origin}
8550
+ }
8551
+ var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse)
8552
+ for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)
8553
+ { makeChange(this$1, changes[i$1]) }
8554
+ if (newSel) { setSelectionReplaceHistory(this, newSel) }
8555
+ else if (this.cm) { ensureCursorVisible(this.cm) }
8556
+ }),
8557
+ undo: docMethodOp(function() {makeChangeFromHistory(this, "undo")}),
8558
+ redo: docMethodOp(function() {makeChangeFromHistory(this, "redo")}),
8559
+ undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true)}),
8560
+ redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true)}),
8561
+
8562
+ setExtending: function(val) {this.extend = val},
8563
+ getExtending: function() {return this.extend},
8564
+
8565
+ historySize: function() {
8566
+ var hist = this.history, done = 0, undone = 0
8567
+ for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done } }
8568
+ for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone } }
8569
+ return {undo: done, redo: undone}
8570
+ },
8571
+ clearHistory: function() {this.history = new History(this.history.maxGeneration)},
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8572
 
8573
+ markClean: function() {
8574
+ this.cleanGeneration = this.changeGeneration(true)
8575
+ },
8576
+ changeGeneration: function(forceSplit) {
8577
+ if (forceSplit)
8578
+ { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null }
8579
+ return this.history.generation
8580
+ },
8581
+ isClean: function (gen) {
8582
+ return this.history.generation == (gen || this.cleanGeneration)
8583
+ },
8584
 
8585
+ getHistory: function() {
8586
+ return {done: copyHistoryArray(this.history.done),
8587
+ undone: copyHistoryArray(this.history.undone)}
8588
+ },
8589
+ setHistory: function(histData) {
8590
+ var hist = this.history = new History(this.history.maxGeneration)
8591
+ hist.done = copyHistoryArray(histData.done.slice(0), null, true)
8592
+ hist.undone = copyHistoryArray(histData.undone.slice(0), null, true)
8593
+ },
8594
 
8595
+ addLineClass: docMethodOp(function(handle, where, cls) {
8596
+ return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
8597
+ var prop = where == "text" ? "textClass"
8598
+ : where == "background" ? "bgClass"
8599
+ : where == "gutter" ? "gutterClass" : "wrapClass"
8600
+ if (!line[prop]) { line[prop] = cls }
8601
+ else if (classTest(cls).test(line[prop])) { return false }
8602
+ else { line[prop] += " " + cls }
8603
+ return true
8604
+ })
8605
+ }),
8606
+ removeLineClass: docMethodOp(function(handle, where, cls) {
8607
+ return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
8608
+ var prop = where == "text" ? "textClass"
8609
+ : where == "background" ? "bgClass"
8610
+ : where == "gutter" ? "gutterClass" : "wrapClass"
8611
+ var cur = line[prop]
8612
+ if (!cur) { return false }
8613
+ else if (cls == null) { line[prop] = null }
8614
+ else {
8615
+ var found = cur.match(classTest(cls))
8616
+ if (!found) { return false }
8617
+ var end = found.index + found[0].length
8618
+ line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null
8619
+ }
8620
+ return true
8621
+ })
8622
+ }),
8623
+
8624
+ addLineWidget: docMethodOp(function(handle, node, options) {
8625
+ return addLineWidget(this, handle, node, options)
8626
+ }),
8627
+ removeLineWidget: function(widget) { widget.clear() },
8628
+
8629
+ markText: function(from, to, options) {
8630
+ return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range")
8631
+ },
8632
+ setBookmark: function(pos, options) {
8633
+ var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
8634
+ insertLeft: options && options.insertLeft,
8635
+ clearWhenEmpty: false, shared: options && options.shared,
8636
+ handleMouseEvents: options && options.handleMouseEvents}
8637
+ pos = clipPos(this, pos)
8638
+ return markText(this, pos, pos, realOpts, "bookmark")
8639
+ },
8640
+ findMarksAt: function(pos) {
8641
+ pos = clipPos(this, pos)
8642
+ var markers = [], spans = getLine(this, pos.line).markedSpans
8643
+ if (spans) { for (var i = 0; i < spans.length; ++i) {
8644
+ var span = spans[i]
8645
+ if ((span.from == null || span.from <= pos.ch) &&
8646
+ (span.to == null || span.to >= pos.ch))
8647
+ { markers.push(span.marker.parent || span.marker) }
8648
+ } }
8649
+ return markers
8650
+ },
8651
+ findMarks: function(from, to, filter) {
8652
+ from = clipPos(this, from); to = clipPos(this, to)
8653
+ var found = [], lineNo = from.line
8654
+ this.iter(from.line, to.line + 1, function (line) {
8655
+ var spans = line.markedSpans
8656
+ if (spans) { for (var i = 0; i < spans.length; i++) {
8657
+ var span = spans[i]
8658
+ if (!(span.to != null && lineNo == from.line && from.ch >= span.to ||
8659
+ span.from == null && lineNo != from.line ||
8660
+ span.from != null && lineNo == to.line && span.from >= to.ch) &&
8661
+ (!filter || filter(span.marker)))
8662
+ { found.push(span.marker.parent || span.marker) }
8663
+ } }
8664
+ ++lineNo
8665
+ })
8666
+ return found
8667
+ },
8668
+ getAllMarks: function() {
8669
+ var markers = []
8670
+ this.iter(function (line) {
8671
+ var sps = line.markedSpans
8672
+ if (sps) { for (var i = 0; i < sps.length; ++i)
8673
+ { if (sps[i].from != null) { markers.push(sps[i].marker) } } }
8674
+ })
8675
+ return markers
8676
+ },
8677
 
8678
+ posFromIndex: function(off) {
8679
+ var ch, lineNo = this.first, sepSize = this.lineSeparator().length
8680
+ this.iter(function (line) {
8681
+ var sz = line.text.length + sepSize
8682
+ if (sz > off) { ch = off; return true }
8683
+ off -= sz
8684
+ ++lineNo
8685
+ })
8686
+ return clipPos(this, Pos(lineNo, ch))
8687
+ },
8688
+ indexFromPos: function (coords) {
8689
+ coords = clipPos(this, coords)
8690
+ var index = coords.ch
8691
+ if (coords.line < this.first || coords.ch < 0) { return 0 }
8692
+ var sepSize = this.lineSeparator().length
8693
+ this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value
8694
+ index += line.text.length + sepSize
8695
+ })
8696
+ return index
8697
+ },
8698
+
8699
+ copy: function(copyHistory) {
8700
+ var doc = new Doc(getLines(this, this.first, this.first + this.size),
8701
+ this.modeOption, this.first, this.lineSep)
8702
+ doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft
8703
+ doc.sel = this.sel
8704
+ doc.extend = false
8705
+ if (copyHistory) {
8706
+ doc.history.undoDepth = this.history.undoDepth
8707
+ doc.setHistory(this.getHistory())
8708
+ }
8709
+ return doc
8710
+ },
8711
+
8712
+ linkedDoc: function(options) {
8713
+ if (!options) { options = {} }
8714
+ var from = this.first, to = this.first + this.size
8715
+ if (options.from != null && options.from > from) { from = options.from }
8716
+ if (options.to != null && options.to < to) { to = options.to }
8717
+ var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep)
8718
+ if (options.sharedHist) { copy.history = this.history
8719
+ ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist})
8720
+ copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]
8721
+ copySharedMarkers(copy, findSharedMarkers(this))
8722
+ return copy
8723
+ },
8724
+ unlinkDoc: function(other) {
8725
+ var this$1 = this;
8726
+
8727
+ if (other instanceof CodeMirror) { other = other.doc }
8728
+ if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {
8729
+ var link = this$1.linked[i]
8730
+ if (link.doc != other) { continue }
8731
+ this$1.linked.splice(i, 1)
8732
+ other.unlinkDoc(this$1)
8733
+ detachSharedMarkers(findSharedMarkers(this$1))
8734
+ break
8735
+ } }
8736
+ // If the histories were shared, split them again
8737
+ if (other.history == this.history) {
8738
+ var splitIds = [other.id]
8739
+ linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true)
8740
+ other.history = new History(null)
8741
+ other.history.done = copyHistoryArray(this.history.done, splitIds)
8742
+ other.history.undone = copyHistoryArray(this.history.undone, splitIds)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8743
  }
8744
+ },
8745
+ iterLinkedDocs: function(f) {linkedDocs(this, f)},
 
8746
 
8747
+ getMode: function() {return this.mode},
8748
+ getEditor: function() {return this.cm},
8749
+
8750
+ splitLines: function(str) {
8751
+ if (this.lineSep) { return str.split(this.lineSep) }
8752
+ return splitLinesAuto(str)
8753
+ },
8754
+ lineSeparator: function() { return this.lineSep || "\n" }
8755
+ })
8756
+
8757
+ // Public alias.
8758
+ Doc.prototype.eachLine = Doc.prototype.iter
8759
+
8760
+ // Kludge to work around strange IE behavior where it'll sometimes
8761
+ // re-fire a series of drag-related events right after the drop (#1551)
8762
+ var lastDrop = 0
8763
+
8764
+ function onDrop(e) {
8765
+ var cm = this
8766
+ clearDragCursor(cm)
8767
+ if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
8768
+ { return }
8769
+ e_preventDefault(e)
8770
+ if (ie) { lastDrop = +new Date }
8771
+ var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files
8772
+ if (!pos || cm.isReadOnly()) { return }
8773
+ // Might be a file drop, in which case we simply extract the text
8774
+ // and insert it.
8775
+ if (files && files.length && window.FileReader && window.File) {
8776
+ var n = files.length, text = Array(n), read = 0
8777
+ var loadFile = function (file, i) {
8778
+ if (cm.options.allowDropFileTypes &&
8779
+ indexOf(cm.options.allowDropFileTypes, file.type) == -1)
8780
+ { return }
8781
+
8782
+ var reader = new FileReader
8783
+ reader.onload = operation(cm, function () {
8784
+ var content = reader.result
8785
+ if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = "" }
8786
+ text[i] = content
8787
+ if (++read == n) {
8788
+ pos = clipPos(cm.doc, pos)
8789
+ var change = {from: pos, to: pos,
8790
+ text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
8791
+ origin: "paste"}
8792
+ makeChange(cm.doc, change)
8793
+ setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)))
8794
+ }
8795
+ })
8796
+ reader.readAsText(file)
8797
+ }
8798
+ for (var i = 0; i < n; ++i) { loadFile(files[i], i) }
8799
+ } else { // Normal drop
8800
+ // Don't do a replace if the drop happened inside of the selected text.
8801
+ if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
8802
+ cm.state.draggingText(e)
8803
+ // Ensure the editor is re-focused
8804
+ setTimeout(function () { return cm.display.input.focus(); }, 20)
8805
+ return
8806
+ }
8807
+ try {
8808
+ var text$1 = e.dataTransfer.getData("Text")
8809
+ if (text$1) {
8810
+ var selected
8811
+ if (cm.state.draggingText && !cm.state.draggingText.copy)
8812
+ { selected = cm.listSelections() }
8813
+ setSelectionNoUndo(cm.doc, simpleSelection(pos, pos))
8814
+ if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1)
8815
+ { replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag") } }
8816
+ cm.replaceSelection(text$1, "around", "paste")
8817
+ cm.display.input.focus()
8818
  }
8819
  }
8820
+ catch(e){}
8821
+ }
8822
+ }
8823
 
8824
+ function onDragStart(cm, e) {
8825
+ if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return }
8826
+ if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return }
 
 
 
8827
 
8828
+ e.dataTransfer.setData("Text", cm.getSelection())
8829
+ e.dataTransfer.effectAllowed = "copyMove"
 
 
 
 
 
 
 
 
 
8830
 
8831
+ // Use dummy image instead of default browsers image.
8832
+ // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
8833
+ if (e.dataTransfer.setDragImage && !safari) {
8834
+ var img = elt("img", null, null, "position: fixed; left: 0; top: 0;")
8835
+ img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
8836
+ if (presto) {
8837
+ img.width = img.height = 1
8838
+ cm.display.wrapper.appendChild(img)
8839
+ // Force a relayout, or Opera won't use our image for some obscure reason
8840
+ img._top = img.offsetTop
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8841
  }
8842
+ e.dataTransfer.setDragImage(img, 0, 0)
8843
+ if (presto) { img.parentNode.removeChild(img) }
8844
+ }
8845
+ }
8846
 
8847
+ function onDragOver(cm, e) {
8848
+ var pos = posFromMouse(cm, e)
8849
+ if (!pos) { return }
8850
+ var frag = document.createDocumentFragment()
8851
+ drawSelectionCursor(cm, pos, frag)
8852
+ if (!cm.display.dragCursor) {
8853
+ cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors")
8854
+ cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv)
8855
+ }
8856
+ removeChildrenAndAdd(cm.display.dragCursor, frag)
8857
+ }
 
 
 
 
8858
 
8859
+ function clearDragCursor(cm) {
8860
+ if (cm.display.dragCursor) {
8861
+ cm.display.lineSpace.removeChild(cm.display.dragCursor)
8862
+ cm.display.dragCursor = null
8863
+ }
8864
+ }
8865
 
8866
+ // These must be handled carefully, because naively registering a
8867
+ // handler for each editor will cause the editors to never be
8868
+ // garbage collected.
8869
 
8870
+ function forEachCodeMirror(f) {
8871
+ if (!document.body.getElementsByClassName) { return }
8872
+ var byClass = document.body.getElementsByClassName("CodeMirror")
8873
+ for (var i = 0; i < byClass.length; i++) {
8874
+ var cm = byClass[i].CodeMirror
8875
+ if (cm) { f(cm) }
8876
+ }
8877
+ }
8878
 
8879
+ var globalsRegistered = false
8880
+ function ensureGlobalHandlers() {
8881
+ if (globalsRegistered) { return }
8882
+ registerGlobalHandlers()
8883
+ globalsRegistered = true
8884
+ }
8885
+ function registerGlobalHandlers() {
8886
+ // When the window resizes, we need to refresh active editors.
8887
+ var resizeTimer
8888
+ on(window, "resize", function () {
8889
+ if (resizeTimer == null) { resizeTimer = setTimeout(function () {
8890
+ resizeTimer = null
8891
+ forEachCodeMirror(onResize)
8892
+ }, 100) }
8893
+ })
8894
+ // When the window loses focus, we want to show the editor as blurred
8895
+ on(window, "blur", function () { return forEachCodeMirror(onBlur); })
8896
+ }
8897
+ // Called when the window resizes
8898
+ function onResize(cm) {
8899
+ var d = cm.display
8900
+ if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)
8901
+ { return }
8902
+ // Might be a text scaling operation, clear size caches.
8903
+ d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null
8904
+ d.scrollbarsClipped = false
8905
+ cm.setSize()
8906
+ }
8907
 
8908
+ var keyNames = {
8909
+ 3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
8910
+ 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
8911
+ 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
8912
+ 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
8913
+ 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete",
8914
+ 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
8915
+ 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
8916
+ 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
8917
+ }
8918
+
8919
+ // Number keys
8920
+ for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i) }
8921
+ // Alphabetic keys
8922
+ for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1) }
8923
+ // Function keys
8924
+ for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2 }
8925
+
8926
+ var keyMap = {}
8927
+
8928
+ keyMap.basic = {
8929
+ "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
8930
+ "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
8931
+ "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
8932
+ "Tab": "defaultTab", "Shift-Tab": "indentAuto",
8933
+ "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
8934
+ "Esc": "singleSelection"
8935
+ }
8936
+ // Note that the save and find-related commands aren't defined by
8937
+ // default. User code or addons can define them. Unknown commands
8938
+ // are simply ignored.
8939
+ keyMap.pcDefault = {
8940
+ "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
8941
+ "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
8942
+ "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
8943
+ "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
8944
+ "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
8945
+ "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
8946
+ "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
8947
+ fallthrough: "basic"
8948
+ }
8949
+ // Very basic readline/emacs-style bindings, which are standard on Mac.
8950
+ keyMap.emacsy = {
8951
+ "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
8952
+ "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
8953
+ "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
8954
+ "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars",
8955
+ "Ctrl-O": "openLine"
8956
+ }
8957
+ keyMap.macDefault = {
8958
+ "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
8959
+ "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
8960
+ "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
8961
+ "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
8962
+ "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
8963
+ "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
8964
+ "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
8965
+ fallthrough: ["basic", "emacsy"]
8966
+ }
8967
+ keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault
8968
+
8969
+ // KEYMAP DISPATCH
8970
+
8971
+ function normalizeKeyName(name) {
8972
+ var parts = name.split(/-(?!$)/)
8973
+ name = parts[parts.length - 1]
8974
+ var alt, ctrl, shift, cmd
8975
+ for (var i = 0; i < parts.length - 1; i++) {
8976
+ var mod = parts[i]
8977
+ if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true }
8978
+ else if (/^a(lt)?$/i.test(mod)) { alt = true }
8979
+ else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true }
8980
+ else if (/^s(hift)?$/i.test(mod)) { shift = true }
8981
+ else { throw new Error("Unrecognized modifier name: " + mod) }
8982
+ }
8983
+ if (alt) { name = "Alt-" + name }
8984
+ if (ctrl) { name = "Ctrl-" + name }
8985
+ if (cmd) { name = "Cmd-" + name }
8986
+ if (shift) { name = "Shift-" + name }
8987
+ return name
8988
+ }
8989
+
8990
+ // This is a kludge to keep keymaps mostly working as raw objects
8991
+ // (backwards compatibility) while at the same time support features
8992
+ // like normalization and multi-stroke key bindings. It compiles a
8993
+ // new normalized keymap, and then updates the old object to reflect
8994
+ // this.
8995
+ function normalizeKeyMap(keymap) {
8996
+ var copy = {}
8997
+ for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) {
8998
+ var value = keymap[keyname]
8999
+ if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue }
9000
+ if (value == "...") { delete keymap[keyname]; continue }
9001
+
9002
+ var keys = map(keyname.split(" "), normalizeKeyName)
9003
+ for (var i = 0; i < keys.length; i++) {
9004
+ var val = void 0, name = void 0
9005
+ if (i == keys.length - 1) {
9006
+ name = keys.join(" ")
9007
+ val = value
9008
  } else {
9009
+ name = keys.slice(0, i + 1).join(" ")
9010
+ val = "..."
 
 
9011
  }
9012
+ var prev = copy[name]
9013
+ if (!prev) { copy[name] = val }
9014
+ else if (prev != val) { throw new Error("Inconsistent bindings for " + name) }
 
 
 
9015
  }
9016
+ delete keymap[keyname]
9017
+ } }
9018
+ for (var prop in copy) { keymap[prop] = copy[prop] }
9019
+ return keymap
9020
+ }
9021
 
9022
+ function lookupKey(key, map, handle, context) {
9023
+ map = getKeyMap(map)
9024
+ var found = map.call ? map.call(key, context) : map[key]
9025
+ if (found === false) { return "nothing" }
9026
+ if (found === "...") { return "multi" }
9027
+ if (found != null && handle(found)) { return "handled" }
9028
 
9029
+ if (map.fallthrough) {
9030
+ if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
9031
+ { return lookupKey(key, map.fallthrough, handle, context) }
9032
+ for (var i = 0; i < map.fallthrough.length; i++) {
9033
+ var result = lookupKey(key, map.fallthrough[i], handle, context)
9034
+ if (result) { return result }
9035
+ }
9036
+ }
9037
+ }
9038
 
9039
+ // Modifier key presses don't count as 'real' key presses for the
9040
+ // purpose of keymap fallthrough.
9041
+ function isModifierKey(value) {
9042
+ var name = typeof value == "string" ? value : keyNames[value.keyCode]
9043
+ return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"
9044
+ }
9045
 
9046
+ // Look up the name of a key as indicated by an event object.
9047
+ function keyName(event, noShift) {
9048
+ if (presto && event.keyCode == 34 && event["char"]) { return false }
9049
+ var base = keyNames[event.keyCode], name = base
9050
+ if (name == null || event.altGraphKey) { return false }
9051
+ if (event.altKey && base != "Alt") { name = "Alt-" + name }
9052
+ if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name }
9053
+ if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name }
9054
+ if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name }
9055
+ return name
9056
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9057
 
9058
+ function getKeyMap(val) {
9059
+ return typeof val == "string" ? keyMap[val] : val
9060
+ }
 
 
 
 
 
 
 
 
9061
 
9062
+ // Helper for deleting text near the selection(s), used to implement
9063
+ // backspace, delete, and similar functionality.
9064
+ function deleteNearSelection(cm, compute) {
9065
+ var ranges = cm.doc.sel.ranges, kill = []
9066
+ // Build up a set of ranges to kill first, merging overlapping
9067
+ // ranges.
9068
+ for (var i = 0; i < ranges.length; i++) {
9069
+ var toKill = compute(ranges[i])
9070
+ while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
9071
+ var replaced = kill.pop()
9072
+ if (cmp(replaced.from, toKill.from) < 0) {
9073
+ toKill.from = replaced.from
9074
+ break
9075
+ }
9076
+ }
9077
+ kill.push(toKill)
9078
+ }
9079
+ // Next, remove those actual ranges.
9080
+ runInOp(cm, function () {
9081
+ for (var i = kill.length - 1; i >= 0; i--)
9082
+ { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete") }
9083
+ ensureCursorVisible(cm)
9084
+ })
9085
+ }
9086
 
9087
+ // Commands are parameter-less actions that can be performed on an
9088
+ // editor, mostly used for keybindings.
9089
+ var commands = {
9090
+ selectAll: selectAll,
9091
+ singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); },
9092
+ killLine: function (cm) { return deleteNearSelection(cm, function (range) {
9093
+ if (range.empty()) {
9094
+ var len = getLine(cm.doc, range.head.line).text.length
9095
+ if (range.head.ch == len && range.head.line < cm.lastLine())
9096
+ { return {from: range.head, to: Pos(range.head.line + 1, 0)} }
9097
+ else
9098
+ { return {from: range.head, to: Pos(range.head.line, len)} }
9099
+ } else {
9100
+ return {from: range.from(), to: range.to()}
9101
+ }
9102
+ }); },
9103
+ deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({
9104
+ from: Pos(range.from().line, 0),
9105
+ to: clipPos(cm.doc, Pos(range.to().line + 1, 0))
9106
+ }); }); },
9107
+ delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({
9108
+ from: Pos(range.from().line, 0), to: range.from()
9109
+ }); }); },
9110
+ delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) {
9111
+ var top = cm.charCoords(range.head, "div").top + 5
9112
+ var leftPos = cm.coordsChar({left: 0, top: top}, "div")
9113
+ return {from: leftPos, to: range.from()}
9114
+ }); },
9115
+ delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) {
9116
+ var top = cm.charCoords(range.head, "div").top + 5
9117
+ var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")
9118
+ return {from: range.from(), to: rightPos }
9119
+ }); },
9120
+ undo: function (cm) { return cm.undo(); },
9121
+ redo: function (cm) { return cm.redo(); },
9122
+ undoSelection: function (cm) { return cm.undoSelection(); },
9123
+ redoSelection: function (cm) { return cm.redoSelection(); },
9124
+ goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); },
9125
+ goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); },
9126
+ goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); },
9127
+ {origin: "+move", bias: 1}
9128
+ ); },
9129
+ goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); },
9130
+ {origin: "+move", bias: 1}
9131
+ ); },
9132
+ goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); },
9133
+ {origin: "+move", bias: -1}
9134
+ ); },
9135
+ goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) {
9136
+ var top = cm.charCoords(range.head, "div").top + 5
9137
+ return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")
9138
+ }, sel_move); },
9139
+ goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) {
9140
+ var top = cm.charCoords(range.head, "div").top + 5
9141
+ return cm.coordsChar({left: 0, top: top}, "div")
9142
+ }, sel_move); },
9143
+ goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) {
9144
+ var top = cm.charCoords(range.head, "div").top + 5
9145
+ var pos = cm.coordsChar({left: 0, top: top}, "div")
9146
+ if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) }
9147
+ return pos
9148
+ }, sel_move); },
9149
+ goLineUp: function (cm) { return cm.moveV(-1, "line"); },
9150
+ goLineDown: function (cm) { return cm.moveV(1, "line"); },
9151
+ goPageUp: function (cm) { return cm.moveV(-1, "page"); },
9152
+ goPageDown: function (cm) { return cm.moveV(1, "page"); },
9153
+ goCharLeft: function (cm) { return cm.moveH(-1, "char"); },
9154
+ goCharRight: function (cm) { return cm.moveH(1, "char"); },
9155
+ goColumnLeft: function (cm) { return cm.moveH(-1, "column"); },
9156
+ goColumnRight: function (cm) { return cm.moveH(1, "column"); },
9157
+ goWordLeft: function (cm) { return cm.moveH(-1, "word"); },
9158
+ goGroupRight: function (cm) { return cm.moveH(1, "group"); },
9159
+ goGroupLeft: function (cm) { return cm.moveH(-1, "group"); },
9160
+ goWordRight: function (cm) { return cm.moveH(1, "word"); },
9161
+ delCharBefore: function (cm) { return cm.deleteH(-1, "char"); },
9162
+ delCharAfter: function (cm) { return cm.deleteH(1, "char"); },
9163
+ delWordBefore: function (cm) { return cm.deleteH(-1, "word"); },
9164
+ delWordAfter: function (cm) { return cm.deleteH(1, "word"); },
9165
+ delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); },
9166
+ delGroupAfter: function (cm) { return cm.deleteH(1, "group"); },
9167
+ indentAuto: function (cm) { return cm.indentSelection("smart"); },
9168
+ indentMore: function (cm) { return cm.indentSelection("add"); },
9169
+ indentLess: function (cm) { return cm.indentSelection("subtract"); },
9170
+ insertTab: function (cm) { return cm.replaceSelection("\t"); },
9171
+ insertSoftTab: function (cm) {
9172
+ var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize
9173
+ for (var i = 0; i < ranges.length; i++) {
9174
+ var pos = ranges[i].from()
9175
+ var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize)
9176
+ spaces.push(spaceStr(tabSize - col % tabSize))
9177
+ }
9178
+ cm.replaceSelections(spaces)
9179
+ },
9180
+ defaultTab: function (cm) {
9181
+ if (cm.somethingSelected()) { cm.indentSelection("add") }
9182
+ else { cm.execCommand("insertTab") }
9183
+ },
9184
+ // Swap the two chars left and right of each selection's head.
9185
+ // Move cursor behind the two swapped characters afterwards.
9186
+ //
9187
+ // Doesn't consider line feeds a character.
9188
+ // Doesn't scan more than one line above to find a character.
9189
+ // Doesn't do anything on an empty line.
9190
+ // Doesn't do anything with non-empty selections.
9191
+ transposeChars: function (cm) { return runInOp(cm, function () {
9192
+ var ranges = cm.listSelections(), newSel = []
9193
+ for (var i = 0; i < ranges.length; i++) {
9194
+ if (!ranges[i].empty()) { continue }
9195
+ var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text
9196
+ if (line) {
9197
+ if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1) }
9198
+ if (cur.ch > 0) {
9199
+ cur = new Pos(cur.line, cur.ch + 1)
9200
+ cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
9201
+ Pos(cur.line, cur.ch - 2), cur, "+transpose")
9202
+ } else if (cur.line > cm.doc.first) {
9203
+ var prev = getLine(cm.doc, cur.line - 1).text
9204
+ if (prev) {
9205
+ cur = new Pos(cur.line, 1)
9206
+ cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
9207
+ prev.charAt(prev.length - 1),
9208
+ Pos(cur.line - 1, prev.length - 1), cur, "+transpose")
9209
+ }
9210
+ }
9211
  }
9212
+ newSel.push(new Range(cur, cur))
9213
+ }
9214
+ cm.setSelections(newSel)
9215
+ }); },
9216
+ newlineAndIndent: function (cm) { return runInOp(cm, function () {
9217
+ var sels = cm.listSelections()
9218
+ for (var i = sels.length - 1; i >= 0; i--)
9219
+ { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input") }
9220
+ sels = cm.listSelections()
9221
+ for (var i$1 = 0; i$1 < sels.length; i$1++)
9222
+ { cm.indentLine(sels[i$1].from().line, null, true) }
9223
+ ensureCursorVisible(cm)
9224
+ }); },
9225
+ openLine: function (cm) { return cm.replaceSelection("\n", "start"); },
9226
+ toggleOverwrite: function (cm) { return cm.toggleOverwrite(); }
9227
+ }
9228
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9229
 
9230
+ function lineStart(cm, lineN) {
9231
+ var line = getLine(cm.doc, lineN)
9232
+ var visual = visualLine(line)
9233
+ if (visual != line) { lineN = lineNo(visual) }
9234
+ var order = getOrder(visual)
9235
+ var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual)
9236
+ return Pos(lineN, ch)
9237
+ }
9238
+ function lineEnd(cm, lineN) {
9239
+ var merged, line = getLine(cm.doc, lineN)
9240
+ while (merged = collapsedSpanAtEnd(line)) {
9241
+ line = merged.find(1, true).line
9242
+ lineN = null
9243
+ }
9244
+ var order = getOrder(line)
9245
+ var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line)
9246
+ return Pos(lineN == null ? lineNo(line) : lineN, ch)
9247
+ }
9248
+ function lineStartSmart(cm, pos) {
9249
+ var start = lineStart(cm, pos.line)
9250
+ var line = getLine(cm.doc, start.line)
9251
+ var order = getOrder(line)
9252
+ if (!order || order[0].level == 0) {
9253
+ var firstNonWS = Math.max(0, line.text.search(/\S/))
9254
+ var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch
9255
+ return Pos(start.line, inWS ? 0 : firstNonWS)
9256
+ }
9257
+ return start
9258
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9259
 
9260
+ // Run a handler that was bound to a key.
9261
+ function doHandleBinding(cm, bound, dropShift) {
9262
+ if (typeof bound == "string") {
9263
+ bound = commands[bound]
9264
+ if (!bound) { return false }
9265
+ }
9266
+ // Ensure previous input has been read, so that the handler sees a
9267
+ // consistent view of the document
9268
+ cm.display.input.ensurePolled()
9269
+ var prevShift = cm.display.shift, done = false
9270
+ try {
9271
+ if (cm.isReadOnly()) { cm.state.suppressEdits = true }
9272
+ if (dropShift) { cm.display.shift = false }
9273
+ done = bound(cm) != Pass
9274
+ } finally {
9275
+ cm.display.shift = prevShift
9276
+ cm.state.suppressEdits = false
9277
+ }
9278
+ return done
9279
+ }
9280
 
9281
+ function lookupKeyForEditor(cm, name, handle) {
9282
+ for (var i = 0; i < cm.state.keyMaps.length; i++) {
9283
+ var result = lookupKey(name, cm.state.keyMaps[i], handle, cm)
9284
+ if (result) { return result }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9285
  }
9286
+ return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
9287
+ || lookupKey(name, cm.options.keyMap, handle, cm)
9288
+ }
9289
 
9290
+ var stopSeq = new Delayed
9291
+ function dispatchKey(cm, name, e, handle) {
9292
+ var seq = cm.state.keySeq
9293
+ if (seq) {
9294
+ if (isModifierKey(name)) { return "handled" }
9295
+ stopSeq.set(50, function () {
9296
+ if (cm.state.keySeq == seq) {
9297
+ cm.state.keySeq = null
9298
+ cm.display.input.reset()
9299
+ }
9300
+ })
9301
+ name = seq + " " + name
9302
+ }
9303
+ var result = lookupKeyForEditor(cm, name, handle)
9304
 
9305
+ if (result == "multi")
9306
+ { cm.state.keySeq = name }
9307
+ if (result == "handled")
9308
+ { signalLater(cm, "keyHandled", cm, name, e) }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9309
 
9310
+ if (result == "handled" || result == "multi") {
9311
+ e_preventDefault(e)
9312
+ restartBlink(cm)
 
 
 
 
 
 
 
 
 
 
9313
  }
9314
 
9315
+ if (seq && !result && /\'$/.test(name)) {
9316
+ e_preventDefault(e)
9317
+ return true
9318
  }
9319
+ return !!result
9320
+ }
9321
 
9322
+ // Handle a key from the keydown event.
9323
+ function handleKeyBinding(cm, e) {
9324
+ var name = keyName(e, true)
9325
+ if (!name) { return false }
9326
+
9327
+ if (e.shiftKey && !cm.state.keySeq) {
9328
+ // First try to resolve full name (including 'Shift-'). Failing
9329
+ // that, see if there is a cursor-motion command (starting with
9330
+ // 'go') bound to the keyname without 'Shift-'.
9331
+ return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); })
9332
+ || dispatchKey(cm, name, e, function (b) {
9333
+ if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
9334
+ { return doHandleBinding(cm, b) }
9335
+ })
9336
+ } else {
9337
+ return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); })
9338
  }
9339
+ }
9340
 
9341
+ // Handle a key from the keypress event
9342
+ function handleCharBinding(cm, e, ch) {
9343
+ return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); })
9344
+ }
 
 
 
 
 
 
 
 
 
9345
 
9346
+ var lastStoppedKey = null
9347
+ function onKeyDown(e) {
9348
+ var cm = this
9349
+ cm.curOp.focus = activeElt()
9350
+ if (signalDOMEvent(cm, e)) { return }
9351
+ // IE does strange things with escape.
9352
+ if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false }
9353
+ var code = e.keyCode
9354
+ cm.display.shift = code == 16 || e.shiftKey
9355
+ var handled = handleKeyBinding(cm, e)
9356
+ if (presto) {
9357
+ lastStoppedKey = handled ? code : null
9358
+ // Opera has no cut event... we try to at least catch the key combo
9359
+ if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
9360
+ { cm.replaceSelection("", null, "cut") }
9361
+ }
9362
+
9363
+ // Turn mouse into crosshair when Alt is held on Mac.
9364
+ if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
9365
+ { showCrossHair(cm) }
9366
+ }
9367
 
9368
+ function showCrossHair(cm) {
9369
+ var lineDiv = cm.display.lineDiv
9370
+ addClass(lineDiv, "CodeMirror-crosshair")
 
9371
 
9372
+ function up(e) {
9373
+ if (e.keyCode == 18 || !e.altKey) {
9374
+ rmClass(lineDiv, "CodeMirror-crosshair")
9375
+ off(document, "keyup", up)
9376
+ off(document, "mouseover", up)
9377
  }
9378
  }
9379
+ on(document, "keyup", up)
9380
+ on(document, "mouseover", up)
9381
+ }
 
 
 
 
 
 
 
 
 
9382
 
9383
+ function onKeyUp(e) {
9384
+ if (e.keyCode == 16) { this.doc.sel.shift = false }
9385
+ signalDOMEvent(this, e)
9386
+ }
9387
+
9388
+ function onKeyPress(e) {
9389
+ var cm = this
9390
+ if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }
9391
+ var keyCode = e.keyCode, charCode = e.charCode
9392
+ if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}
9393
+ if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return }
9394
+ var ch = String.fromCharCode(charCode == null ? keyCode : charCode)
9395
+ // Some browsers fire keypress events for backspace
9396
+ if (ch == "\x08") { return }
9397
+ if (handleCharBinding(cm, e, ch)) { return }
9398
+ cm.display.input.onKeyPress(e)
9399
+ }
9400
+
9401
+ // A mouse down can be a single click, double click, triple click,
9402
+ // start of selection drag, start of text drag, new cursor
9403
+ // (ctrl-click), rectangle drag (alt-drag), or xwin
9404
+ // middle-click-paste. Or it might be a click on something we should
9405
+ // not interfere with, such as a scrollbar or widget.
9406
+ function onMouseDown(e) {
9407
+ var cm = this, display = cm.display
9408
+ if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return }
9409
+ display.shift = e.shiftKey
9410
+
9411
+ if (eventInWidget(display, e)) {
9412
+ if (!webkit) {
9413
+ // Briefly turn off draggability, to allow widgets to do
9414
+ // normal dragging things.
9415
+ display.scroller.draggable = false
9416
+ setTimeout(function () { return display.scroller.draggable = true; }, 100)
9417
+ }
9418
+ return
9419
+ }
9420
+ if (clickInGutter(cm, e)) { return }
9421
+ var start = posFromMouse(cm, e)
9422
+ window.focus()
9423
+
9424
+ switch (e_button(e)) {
9425
+ case 1:
9426
+ // #3261: make sure, that we're not starting a second selection
9427
+ if (cm.state.selectingText)
9428
+ { cm.state.selectingText(e) }
9429
+ else if (start)
9430
+ { leftButtonDown(cm, e, start) }
9431
+ else if (e_target(e) == display.scroller)
9432
+ { e_preventDefault(e) }
9433
+ break
9434
+ case 2:
9435
+ if (webkit) { cm.state.lastMiddleDown = +new Date }
9436
+ if (start) { extendSelection(cm.doc, start) }
9437
+ setTimeout(function () { return display.input.focus(); }, 20)
9438
+ e_preventDefault(e)
9439
+ break
9440
+ case 3:
9441
+ if (captureRightClick) { onContextMenu(cm, e) }
9442
+ else { delayBlurEvent(cm) }
9443
+ break
9444
  }
9445
+ }
9446
+
9447
+ var lastClick;
9448
+ var lastDoubleClick;
9449
+ function leftButtonDown(cm, e, start) {
9450
+ if (ie) { setTimeout(bind(ensureFocus, cm), 0) }
9451
+ else { cm.curOp.focus = activeElt() }
9452
+
9453
+ var now = +new Date, type
9454
+ if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) {
9455
+ type = "triple"
9456
+ } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) {
9457
+ type = "double"
9458
+ lastDoubleClick = {time: now, pos: start}
9459
+ } else {
9460
+ type = "single"
9461
+ lastClick = {time: now, pos: start}
9462
+ }
9463
+
9464
+ var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained
9465
+ if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
9466
+ type == "single" && (contained = sel.contains(start)) > -1 &&
9467
+ (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) &&
9468
+ (cmp(contained.to(), start) > 0 || start.xRel < 0))
9469
+ { leftButtonStartDrag(cm, e, start, modifier) }
9470
+ else
9471
+ { leftButtonSelect(cm, e, start, type, modifier) }
9472
+ }
9473
+
9474
+ // Start a text drag. When it ends, see if any dragging actually
9475
+ // happen, and treat as a click if it didn't.
9476
+ function leftButtonStartDrag(cm, e, start, modifier) {
9477
+ var display = cm.display, startTime = +new Date
9478
+ var dragEnd = operation(cm, function (e2) {
9479
+ if (webkit) { display.scroller.draggable = false }
9480
+ cm.state.draggingText = false
9481
+ off(document, "mouseup", dragEnd)
9482
+ off(display.scroller, "drop", dragEnd)
9483
+ if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
9484
+ e_preventDefault(e2)
9485
+ if (!modifier && +new Date - 200 < startTime)
9486
+ { extendSelection(cm.doc, start) }
9487
+ // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
9488
+ if (webkit || ie && ie_version == 9)
9489
+ { setTimeout(function () {document.body.focus(); display.input.focus()}, 20) }
9490
+ else
9491
+ { display.input.focus() }
9492
+ }
9493
+ })
9494
+ // Let the drag handler handle this.
9495
+ if (webkit) { display.scroller.draggable = true }
9496
+ cm.state.draggingText = dragEnd
9497
+ dragEnd.copy = mac ? e.altKey : e.ctrlKey
9498
+ // IE's approach to draggable
9499
+ if (display.scroller.dragDrop) { display.scroller.dragDrop() }
9500
+ on(document, "mouseup", dragEnd)
9501
+ on(display.scroller, "drop", dragEnd)
9502
+ }
9503
+
9504
+ // Normal selection, as opposed to text dragging.
9505
+ function leftButtonSelect(cm, e, start, type, addNew) {
9506
+ var display = cm.display, doc = cm.doc
9507
+ e_preventDefault(e)
9508
+
9509
+ var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges
9510
+ if (addNew && !e.shiftKey) {
9511
+ ourIndex = doc.sel.contains(start)
9512
+ if (ourIndex > -1)
9513
+ { ourRange = ranges[ourIndex] }
9514
+ else
9515
+ { ourRange = new Range(start, start) }
9516
+ } else {
9517
+ ourRange = doc.sel.primary()
9518
+ ourIndex = doc.sel.primIndex
9519
+ }
9520
+
9521
+ if (chromeOS ? e.shiftKey && e.metaKey : e.altKey) {
9522
+ type = "rect"
9523
+ if (!addNew) { ourRange = new Range(start, start) }
9524
+ start = posFromMouse(cm, e, true, true)
9525
+ ourIndex = -1
9526
+ } else if (type == "double") {
9527
+ var word = cm.findWordAt(start)
9528
+ if (cm.display.shift || doc.extend)
9529
+ { ourRange = extendRange(doc, ourRange, word.anchor, word.head) }
9530
+ else
9531
+ { ourRange = word }
9532
+ } else if (type == "triple") {
9533
+ var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0)))
9534
+ if (cm.display.shift || doc.extend)
9535
+ { ourRange = extendRange(doc, ourRange, line.anchor, line.head) }
9536
+ else
9537
+ { ourRange = line }
9538
+ } else {
9539
+ ourRange = extendRange(doc, ourRange, start)
9540
+ }
9541
+
9542
+ if (!addNew) {
9543
+ ourIndex = 0
9544
+ setSelection(doc, new Selection([ourRange], 0), sel_mouse)
9545
+ startSel = doc.sel
9546
+ } else if (ourIndex == -1) {
9547
+ ourIndex = ranges.length
9548
+ setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
9549
+ {scroll: false, origin: "*mouse"})
9550
+ } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) {
9551
+ setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
9552
+ {scroll: false, origin: "*mouse"})
9553
+ startSel = doc.sel
9554
+ } else {
9555
+ replaceOneSelection(doc, ourIndex, ourRange, sel_mouse)
9556
+ }
9557
+
9558
+ var lastPos = start
9559
+ function extendTo(pos) {
9560
+ if (cmp(lastPos, pos) == 0) { return }
9561
+ lastPos = pos
9562
+
9563
+ if (type == "rect") {
9564
+ var ranges = [], tabSize = cm.options.tabSize
9565
+ var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize)
9566
+ var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize)
9567
+ var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol)
9568
+ for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
9569
+ line <= end; line++) {
9570
+ var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize)
9571
+ if (left == right)
9572
+ { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))) }
9573
+ else if (text.length > leftPos)
9574
+ { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))) }
9575
+ }
9576
+ if (!ranges.length) { ranges.push(new Range(start, start)) }
9577
+ setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
9578
+ {origin: "*mouse", scroll: false})
9579
+ cm.scrollIntoView(pos)
9580
+ } else {
9581
+ var oldRange = ourRange
9582
+ var anchor = oldRange.anchor, head = pos
9583
+ if (type != "single") {
9584
+ var range
9585
+ if (type == "double")
9586
+ { range = cm.findWordAt(pos) }
9587
+ else
9588
+ { range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))) }
9589
+ if (cmp(range.anchor, anchor) > 0) {
9590
+ head = range.head
9591
+ anchor = minPos(oldRange.from(), range.anchor)
9592
  } else {
9593
+ head = range.anchor
9594
+ anchor = maxPos(oldRange.to(), range.head)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9595
  }
 
 
9596
  }
9597
+ var ranges$1 = startSel.ranges.slice(0)
9598
+ ranges$1[ourIndex] = new Range(clipPos(doc, anchor), head)
9599
+ setSelection(doc, normalizeSelection(ranges$1, ourIndex), sel_mouse)
9600
+ }
9601
+ }
9602
+
9603
+ var editorSize = display.wrapper.getBoundingClientRect()
9604
+ // Used to ensure timeout re-tries don't fire when another extend
9605
+ // happened in the meantime (clearTimeout isn't reliable -- at
9606
+ // least on Chrome, the timeouts still happen even when cleared,
9607
+ // if the clear happens after their scheduled firing time).
9608
+ var counter = 0
9609
+
9610
+ function extend(e) {
9611
+ var curCount = ++counter
9612
+ var cur = posFromMouse(cm, e, true, type == "rect")
9613
+ if (!cur) { return }
9614
+ if (cmp(cur, lastPos) != 0) {
9615
+ cm.curOp.focus = activeElt()
9616
+ extendTo(cur)
9617
+ var visible = visibleLines(display, doc)
9618
+ if (cur.line >= visible.to || cur.line < visible.from)
9619
+ { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e) }}), 150) }
9620
+ } else {
9621
+ var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0
9622
+ if (outside) { setTimeout(operation(cm, function () {
9623
+ if (counter != curCount) { return }
9624
+ display.scroller.scrollTop += outside
9625
+ extend(e)
9626
+ }), 50) }
9627
+ }
9628
+ }
9629
+
9630
+ function done(e) {
9631
+ cm.state.selectingText = false
9632
+ counter = Infinity
9633
+ e_preventDefault(e)
9634
+ display.input.focus()
9635
+ off(document, "mousemove", move)
9636
+ off(document, "mouseup", up)
9637
+ doc.history.lastSelOrigin = null
9638
+ }
9639
+
9640
+ var move = operation(cm, function (e) {
9641
+ if (!e_button(e)) { done(e) }
9642
+ else { extend(e) }
9643
+ })
9644
+ var up = operation(cm, done)
9645
+ cm.state.selectingText = up
9646
+ on(document, "mousemove", move)
9647
+ on(document, "mouseup", up)
9648
+ }
9649
+
9650
+
9651
+ // Determines whether an event happened in the gutter, and fires the
9652
+ // handlers for the corresponding event.
9653
+ function gutterEvent(cm, e, type, prevent) {
9654
+ var mX, mY
9655
+ try { mX = e.clientX; mY = e.clientY }
9656
+ catch(e) { return false }
9657
+ if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
9658
+ if (prevent) { e_preventDefault(e) }
9659
+
9660
+ var display = cm.display
9661
+ var lineBox = display.lineDiv.getBoundingClientRect()
9662
+
9663
+ if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }
9664
+ mY -= lineBox.top - display.viewOffset
9665
+
9666
+ for (var i = 0; i < cm.options.gutters.length; ++i) {
9667
+ var g = display.gutters.childNodes[i]
9668
+ if (g && g.getBoundingClientRect().right >= mX) {
9669
+ var line = lineAtHeight(cm.doc, mY)
9670
+ var gutter = cm.options.gutters[i]
9671
+ signal(cm, type, cm, line, gutter, e)
9672
+ return e_defaultPrevented(e)
9673
  }
 
9674
  }
9675
+ }
9676
 
9677
+ function clickInGutter(cm, e) {
9678
+ return gutterEvent(cm, e, "gutterClick", true)
9679
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9680
 
9681
+ // CONTEXT MENU HANDLING
9682
+
9683
+ // To make the context menu work, we need to briefly unhide the
9684
+ // textarea (making it as unobtrusive as possible) to let the
9685
+ // right-click take effect on it.
9686
+ function onContextMenu(cm, e) {
9687
+ if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return }
9688
+ if (signalDOMEvent(cm, e, "contextmenu")) { return }
9689
+ cm.display.input.onContextMenu(e)
9690
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9691
 
9692
+ function contextMenuInGutter(cm, e) {
9693
+ if (!hasHandler(cm, "gutterContextMenu")) { return false }
9694
+ return gutterEvent(cm, e, "gutterContextMenu", false)
9695
+ }
9696
 
9697
+ function themeChanged(cm) {
9698
+ cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
9699
+ cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-")
9700
+ clearCaches(cm)
9701
+ }
9702
+
9703
+ var Init = {toString: function(){return "CodeMirror.Init"}}
9704
+
9705
+ var defaults = {}
9706
+ var optionHandlers = {}
9707
+
9708
+ function defineOptions(CodeMirror) {
9709
+ var optionHandlers = CodeMirror.optionHandlers
9710
+
9711
+ function option(name, deflt, handle, notOnInit) {
9712
+ CodeMirror.defaults[name] = deflt
9713
+ if (handle) { optionHandlers[name] =
9714
+ notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old) }} : handle }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9715
  }
9716
 
9717
+ CodeMirror.defineOption = option
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9718
 
9719
+ // Passed to option handlers when there is no old value.
9720
+ CodeMirror.Init = Init
 
9721
 
9722
+ // These two are, on init, called from the constructor because they
9723
+ // have to be initialized before the editor can start at all.
9724
+ option("value", "", function (cm, val) { return cm.setValue(val); }, true)
9725
+ option("mode", null, function (cm, val) {
9726
+ cm.doc.modeOption = val
9727
+ loadMode(cm)
9728
+ }, true)
9729
+
9730
+ option("indentUnit", 2, loadMode, true)
9731
+ option("indentWithTabs", false)
9732
+ option("smartIndent", true)
9733
+ option("tabSize", 4, function (cm) {
9734
+ resetModeState(cm)
9735
+ clearCaches(cm)
9736
+ regChange(cm)
9737
+ }, true)
9738
+ option("lineSeparator", null, function (cm, val) {
9739
+ cm.doc.lineSep = val
9740
+ if (!val) { return }
9741
+ var newBreaks = [], lineNo = cm.doc.first
9742
+ cm.doc.iter(function (line) {
9743
+ for (var pos = 0;;) {
9744
+ var found = line.text.indexOf(val, pos)
9745
+ if (found == -1) { break }
9746
+ pos = found + val.length
9747
+ newBreaks.push(Pos(lineNo, found))
9748
  }
9749
+ lineNo++
9750
+ })
9751
+ for (var i = newBreaks.length - 1; i >= 0; i--)
9752
+ { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)) }
9753
+ })
9754
+ option("specialChars", /[\u0000-\u001f\u007f\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) {
9755
+ cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g")
9756
+ if (old != Init) { cm.refresh() }
9757
+ })
9758
+ option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true)
9759
+ option("electricChars", true)
9760
+ option("inputStyle", mobile ? "contenteditable" : "textarea", function () {
9761
+ throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME
9762
+ }, true)
9763
+ option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true)
9764
+ option("rtlMoveVisually", !windows)
9765
+ option("wholeLineUpdateBefore", true)
9766
+
9767
+ option("theme", "default", function (cm) {
9768
+ themeChanged(cm)
9769
+ guttersChanged(cm)
9770
+ }, true)
9771
+ option("keyMap", "default", function (cm, val, old) {
9772
+ var next = getKeyMap(val)
9773
+ var prev = old != Init && getKeyMap(old)
9774
+ if (prev && prev.detach) { prev.detach(cm, next) }
9775
+ if (next.attach) { next.attach(cm, prev || null) }
9776
+ })
9777
+ option("extraKeys", null)
9778
+
9779
+ option("lineWrapping", false, wrappingChanged, true)
9780
+ option("gutters", [], function (cm) {
9781
+ setGuttersForLineNumbers(cm.options)
9782
+ guttersChanged(cm)
9783
+ }, true)
9784
+ option("fixedGutter", true, function (cm, val) {
9785
+ cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"
9786
+ cm.refresh()
9787
+ }, true)
9788
+ option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true)
9789
+ option("scrollbarStyle", "native", function (cm) {
9790
+ initScrollbars(cm)
9791
+ updateScrollbars(cm)
9792
+ cm.display.scrollbars.setScrollTop(cm.doc.scrollTop)
9793
+ cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft)
9794
+ }, true)
9795
+ option("lineNumbers", false, function (cm) {
9796
+ setGuttersForLineNumbers(cm.options)
9797
+ guttersChanged(cm)
9798
+ }, true)
9799
+ option("firstLineNumber", 1, guttersChanged, true)
9800
+ option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true)
9801
+ option("showCursorWhenSelecting", false, updateSelection, true)
9802
+
9803
+ option("resetSelectionOnContextMenu", true)
9804
+ option("lineWiseCopyCut", true)
9805
+
9806
+ option("readOnly", false, function (cm, val) {
9807
+ if (val == "nocursor") {
9808
+ onBlur(cm)
9809
+ cm.display.input.blur()
9810
+ cm.display.disabled = true
9811
+ } else {
9812
+ cm.display.disabled = false
9813
  }
9814
+ cm.display.input.readOnlyChanged(val)
9815
+ })
9816
+ option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset() }}, true)
9817
+ option("dragDrop", true, dragDropChanged)
9818
+ option("allowDropFileTypes", null)
9819
+
9820
+ option("cursorBlinkRate", 530)
9821
+ option("cursorScrollMargin", 0)
9822
+ option("cursorHeight", 1, updateSelection, true)
9823
+ option("singleCursorHeightPerLine", true, updateSelection, true)
9824
+ option("workTime", 100)
9825
+ option("workDelay", 100)
9826
+ option("flattenSpans", true, resetModeState, true)
9827
+ option("addModeClass", false, resetModeState, true)
9828
+ option("pollInterval", 100)
9829
+ option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; })
9830
+ option("historyEventDelay", 1250)
9831
+ option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true)
9832
+ option("maxHighlightLength", 10000, resetModeState, true)
9833
+ option("moveInputWithCursor", true, function (cm, val) {
9834
+ if (!val) { cm.display.input.resetPosition() }
9835
+ })
9836
+
9837
+ option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; })
9838
+ option("autofocus", null)
9839
+ }
9840
 
9841
+ function guttersChanged(cm) {
9842
+ updateGutters(cm)
9843
+ regChange(cm)
9844
+ setTimeout(function () { return alignHorizontally(cm); }, 20)
9845
+ }
 
 
 
 
 
9846
 
9847
+ function dragDropChanged(cm, value, old) {
9848
+ var wasOn = old && old != Init
9849
+ if (!value != !wasOn) {
9850
+ var funcs = cm.display.dragFunctions
9851
+ var toggle = value ? on : off
9852
+ toggle(cm.display.scroller, "dragstart", funcs.start)
9853
+ toggle(cm.display.scroller, "dragenter", funcs.enter)
9854
+ toggle(cm.display.scroller, "dragover", funcs.over)
9855
+ toggle(cm.display.scroller, "dragleave", funcs.leave)
9856
+ toggle(cm.display.scroller, "drop", funcs.drop)
9857
  }
9858
+ }
9859
 
9860
+ function wrappingChanged(cm) {
9861
+ if (cm.options.lineWrapping) {
9862
+ addClass(cm.display.wrapper, "CodeMirror-wrap")
9863
+ cm.display.sizer.style.minWidth = ""
9864
+ cm.display.sizerWidth = null
9865
+ } else {
9866
+ rmClass(cm.display.wrapper, "CodeMirror-wrap")
9867
+ findMaxLine(cm)
9868
+ }
9869
+ estimateLineHeights(cm)
9870
+ regChange(cm)
9871
+ clearCaches(cm)
9872
+ setTimeout(function () { return updateScrollbars(cm); }, 100)
9873
+ }
9874
 
9875
+ // A CodeMirror instance represents an editor. This is the object
9876
+ // that user code is usually dealing with.
9877
+
9878
+ function CodeMirror(place, options) {
9879
+ var this$1 = this;
9880
+
9881
+ if (!(this instanceof CodeMirror)) { return new CodeMirror(place, options) }
9882
+
9883
+ this.options = options = options ? copyObj(options) : {}
9884
+ // Determine effective options based on given values and defaults.
9885
+ copyObj(defaults, options, false)
9886
+ setGuttersForLineNumbers(options)
9887
+
9888
+ var doc = options.value
9889
+ if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator) }
9890
+ this.doc = doc
9891
+
9892
+ var input = new CodeMirror.inputStyles[options.inputStyle](this)
9893
+ var display = this.display = new Display(place, doc, input)
9894
+ display.wrapper.CodeMirror = this
9895
+ updateGutters(this)
9896
+ themeChanged(this)
9897
+ if (options.lineWrapping)
9898
+ { this.display.wrapper.className += " CodeMirror-wrap" }
9899
+ if (options.autofocus && !mobile) { display.input.focus() }
9900
+ initScrollbars(this)
9901
+
9902
+ this.state = {
9903
+ keyMaps: [], // stores maps added by addKeyMap
9904
+ overlays: [], // highlighting overlays, as added by addOverlay
9905
+ modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
9906
+ overwrite: false,
9907
+ delayingBlurEvent: false,
9908
+ focused: false,
9909
+ suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
9910
+ pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
9911
+ selectingText: false,
9912
+ draggingText: false,
9913
+ highlight: new Delayed(), // stores highlight worker timeout
9914
+ keySeq: null, // Unfinished key sequence
9915
+ specialChars: null
9916
+ }
9917
+
9918
+ // Override magic textarea content restore that IE sometimes does
9919
+ // on our hidden textarea on reload
9920
+ if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20) }
9921
+
9922
+ registerEventHandlers(this)
9923
+ ensureGlobalHandlers()
9924
+
9925
+ startOperation(this)
9926
+ this.curOp.forceUpdate = true
9927
+ attachDoc(this, doc)
9928
+
9929
+ if ((options.autofocus && !mobile) || this.hasFocus())
9930
+ { setTimeout(bind(onFocus, this), 20) }
9931
+ else
9932
+ { onBlur(this) }
9933
+
9934
+ for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))
9935
+ { optionHandlers[opt](this$1, options[opt], Init) } }
9936
+ maybeUpdateLineNumberWidth(this)
9937
+ if (options.finishInit) { options.finishInit(this) }
9938
+ for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1) }
9939
+ endOperation(this)
9940
+ // Suppress optimizelegibility in Webkit, since it breaks text
9941
+ // measuring on line wrapping boundaries.
9942
+ if (webkit && options.lineWrapping &&
9943
+ getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
9944
+ { display.lineDiv.style.textRendering = "auto" }
9945
+ }
9946
+
9947
+ // The default configuration options.
9948
+ CodeMirror.defaults = defaults
9949
+ // Functions to run when options are changed.
9950
+ CodeMirror.optionHandlers = optionHandlers
9951
+
9952
+ // Attach the necessary event handlers when initializing the editor
9953
+ function registerEventHandlers(cm) {
9954
+ var d = cm.display
9955
+ on(d.scroller, "mousedown", operation(cm, onMouseDown))
9956
+ // Older IE's will not fire a second mousedown for a double click
9957
+ if (ie && ie_version < 11)
9958
+ { on(d.scroller, "dblclick", operation(cm, function (e) {
9959
+ if (signalDOMEvent(cm, e)) { return }
9960
+ var pos = posFromMouse(cm, e)
9961
+ if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return }
9962
+ e_preventDefault(e)
9963
+ var word = cm.findWordAt(pos)
9964
+ extendSelection(cm.doc, word.anchor, word.head)
9965
+ })) }
9966
+ else
9967
+ { on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }) }
9968
+ // Some browsers fire contextmenu *after* opening the menu, at
9969
+ // which point we can't mess with it anymore. Context menu is
9970
+ // handled in onMouseDown for these browsers.
9971
+ if (!captureRightClick) { on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); }) }
9972
+
9973
+ // Used to suppress mouse event handling when a touch happens
9974
+ var touchFinished, prevTouch = {end: 0}
9975
+ function finishTouch() {
9976
+ if (d.activeTouch) {
9977
+ touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000)
9978
+ prevTouch = d.activeTouch
9979
+ prevTouch.end = +new Date
9980
+ }
9981
+ }
9982
+ function isMouseLikeTouchEvent(e) {
9983
+ if (e.touches.length != 1) { return false }
9984
+ var touch = e.touches[0]
9985
+ return touch.radiusX <= 1 && touch.radiusY <= 1
9986
+ }
9987
+ function farAway(touch, other) {
9988
+ if (other.left == null) { return true }
9989
+ var dx = other.left - touch.left, dy = other.top - touch.top
9990
+ return dx * dx + dy * dy > 20 * 20
9991
+ }
9992
+ on(d.scroller, "touchstart", function (e) {
9993
+ if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) {
9994
+ clearTimeout(touchFinished)
9995
+ var now = +new Date
9996
+ d.activeTouch = {start: now, moved: false,
9997
+ prev: now - prevTouch.end <= 300 ? prevTouch : null}
9998
+ if (e.touches.length == 1) {
9999
+ d.activeTouch.left = e.touches[0].pageX
10000
+ d.activeTouch.top = e.touches[0].pageY
10001
+ }
10002
+ }
10003
+ })
10004
+ on(d.scroller, "touchmove", function () {
10005
+ if (d.activeTouch) { d.activeTouch.moved = true }
10006
+ })
10007
+ on(d.scroller, "touchend", function (e) {
10008
+ var touch = d.activeTouch
10009
+ if (touch && !eventInWidget(d, e) && touch.left != null &&
10010
+ !touch.moved && new Date - touch.start < 300) {
10011
+ var pos = cm.coordsChar(d.activeTouch, "page"), range
10012
+ if (!touch.prev || farAway(touch, touch.prev)) // Single tap
10013
+ { range = new Range(pos, pos) }
10014
+ else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
10015
+ { range = cm.findWordAt(pos) }
10016
+ else // Triple tap
10017
+ { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) }
10018
+ cm.setSelection(range.anchor, range.head)
10019
+ cm.focus()
10020
+ e_preventDefault(e)
10021
+ }
10022
+ finishTouch()
10023
+ })
10024
+ on(d.scroller, "touchcancel", finishTouch)
10025
+
10026
+ // Sync scrolling between fake scrollbars and real scrollable
10027
+ // area, ensure viewport is updated when scrolling.
10028
+ on(d.scroller, "scroll", function () {
10029
+ if (d.scroller.clientHeight) {
10030
+ setScrollTop(cm, d.scroller.scrollTop)
10031
+ setScrollLeft(cm, d.scroller.scrollLeft, true)
10032
+ signal(cm, "scroll", cm)
10033
+ }
10034
+ })
10035
+
10036
+ // Listen to wheel events in order to try and update the viewport on time.
10037
+ on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); })
10038
+ on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); })
10039
+
10040
+ // Prevent wrapper from ever scrolling
10041
+ on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; })
10042
+
10043
+ d.dragFunctions = {
10044
+ enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e) }},
10045
+ over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e) }},
10046
+ start: function (e) { return onDragStart(cm, e); },
10047
+ drop: operation(cm, onDrop),
10048
+ leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm) }}
10049
+ }
10050
+
10051
+ var inp = d.input.getField()
10052
+ on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); })
10053
+ on(inp, "keydown", operation(cm, onKeyDown))
10054
+ on(inp, "keypress", operation(cm, onKeyPress))
10055
+ on(inp, "focus", function (e) { return onFocus(cm, e); })
10056
+ on(inp, "blur", function (e) { return onBlur(cm, e); })
10057
+ }
10058
+
10059
+ var initHooks = []
10060
+ CodeMirror.defineInitHook = function (f) { return initHooks.push(f); }
10061
+
10062
+ // Indent the given line. The how parameter can be "smart",
10063
+ // "add"/null, "subtract", or "prev". When aggressive is false
10064
+ // (typically set to true for forced single-line indents), empty
10065
+ // lines are not indented, and places where the mode returns Pass
10066
+ // are left alone.
10067
+ function indentLine(cm, n, how, aggressive) {
10068
+ var doc = cm.doc, state
10069
+ if (how == null) { how = "add" }
10070
+ if (how == "smart") {
10071
+ // Fall back to "prev" when the mode doesn't have an indentation
10072
+ // method.
10073
+ if (!doc.mode.indent) { how = "prev" }
10074
+ else { state = getStateBefore(cm, n) }
10075
+ }
10076
+
10077
+ var tabSize = cm.options.tabSize
10078
+ var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize)
10079
+ if (line.stateAfter) { line.stateAfter = null }
10080
+ var curSpaceString = line.text.match(/^\s*/)[0], indentation
10081
+ if (!aggressive && !/\S/.test(line.text)) {
10082
+ indentation = 0
10083
+ how = "not"
10084
+ } else if (how == "smart") {
10085
+ indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text)
10086
+ if (indentation == Pass || indentation > 150) {
10087
+ if (!aggressive) { return }
10088
+ how = "prev"
10089
+ }
10090
+ }
10091
+ if (how == "prev") {
10092
+ if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize) }
10093
+ else { indentation = 0 }
10094
+ } else if (how == "add") {
10095
+ indentation = curSpace + cm.options.indentUnit
10096
+ } else if (how == "subtract") {
10097
+ indentation = curSpace - cm.options.indentUnit
10098
+ } else if (typeof how == "number") {
10099
+ indentation = curSpace + how
10100
+ }
10101
+ indentation = Math.max(0, indentation)
10102
+
10103
+ var indentString = "", pos = 0
10104
+ if (cm.options.indentWithTabs)
10105
+ { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t"} }
10106
+ if (pos < indentation) { indentString += spaceStr(indentation - pos) }
10107
+
10108
+ if (indentString != curSpaceString) {
10109
+ replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input")
10110
+ line.stateAfter = null
10111
+ return true
10112
+ } else {
10113
+ // Ensure that, if the cursor was in the whitespace at the start
10114
+ // of the line, it is moved to the end of that space.
10115
+ for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) {
10116
+ var range = doc.sel.ranges[i$1]
10117
+ if (range.head.line == n && range.head.ch < curSpaceString.length) {
10118
+ var pos$1 = Pos(n, curSpaceString.length)
10119
+ replaceOneSelection(doc, i$1, new Range(pos$1, pos$1))
10120
+ break
10121
  }
10122
  }
 
 
 
 
 
 
 
 
 
 
10123
  }
10124
+ }
10125
 
10126
+ // This will be set to a {lineWise: bool, text: [string]} object, so
10127
+ // that, when pasting, we know what kind of selections the copied
10128
+ // text was made out of.
10129
+ var lastCopied = null
10130
+
10131
+ function setLastCopied(newLastCopied) {
10132
+ lastCopied = newLastCopied
10133
+ }
10134
+
10135
+ function applyTextInput(cm, inserted, deleted, sel, origin) {
10136
+ var doc = cm.doc
10137
+ cm.display.shift = false
10138
+ if (!sel) { sel = doc.sel }
10139
+
10140
+ var paste = cm.state.pasteIncoming || origin == "paste"
10141
+ var textLines = splitLinesAuto(inserted), multiPaste = null
10142
+ // When pasing N lines into N selections, insert one line per selection
10143
+ if (paste && sel.ranges.length > 1) {
10144
+ if (lastCopied && lastCopied.text.join("\n") == inserted) {
10145
+ if (sel.ranges.length % lastCopied.text.length == 0) {
10146
+ multiPaste = []
10147
+ for (var i = 0; i < lastCopied.text.length; i++)
10148
+ { multiPaste.push(doc.splitLines(lastCopied.text[i])) }
10149
+ }
10150
+ } else if (textLines.length == sel.ranges.length) {
10151
+ multiPaste = map(textLines, function (l) { return [l]; })
10152
+ }
10153
+ }
10154
+
10155
+ var updateInput
10156
+ // Normal behavior is to insert the new text into every selection
10157
+ for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {
10158
+ var range = sel.ranges[i$1]
10159
+ var from = range.from(), to = range.to()
10160
+ if (range.empty()) {
10161
+ if (deleted && deleted > 0) // Handle deletion
10162
+ { from = Pos(from.line, from.ch - deleted) }
10163
+ else if (cm.state.overwrite && !paste) // Handle overwrite
10164
+ { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)) }
10165
+ else if (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted)
10166
+ { from = to = Pos(from.line, 0) }
10167
+ }
10168
+ updateInput = cm.curOp.updateInput
10169
+ var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,
10170
+ origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")}
10171
+ makeChange(cm.doc, changeEvent)
10172
+ signalLater(cm, "inputRead", cm, changeEvent)
10173
+ }
10174
+ if (inserted && !paste)
10175
+ { triggerElectric(cm, inserted) }
10176
+
10177
+ ensureCursorVisible(cm)
10178
+ cm.curOp.updateInput = updateInput
10179
+ cm.curOp.typing = true
10180
+ cm.state.pasteIncoming = cm.state.cutIncoming = false
10181
+ }
10182
+
10183
+ function handlePaste(e, cm) {
10184
+ var pasted = e.clipboardData && e.clipboardData.getData("Text")
10185
+ if (pasted) {
10186
+ e.preventDefault()
10187
+ if (!cm.isReadOnly() && !cm.options.disableInput)
10188
+ { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }) }
10189
+ return true
10190
  }
10191
+ }
10192
 
10193
+ function triggerElectric(cm, inserted) {
10194
+ // When an 'electric' character is inserted, immediately trigger a reindent
10195
+ if (!cm.options.electricChars || !cm.options.smartIndent) { return }
10196
+ var sel = cm.doc.sel
10197
+
10198
+ for (var i = sel.ranges.length - 1; i >= 0; i--) {
10199
+ var range = sel.ranges[i]
10200
+ if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) { continue }
10201
+ var mode = cm.getModeAt(range.head)
10202
+ var indented = false
10203
+ if (mode.electricChars) {
10204
+ for (var j = 0; j < mode.electricChars.length; j++)
10205
+ { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
10206
+ indented = indentLine(cm, range.head.line, "smart")
10207
+ break
10208
+ } }
10209
+ } else if (mode.electricInput) {
10210
+ if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch)))
10211
+ { indented = indentLine(cm, range.head.line, "smart") }
10212
+ }
10213
+ if (indented) { signalLater(cm, "electricInput", cm, range.head.line) }
10214
  }
10215
+ }
10216
 
10217
+ function copyableRanges(cm) {
10218
+ var text = [], ranges = []
10219
+ for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
10220
+ var line = cm.doc.sel.ranges[i].head.line
10221
+ var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)}
10222
+ ranges.push(lineRange)
10223
+ text.push(cm.getRange(lineRange.anchor, lineRange.head))
 
 
 
 
 
 
 
10224
  }
10225
+ return {text: text, ranges: ranges}
10226
+ }
10227
 
10228
+ function disableBrowserMagic(field, spellcheck) {
10229
+ field.setAttribute("autocorrect", "off")
10230
+ field.setAttribute("autocapitalize", "off")
10231
+ field.setAttribute("spellcheck", !!spellcheck)
10232
+ }
 
 
 
 
10233
 
10234
+ function hiddenTextarea() {
10235
+ var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none")
10236
+ var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;")
10237
+ // The textarea is kept positioned near the cursor to prevent the
10238
+ // fact that it'll be scrolled into view on input from scrolling
10239
+ // our fake cursor out of view. On webkit, when wrap=off, paste is
10240
+ // very slow. So make the area wide instead.
10241
+ if (webkit) { te.style.width = "1000px" }
10242
+ else { te.setAttribute("wrap", "off") }
10243
+ // If border: 0; -- iOS fails to open keyboard (issue #1287)
10244
+ if (ios) { te.style.border = "1px solid black" }
10245
+ disableBrowserMagic(te)
10246
+ return div
10247
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10248
 
10249
+ // The publicly visible API. Note that methodOp(f) means
10250
+ // 'wrap f in an operation, performed on its `this` parameter'.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10251
 
10252
+ // This is not the complete set of editor methods. Most of the
10253
+ // methods defined on the Doc type are also injected into
10254
+ // CodeMirror.prototype, for backwards compatibility and
10255
+ // convenience.
10256
 
10257
+ function addEditorMethods(CodeMirror) {
10258
+ var optionHandlers = CodeMirror.optionHandlers
10259
+
10260
+ var helpers = CodeMirror.helpers = {}
10261
+
10262
+ CodeMirror.prototype = {
10263
+ constructor: CodeMirror,
10264
+ focus: function(){window.focus(); this.display.input.focus()},
10265
+
10266
+ setOption: function(option, value) {
10267
+ var options = this.options, old = options[option]
10268
+ if (options[option] == value && option != "mode") { return }
10269
+ options[option] = value
10270
+ if (optionHandlers.hasOwnProperty(option))
10271
+ { operation(this, optionHandlers[option])(this, value, old) }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10272
  },
10273
+
10274
+ getOption: function(option) {return this.options[option]},
10275
+ getDoc: function() {return this.doc},
10276
+
10277
+ addKeyMap: function(map, bottom) {
10278
+ this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map))
10279
  },
10280
+ removeKeyMap: function(map) {
10281
+ var maps = this.state.keyMaps
10282
+ for (var i = 0; i < maps.length; ++i)
10283
+ { if (maps[i] == map || maps[i].name == map) {
10284
+ maps.splice(i, 1)
10285
+ return true
10286
+ } }
10287
  },
 
 
 
 
 
 
10288
 
10289
+ addOverlay: methodOp(function(spec, options) {
10290
+ var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec)
10291
+ if (mode.startState) { throw new Error("Overlays may not be stateful.") }
10292
+ insertSorted(this.state.overlays,
10293
+ {mode: mode, modeSpec: spec, opaque: options && options.opaque,
10294
+ priority: (options && options.priority) || 0},
10295
+ function (overlay) { return overlay.priority; })
10296
+ this.state.modeGen++
10297
+ regChange(this)
10298
+ }),
10299
+ removeOverlay: methodOp(function(spec) {
10300
+ var this$1 = this;
10301
+
10302
+ var overlays = this.state.overlays
10303
+ for (var i = 0; i < overlays.length; ++i) {
10304
+ var cur = overlays[i].modeSpec
10305
+ if (cur == spec || typeof spec == "string" && cur.name == spec) {
10306
+ overlays.splice(i, 1)
10307
+ this$1.state.modeGen++
10308
+ regChange(this$1)
10309
+ return
10310
+ }
 
 
 
 
 
10311
  }
10312
+ }),
10313
+
10314
+ indentLine: methodOp(function(n, dir, aggressive) {
10315
+ if (typeof dir != "string" && typeof dir != "number") {
10316
+ if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev" }
10317
+ else { dir = dir ? "add" : "subtract" }
 
 
10318
  }
10319
+ if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive) }
10320
+ }),
10321
+ indentSelection: methodOp(function(how) {
10322
+ var this$1 = this;
10323
+
10324
+ var ranges = this.doc.sel.ranges, end = -1
10325
+ for (var i = 0; i < ranges.length; i++) {
10326
+ var range = ranges[i]
10327
+ if (!range.empty()) {
10328
+ var from = range.from(), to = range.to()
10329
+ var start = Math.max(end, from.line)
10330
+ end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1
10331
+ for (var j = start; j < end; ++j)
10332
+ { indentLine(this$1, j, how) }
10333
+ var newRanges = this$1.doc.sel.ranges
10334
+ if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
10335
+ { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll) }
10336
+ } else if (range.head.line > end) {
10337
+ indentLine(this$1, range.head.line, how, true)
10338
+ end = range.head.line
10339
+ if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1) }
 
 
 
 
10340
  }
 
10341
  }
10342
+ }),
10343
+
10344
+ // Fetch the parser token for a given character. Useful for hacks
10345
+ // that want to inspect the mode state (say, for completion).
10346
+ getTokenAt: function(pos, precise) {
10347
+ return takeToken(this, pos, precise)
10348
  },
10349
+
10350
+ getLineTokens: function(line, precise) {
10351
+ return takeToken(this, Pos(line), precise, true)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10352
  },
 
 
 
 
 
 
 
 
 
 
 
 
10353
 
10354
+ getTokenTypeAt: function(pos) {
10355
+ pos = clipPos(this.doc, pos)
10356
+ var styles = getLineStyles(this, getLine(this.doc, pos.line))
10357
+ var before = 0, after = (styles.length - 1) / 2, ch = pos.ch
10358
+ var type
10359
+ if (ch == 0) { type = styles[2] }
10360
+ else { for (;;) {
10361
+ var mid = (before + after) >> 1
10362
+ if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid }
10363
+ else if (styles[mid * 2 + 1] < ch) { before = mid + 1 }
10364
+ else { type = styles[mid * 2 + 2]; break }
10365
+ } }
10366
+ var cut = type ? type.indexOf("overlay ") : -1
10367
+ return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1)
10368
+ },
 
 
 
 
 
 
 
 
10369
 
10370
+ getModeAt: function(pos) {
10371
+ var mode = this.doc.mode
10372
+ if (!mode.innerMode) { return mode }
10373
+ return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode
 
 
 
 
 
10374
  },
10375
 
10376
+ getHelper: function(pos, type) {
10377
+ return this.getHelpers(pos, type)[0]
 
 
 
10378
  },
 
10379
 
10380
+ getHelpers: function(pos, type) {
10381
+ var this$1 = this;
10382
 
10383
+ var found = []
10384
+ if (!helpers.hasOwnProperty(type)) { return found }
10385
+ var help = helpers[type], mode = this.getModeAt(pos)
10386
+ if (typeof mode[type] == "string") {
10387
+ if (help[mode[type]]) { found.push(help[mode[type]]) }
10388
+ } else if (mode[type]) {
10389
+ for (var i = 0; i < mode[type].length; i++) {
10390
+ var val = help[mode[type][i]]
10391
+ if (val) { found.push(val) }
10392
+ }
10393
+ } else if (mode.helperType && help[mode.helperType]) {
10394
+ found.push(help[mode.helperType])
10395
+ } else if (help[mode.name]) {
10396
+ found.push(help[mode.name])
10397
+ }
10398
+ for (var i$1 = 0; i$1 < help._global.length; i$1++) {
10399
+ var cur = help._global[i$1]
10400
+ if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1)
10401
+ { found.push(cur.val) }
10402
+ }
10403
+ return found
10404
  },
10405
+
10406
+ getStateAfter: function(line, precise) {
10407
+ var doc = this.doc
10408
+ line = clipLine(doc, line == null ? doc.first + doc.size - 1: line)
10409
+ return getStateBefore(this, line + 1, precise)
 
 
 
 
 
10410
  },
10411
+
10412
+ cursorCoords: function(start, mode) {
10413
+ var pos, range = this.doc.sel.primary()
10414
+ if (start == null) { pos = range.head }
10415
+ else if (typeof start == "object") { pos = clipPos(this.doc, start) }
10416
+ else { pos = start ? range.from() : range.to() }
10417
+ return cursorCoords(this, pos, mode || "page")
10418
  },
10419
 
10420
+ charCoords: function(pos, mode) {
10421
+ return charCoords(this, clipPos(this.doc, pos), mode || "page")
10422
+ },
10423
 
10424
+ coordsChar: function(coords, mode) {
10425
+ coords = fromCoordSystem(this, coords, mode || "page")
10426
+ return coordsChar(this, coords.left, coords.top)
10427
+ },
10428
 
10429
+ lineAtHeight: function(height, mode) {
10430
+ height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top
10431
+ return lineAtHeight(this.doc, height + this.display.viewOffset)
10432
+ },
10433
+ heightAtLine: function(line, mode) {
10434
+ var end = false, lineObj
10435
+ if (typeof line == "number") {
10436
+ var last = this.doc.first + this.doc.size - 1
10437
+ if (line < this.doc.first) { line = this.doc.first }
10438
+ else if (line > last) { line = last; end = true }
10439
+ lineObj = getLine(this.doc, line)
10440
+ } else {
10441
+ lineObj = line
10442
+ }
10443
+ return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top +
10444
+ (end ? this.doc.height - heightAtLine(lineObj) : 0)
10445
  },
10446
 
10447
+ defaultTextHeight: function() { return textHeight(this.display) },
10448
+ defaultCharWidth: function() { return charWidth(this.display) },
 
10449
 
10450
+ setGutterMarker: methodOp(function(line, gutterID, value) {
10451
+ return changeLine(this.doc, line, "gutter", function (line) {
10452
+ var markers = line.gutterMarkers || (line.gutterMarkers = {})
10453
+ markers[gutterID] = value
10454
+ if (!value && isEmpty(markers)) { line.gutterMarkers = null }
10455
+ return true
10456
+ })
10457
+ }),
10458
 
10459
+ clearGutter: methodOp(function(gutterID) {
10460
+ var this$1 = this;
 
 
 
 
 
 
 
 
10461
 
10462
+ var doc = this.doc, i = doc.first
10463
+ doc.iter(function (line) {
10464
+ if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
10465
+ line.gutterMarkers[gutterID] = null
10466
+ regLineChange(this$1, i, "gutter")
10467
+ if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null }
10468
+ }
10469
+ ++i
10470
+ })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10471
  }),
10472
 
10473
+ lineInfo: function(line) {
10474
+ var n
10475
+ if (typeof line == "number") {
10476
+ if (!isLine(this.doc, line)) { return null }
10477
+ n = line
10478
+ line = getLine(this.doc, line)
10479
+ if (!line) { return null }
10480
+ } else {
10481
+ n = lineNo(line)
10482
+ if (n == null) { return null }
10483
  }
10484
+ return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
10485
+ textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
10486
+ widgets: line.widgets}
10487
  },
10488
+
10489
+ getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}},
10490
+
10491
+ addWidget: function(pos, node, scroll, vert, horiz) {
10492
+ var display = this.display
10493
+ pos = cursorCoords(this, clipPos(this.doc, pos))
10494
+ var top = pos.bottom, left = pos.left
10495
+ node.style.position = "absolute"
10496
+ node.setAttribute("cm-ignore-events", "true")
10497
+ this.display.input.setUneditable(node)
10498
+ display.sizer.appendChild(node)
10499
+ if (vert == "over") {
10500
+ top = pos.top
10501
+ } else if (vert == "above" || vert == "near") {
10502
+ var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
10503
+ hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth)
10504
+ // Default to positioning above (if specified and possible); otherwise default to positioning below
10505
+ if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
10506
+ { top = pos.top - node.offsetHeight }
10507
+ else if (pos.bottom + node.offsetHeight <= vspace)
10508
+ { top = pos.bottom }
10509
+ if (left + node.offsetWidth > hspace)
10510
+ { left = hspace - node.offsetWidth }
10511
  }
10512
+ node.style.top = top + "px"
10513
+ node.style.left = node.style.right = ""
10514
+ if (horiz == "right") {
10515
+ left = display.sizer.clientWidth - node.offsetWidth
10516
+ node.style.right = "0px"
10517
+ } else {
10518
+ if (horiz == "left") { left = 0 }
10519
+ else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2 }
10520
+ node.style.left = left + "px"
 
 
 
 
10521
  }
10522
+ if (scroll)
10523
+ { scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight) }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10524
  },
 
10525
 
10526
+ triggerOnKeyDown: methodOp(onKeyDown),
10527
+ triggerOnKeyPress: methodOp(onKeyPress),
10528
+ triggerOnKeyUp: onKeyUp,
 
 
 
 
 
 
 
 
10529
 
10530
+ execCommand: function(cmd) {
10531
+ if (commands.hasOwnProperty(cmd))
10532
+ { return commands[cmd].call(null, this) }
10533
  },
10534
+
10535
+ triggerElectric: methodOp(function(text) { triggerElectric(this, text) }),
10536
+
10537
+ findPosH: function(from, amount, unit, visually) {
10538
+ var this$1 = this;
10539
+
10540
+ var dir = 1
10541
+ if (amount < 0) { dir = -1; amount = -amount }
10542
+ var cur = clipPos(this.doc, from)
10543
+ for (var i = 0; i < amount; ++i) {
10544
+ cur = findPosH(this$1.doc, cur, dir, unit, visually)
10545
+ if (cur.hitSide) { break }
10546
+ }
10547
+ return cur
10548
  },
10549
 
10550
+ moveH: methodOp(function(dir, unit) {
10551
+ var this$1 = this;
10552
+
10553
+ this.extendSelectionsBy(function (range) {
10554
+ if (this$1.display.shift || this$1.doc.extend || range.empty())
10555
+ { return findPosH(this$1.doc, range.head, dir, unit, this$1.options.rtlMoveVisually) }
10556
+ else
10557
+ { return dir < 0 ? range.from() : range.to() }
10558
+ }, sel_move)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10559
  }),
10560
 
10561
+ deleteH: methodOp(function(dir, unit) {
10562
+ var sel = this.doc.sel, doc = this.doc
10563
+ if (sel.somethingSelected())
10564
+ { doc.replaceSelection("", null, "+delete") }
10565
+ else
10566
+ { deleteNearSelection(this, function (range) {
10567
+ var other = findPosH(doc, range.head, dir, unit, false)
10568
+ return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other}
10569
+ }) }
10570
  }),
 
10571
 
10572
+ findPosV: function(from, amount, unit, goalColumn) {
10573
+ var this$1 = this;
10574
+
10575
+ var dir = 1, x = goalColumn
10576
+ if (amount < 0) { dir = -1; amount = -amount }
10577
+ var cur = clipPos(this.doc, from)
10578
+ for (var i = 0; i < amount; ++i) {
10579
+ var coords = cursorCoords(this$1, cur, "div")
10580
+ if (x == null) { x = coords.left }
10581
+ else { coords.left = x }
10582
+ cur = findPosV(this$1, coords, dir, unit)
10583
+ if (cur.hitSide) { break }
 
 
 
 
 
 
 
10584
  }
10585
+ return cur
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10586
  },
10587
 
10588
+ moveV: methodOp(function(dir, unit) {
10589
+ var this$1 = this;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10590
 
10591
+ var doc = this.doc, goals = []
10592
+ var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected()
10593
+ doc.extendSelectionsBy(function (range) {
10594
+ if (collapse)
10595
+ { return dir < 0 ? range.from() : range.to() }
10596
+ var headPos = cursorCoords(this$1, range.head, "div")
10597
+ if (range.goalColumn != null) { headPos.left = range.goalColumn }
10598
+ goals.push(headPos.left)
10599
+ var pos = findPosV(this$1, headPos, dir, unit)
10600
+ if (unit == "page" && range == doc.sel.primary())
10601
+ { addToScrollPos(this$1, null, charCoords(this$1, pos, "div").top - headPos.top) }
10602
+ return pos
10603
+ }, sel_move)
10604
+ if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++)
10605
+ { doc.sel.ranges[i].goalColumn = goals[i] } }
10606
+ }),
10607
 
10608
+ // Find the word at the given position (as returned by coordsChar).
10609
+ findWordAt: function(pos) {
10610
+ var doc = this.doc, line = getLine(doc, pos.line).text
10611
+ var start = pos.ch, end = pos.ch
10612
+ if (line) {
10613
+ var helper = this.getHelper(pos, "wordChars")
10614
+ if ((pos.xRel < 0 || end == line.length) && start) { --start; } else { ++end }
10615
+ var startChar = line.charAt(start)
10616
+ var check = isWordChar(startChar, helper)
10617
+ ? function (ch) { return isWordChar(ch, helper); }
10618
+ : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); }
10619
+ : function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); }
10620
+ while (start > 0 && check(line.charAt(start - 1))) { --start }
10621
+ while (end < line.length && check(line.charAt(end))) { ++end }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10622
  }
10623
+ return new Range(Pos(pos.line, start), Pos(pos.line, end))
10624
  },
 
10625
 
10626
+ toggleOverwrite: function(value) {
10627
+ if (value != null && value == this.state.overwrite) { return }
10628
+ if (this.state.overwrite = !this.state.overwrite)
10629
+ { addClass(this.display.cursorDiv, "CodeMirror-overwrite") }
10630
+ else
10631
+ { rmClass(this.display.cursorDiv, "CodeMirror-overwrite") }
10632
 
10633
+ signal(this, "overwriteToggle", this, this.state.overwrite)
 
 
10634
  },
10635
+ hasFocus: function() { return this.display.input.getField() == activeElt() },
10636
+ isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10637
 
10638
+ scrollTo: methodOp(function(x, y) {
10639
+ if (x != null || y != null) { resolveScrollToPos(this) }
10640
+ if (x != null) { this.curOp.scrollLeft = x }
10641
+ if (y != null) { this.curOp.scrollTop = y }
10642
+ }),
10643
+ getScrollInfo: function() {
10644
+ var scroller = this.display.scroller
10645
+ return {left: scroller.scrollLeft, top: scroller.scrollTop,
10646
+ height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
10647
+ width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
10648
+ clientHeight: displayHeight(this), clientWidth: displayWidth(this)}
10649
+ },
10650
 
10651
+ scrollIntoView: methodOp(function(range, margin) {
10652
+ if (range == null) {
10653
+ range = {from: this.doc.sel.primary().head, to: null}
10654
+ if (margin == null) { margin = this.options.cursorScrollMargin }
10655
+ } else if (typeof range == "number") {
10656
+ range = {from: Pos(range, 0), to: null}
10657
+ } else if (range.from == null) {
10658
+ range = {from: range, to: null}
 
10659
  }
10660
+ if (!range.to) { range.to = range.from }
10661
+ range.margin = margin || 0
 
10662
 
10663
+ if (range.from.line != null) {
10664
+ resolveScrollToPos(this)
10665
+ this.curOp.scrollToPos = range
10666
+ } else {
10667
+ var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left),
10668
+ Math.min(range.from.top, range.to.top) - range.margin,
10669
+ Math.max(range.from.right, range.to.right),
10670
+ Math.max(range.from.bottom, range.to.bottom) + range.margin)
10671
+ this.scrollTo(sPos.scrollLeft, sPos.scrollTop)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10672
  }
10673
+ }),
 
 
10674
 
10675
+ setSize: methodOp(function(width, height) {
10676
+ var this$1 = this;
10677
+
10678
+ var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; }
10679
+ if (width != null) { this.display.wrapper.style.width = interpret(width) }
10680
+ if (height != null) { this.display.wrapper.style.height = interpret(height) }
10681
+ if (this.options.lineWrapping) { clearLineMeasurementCache(this) }
10682
+ var lineNo = this.display.viewFrom
10683
+ this.doc.iter(lineNo, this.display.viewTo, function (line) {
10684
+ if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)
10685
+ { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo, "widget"); break } } }
10686
+ ++lineNo
10687
+ })
10688
+ this.curOp.forceUpdate = true
10689
+ signal(this, "refresh", this)
10690
+ }),
 
 
 
 
10691
 
10692
+ operation: function(f){return runInOp(this, f)},
10693
 
10694
+ refresh: methodOp(function() {
10695
+ var oldHeight = this.display.cachedTextHeight
10696
+ regChange(this)
10697
+ this.curOp.forceUpdate = true
10698
+ clearCaches(this)
10699
+ this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop)
10700
+ updateGutterSpace(this)
10701
+ if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
10702
+ { estimateLineHeights(this) }
10703
+ signal(this, "refresh", this)
10704
+ }),
10705
 
10706
+ swapDoc: methodOp(function(doc) {
10707
+ var old = this.doc
10708
+ old.cm = null
10709
+ attachDoc(this, doc)
10710
+ clearCaches(this)
10711
+ this.display.input.reset()
10712
+ this.scrollTo(doc.scrollLeft, doc.scrollTop)
10713
+ this.curOp.forceScroll = true
10714
+ signalLater(this, "swapDoc", this, old)
10715
+ return old
10716
+ }),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10717
 
10718
+ getInputField: function(){return this.display.input.getField()},
10719
+ getWrapperElement: function(){return this.display.wrapper},
10720
+ getScrollerElement: function(){return this.display.scroller},
10721
+ getGutterElement: function(){return this.display.gutters}
 
10722
  }
10723
+ eventMixin(CodeMirror)
10724
 
10725
+ CodeMirror.registerHelper = function(type, name, value) {
10726
+ if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []} }
10727
+ helpers[type][name] = value
 
10728
  }
10729
+ CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
10730
+ CodeMirror.registerHelper(type, name, value)
10731
+ helpers[type]._global.push({pred: predicate, val: value})
 
 
 
 
 
 
10732
  }
10733
+ }
10734
 
10735
+ // Used for horizontal relative motion. Dir is -1 or 1 (left or
10736
+ // right), unit can be "char", "column" (like char, but doesn't
10737
+ // cross line boundaries), "word" (across next word), or "group" (to
10738
+ // the start of next group of word or non-word-non-whitespace
10739
+ // chars). The visually param controls whether, in right-to-left
10740
+ // text, direction 1 means to move towards the next index in the
10741
+ // string, or towards the character to the right of the current
10742
+ // position. The resulting position will have a hitSide=true
10743
+ // property if it reached the end of the document.
10744
+ function findPosH(doc, pos, dir, unit, visually) {
10745
+ var line = pos.line, ch = pos.ch, origDir = dir
10746
+ var lineObj = getLine(doc, line)
10747
+ function findNextLine() {
10748
+ var l = line + dir
10749
+ if (l < doc.first || l >= doc.first + doc.size) { return false }
10750
+ line = l
10751
+ return lineObj = getLine(doc, l)
10752
+ }
10753
+ function moveOnce(boundToLine) {
10754
+ var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true)
10755
+ if (next == null) {
10756
+ if (!boundToLine && findNextLine()) {
10757
+ if (visually) { ch = (dir < 0 ? lineRight : lineLeft)(lineObj) }
10758
+ else { ch = dir < 0 ? lineObj.text.length : 0 }
10759
+ } else { return false }
10760
+ } else { ch = next }
10761
+ return true
10762
+ }
10763
+
10764
+ if (unit == "char") {
10765
+ moveOnce()
10766
+ } else if (unit == "column") {
10767
+ moveOnce(true)
10768
+ } else if (unit == "word" || unit == "group") {
10769
+ var sawType = null, group = unit == "group"
10770
+ var helper = doc.cm && doc.cm.getHelper(pos, "wordChars")
10771
+ for (var first = true;; first = false) {
10772
+ if (dir < 0 && !moveOnce(!first)) { break }
10773
+ var cur = lineObj.text.charAt(ch) || "\n"
10774
+ var type = isWordChar(cur, helper) ? "w"
10775
+ : group && cur == "\n" ? "n"
10776
+ : !group || /\s/.test(cur) ? null
10777
+ : "p"
10778
+ if (group && !first && !type) { type = "s" }
10779
+ if (sawType && sawType != type) {
10780
+ if (dir < 0) {dir = 1; moveOnce()}
10781
+ break
10782
+ }
10783
+
10784
+ if (type) { sawType = type }
10785
+ if (dir > 0 && !moveOnce(!first)) { break }
10786
  }
 
10787
  }
10788
+ var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true)
10789
+ if (!cmp(pos, result)) { result.hitSide = true }
10790
+ return result
10791
+ }
10792
 
10793
+ // For relative vertical movement. Dir may be -1 or 1. Unit can be
10794
+ // "page" or "line". The resulting position will have a hitSide=true
10795
+ // property if it reached the end of the document.
10796
+ function findPosV(cm, pos, dir, unit) {
10797
+ var doc = cm.doc, x = pos.left, y
10798
+ if (unit == "page") {
10799
+ var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight)
10800
+ var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3)
10801
+ y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount
10802
+
10803
+ } else if (unit == "line") {
10804
+ y = dir > 0 ? pos.bottom + 3 : pos.top - 3
10805
+ }
10806
+ var target
10807
+ for (;;) {
10808
+ target = coordsChar(cm, x, y)
10809
+ if (!target.outside) { break }
10810
+ if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break }
10811
+ y += dir * 5
10812
+ }
10813
+ return target
10814
+ }
10815
+
10816
+ // CONTENTEDITABLE INPUT STYLE
10817
+
10818
+ function ContentEditableInput(cm) {
10819
+ this.cm = cm
10820
+ this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null
10821
+ this.polling = new Delayed()
10822
+ this.gracePeriod = false
10823
+ }
10824
 
10825
+ ContentEditableInput.prototype = copyObj({
10826
+ init: function(display) {
10827
+ var input = this, cm = input.cm
10828
+ var div = input.div = display.lineDiv
10829
+ disableBrowserMagic(div, cm.options.spellcheck)
10830
+
10831
+ on(div, "paste", function (e) {
10832
+ if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
10833
+ // IE doesn't fire input events, so we schedule a read for the pasted content in this way
10834
+ if (ie_version <= 11) { setTimeout(operation(cm, function () {
10835
+ if (!input.pollContent()) { regChange(cm) }
10836
+ }), 20) }
10837
+ })
10838
+
10839
+ on(div, "compositionstart", function (e) {
10840
+ var data = e.data
10841
+ input.composing = {sel: cm.doc.sel, data: data, startData: data}
10842
+ if (!data) { return }
10843
+ var prim = cm.doc.sel.primary()
10844
+ var line = cm.getLine(prim.head.line)
10845
+ var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length))
10846
+ if (found > -1 && found <= prim.head.ch)
10847
+ { input.composing.sel = simpleSelection(Pos(prim.head.line, found),
10848
+ Pos(prim.head.line, found + data.length)) }
10849
+ })
10850
+ on(div, "compositionupdate", function (e) { return input.composing.data = e.data; })
10851
+ on(div, "compositionend", function (e) {
10852
+ var ours = input.composing
10853
+ if (!ours) { return }
10854
+ if (e.data != ours.startData && !/\u200b/.test(e.data))
10855
+ { ours.data = e.data }
10856
+ // Need a small delay to prevent other code (input event,
10857
+ // selection polling) from doing damage when fired right after
10858
+ // compositionend.
10859
+ setTimeout(function () {
10860
+ if (!ours.handled)
10861
+ { input.applyComposition(ours) }
10862
+ if (input.composing == ours)
10863
+ { input.composing = null }
10864
+ }, 50)
10865
+ })
10866
+
10867
+ on(div, "touchstart", function () { return input.forceCompositionEnd(); })
10868
+
10869
+ on(div, "input", function () {
10870
+ if (input.composing) { return }
10871
+ if (cm.isReadOnly() || !input.pollContent())
10872
+ { runInOp(input.cm, function () { return regChange(cm); }) }
10873
+ })
10874
+
10875
+ function onCopyCut(e) {
10876
+ if (signalDOMEvent(cm, e)) { return }
10877
+ if (cm.somethingSelected()) {
10878
+ setLastCopied({lineWise: false, text: cm.getSelections()})
10879
+ if (e.type == "cut") { cm.replaceSelection("", null, "cut") }
10880
+ } else if (!cm.options.lineWiseCopyCut) {
10881
+ return
10882
+ } else {
10883
+ var ranges = copyableRanges(cm)
10884
+ setLastCopied({lineWise: true, text: ranges.text})
10885
+ if (e.type == "cut") {
10886
+ cm.operation(function () {
10887
+ cm.setSelections(ranges.ranges, 0, sel_dontScroll)
10888
+ cm.replaceSelection("", null, "cut")
10889
+ })
10890
+ }
10891
  }
10892
+ if (e.clipboardData) {
10893
+ e.clipboardData.clearData()
10894
+ var content = lastCopied.text.join("\n")
10895
+ // iOS exposes the clipboard API, but seems to discard content inserted into it
10896
+ e.clipboardData.setData("Text", content)
10897
+ if (e.clipboardData.getData("Text") == content) {
10898
+ e.preventDefault()
10899
+ return
 
 
10900
  }
10901
  }
10902
+ // Old-fashioned briefly-focus-a-textarea hack
10903
+ var kludge = hiddenTextarea(), te = kludge.firstChild
10904
+ cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild)
10905
+ te.value = lastCopied.text.join("\n")
10906
+ var hadFocus = document.activeElement
10907
+ selectInput(te)
10908
+ setTimeout(function () {
10909
+ cm.display.lineSpace.removeChild(kludge)
10910
+ hadFocus.focus()
10911
+ if (hadFocus == div) { input.showPrimarySelection() }
10912
+ }, 50)
10913
+ }
10914
+ on(div, "copy", onCopyCut)
10915
+ on(div, "cut", onCopyCut)
10916
+ },
10917
 
10918
+ prepareSelection: function() {
10919
+ var result = prepareSelection(this.cm, false)
10920
+ result.focus = this.cm.state.focused
10921
+ return result
10922
+ },
10923
 
10924
+ showSelection: function(info, takeFocus) {
10925
+ if (!info || !this.cm.display.view.length) { return }
10926
+ if (info.focus || takeFocus) { this.showPrimarySelection() }
10927
+ this.showMultipleSelections(info)
10928
+ },
 
 
 
10929
 
10930
+ showPrimarySelection: function() {
10931
+ var sel = window.getSelection(), prim = this.cm.doc.sel.primary()
10932
+ var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset)
10933
+ var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset)
10934
+ if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
10935
+ cmp(minPos(curAnchor, curFocus), prim.from()) == 0 &&
10936
+ cmp(maxPos(curAnchor, curFocus), prim.to()) == 0)
10937
+ { return }
10938
+
10939
+ var start = posToDOM(this.cm, prim.from())
10940
+ var end = posToDOM(this.cm, prim.to())
10941
+ if (!start && !end) { return }
10942
+
10943
+ var view = this.cm.display.view
10944
+ var old = sel.rangeCount && sel.getRangeAt(0)
10945
+ if (!start) {
10946
+ start = {node: view[0].measure.map[2], offset: 0}
10947
+ } else if (!end) { // FIXME dangerously hacky
10948
+ var measure = view[view.length - 1].measure
10949
+ var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map
10950
+ end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}
10951
+ }
10952
+
10953
+ var rng
10954
+ try { rng = range(start.node, start.offset, end.offset, end.node) }
10955
+ catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
10956
+ if (rng) {
10957
+ if (!gecko && this.cm.state.focused) {
10958
+ sel.collapse(start.node, start.offset)
10959
+ if (!rng.collapsed) {
10960
+ sel.removeAllRanges()
10961
+ sel.addRange(rng)
10962
  }
10963
+ } else {
10964
+ sel.removeAllRanges()
10965
+ sel.addRange(rng)
10966
  }
10967
+ if (old && sel.anchorNode == null) { sel.addRange(old) }
10968
+ else if (gecko) { this.startGracePeriod() }
 
 
10969
  }
10970
+ this.rememberSelection()
10971
+ },
10972
 
10973
+ startGracePeriod: function() {
10974
+ var this$1 = this;
10975
+
10976
+ clearTimeout(this.gracePeriod)
10977
+ this.gracePeriod = setTimeout(function () {
10978
+ this$1.gracePeriod = false
10979
+ if (this$1.selectionChanged())
10980
+ { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }) }
10981
+ }, 20)
10982
+ },
10983
 
10984
+ showMultipleSelections: function(info) {
10985
+ removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors)
10986
+ removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection)
10987
+ },
10988
 
10989
+ rememberSelection: function() {
10990
+ var sel = window.getSelection()
10991
+ this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset
10992
+ this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset
10993
+ },
10994
 
10995
+ selectionInEditor: function() {
10996
+ var sel = window.getSelection()
10997
+ if (!sel.rangeCount) { return false }
10998
+ var node = sel.getRangeAt(0).commonAncestorContainer
10999
+ return contains(this.div, node)
11000
+ },
 
 
 
 
 
 
11001
 
11002
+ focus: function() {
11003
+ if (this.cm.options.readOnly != "nocursor") { this.div.focus() }
11004
+ },
11005
+ blur: function() { this.div.blur() },
11006
+ getField: function() { return this.div },
 
 
 
 
 
 
11007
 
11008
+ supportsTouch: function() { return true },
11009
 
11010
+ receivedFocus: function() {
11011
+ var input = this
11012
+ if (this.selectionInEditor())
11013
+ { this.pollSelection() }
11014
+ else
11015
+ { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }) }
11016
 
11017
+ function poll() {
11018
+ if (input.cm.state.focused) {
11019
+ input.pollSelection()
11020
+ input.polling.set(input.cm.options.pollInterval, poll)
11021
+ }
 
 
 
 
11022
  }
11023
+ this.polling.set(this.cm.options.pollInterval, poll)
11024
+ },
11025
 
11026
+ selectionChanged: function() {
11027
+ var sel = window.getSelection()
11028
+ return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
11029
+ sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
11030
+ },
 
11031
 
11032
+ pollSelection: function() {
11033
+ if (!this.composing && !this.gracePeriod && this.selectionChanged()) {
11034
+ var sel = window.getSelection(), cm = this.cm
11035
+ this.rememberSelection()
11036
+ var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset)
11037
+ var head = domToPos(cm, sel.focusNode, sel.focusOffset)
11038
+ if (anchor && head) { runInOp(cm, function () {
11039
+ setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll)
11040
+ if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true }
11041
+ }) }
11042
  }
11043
+ },
11044
 
11045
+ pollContent: function() {
11046
+ var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary()
11047
+ var from = sel.from(), to = sel.to()
11048
+ if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }
 
 
11049
 
11050
+ var fromIndex, fromLine, fromNode
11051
+ if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
11052
+ fromLine = lineNo(display.view[0].line)
11053
+ fromNode = display.view[0].node
 
 
 
 
 
 
 
 
 
 
 
 
 
11054
  } else {
11055
+ fromLine = lineNo(display.view[fromIndex].line)
11056
+ fromNode = display.view[fromIndex - 1].node.nextSibling
11057
+ }
11058
+ var toIndex = findViewIndex(cm, to.line)
11059
+ var toLine, toNode
11060
+ if (toIndex == display.view.length - 1) {
11061
+ toLine = display.viewTo - 1
11062
+ toNode = display.lineDiv.lastChild
11063
+ } else {
11064
+ toLine = lineNo(display.view[toIndex + 1].line) - 1
11065
+ toNode = display.view[toIndex + 1].node.previousSibling
11066
+ }
11067
+
11068
+ var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine))
11069
+ var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length))
11070
+ while (newText.length > 1 && oldText.length > 1) {
11071
+ if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine-- }
11072
+ else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++ }
11073
+ else { break }
11074
+ }
11075
+
11076
+ var cutFront = 0, cutEnd = 0
11077
+ var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length)
11078
+ while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
11079
+ { ++cutFront }
11080
+ var newBot = lst(newText), oldBot = lst(oldText)
11081
+ var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
11082
+ oldBot.length - (oldText.length == 1 ? cutFront : 0))
11083
+ while (cutEnd < maxCutEnd &&
11084
+ newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
11085
+ { ++cutEnd }
11086
+
11087
+ newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd)
11088
+ newText[0] = newText[0].slice(cutFront)
11089
+
11090
+ var chFrom = Pos(fromLine, cutFront)
11091
+ var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0)
11092
+ if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
11093
+ replaceRange(cm.doc, newText, chFrom, chTo, "+input")
11094
+ return true
11095
  }
11096
+ },
 
 
 
 
 
 
 
 
 
11097
 
11098
+ ensurePolled: function() {
11099
+ this.forceCompositionEnd()
11100
+ },
11101
+ reset: function() {
11102
+ this.forceCompositionEnd()
11103
+ },
11104
+ forceCompositionEnd: function() {
11105
+ if (!this.composing || this.composing.handled) { return }
11106
+ this.applyComposition(this.composing)
11107
+ this.composing.handled = true
11108
+ this.div.blur()
11109
+ this.div.focus()
11110
+ },
11111
+ applyComposition: function(composing) {
11112
+ if (this.cm.isReadOnly())
11113
+ { operation(this.cm, regChange)(this.cm) }
11114
+ else if (composing.data && composing.data != composing.startData)
11115
+ { operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel) }
11116
+ },
11117
 
11118
+ setUneditable: function(node) {
11119
+ node.contentEditable = "false"
11120
+ },
 
 
 
 
11121
 
11122
+ onKeyPress: function(e) {
11123
+ e.preventDefault()
11124
+ if (!this.cm.isReadOnly())
11125
+ { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0) }
11126
+ },
11127
 
11128
+ readOnlyChanged: function(val) {
11129
+ this.div.contentEditable = String(val != "nocursor")
11130
+ },
 
 
 
11131
 
11132
+ onContextMenu: nothing,
11133
+ resetPosition: nothing,
11134
 
11135
+ needsContentAttribute: true
11136
+ }, ContentEditableInput.prototype)
11137
 
11138
+ function posToDOM(cm, pos) {
11139
+ var view = findViewForLine(cm, pos.line)
11140
+ if (!view || view.hidden) { return null }
11141
+ var line = getLine(cm.doc, pos.line)
11142
+ var info = mapFromLineView(view, line, pos.line)
11143
 
11144
+ var order = getOrder(line), side = "left"
11145
+ if (order) {
11146
+ var partPos = getBidiPartAt(order, pos.ch)
11147
+ side = partPos % 2 ? "right" : "left"
11148
+ }
11149
+ var result = nodeAndOffsetInLineMap(info.map, pos.ch, side)
11150
+ result.offset = result.collapse == "right" ? result.end : result.start
11151
+ return result
11152
+ }
11153
 
11154
+ function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
11155
+
11156
+ function domTextBetween(cm, from, to, fromLine, toLine) {
11157
+ var text = "", closing = false, lineSep = cm.doc.lineSeparator()
11158
+ function recognizeMarker(id) { return function (marker) { return marker.id == id; } }
11159
+ function walk(node) {
11160
+ if (node.nodeType == 1) {
11161
+ var cmText = node.getAttribute("cm-text")
11162
+ if (cmText != null) {
11163
+ if (cmText == "") { cmText = node.textContent.replace(/\u200b/g, "") }
11164
+ text += cmText
11165
+ return
11166
+ }
11167
+ var markerID = node.getAttribute("cm-marker"), range
11168
+ if (markerID) {
11169
+ var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID))
11170
+ if (found.length && (range = found[0].find()))
11171
+ { text += getBetween(cm.doc, range.from, range.to).join(lineSep) }
11172
+ return
11173
+ }
11174
+ if (node.getAttribute("contenteditable") == "false") { return }
11175
+ for (var i = 0; i < node.childNodes.length; i++)
11176
+ { walk(node.childNodes[i]) }
11177
+ if (/^(pre|div|p)$/i.test(node.nodeName))
11178
+ { closing = true }
11179
+ } else if (node.nodeType == 3) {
11180
+ var val = node.nodeValue
11181
+ if (!val) { return }
11182
+ if (closing) {
11183
+ text += lineSep
11184
+ closing = false
11185
+ }
11186
+ text += val
11187
+ }
11188
+ }
11189
+ for (;;) {
11190
+ walk(from)
11191
+ if (from == to) { break }
11192
+ from = from.nextSibling
11193
+ }
11194
+ return text
11195
+ }
11196
 
11197
+ function domToPos(cm, node, offset) {
11198
+ var lineNode
11199
+ if (node == cm.display.lineDiv) {
11200
+ lineNode = cm.display.lineDiv.childNodes[offset]
11201
+ if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) }
11202
+ node = null; offset = 0
11203
+ } else {
11204
+ for (lineNode = node;; lineNode = lineNode.parentNode) {
11205
+ if (!lineNode || lineNode == cm.display.lineDiv) { return null }
11206
+ if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break }
 
 
 
 
11207
  }
11208
+ }
11209
+ for (var i = 0; i < cm.display.view.length; i++) {
11210
+ var lineView = cm.display.view[i]
11211
+ if (lineView.node == lineNode)
11212
+ { return locateNodeInLineView(lineView, node, offset) }
11213
+ }
11214
+ }
11215
 
11216
+ function locateNodeInLineView(lineView, node, offset) {
11217
+ var wrapper = lineView.text.firstChild, bad = false
11218
+ if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) }
11219
+ if (node == wrapper) {
11220
+ bad = true
11221
+ node = wrapper.childNodes[offset]
11222
+ offset = 0
11223
+ if (!node) {
11224
+ var line = lineView.rest ? lst(lineView.rest) : lineView.line
11225
+ return badPos(Pos(lineNo(line), line.text.length), bad)
11226
+ }
11227
+ }
11228
+
11229
+ var textNode = node.nodeType == 3 ? node : null, topNode = node
11230
+ if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
11231
+ textNode = node.firstChild
11232
+ if (offset) { offset = textNode.nodeValue.length }
11233
+ }
11234
+ while (topNode.parentNode != wrapper) { topNode = topNode.parentNode }
11235
+ var measure = lineView.measure, maps = measure.maps
11236
+
11237
+ function find(textNode, topNode, offset) {
11238
+ for (var i = -1; i < (maps ? maps.length : 0); i++) {
11239
+ var map = i < 0 ? measure.map : maps[i]
11240
+ for (var j = 0; j < map.length; j += 3) {
11241
+ var curNode = map[j + 2]
11242
+ if (curNode == textNode || curNode == topNode) {
11243
+ var line = lineNo(i < 0 ? lineView.line : lineView.rest[i])
11244
+ var ch = map[j] + offset
11245
+ if (offset < 0 || curNode != textNode) { ch = map[j + (offset ? 1 : 0)] }
11246
+ return Pos(line, ch)
11247
+ }
11248
+ }
11249
  }
11250
  }
11251
+ var found = find(textNode, topNode, offset)
11252
+ if (found) { return badPos(found, bad) }
11253
 
11254
+ // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
11255
+ for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
11256
+ found = find(after, after.firstChild, 0)
11257
+ if (found)
11258
+ { return badPos(Pos(found.line, found.ch - dist), bad) }
11259
+ else
11260
+ { dist += after.textContent.length }
11261
+ }
11262
+ for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) {
11263
+ found = find(before, before.firstChild, -1)
11264
+ if (found)
11265
+ { return badPos(Pos(found.line, found.ch + dist$1), bad) }
11266
+ else
11267
+ { dist$1 += before.textContent.length }
11268
  }
11269
+ }
11270
 
11271
+ // TEXTAREA INPUT STYLE
11272
+
11273
+ function TextareaInput(cm) {
11274
+ this.cm = cm
11275
+ // See input.poll and input.reset
11276
+ this.prevInput = ""
11277
+
11278
+ // Flag that indicates whether we expect input to appear real soon
11279
+ // now (after some event like 'keypress' or 'input') and are
11280
+ // polling intensively.
11281
+ this.pollingFast = false
11282
+ // Self-resetting timeout for the poller
11283
+ this.polling = new Delayed()
11284
+ // Tracks when input.reset has punted to just putting a short
11285
+ // string into the textarea instead of the full selection.
11286
+ this.inaccurateSelection = false
11287
+ // Used to work around IE issue with selection being forgotten when focus moves away from textarea
11288
+ this.hasSelection = false
11289
+ this.composing = null
11290
+ }
11291
 
11292
+ TextareaInput.prototype = copyObj({
11293
+ init: function(display) {
11294
+ var this$1 = this;
 
 
11295
 
11296
+ var input = this, cm = this.cm
 
 
 
 
 
 
 
 
 
11297
 
11298
+ // Wraps and hides input textarea
11299
+ var div = this.wrapper = hiddenTextarea()
11300
+ // The semihidden textarea that is focused when the editor is
11301
+ // focused, and receives input.
11302
+ var te = this.textarea = div.firstChild
11303
+ display.wrapper.insertBefore(div, display.wrapper.firstChild)
11304
 
11305
+ // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
11306
+ if (ios) { te.style.width = "0px" }
11307
 
11308
+ on(te, "input", function () {
11309
+ if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null }
11310
+ input.poll()
11311
+ })
11312
+
11313
+ on(te, "paste", function (e) {
11314
+ if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
11315
+
11316
+ cm.state.pasteIncoming = true
11317
+ input.fastPoll()
11318
+ })
11319
+
11320
+ function prepareCopyCut(e) {
11321
+ if (signalDOMEvent(cm, e)) { return }
11322
+ if (cm.somethingSelected()) {
11323
+ setLastCopied({lineWise: false, text: cm.getSelections()})
11324
+ if (input.inaccurateSelection) {
11325
+ input.prevInput = ""
11326
+ input.inaccurateSelection = false
11327
+ te.value = lastCopied.text.join("\n")
11328
+ selectInput(te)
11329
+ }
11330
+ } else if (!cm.options.lineWiseCopyCut) {
11331
+ return
11332
+ } else {
11333
+ var ranges = copyableRanges(cm)
11334
+ setLastCopied({lineWise: true, text: ranges.text})
11335
+ if (e.type == "cut") {
11336
+ cm.setSelections(ranges.ranges, null, sel_dontScroll)
11337
+ } else {
11338
+ input.prevInput = ""
11339
+ te.value = ranges.text.join("\n")
11340
+ selectInput(te)
11341
+ }
11342
+ }
11343
+ if (e.type == "cut") { cm.state.cutIncoming = true }
11344
+ }
11345
+ on(te, "cut", prepareCopyCut)
11346
+ on(te, "copy", prepareCopyCut)
11347
+
11348
+ on(display.scroller, "paste", function (e) {
11349
+ if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }
11350
+ cm.state.pasteIncoming = true
11351
+ input.focus()
11352
+ })
11353
+
11354
+ // Prevent normal selection in the editor (we handle our own)
11355
+ on(display.lineSpace, "selectstart", function (e) {
11356
+ if (!eventInWidget(display, e)) { e_preventDefault(e) }
11357
+ })
11358
+
11359
+ on(te, "compositionstart", function () {
11360
+ var start = cm.getCursor("from")
11361
+ if (input.composing) { input.composing.range.clear() }
11362
+ input.composing = {
11363
+ start: start,
11364
+ range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
11365
+ }
11366
+ })
11367
+ on(te, "compositionend", function () {
11368
+ if (input.composing) {
11369
+ input.poll()
11370
+ input.composing.range.clear()
11371
+ input.composing = null
11372
+ }
11373
+ })
11374
+ },
11375
+
11376
+ prepareSelection: function() {
11377
+ // Redraw the selection and/or cursor
11378
+ var cm = this.cm, display = cm.display, doc = cm.doc
11379
+ var result = prepareSelection(cm)
11380
+
11381
+ // Move the hidden textarea near the cursor to prevent scrolling artifacts
11382
+ if (cm.options.moveInputWithCursor) {
11383
+ var headPos = cursorCoords(cm, doc.sel.primary().head, "div")
11384
+ var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect()
11385
+ result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
11386
+ headPos.top + lineOff.top - wrapOff.top))
11387
+ result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
11388
+ headPos.left + lineOff.left - wrapOff.left))
11389
  }
 
 
 
11390
 
11391
+ return result
11392
+ },
 
 
 
 
 
11393
 
11394
+ showSelection: function(drawn) {
11395
+ var cm = this.cm, display = cm.display
11396
+ removeChildrenAndAdd(display.cursorDiv, drawn.cursors)
11397
+ removeChildrenAndAdd(display.selectionDiv, drawn.selection)
11398
+ if (drawn.teTop != null) {
11399
+ this.wrapper.style.top = drawn.teTop + "px"
11400
+ this.wrapper.style.left = drawn.teLeft + "px"
11401
+ }
11402
+ },
11403
 
11404
+ // Reset the input to correspond to the selection (or to be empty,
11405
+ // when not typing and nothing is selected)
11406
+ reset: function(typing) {
11407
+ if (this.contextMenuPending) { return }
11408
+ var minimal, selected, cm = this.cm, doc = cm.doc
11409
+ if (cm.somethingSelected()) {
11410
+ this.prevInput = ""
11411
+ var range = doc.sel.primary()
11412
+ minimal = hasCopyEvent &&
11413
+ (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000)
11414
+ var content = minimal ? "-" : selected || cm.getSelection()
11415
+ this.textarea.value = content
11416
+ if (cm.state.focused) { selectInput(this.textarea) }
11417
+ if (ie && ie_version >= 9) { this.hasSelection = content }
11418
+ } else if (!typing) {
11419
+ this.prevInput = this.textarea.value = ""
11420
+ if (ie && ie_version >= 9) { this.hasSelection = null }
11421
+ }
11422
+ this.inaccurateSelection = minimal
11423
+ },
11424
 
11425
+ getField: function() { return this.textarea },
 
 
 
11426
 
11427
+ supportsTouch: function() { return false },
 
 
 
 
 
 
11428
 
11429
+ focus: function() {
11430
+ if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
11431
+ try { this.textarea.focus() }
11432
+ catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
11433
+ }
11434
+ },
11435
 
11436
+ blur: function() { this.textarea.blur() },
 
 
 
 
 
 
 
11437
 
11438
+ resetPosition: function() {
11439
+ this.wrapper.style.top = this.wrapper.style.left = 0
11440
+ },
 
 
 
 
 
 
 
 
 
 
 
 
 
11441
 
11442
+ receivedFocus: function() { this.slowPoll() },
 
 
 
 
11443
 
11444
+ // Poll for input changes, using the normal rate of polling. This
11445
+ // runs as long as the editor is focused.
11446
+ slowPoll: function() {
11447
+ var this$1 = this;
11448
 
11449
+ if (this.pollingFast) { return }
11450
+ this.polling.set(this.cm.options.pollInterval, function () {
11451
+ this$1.poll()
11452
+ if (this$1.cm.state.focused) { this$1.slowPoll() }
11453
+ })
11454
+ },
 
 
 
 
11455
 
11456
+ // When an event has just come in that is likely to add or change
11457
+ // something in the input textarea, we poll faster, to ensure that
11458
+ // the change appears on the screen quickly.
11459
+ fastPoll: function() {
11460
+ var missed = false, input = this
11461
+ input.pollingFast = true
11462
+ function p() {
11463
+ var changed = input.poll()
11464
+ if (!changed && !missed) {missed = true; input.polling.set(60, p)}
11465
+ else {input.pollingFast = false; input.slowPoll()}
11466
+ }
11467
+ input.polling.set(20, p)
11468
+ },
11469
 
11470
+ // Read input from the textarea, and update the document to match.
11471
+ // When something is selected, it is present in the textarea, and
11472
+ // selected (unless it is huge, in which case a placeholder is
11473
+ // used). When nothing is selected, the cursor sits after previously
11474
+ // seen text (can be empty), which is stored in prevInput (we must
11475
+ // not reset the textarea when typing, because that breaks IME).
11476
+ poll: function() {
11477
+ var this$1 = this;
11478
+
11479
+ var cm = this.cm, input = this.textarea, prevInput = this.prevInput
11480
+ // Since this is called a *lot*, try to bail out as cheaply as
11481
+ // possible when it is clear that nothing happened. hasSelection
11482
+ // will be the case when there is a lot of text in the textarea,
11483
+ // in which case reading its value would be expensive.
11484
+ if (this.contextMenuPending || !cm.state.focused ||
11485
+ (hasSelection(input) && !prevInput && !this.composing) ||
11486
+ cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
11487
+ { return false }
11488
+
11489
+ var text = input.value
11490
+ // If nothing changed, bail.
11491
+ if (text == prevInput && !cm.somethingSelected()) { return false }
11492
+ // Work around nonsensical selection resetting in IE9/10, and
11493
+ // inexplicable appearance of private area unicode characters on
11494
+ // some key combos in Mac (#2689).
11495
+ if (ie && ie_version >= 9 && this.hasSelection === text ||
11496
+ mac && /[\uf700-\uf7ff]/.test(text)) {
11497
+ cm.display.input.reset()
11498
+ return false
11499
+ }
11500
+
11501
+ if (cm.doc.sel == cm.display.selForContextMenu) {
11502
+ var first = text.charCodeAt(0)
11503
+ if (first == 0x200b && !prevInput) { prevInput = "\u200b" }
11504
+ if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") }
11505
+ }
11506
+ // Find the part of the input that is actually new
11507
+ var same = 0, l = Math.min(prevInput.length, text.length)
11508
+ while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same }
11509
+
11510
+ runInOp(cm, function () {
11511
+ applyTextInput(cm, text.slice(same), prevInput.length - same,
11512
+ null, this$1.composing ? "*compose" : null)
11513
+
11514
+ // Don't leave long text in the textarea, since it makes further polling slow
11515
+ if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = "" }
11516
+ else { this$1.prevInput = text }
11517
+
11518
+ if (this$1.composing) {
11519
+ this$1.composing.range.clear()
11520
+ this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"),
11521
+ {className: "CodeMirror-composing"})
11522
+ }
11523
+ })
11524
+ return true
11525
+ },
11526
 
11527
+ ensurePolled: function() {
11528
+ if (this.pollingFast && this.poll()) { this.pollingFast = false }
11529
+ },
11530
 
11531
+ onKeyPress: function() {
11532
+ if (ie && ie_version >= 9) { this.hasSelection = null }
11533
+ this.fastPoll()
11534
+ },
 
 
 
 
11535
 
11536
+ onContextMenu: function(e) {
11537
+ var input = this, cm = input.cm, display = cm.display, te = input.textarea
11538
+ var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop
11539
+ if (!pos || presto) { return } // Opera is difficult.
11540
+
11541
+ // Reset the current text selection only if the click is done outside of the selection
11542
+ // and 'resetSelectionOnContextMenu' option is true.
11543
+ var reset = cm.options.resetSelectionOnContextMenu
11544
+ if (reset && cm.doc.sel.contains(pos) == -1)
11545
+ { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll) }
11546
+
11547
+ var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText
11548
+ input.wrapper.style.cssText = "position: absolute"
11549
+ var wrapperBox = input.wrapper.getBoundingClientRect()
11550
+ te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"
11551
+ var oldScrollY
11552
+ if (webkit) { oldScrollY = window.scrollY } // Work around Chrome issue (#2712)
11553
+ display.input.focus()
11554
+ if (webkit) { window.scrollTo(null, oldScrollY) }
11555
+ display.input.reset()
11556
+ // Adds "Select all" to context menu in FF
11557
+ if (!cm.somethingSelected()) { te.value = input.prevInput = " " }
11558
+ input.contextMenuPending = true
11559
+ display.selForContextMenu = cm.doc.sel
11560
+ clearTimeout(display.detectingSelectAll)
11561
+
11562
+ // Select-all will be greyed out if there's nothing to select, so
11563
+ // this adds a zero-width space so that we can later check whether
11564
+ // it got selected.
11565
+ function prepareSelectAllHack() {
11566
+ if (te.selectionStart != null) {
11567
+ var selected = cm.somethingSelected()
11568
+ var extval = "\u200b" + (selected ? te.value : "")
11569
+ te.value = "\u21da" // Used to catch context-menu undo
11570
+ te.value = extval
11571
+ input.prevInput = selected ? "" : "\u200b"
11572
+ te.selectionStart = 1; te.selectionEnd = extval.length
11573
+ // Re-set this, in case some other handler touched the
11574
+ // selection in the meantime.
11575
+ display.selForContextMenu = cm.doc.sel
11576
+ }
11577
+ }
11578
+ function rehide() {
11579
+ input.contextMenuPending = false
11580
+ input.wrapper.style.cssText = oldWrapperCSS
11581
+ te.style.cssText = oldCSS
11582
+ if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos) }
11583
+
11584
+ // Try to detect the user choosing select-all
11585
+ if (te.selectionStart != null) {
11586
+ if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack() }
11587
+ var i = 0, poll = function () {
11588
+ if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
11589
+ te.selectionEnd > 0 && input.prevInput == "\u200b")
11590
+ { operation(cm, selectAll)(cm) }
11591
+ else if (i++ < 10) { display.detectingSelectAll = setTimeout(poll, 500) }
11592
+ else { display.input.reset() }
11593
+ }
11594
+ display.detectingSelectAll = setTimeout(poll, 200)
11595
  }
11596
  }
 
 
 
 
 
 
 
 
 
 
 
 
11597
 
11598
+ if (ie && ie_version >= 9) { prepareSelectAllHack() }
11599
+ if (captureRightClick) {
11600
+ e_stop(e)
11601
+ var mouseup = function () {
11602
+ off(window, "mouseup", mouseup)
11603
+ setTimeout(rehide, 20)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11604
  }
11605
+ on(window, "mouseup", mouseup)
11606
+ } else {
11607
+ setTimeout(rehide, 50)
11608
  }
11609
+ },
11610
+
11611
+ readOnlyChanged: function(val) {
11612
+ if (!val) { this.reset() }
11613
+ },
11614
+
11615
+ setUneditable: nothing,
11616
+
11617
+ needsContentAttribute: false
11618
+ }, TextareaInput.prototype)
11619
+
11620
+ function fromTextArea(textarea, options) {
11621
+ options = options ? copyObj(options) : {}
11622
+ options.value = textarea.value
11623
+ if (!options.tabindex && textarea.tabIndex)
11624
+ { options.tabindex = textarea.tabIndex }
11625
+ if (!options.placeholder && textarea.placeholder)
11626
+ { options.placeholder = textarea.placeholder }
11627
+ // Set autofocus to true if this textarea is focused, or if it has
11628
+ // autofocus and no other element is focused.
11629
+ if (options.autofocus == null) {
11630
+ var hasFocus = activeElt()
11631
+ options.autofocus = hasFocus == textarea ||
11632
+ textarea.getAttribute("autofocus") != null && hasFocus == document.body
11633
+ }
11634
+
11635
+ function save() {textarea.value = cm.getValue()}
11636
+
11637
+ var realSubmit
11638
+ if (textarea.form) {
11639
+ on(textarea.form, "submit", save)
11640
+ // Deplorable hack to make the submit method do the right thing.
11641
+ if (!options.leaveSubmitMethodAlone) {
11642
+ var form = textarea.form
11643
+ realSubmit = form.submit
11644
+ try {
11645
+ var wrappedSubmit = form.submit = function () {
11646
+ save()
11647
+ form.submit = realSubmit
11648
+ form.submit()
11649
+ form.submit = wrappedSubmit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11650
  }
11651
+ } catch(e) {}
11652
  }
 
 
 
 
 
 
 
 
11653
  }
11654
 
11655
+ options.finishInit = function (cm) {
11656
+ cm.save = save
11657
+ cm.getTextArea = function () { return textarea; }
11658
+ cm.toTextArea = function () {
11659
+ cm.toTextArea = isNaN // Prevent this from being ran twice
11660
+ save()
11661
+ textarea.parentNode.removeChild(cm.getWrapperElement())
11662
+ textarea.style.display = ""
11663
+ if (textarea.form) {
11664
+ off(textarea.form, "submit", save)
11665
+ if (typeof textarea.form.submit == "function")
11666
+ { textarea.form.submit = realSubmit }
 
 
 
 
 
 
 
 
 
 
 
 
11667
  }
11668
  }
11669
  }
11670