PluginProbe
HTML Forms – Simple WordPress Forms Plugin / 1.1.2
HTML Forms – Simple WordPress Forms Plugin v1.1.2
1.7.0 trunk 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2.0 1.3.0 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 All 67 releases
html-forms / assets / js / admin.js

admin.js in HTML Forms – Simple WordPress Forms Plugin 1.1.2, at assets/js/admin.js

14,750 lines 558.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () { var require = undefined; var module = undefined; var exports = 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){
2 'use strict';
3
4 Object.defineProperty(exports, "__esModule", {
5 value: true
6 });
7 function init() {
8 document.body.addEventListener('click', handleClickEvent, true);
9 }
10
11 function handleClickEvent(e) {
12 if (e.target.tagName !== 'A') {
13 return;
14 }
15
16 if (e.target.hasAttribute('data-hf-confirm')) {
17 var sure = confirm(e.target.getAttribute('data-hf-confirm'));
18
19 if (!sure) {
20 e.preventDefault();
21 }
22 }
23 }
24
25 exports.default = {
26 'init': init
27 };
28
29 },{}],2:[function(require,module,exports){
30 'use strict';
31
32 var _tabs = require('./tabs.js');
33
34 var _tabs2 = _interopRequireDefault(_tabs);
35
36 var _formEditor = require('./form-editor.js');
37
38 var _formEditor2 = _interopRequireDefault(_formEditor);
39
40 var _formActions = require('./form-actions.js');
41
42 var _formActions2 = _interopRequireDefault(_formActions);
43
44 var _fieldBuilder = require('./field-builder.js');
45
46 var _fieldBuilder2 = _interopRequireDefault(_fieldBuilder);
47
48 var _actionConfirmations = require('./action-confirmations.js');
49
50 var _actionConfirmations2 = _interopRequireDefault(_actionConfirmations);
51
52 var _tlite = require('tlite');
53
54 var _tlite2 = _interopRequireDefault(_tlite);
55
56 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
57
58 _tabs2.default.init();
59 _actionConfirmations2.default.init();
60
61 if (document.getElementById('hf-form-editor')) {
62 _formEditor2.default.init();
63 _formActions2.default.init();
64
65 _fieldBuilder2.default.init(_formEditor2.default);
66 }
67
68 (0, _tlite2.default)(function (el) {
69 return el.className.indexOf('hf-tooltip') > -1;
70 });
71
72 },{"./action-confirmations.js":1,"./field-builder.js":3,"./form-actions.js":6,"./form-editor.js":7,"./tabs.js":8,"tlite":22}],3:[function(require,module,exports){
73 'use strict';
74
75 Object.defineProperty(exports, "__esModule", {
76 value: true
77 });
78
79 var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
80
81 var _desc, _value, _class, _desc2, _value2, _class2;
82
83 var _preact = require('preact');
84
85 var _linkstate = require('linkstate');
86
87 var _linkstate2 = _interopRequireDefault(_linkstate);
88
89 var _configFields = require('./field-builder/config-fields.js');
90
91 var _html = require('./field-builder/html.js');
92
93 var _decko = require('decko');
94
95 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
96
97 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
98
99 function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
100
101 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
102
103 function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
104 var desc = {};
105 Object['ke' + 'ys'](descriptor).forEach(function (key) {
106 desc[key] = descriptor[key];
107 });
108 desc.enumerable = !!desc.enumerable;
109 desc.configurable = !!desc.configurable;
110
111 if ('value' in desc || desc.initializer) {
112 desc.writable = true;
113 }
114
115 desc = decorators.slice().reverse().reduce(function (desc, decorator) {
116 return decorator(target, property, desc) || desc;
117 }, desc);
118
119 if (context && desc.initializer !== void 0) {
120 desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
121 desc.initializer = undefined;
122 }
123
124 if (desc.initializer === void 0) {
125 Object['define' + 'Property'](target, property, desc);
126 desc = null;
127 }
128
129 return desc;
130 }
131
132 var Editor = void 0;
133
134
135 var fields = {
136 "text": "Text",
137 "email": "Email",
138 "url": "URL",
139 "number": "Number",
140 "date": "Date",
141 "textarea": "Textarea",
142 "dropdown": "Dropdown",
143 "checkboxes": "Checkboxes",
144 "radio-buttons": "Radio buttons",
145 "submit": "Submit button"
146 };
147
148 var FieldBuilder = (_class = function (_Component) {
149 _inherits(FieldBuilder, _Component);
150
151 function FieldBuilder() {
152 _classCallCheck(this, FieldBuilder);
153
154 var _this = _possibleConstructorReturn(this, (FieldBuilder.__proto__ || Object.getPrototypeOf(FieldBuilder)).call(this));
155
156 _this.state = {
157 fieldType: ""
158 };
159 return _this;
160 }
161
162 _createClass(FieldBuilder, [{
163 key: 'handleCancel',
164 value: function handleCancel() {
165 this.setState({
166 fieldType: ""
167 });
168 }
169 }, {
170 key: 'openFieldConfig',
171 value: function openFieldConfig(e) {
172 var newFieldType = e.target.value;
173
174 if (this.state.fieldType === newFieldType) {
175 this.setState({ fieldType: "" });
176 } else {
177 this.setState({ fieldType: newFieldType });
178 }
179 }
180 }, {
181 key: 'render',
182 value: function render(props, state) {
183 var _this2 = this;
184
185 var fieldButtons = Object.keys(fields).map(function (key) {
186 var label = fields[key];
187 return (0, _preact.h)(
188 'button',
189 { type: 'button', value: key, className: "button " + (state.fieldType === key ? "active" : ""), onClick: _this2.openFieldConfig },
190 label
191 );
192 });
193
194 return (0, _preact.h)(
195 'div',
196 { 'class': 'hf-field-builder' },
197 (0, _preact.h)(
198 'h4',
199 null,
200 'Add field'
201 ),
202 (0, _preact.h)(
203 'div',
204 { 'class': 'available-fields' },
205 fieldButtons
206 ),
207 (0, _preact.h)(
208 'div',
209 { style: 'max-width: 480px;' },
210 (0, _preact.h)(FieldConfigurator, { fieldType: state.fieldType, onCancel: this.handleCancel })
211 ),
212 state.fieldType === "" ? (0, _preact.h)(
213 'p',
214 { 'class': 'help', style: 'margin-bottom: 0;' },
215 'Use the buttons above to generate your field HTML, or manually modify your form below.'
216 ) : ""
217 );
218 }
219 }]);
220
221 return FieldBuilder;
222 }(_preact.Component), (_applyDecoratedDescriptor(_class.prototype, 'handleCancel', [_decko.bind], Object.getOwnPropertyDescriptor(_class.prototype, 'handleCancel'), _class.prototype), _applyDecoratedDescriptor(_class.prototype, 'openFieldConfig', [_decko.bind], Object.getOwnPropertyDescriptor(_class.prototype, 'openFieldConfig'), _class.prototype)), _class);
223 var FieldConfigurator = (_class2 = function (_Component2) {
224 _inherits(FieldConfigurator, _Component2);
225
226 function FieldConfigurator(props) {
227 _classCallCheck(this, FieldConfigurator);
228
229 var _this3 = _possibleConstructorReturn(this, (FieldConfigurator.__proto__ || Object.getPrototypeOf(FieldConfigurator)).call(this, props));
230
231 _this3.state = _this3.getInitialState();
232 _this3.choiceHandlers = {
233 "add": _this3.addChoice,
234 "delete": _this3.deleteChoice,
235 "changeLabel": _this3.changeChoiceLabel,
236 "toggleChecked": _this3.toggleChoiceChecked
237 };
238 return _this3;
239 }
240
241 _createClass(FieldConfigurator, [{
242 key: 'getInitialState',
243 value: function getInitialState() {
244 return {
245 fieldType: this.props.fieldType,
246 fieldLabel: "",
247 placeholder: "",
248 value: "",
249 wrap: true,
250 required: false,
251 choices: [{
252 checked: false,
253 label: "One"
254 }, {
255 checked: false,
256 label: "Two"
257 }]
258 };
259 }
260 }, {
261 key: 'componentWillReceiveProps',
262 value: function componentWillReceiveProps(props) {
263 this.setState({
264 fieldType: props.fieldType
265 });
266 }
267 }, {
268 key: 'addToForm',
269 value: function addToForm() {
270 var html = (0, _html.htmlgenerate)(this.state);
271 Editor.replaceSelection(html);
272 }
273 }, {
274 key: 'addChoice',
275 value: function addChoice() {
276 var arr = this.state.choices;
277 arr.push({ checked: false, label: "..." });
278 this.setState({ choices: arr });
279 }
280 }, {
281 key: 'deleteChoice',
282 value: function deleteChoice(e) {
283 var arr = this.state.choices;
284 var index = e.target.parentElement.getAttribute('data-key');
285 arr.splice(index, 1);
286 this.setState({ choices: arr });
287 }
288 }, {
289 key: 'changeChoiceLabel',
290 value: function changeChoiceLabel(e) {
291 var arr = this.state.choices;
292 var index = e.target.parentElement.getAttribute('data-key');
293 arr[index].label = e.target.value;
294 this.setState({ choices: arr });
295 }
296 }, {
297 key: 'toggleChoiceChecked',
298 value: function toggleChoiceChecked(e) {
299 var arr = this.state.choices;
300 var index = e.target.parentElement.getAttribute('data-key');
301 arr[index].checked = !arr[index].checked;
302 this.setState({ choices: arr });
303 }
304 }, {
305 key: 'handleCancel',
306 value: function handleCancel() {
307 // revert back to initial state
308 this.setState(this.getInitialState());
309 this.props.onCancel();
310 }
311 }, {
312 key: 'render',
313 value: function render(props, state) {
314 if (state.fieldType === "") {
315 return "";
316 }
317
318 var formFields = void 0;
319
320 switch (state.fieldType) {
321 case "text":
322 case "email":
323 case "url":
324 case "number":
325 case "textarea":
326 formFields = (0, _preact.h)(
327 'div',
328 null,
329 (0, _preact.h)(_configFields.Label, { value: state.fieldLabel, onChange: (0, _linkstate2.default)(this, 'fieldLabel') }),
330 (0, _preact.h)(_configFields.Placeholder, { value: state.placeholder, onChange: (0, _linkstate2.default)(this, 'placeholder') }),
331 (0, _preact.h)(_configFields.DefaultValue, { value: state.value, onChange: (0, _linkstate2.default)(this, 'value') }),
332 (0, _preact.h)(_configFields.Required, { checked: state.required, onChange: (0, _linkstate2.default)(this, 'required') }),
333 (0, _preact.h)(_configFields.Wrap, { checked: state.wrap, onChange: (0, _linkstate2.default)(this, 'wrap') }),
334 (0, _preact.h)(_configFields.AddToForm, { onSubmit: this.addToForm, onCancel: this.handleCancel })
335 );
336 break;
337 case "submit":
338 formFields = (0, _preact.h)(
339 'div',
340 null,
341 (0, _preact.h)(_configFields.ButtonText, { value: state.value, onChange: (0, _linkstate2.default)(this, 'value') }),
342 (0, _preact.h)(_configFields.Wrap, { checked: state.wrap, onChange: (0, _linkstate2.default)(this, 'wrap') }),
343 (0, _preact.h)(_configFields.AddToForm, { onSubmit: this.addToForm, onCancel: this.handleCancel })
344 );
345 break;
346
347 case "date":
348 formFields = (0, _preact.h)(
349 'div',
350 null,
351 (0, _preact.h)(_configFields.Label, { value: state.fieldLabel, onChange: (0, _linkstate2.default)(this, 'fieldLabel') }),
352 (0, _preact.h)(_configFields.DefaultValue, { value: state.value, onChange: (0, _linkstate2.default)(this, 'value') }),
353 (0, _preact.h)(_configFields.Required, { checked: state.required, onChange: (0, _linkstate2.default)(this, 'required') }),
354 (0, _preact.h)(_configFields.Wrap, { checked: state.wrap, onChange: (0, _linkstate2.default)(this, 'wrap') }),
355 (0, _preact.h)(_configFields.AddToForm, { onSubmit: this.addToForm, onCancel: this.handleCancel })
356 );
357 break;
358 case "dropdown":
359 formFields = (0, _preact.h)(
360 'div',
361 null,
362 (0, _preact.h)(_configFields.Label, { value: state.fieldLabel, onChange: (0, _linkstate2.default)(this, 'fieldLabel') }),
363 (0, _preact.h)(_configFields.Choices, { multiple: false, choices: state.choices, handlers: this.choiceHandlers }),
364 (0, _preact.h)(_configFields.Required, { checked: state.required, onChange: (0, _linkstate2.default)(this, 'required') }),
365 (0, _preact.h)(_configFields.Wrap, { checked: state.wrap, onChange: (0, _linkstate2.default)(this, 'wrap') }),
366 (0, _preact.h)(_configFields.AddToForm, { onSubmit: this.addToForm, onCancel: this.handleCancel })
367 );
368 break;
369
370 case "radio-buttons":
371 case "checkboxes":
372 formFields = (0, _preact.h)(
373 'div',
374 null,
375 (0, _preact.h)(_configFields.Label, { value: state.fieldLabel, onChange: (0, _linkstate2.default)(this, 'fieldLabel') }),
376 (0, _preact.h)(_configFields.Choices, { multiple: state.fieldType === "checkboxes", choices: state.choices, handlers: this.choiceHandlers }),
377 (0, _preact.h)(_configFields.Wrap, { checked: state.wrap, onChange: (0, _linkstate2.default)(this, 'wrap') }),
378 (0, _preact.h)(_configFields.AddToForm, { onSubmit: this.addToForm, onCancel: this.handleCancel })
379 );
380 break;
381 }
382
383 return (0, _preact.h)(
384 'div',
385 { 'class': 'field-config', onKeyPress: FieldConfigurator.handleKeyPress },
386 formFields
387 );
388 }
389 }], [{
390 key: 'handleKeyPress',
391 value: function handleKeyPress(e) {
392 // stop RETURN from submitting the parent form.
393 if (e.keyCode === 13) {
394 e.preventDefault();
395 }
396 }
397 }]);
398
399 return FieldConfigurator;
400 }(_preact.Component), (_applyDecoratedDescriptor(_class2.prototype, 'addToForm', [_decko.bind], Object.getOwnPropertyDescriptor(_class2.prototype, 'addToForm'), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, 'addChoice', [_decko.bind], Object.getOwnPropertyDescriptor(_class2.prototype, 'addChoice'), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, 'deleteChoice', [_decko.bind], Object.getOwnPropertyDescriptor(_class2.prototype, 'deleteChoice'), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, 'changeChoiceLabel', [_decko.bind], Object.getOwnPropertyDescriptor(_class2.prototype, 'changeChoiceLabel'), _class2.prototype), _applyDecoratedDescriptor(_class2.prototype, 'toggleChoiceChecked', [_decko.bind], Object.getOwnPropertyDescriptor(_class2.prototype, 'toggleChoiceChecked'), _class2.prototype), _applyDecoratedDescriptor(_class2, 'handleKeyPress', [_decko.bind], Object.getOwnPropertyDescriptor(_class2, 'handleKeyPress'), _class2), _applyDecoratedDescriptor(_class2.prototype, 'handleCancel', [_decko.bind], Object.getOwnPropertyDescriptor(_class2.prototype, 'handleCancel'), _class2.prototype)), _class2);
401 exports.default = {
402 init: function init(editor) {
403 Editor = editor;
404
405 (0, _preact.render)((0, _preact.h)(FieldBuilder, null), document.getElementById('hf-field-builder'));
406 }
407 };
408
409 },{"./field-builder/config-fields.js":4,"./field-builder/html.js":5,"decko":17,"linkstate":19,"preact":21}],4:[function(require,module,exports){
410 "use strict";
411
412 Object.defineProperty(exports, "__esModule", {
413 value: true
414 });
415 exports.ButtonText = exports.Choices = exports.Required = exports.Wrap = exports.DefaultValue = exports.Placeholder = exports.Label = exports.AddToForm = undefined;
416
417 var _preact = require("preact");
418
419 function AddToForm(props) {
420 return (0, _preact.h)(
421 "div",
422 { "class": "hf-small-margin" },
423 (0, _preact.h)(
424 "button",
425 { "class": "button", type: "button", onClick: props.onSubmit },
426 "Add field to form"
427 ),
428 " \xA0 ",
429 (0, _preact.h)(
430 "a",
431 { href: "javascript:void(0);", "class": "hf-small", style: "vertical-align: middle;", onClick: props.onCancel },
432 "or close field helper"
433 )
434 );
435 }
436
437 function Label(props) {
438 return (0, _preact.h)(
439 "div",
440 { "class": "hf-small-margin" },
441 (0, _preact.h)(
442 "label",
443 { "for": "hf-fg-field-label" },
444 "Field label ",
445 (0, _preact.h)(
446 "span",
447 { "class": "hf-required" },
448 "*"
449 )
450 ),
451 (0, _preact.h)("input", { id: "hf-fg-field-label", type: "text", value: props.value, onChange: props.onChange })
452 );
453 }
454
455 function Placeholder(props) {
456 return (0, _preact.h)(
457 "div",
458 { "class": "hf-small-margin" },
459 (0, _preact.h)(
460 "label",
461 { "for": "hf-fg-placeholder" },
462 "Placeholder ",
463 (0, _preact.h)(
464 "span",
465 { "class": "hf-italic hf-pull-right" },
466 "Optional"
467 )
468 ),
469 (0, _preact.h)("input", { id: "hf-fg-placeholder", type: "text", value: props.value, onChange: props.onChange }),
470 (0, _preact.h)(
471 "p",
472 { "class": "help" },
473 "Text to show when field has no value."
474 )
475 );
476 }
477
478 function ButtonText(props) {
479 return (0, _preact.h)(
480 "div",
481 { "class": "hf-small-margin" },
482 (0, _preact.h)(
483 "label",
484 { "for": "hf-fg-default-value" },
485 "Button text ",
486 (0, _preact.h)(
487 "span",
488 { "class": "hf-required" },
489 "*"
490 )
491 ),
492 (0, _preact.h)("input", { id: "hf-fg-default-value", type: "text", value: props.value, onChange: props.onChange }),
493 (0, _preact.h)(
494 "p",
495 { "class": "help" },
496 "Text to show on the button."
497 )
498 );
499 }
500
501 function DefaultValue(props) {
502 return (0, _preact.h)(
503 "div",
504 { "class": "hf-small-margin" },
505 (0, _preact.h)(
506 "label",
507 { "for": "hf-fg-default-value" },
508 "Default value ",
509 (0, _preact.h)(
510 "span",
511 { "class": "hf-italic hf-pull-right" },
512 "Optional"
513 )
514 ),
515 (0, _preact.h)("input", { id: "hf-fg-default-value", type: "text", value: props.value, onChange: props.onChange }),
516 (0, _preact.h)(
517 "p",
518 { "class": "help" },
519 "Text to pre-fill this field with."
520 )
521 );
522 }
523
524 function Wrap(props) {
525 return (0, _preact.h)(
526 "div",
527 { "class": "hf-small-margin" },
528 (0, _preact.h)(
529 "label",
530 { "class": "inline" },
531 (0, _preact.h)("input", { type: "checkbox", value: "1", defaultChecked: props.checked, onChange: props.onChange }),
532 "Wrap this field in paragraph tags."
533 )
534 );
535 }
536
537 function Required(props) {
538 return (0, _preact.h)(
539 "div",
540 { "class": "hf-small-margin" },
541 (0, _preact.h)(
542 "label",
543 { "class": "inline" },
544 (0, _preact.h)("input", { type: "checkbox", value: "1", defaultChecked: props.checked, onChange: props.onChange }),
545 "This field is required."
546 )
547 );
548 }
549
550 function Choices(props) {
551 var choiceFields = props.choices.map(function (choice, k) {
552 return (0, _preact.h)(
553 "div",
554 { "data-key": k },
555 (0, _preact.h)("input", { type: props.multiple ? "checkbox" : "radio", name: "selected", defaultChecked: choice.checked, onChange: props.handlers.toggleChecked, title: "Pre-select this choice?" }),
556 (0, _preact.h)("input", { type: "text", value: choice.label, placeholder: "Choice label", style: "width: 80%;", onChange: props.handlers.changeLabel }),
557 (0, _preact.h)(
558 "a",
559 { href: "javascript:void(0);", onClick: props.handlers.delete, style: "text-decoration: none;", title: "Delete choice" },
560 "\u2715"
561 )
562 );
563 });
564
565 return (0, _preact.h)(
566 "div",
567 { "class": "hf-small-margin" },
568 (0, _preact.h)(
569 "label",
570 null,
571 "Choices"
572 ),
573 choiceFields,
574 (0, _preact.h)("input", { type: props.multiple ? "checkbox" : "radio", style: "visibility: hidden;" }),
575 (0, _preact.h)(
576 "a",
577 { href: "javascript:void(0);", onClick: props.handlers.add },
578 "Add choice"
579 )
580 );
581 }
582
583 exports.AddToForm = AddToForm;
584 exports.Label = Label;
585 exports.Placeholder = Placeholder;
586 exports.DefaultValue = DefaultValue;
587 exports.Wrap = Wrap;
588 exports.Required = Required;
589 exports.Choices = Choices;
590 exports.ButtonText = ButtonText;
591
592 },{"preact":21}],5:[function(require,module,exports){
593 'use strict';
594
595 Object.defineProperty(exports, "__esModule", {
596 value: true
597 });
598 exports.htmlgenerate = undefined;
599
600 var _html = require('html');
601
602 var _html2 = _interopRequireDefault(_html);
603
604 var _preactRenderToString = require('preact-render-to-string');
605
606 var _preactRenderToString2 = _interopRequireDefault(_preactRenderToString);
607
608 var _preact = require('preact');
609
610 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
611
612 function htmlgenerate(conf) {
613 var label = conf.fieldLabel.length && conf.fieldType !== 'submit' ? (0, _preact.h)("label", {}, conf.fieldLabel) : "";
614 var fieldAttr = void 0,
615 field = void 0;
616
617 switch (conf.fieldType) {
618 case "text":
619 default:
620 fieldAttr = {
621 type: conf.fieldType,
622 name: namify(conf.fieldLabel),
623 value: conf.value,
624 placeholder: conf.placeholder,
625 required: conf.required
626 };
627 field = html("input", fieldAttr);
628 break;
629 case "textarea":
630 fieldAttr = {
631 name: namify(conf.fieldLabel),
632 placeholder: conf.placeholder,
633 required: conf.required
634 };
635 field = html("textarea", fieldAttr, conf.value);
636 break;
637
638 case "dropdown":
639 fieldAttr = {
640 name: namify(conf.fieldLabel),
641 required: conf.required
642 };
643 var opts = conf.choices.map(function (choice) {
644 return html("option", { defaultChecked: choice.checked }, choice.label);
645 });
646 field = html("select", fieldAttr, opts);
647 break;
648
649 case "radio-buttons":
650 field = conf.choices.map(function (choice) {
651 return html("label", {}, [html("input", {
652 type: "radio",
653 name: namify(conf.fieldLabel),
654 value: choice.label,
655 selected: choice.checked
656 }), " ", html("span", {}, choice.label)]);
657 });
658 break;
659
660 case "checkboxes":
661 field = conf.choices.map(function (choice) {
662 return html("label", {}, [html("input", {
663 type: "checkbox",
664 name: namify(conf.fieldLabel) + "[]",
665 value: choice.label,
666 checked: choice.checked
667 }), " ", html("span", {}, choice.label)]);
668 });
669 break;
670
671 case "submit":
672 fieldAttr = {
673 type: "submit",
674 value: conf.value
675 };
676 field = html("input", fieldAttr);
677 break;
678
679 }
680
681 var str = "";
682 if (conf.wrap) {
683 var tmpl = (0, _preact.h)("p", {}, [label, field]);
684 str = (0, _preactRenderToString2.default)(tmpl);
685 } else {
686 str += (0, _preactRenderToString2.default)(label);
687 str += (0, _preactRenderToString2.default)(field);
688 }
689
690 str = _html2.default.prettyPrint(str);
691
692 return str;
693 }
694
695 function html(tag, attr, children) {
696 return (0, _preact.h)(tag, filterEmptyObjectValues(attr), children);
697 }
698
699 function namify(str) {
700 return str.replace(/ /g, '_').replace(/[^\w\[\]_]*/g, "").toUpperCase();
701 }
702
703 function filterEmptyObjectValues(obj) {
704 var newObj = {};
705 for (var propName in obj) {
706 if (obj[propName] !== false && obj[propName] !== "") {
707 newObj[propName] = obj[propName];
708 }
709 }
710 return newObj;
711 }
712
713 exports.htmlgenerate = htmlgenerate;
714
715 },{"html":18,"preact":21,"preact-render-to-string":20}],6:[function(require,module,exports){
716 'use strict';
717
718 Object.defineProperty(exports, "__esModule", {
719 value: true
720 });
721 var availableActions = void 0,
722 actionTemplates = void 0,
723 actions = void 0;
724
725 function init() {
726 actions = document.getElementById('hf-form-actions');
727 availableActions = document.getElementById('hf-available-form-actions');
728 actionTemplates = document.getElementById('hf-form-action-templates');
729
730 // turn settings into accordions
731 [].forEach.call(actions.querySelectorAll('.hf-action-settings'), function (el) {
732 el.parentNode.removeChild(el);
733
734 var heading = el.getAttribute('data-title');
735 var summary = el.querySelector('.hf-action-summary');
736 if (summary) {
737 heading += ' &mdash; <span class="hf-muted">' + summary.innerHTML + '</span>';
738 }
739 var wrap = createAccordion(heading, el.innerHTML);
740 actions.appendChild(wrap);
741
742 actions.querySelector('#hf-form-actions-empty').style.display = 'none';
743 });
744
745 availableActions.addEventListener('click', addAction, true);
746 }
747
748 function createAccordion(headingHTML, contentHTML) {
749 var wrap = document.createElement('div');
750 wrap.className = "hf-accordion expanded ";
751
752 var heading = document.createElement('h4');
753 heading.className = "hf-accordion-heading";
754 heading.innerHTML = headingHTML;
755 wrap.appendChild(heading);
756
757 var content = document.createElement('div');
758 content.className = "hf-accordion-content";
759 content.innerHTML = contentHTML;
760 wrap.appendChild(content);
761
762 var deleteWrap = document.createElement('p');
763 deleteWrap.style.textAlign = 'right';
764 var deleteLink = document.createElement('a');
765 deleteLink.href = 'javascript:void(0);';
766 deleteLink.className = "danger";
767 deleteLink.innerText = 'Delete this action';
768 deleteWrap.appendChild(deleteLink);
769 content.appendChild(deleteWrap);
770
771 // bind handlers
772 heading.addEventListener('click', createToggleActionHandler(wrap, content));
773 deleteLink.addEventListener('click', createDeleteActionHandler(wrap));
774 return wrap;
775 }
776
777 function addAction(e) {
778 var el = e.target || e.srcElement;
779 if (el.tagName !== 'INPUT') {
780 return;
781 }
782
783 var actionType = el.getAttribute('data-action-type');
784 var actionTemplate = actionTemplates.querySelector('#hf-action-type-' + actionType + '-template');
785
786 // append HTML to actions wrapper
787 var index = actions.querySelectorAll('div').length - 1;
788 var wrap = createAccordion(el.value, actionTemplate.innerHTML.replace(/\$index/g, index));
789 actions.appendChild(wrap);
790
791 // hide "no form actions" message
792 actions.querySelector('#hf-form-actions-empty').style.display = 'none';
793 }
794
795 function createDeleteActionHandler(wrap) {
796 return function () {
797 actions.removeChild(wrap);
798
799 if (actions.childElementCount === 1) {
800 actions.querySelector('#hf-form-actions-empty').style.display = '';
801 }
802 };
803 }
804
805 function createToggleActionHandler(wrap, content) {
806 return function () {
807 var show = content.offsetParent === null;
808 wrap.className = wrap.className.replace('expanded', '') + (show ? ' expanded' : '');
809 content.style.display = show ? 'block' : 'none';
810 };
811 }
812
813 exports.default = {
814 'init': init
815 };
816
817 },{}],7:[function(require,module,exports){
818 'use strict';
819
820 // load CodeMirror & plugins
821
822 Object.defineProperty(exports, "__esModule", {
823 value: true
824 });
825 var CodeMirror = require('codemirror');
826 require('codemirror/mode/xml/xml');
827 require('codemirror/mode/javascript/javascript');
828 require('codemirror/mode/css/css');
829 require('codemirror/mode/htmlmixed/htmlmixed');
830 require('codemirror/addon/fold/xml-fold');
831 require('codemirror/addon/edit/matchtags');
832 require('codemirror/addon/edit/closetag.js');
833
834 var editor = void 0,
835 element = void 0,
836 dom = void 0,
837 requiredFieldsInput = void 0,
838 emailFieldsInput = void 0,
839 previewFrame = void 0,
840 previewDom = void 0;
841 var templateRegex = /\{\{ *(\w+)(?:\.([\w\.]+))? *(?:\|\| *(\w+))? *\}\}/g;
842
843 function init() {
844 previewFrame = document.getElementById('hf-form-preview');
845 element = document.getElementById('hf-form-editor');
846 dom = document.createElement('form');
847 requiredFieldsInput = document.getElementById('hf-required-fields');
848 emailFieldsInput = document.getElementById('hf-email-fields');
849
850 dom.innerHTML = element.value;
851 editor = CodeMirror.fromTextArea(element, {
852 selectionPointer: true,
853 matchTags: { bothTags: true },
854 mode: "htmlmixed",
855 htmlMode: true,
856 autoCloseTags: true,
857 autoRefresh: true,
858 styleActiveLine: true,
859 matchBrackets: true
860 });
861
862 editor.on('changes', debounce(updatePreview, 500));
863 editor.on('changes', debounce(updateShadowDOM, 100));
864 editor.on('blur', updatePreview);
865 editor.on('blur', updateShadowDOM);
866 editor.on('blur', updateFieldVariables);
867 editor.on('blur', updateRequiredFields);
868 editor.on('blur', updateEmailFields);
869
870 previewFrame.addEventListener('load', setPreviewDom);
871 setPreviewDom();
872
873 document.getElementById('wpbody').addEventListener('click', updateFieldVariables);
874 updateFieldVariables();
875 }
876
877 function setPreviewDom() {
878 var frameContent = previewFrame.contentDocument || previewFrame.contentWindow.document;
879 previewDom = frameContent.querySelector('.hf-fields-wrap');
880
881 if (previewDom) {
882 updatePreview();
883 }
884 }
885
886 function getFieldVariableName(f) {
887 return f.name.replace('[]', '').replace(/\[(\w+)\]/g, '.$1');
888 }
889
890 function updateFieldVariables() {
891 var fields = dom.querySelectorAll('input[name], select[name], textarea[name], button[name]');
892 var fieldVariables = uniq([].map.call(fields, function (f) {
893 return '[' + getFieldVariableName(f) + ']';
894 }));
895
896 [].forEach.call(document.querySelectorAll('.hf-field-names'), function (el) {
897 while (el.firstChild) {
898 el.removeChild(el.firstChild);
899 }
900
901 var variableElements = fieldVariables.map(function (n) {
902 var el = document.createElement('code');
903 el.innerText = n;
904 return el;
905 });
906
907 variableElements.forEach(function (vel, i, arr) {
908 el.appendChild(vel);
909
910 if (i < arr.length - 1) {
911 el.appendChild(document.createTextNode(', '));
912 }
913 });
914 });
915 }
916
917 function updatePreview() {
918 var markup = editor.getValue();
919
920 // replace template tags
921 markup = markup.replace(templateRegex, function (s, m) {
922 if (arguments[3]) {
923 return arguments[3];
924 }
925
926 return '';
927 });
928
929 // update dom
930 previewDom.innerHTML = markup;
931 previewDom.dispatchEvent(new Event('hf-refresh'));
932 }
933
934 function updateShadowDOM() {
935 dom.innerHTML = editor.getValue();
936 }
937
938 function updateRequiredFields() {
939 var fields = dom.querySelectorAll('[required]');
940 var fieldNames = [].map.call(fields, getFieldVariableName);
941 requiredFieldsInput.value = fieldNames.join(',');
942 }
943
944 function updateEmailFields() {
945 var fields = dom.querySelectorAll('input[type="email"]');
946 var fieldNames = [].map.call(fields, getFieldVariableName);
947 emailFieldsInput.value = fieldNames.join(',');
948 }
949
950 function replaceSelection(str) {
951 editor.replaceSelection(str);
952 editor.focus();
953 }
954
955 function debounce(func, wait, immediate) {
956 var timeout;
957 return function () {
958 var context = this,
959 args = arguments;
960 var later = function later() {
961 timeout = null;
962 if (!immediate) func.apply(context, args);
963 };
964 var callNow = immediate && !timeout;
965 clearTimeout(timeout);
966 timeout = setTimeout(later, wait);
967 if (callNow) func.apply(context, args);
968 };
969 };
970
971 function uniq(a) {
972 var seen = {};
973 return a.filter(function (item) {
974 return seen.hasOwnProperty(item) ? false : seen[item] = true;
975 });
976 }
977
978 exports.default = {
979 'init': init,
980 'replaceSelection': replaceSelection
981 };
982
983 },{"codemirror":12,"codemirror/addon/edit/closetag.js":9,"codemirror/addon/edit/matchtags":10,"codemirror/addon/fold/xml-fold":11,"codemirror/mode/css/css":13,"codemirror/mode/htmlmixed/htmlmixed":14,"codemirror/mode/javascript/javascript":15,"codemirror/mode/xml/xml":16}],8:[function(require,module,exports){
984 'use strict';
985
986 Object.defineProperty(exports, "__esModule", {
987 value: true
988 });
989 var tabs = void 0,
990 tabNavs = void 0;
991 var Tabs = {};
992
993 Tabs.init = function () {
994 tabs = document.querySelectorAll('.hf-tab');
995 tabNavs = document.querySelectorAll('#hf-tabs-nav a');
996 for (var i = 0; i < tabNavs.length; i++) {
997 tabNavs[i].addEventListener('click', Tabs.open);
998 }
999 };
1000
1001 Tabs.open = function (e) {
1002 var tabTarget = this.getAttribute('data-tab-target');
1003 for (var i = 0; i < tabNavs.length; i++) {
1004 tabNavs[i].classList.toggle('nav-tab-active', tabNavs[i] === this);
1005 }
1006 this.blur();
1007
1008 for (var _i = 0; _i < tabs.length; _i++) {
1009 var tab = tabs[_i];
1010 tab.classList.toggle('hf-tab-active', tab.getAttribute('data-tab') === tabTarget);
1011 }
1012
1013 document.title = document.title.replace(document.title.split(' - ').shift(), this.innerText + " ");
1014
1015 e.preventDefault();
1016 };
1017
1018 exports.default = Tabs;
1019
1020 },{}],9:[function(require,module,exports){
1021 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1022 // Distributed under an MIT license: http://codemirror.net/LICENSE
1023
1024 /**
1025 * Tag-closer extension for CodeMirror.
1026 *
1027 * This extension adds an "autoCloseTags" option that can be set to
1028 * either true to get the default behavior, or an object to further
1029 * configure its behavior.
1030 *
1031 * These are supported options:
1032 *
1033 * `whenClosing` (default true)
1034 * Whether to autoclose when the '/' of a closing tag is typed.
1035 * `whenOpening` (default true)
1036 * Whether to autoclose the tag when the final '>' of an opening
1037 * tag is typed.
1038 * `dontCloseTags` (default is empty tags for HTML, none for XML)
1039 * An array of tag names that should not be autoclosed.
1040 * `indentTags` (default is block tags for HTML, none for XML)
1041 * An array of tag names that should, when opened, cause a
1042 * blank line to be added inside the tag, and the blank line and
1043 * closing line to be indented.
1044 *
1045 * See demos/closetag.html for a usage example.
1046 */
1047
1048 (function(mod) {
1049 if (typeof exports == "object" && typeof module == "object") // CommonJS
1050 mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
1051 else if (typeof define == "function" && define.amd) // AMD
1052 define(["../../lib/codemirror", "../fold/xml-fold"], mod);
1053 else // Plain browser env
1054 mod(CodeMirror);
1055 })(function(CodeMirror) {
1056 CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
1057 if (old != CodeMirror.Init && old)
1058 cm.removeKeyMap("autoCloseTags");
1059 if (!val) return;
1060 var map = {name: "autoCloseTags"};
1061 if (typeof val != "object" || val.whenClosing)
1062 map["'/'"] = function(cm) { return autoCloseSlash(cm); };
1063 if (typeof val != "object" || val.whenOpening)
1064 map["'>'"] = function(cm) { return autoCloseGT(cm); };
1065 cm.addKeyMap(map);
1066 });
1067
1068 var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
1069 "source", "track", "wbr"];
1070 var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4",
1071 "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"];
1072
1073 function autoCloseGT(cm) {
1074 if (cm.getOption("disableInput")) return CodeMirror.Pass;
1075 var ranges = cm.listSelections(), replacements = [];
1076 var opt = cm.getOption("autoCloseTags");
1077 for (var i = 0; i < ranges.length; i++) {
1078 if (!ranges[i].empty()) return CodeMirror.Pass;
1079 var pos = ranges[i].head, tok = cm.getTokenAt(pos);
1080 var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
1081 if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;
1082
1083 var html = inner.mode.configuration == "html";
1084 var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
1085 var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
1086
1087 var tagName = state.tagName;
1088 if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
1089 var lowerTagName = tagName.toLowerCase();
1090 // Don't process the '>' at the end of an end-tag or self-closing tag
1091 if (!tagName ||
1092 tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
1093 tok.type == "tag" && state.type == "closeTag" ||
1094 tok.string.indexOf("/") == (tok.string.length - 1) || // match something like <someTagName />
1095 dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
1096 closingTagExists(cm, tagName, pos, state, true))
1097 return CodeMirror.Pass;
1098
1099 var indent = indentTags && indexOf(indentTags, lowerTagName) > -1;
1100 replacements[i] = {indent: indent,
1101 text: ">" + (indent ? "\n\n" : "") + "</" + tagName + ">",
1102 newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)};
1103 }
1104
1105 var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnAutoClose);
1106 for (var i = ranges.length - 1; i >= 0; i--) {
1107 var info = replacements[i];
1108 cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert");
1109 var sel = cm.listSelections().slice(0);
1110 sel[i] = {head: info.newPos, anchor: info.newPos};
1111 cm.setSelections(sel);
1112 if (!dontIndentOnAutoClose && info.indent) {
1113 cm.indentLine(info.newPos.line, null, true);
1114 cm.indentLine(info.newPos.line + 1, null, true);
1115 }
1116 }
1117 }
1118
1119 function autoCloseCurrent(cm, typingSlash) {
1120 var ranges = cm.listSelections(), replacements = [];
1121 var head = typingSlash ? "/" : "</";
1122 var opt = cm.getOption("autoCloseTags");
1123 var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnSlash);
1124 for (var i = 0; i < ranges.length; i++) {
1125 if (!ranges[i].empty()) return CodeMirror.Pass;
1126 var pos = ranges[i].head, tok = cm.getTokenAt(pos);
1127 var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
1128 if (typingSlash && (tok.type == "string" || tok.string.charAt(0) != "<" ||
1129 tok.start != pos.ch - 1))
1130 return CodeMirror.Pass;
1131 // Kludge to get around the fact that we are not in XML mode
1132 // when completing in JS/CSS snippet in htmlmixed mode. Does not
1133 // work for other XML embedded languages (there is no general
1134 // way to go from a mixed mode to its current XML state).
1135 var replacement;
1136 if (inner.mode.name != "xml") {
1137 if (cm.getMode().name == "htmlmixed" && inner.mode.name == "javascript")
1138 replacement = head + "script";
1139 else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css")
1140 replacement = head + "style";
1141 else
1142 return CodeMirror.Pass;
1143 } else {
1144 if (!state.context || !state.context.tagName ||
1145 closingTagExists(cm, state.context.tagName, pos, state))
1146 return CodeMirror.Pass;
1147 replacement = head + state.context.tagName;
1148 }
1149 if (cm.getLine(pos.line).charAt(tok.end) != ">") replacement += ">";
1150 replacements[i] = replacement;
1151 }
1152 cm.replaceSelections(replacements);
1153 ranges = cm.listSelections();
1154 if (!dontIndentOnAutoClose) {
1155 for (var i = 0; i < ranges.length; i++)
1156 if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line)
1157 cm.indentLine(ranges[i].head.line);
1158 }
1159 }
1160
1161 function autoCloseSlash(cm) {
1162 if (cm.getOption("disableInput")) return CodeMirror.Pass;
1163 return autoCloseCurrent(cm, true);
1164 }
1165
1166 CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); };
1167
1168 function indexOf(collection, elt) {
1169 if (collection.indexOf) return collection.indexOf(elt);
1170 for (var i = 0, e = collection.length; i < e; ++i)
1171 if (collection[i] == elt) return i;
1172 return -1;
1173 }
1174
1175 // If xml-fold is loaded, we use its functionality to try and verify
1176 // whether a given tag is actually unclosed.
1177 function closingTagExists(cm, tagName, pos, state, newTag) {
1178 if (!CodeMirror.scanForClosingTag) return false;
1179 var end = Math.min(cm.lastLine() + 1, pos.line + 500);
1180 var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end);
1181 if (!nextClose || nextClose.tag != tagName) return false;
1182 var cx = state.context;
1183 // If the immediate wrapping context contains onCx instances of
1184 // the same tag, a closing tag only exists if there are at least
1185 // that many closing tags of that type following.
1186 for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx;
1187 pos = nextClose.to;
1188 for (var i = 1; i < onCx; i++) {
1189 var next = CodeMirror.scanForClosingTag(cm, pos, null, end);
1190 if (!next || next.tag != tagName) return false;
1191 pos = next.to;
1192 }
1193 return true;
1194 }
1195 });
1196
1197 },{"../../lib/codemirror":12,"../fold/xml-fold":11}],10:[function(require,module,exports){
1198 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1199 // Distributed under an MIT license: http://codemirror.net/LICENSE
1200
1201 (function(mod) {
1202 if (typeof exports == "object" && typeof module == "object") // CommonJS
1203 mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
1204 else if (typeof define == "function" && define.amd) // AMD
1205 define(["../../lib/codemirror", "../fold/xml-fold"], mod);
1206 else // Plain browser env
1207 mod(CodeMirror);
1208 })(function(CodeMirror) {
1209 "use strict";
1210
1211 CodeMirror.defineOption("matchTags", false, function(cm, val, old) {
1212 if (old && old != CodeMirror.Init) {
1213 cm.off("cursorActivity", doMatchTags);
1214 cm.off("viewportChange", maybeUpdateMatch);
1215 clear(cm);
1216 }
1217 if (val) {
1218 cm.state.matchBothTags = typeof val == "object" && val.bothTags;
1219 cm.on("cursorActivity", doMatchTags);
1220 cm.on("viewportChange", maybeUpdateMatch);
1221 doMatchTags(cm);
1222 }
1223 });
1224
1225 function clear(cm) {
1226 if (cm.state.tagHit) cm.state.tagHit.clear();
1227 if (cm.state.tagOther) cm.state.tagOther.clear();
1228 cm.state.tagHit = cm.state.tagOther = null;
1229 }
1230
1231 function doMatchTags(cm) {
1232 cm.state.failedTagMatch = false;
1233 cm.operation(function() {
1234 clear(cm);
1235 if (cm.somethingSelected()) return;
1236 var cur = cm.getCursor(), range = cm.getViewport();
1237 range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to);
1238 var match = CodeMirror.findMatchingTag(cm, cur, range);
1239 if (!match) return;
1240 if (cm.state.matchBothTags) {
1241 var hit = match.at == "open" ? match.open : match.close;
1242 if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"});
1243 }
1244 var other = match.at == "close" ? match.open : match.close;
1245 if (other)
1246 cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"});
1247 else
1248 cm.state.failedTagMatch = true;
1249 });
1250 }
1251
1252 function maybeUpdateMatch(cm) {
1253 if (cm.state.failedTagMatch) doMatchTags(cm);
1254 }
1255
1256 CodeMirror.commands.toMatchingTag = function(cm) {
1257 var found = CodeMirror.findMatchingTag(cm, cm.getCursor());
1258 if (found) {
1259 var other = found.at == "close" ? found.open : found.close;
1260 if (other) cm.extendSelection(other.to, other.from);
1261 }
1262 };
1263 });
1264
1265 },{"../../lib/codemirror":12,"../fold/xml-fold":11}],11:[function(require,module,exports){
1266 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1267 // Distributed under an MIT license: http://codemirror.net/LICENSE
1268
1269 (function(mod) {
1270 if (typeof exports == "object" && typeof module == "object") // CommonJS
1271 mod(require("../../lib/codemirror"));
1272 else if (typeof define == "function" && define.amd) // AMD
1273 define(["../../lib/codemirror"], mod);
1274 else // Plain browser env
1275 mod(CodeMirror);
1276 })(function(CodeMirror) {
1277 "use strict";
1278
1279 var Pos = CodeMirror.Pos;
1280 function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
1281
1282 var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
1283 var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
1284 var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
1285
1286 function Iter(cm, line, ch, range) {
1287 this.line = line; this.ch = ch;
1288 this.cm = cm; this.text = cm.getLine(line);
1289 this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine();
1290 this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine();
1291 }
1292
1293 function tagAt(iter, ch) {
1294 var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
1295 return type && /\btag\b/.test(type);
1296 }
1297
1298 function nextLine(iter) {
1299 if (iter.line >= iter.max) return;
1300 iter.ch = 0;
1301 iter.text = iter.cm.getLine(++iter.line);
1302 return true;
1303 }
1304 function prevLine(iter) {
1305 if (iter.line <= iter.min) return;
1306 iter.text = iter.cm.getLine(--iter.line);
1307 iter.ch = iter.text.length;
1308 return true;
1309 }
1310
1311 function toTagEnd(iter) {
1312 for (;;) {
1313 var gt = iter.text.indexOf(">", iter.ch);
1314 if (gt == -1) { if (nextLine(iter)) continue; else return; }
1315 if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
1316 var lastSlash = iter.text.lastIndexOf("/", gt);
1317 var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
1318 iter.ch = gt + 1;
1319 return selfClose ? "selfClose" : "regular";
1320 }
1321 }
1322 function toTagStart(iter) {
1323 for (;;) {
1324 var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;
1325 if (lt == -1) { if (prevLine(iter)) continue; else return; }
1326 if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
1327 xmlTagStart.lastIndex = lt;
1328 iter.ch = lt;
1329 var match = xmlTagStart.exec(iter.text);
1330 if (match && match.index == lt) return match;
1331 }
1332 }
1333
1334 function toNextTag(iter) {
1335 for (;;) {
1336 xmlTagStart.lastIndex = iter.ch;
1337 var found = xmlTagStart.exec(iter.text);
1338 if (!found) { if (nextLine(iter)) continue; else return; }
1339 if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
1340 iter.ch = found.index + found[0].length;
1341 return found;
1342 }
1343 }
1344 function toPrevTag(iter) {
1345 for (;;) {
1346 var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;
1347 if (gt == -1) { if (prevLine(iter)) continue; else return; }
1348 if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
1349 var lastSlash = iter.text.lastIndexOf("/", gt);
1350 var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
1351 iter.ch = gt + 1;
1352 return selfClose ? "selfClose" : "regular";
1353 }
1354 }
1355
1356 function findMatchingClose(iter, tag) {
1357 var stack = [];
1358 for (;;) {
1359 var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
1360 if (!next || !(end = toTagEnd(iter))) return;
1361 if (end == "selfClose") continue;
1362 if (next[1]) { // closing tag
1363 for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
1364 stack.length = i;
1365 break;
1366 }
1367 if (i < 0 && (!tag || tag == next[2])) return {
1368 tag: next[2],
1369 from: Pos(startLine, startCh),
1370 to: Pos(iter.line, iter.ch)
1371 };
1372 } else { // opening tag
1373 stack.push(next[2]);
1374 }
1375 }
1376 }
1377 function findMatchingOpen(iter, tag) {
1378 var stack = [];
1379 for (;;) {
1380 var prev = toPrevTag(iter);
1381 if (!prev) return;
1382 if (prev == "selfClose") { toTagStart(iter); continue; }
1383 var endLine = iter.line, endCh = iter.ch;
1384 var start = toTagStart(iter);
1385 if (!start) return;
1386 if (start[1]) { // closing tag
1387 stack.push(start[2]);
1388 } else { // opening tag
1389 for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
1390 stack.length = i;
1391 break;
1392 }
1393 if (i < 0 && (!tag || tag == start[2])) return {
1394 tag: start[2],
1395 from: Pos(iter.line, iter.ch),
1396 to: Pos(endLine, endCh)
1397 };
1398 }
1399 }
1400 }
1401
1402 CodeMirror.registerHelper("fold", "xml", function(cm, start) {
1403 var iter = new Iter(cm, start.line, 0);
1404 for (;;) {
1405 var openTag = toNextTag(iter), end;
1406 if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
1407 if (!openTag[1] && end != "selfClose") {
1408 var startPos = Pos(iter.line, iter.ch);
1409 var endPos = findMatchingClose(iter, openTag[2]);
1410 return endPos && {from: startPos, to: endPos.from};
1411 }
1412 }
1413 });
1414 CodeMirror.findMatchingTag = function(cm, pos, range) {
1415 var iter = new Iter(cm, pos.line, pos.ch, range);
1416 if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
1417 var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
1418 var start = end && toTagStart(iter);
1419 if (!end || !start || cmp(iter, pos) > 0) return;
1420 var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
1421 if (end == "selfClose") return {open: here, close: null, at: "open"};
1422
1423 if (start[1]) { // closing tag
1424 return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
1425 } else { // opening tag
1426 iter = new Iter(cm, to.line, to.ch, range);
1427 return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};
1428 }
1429 };
1430
1431 CodeMirror.findEnclosingTag = function(cm, pos, range, tag) {
1432 var iter = new Iter(cm, pos.line, pos.ch, range);
1433 for (;;) {
1434 var open = findMatchingOpen(iter, tag);
1435 if (!open) break;
1436 var forward = new Iter(cm, pos.line, pos.ch, range);
1437 var close = findMatchingClose(forward, open.tag);
1438 if (close) return {open: open, close: close};
1439 }
1440 };
1441
1442 // Used by addon/edit/closetag.js
1443 CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
1444 var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
1445 return findMatchingClose(iter, name);
1446 };
1447 });
1448
1449 },{"../../lib/codemirror":12}],12:[function(require,module,exports){
1450 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1451 // Distributed under an MIT license: http://codemirror.net/LICENSE
1452
1453 // This is CodeMirror (http://codemirror.net), a code editor
1454 // implemented in JavaScript on top of the browser's DOM.
1455 //
1456 // You can find some technical background for some of the code below
1457 // at http://marijnhaverbeke.nl/blog/#cm-internals .
1458
1459 (function (global, factory) {
1460 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
1461 typeof define === 'function' && define.amd ? define(factory) :
1462 (global.CodeMirror = factory());
1463 }(this, (function () { 'use strict';
1464
1465 // Kludges for bugs and behavior differences that can't be feature
1466 // detected are enabled based on userAgent etc sniffing.
1467 var userAgent = navigator.userAgent;
1468 var platform = navigator.platform;
1469
1470 var gecko = /gecko\/\d/i.test(userAgent);
1471 var ie_upto10 = /MSIE \d/.test(userAgent);
1472 var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
1473 var edge = /Edge\/(\d+)/.exec(userAgent);
1474 var ie = ie_upto10 || ie_11up || edge;
1475 var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]);
1476 var webkit = !edge && /WebKit\//.test(userAgent);
1477 var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
1478 var chrome = !edge && /Chrome\//.test(userAgent);
1479 var presto = /Opera\//.test(userAgent);
1480 var safari = /Apple Computer/.test(navigator.vendor);
1481 var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
1482 var phantom = /PhantomJS/.test(userAgent);
1483
1484 var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
1485 var android = /Android/.test(userAgent);
1486 // This is woefully incomplete. Suggestions for alternative methods welcome.
1487 var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
1488 var mac = ios || /Mac/.test(platform);
1489 var chromeOS = /\bCrOS\b/.test(userAgent);
1490 var windows = /win/i.test(platform);
1491
1492 var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
1493 if (presto_version) { presto_version = Number(presto_version[1]); }
1494 if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
1495 // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
1496 var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
1497 var captureRightClick = gecko || (ie && ie_version >= 9);
1498
1499 function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
1500
1501 var rmClass = function(node, cls) {
1502 var current = node.className;
1503 var match = classTest(cls).exec(current);
1504 if (match) {
1505 var after = current.slice(match.index + match[0].length);
1506 node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
1507 }
1508 };
1509
1510 function removeChildren(e) {
1511 for (var count = e.childNodes.length; count > 0; --count)
1512 { e.removeChild(e.firstChild); }
1513 return e
1514 }
1515
1516 function removeChildrenAndAdd(parent, e) {
1517 return removeChildren(parent).appendChild(e)
1518 }
1519
1520 function elt(tag, content, className, style) {
1521 var e = document.createElement(tag);
1522 if (className) { e.className = className; }
1523 if (style) { e.style.cssText = style; }
1524 if (typeof content == "string") { e.appendChild(document.createTextNode(content)); }
1525 else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } }
1526 return e
1527 }
1528 // wrapper for elt, which removes the elt from the accessibility tree
1529 function eltP(tag, content, className, style) {
1530 var e = elt(tag, content, className, style);
1531 e.setAttribute("role", "presentation");
1532 return e
1533 }
1534
1535 var range;
1536 if (document.createRange) { range = function(node, start, end, endNode) {
1537 var r = document.createRange();
1538 r.setEnd(endNode || node, end);
1539 r.setStart(node, start);
1540 return r
1541 }; }
1542 else { range = function(node, start, end) {
1543 var r = document.body.createTextRange();
1544 try { r.moveToElementText(node.parentNode); }
1545 catch(e) { return r }
1546 r.collapse(true);
1547 r.moveEnd("character", end);
1548 r.moveStart("character", start);
1549 return r
1550 }; }
1551
1552 function contains(parent, child) {
1553 if (child.nodeType == 3) // Android browser always returns false when child is a textnode
1554 { child = child.parentNode; }
1555 if (parent.contains)
1556 { return parent.contains(child) }
1557 do {
1558 if (child.nodeType == 11) { child = child.host; }
1559 if (child == parent) { return true }
1560 } while (child = child.parentNode)
1561 }
1562
1563 function activeElt() {
1564 // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement.
1565 // IE < 10 will throw when accessed while the page is loading or in an iframe.
1566 // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.
1567 var activeElement;
1568 try {
1569 activeElement = document.activeElement;
1570 } catch(e) {
1571 activeElement = document.body || null;
1572 }
1573 while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
1574 { activeElement = activeElement.shadowRoot.activeElement; }
1575 return activeElement
1576 }
1577
1578 function addClass(node, cls) {
1579 var current = node.className;
1580 if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls; }
1581 }
1582 function joinClasses(a, b) {
1583 var as = a.split(" ");
1584 for (var i = 0; i < as.length; i++)
1585 { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i]; } }
1586 return b
1587 }
1588
1589 var selectInput = function(node) { node.select(); };
1590 if (ios) // Mobile Safari apparently has a bug where select() is broken.
1591 { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; }
1592 else if (ie) // Suppress mysterious IE10 errors
1593 { selectInput = function(node) { try { node.select(); } catch(_e) {} }; }
1594
1595 function bind(f) {
1596 var args = Array.prototype.slice.call(arguments, 1);
1597 return function(){return f.apply(null, args)}
1598 }
1599
1600 function copyObj(obj, target, overwrite) {
1601 if (!target) { target = {}; }
1602 for (var prop in obj)
1603 { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
1604 { target[prop] = obj[prop]; } }
1605 return target
1606 }
1607
1608 // Counts the column offset in a string, taking tabs into account.
1609 // Used mostly to find indentation.
1610 function countColumn(string, end, tabSize, startIndex, startValue) {
1611 if (end == null) {
1612 end = string.search(/[^\s\u00a0]/);
1613 if (end == -1) { end = string.length; }
1614 }
1615 for (var i = startIndex || 0, n = startValue || 0;;) {
1616 var nextTab = string.indexOf("\t", i);
1617 if (nextTab < 0 || nextTab >= end)
1618 { return n + (end - i) }
1619 n += nextTab - i;
1620 n += tabSize - (n % tabSize);
1621 i = nextTab + 1;
1622 }
1623 }
1624
1625 var Delayed = function() {this.id = null;};
1626 Delayed.prototype.set = function (ms, f) {
1627 clearTimeout(this.id);
1628 this.id = setTimeout(f, ms);
1629 };
1630
1631 function indexOf(array, elt) {
1632 for (var i = 0; i < array.length; ++i)
1633 { if (array[i] == elt) { return i } }
1634 return -1
1635 }
1636
1637 // Number of pixels added to scroller and sizer to hide scrollbar
1638 var scrollerGap = 30;
1639
1640 // Returned or thrown by various protocols to signal 'I'm not
1641 // handling this'.
1642 var Pass = {toString: function(){return "CodeMirror.Pass"}};
1643
1644 // Reused option objects for setSelection & friends
1645 var sel_dontScroll = {scroll: false};
1646 var sel_mouse = {origin: "*mouse"};
1647 var sel_move = {origin: "+move"};
1648
1649 // The inverse of countColumn -- find the offset that corresponds to
1650 // a particular column.
1651 function findColumn(string, goal, tabSize) {
1652 for (var pos = 0, col = 0;;) {
1653 var nextTab = string.indexOf("\t", pos);
1654 if (nextTab == -1) { nextTab = string.length; }
1655 var skipped = nextTab - pos;
1656 if (nextTab == string.length || col + skipped >= goal)
1657 { return pos + Math.min(skipped, goal - col) }
1658 col += nextTab - pos;
1659 col += tabSize - (col % tabSize);
1660 pos = nextTab + 1;
1661 if (col >= goal) { return pos }
1662 }
1663 }
1664
1665 var spaceStrs = [""];
1666 function spaceStr(n) {
1667 while (spaceStrs.length <= n)
1668 { spaceStrs.push(lst(spaceStrs) + " "); }
1669 return spaceStrs[n]
1670 }
1671
1672 function lst(arr) { return arr[arr.length-1] }
1673
1674 function map(array, f) {
1675 var out = [];
1676 for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i); }
1677 return out
1678 }
1679
1680 function insertSorted(array, value, score) {
1681 var pos = 0, priority = score(value);
1682 while (pos < array.length && score(array[pos]) <= priority) { pos++; }
1683 array.splice(pos, 0, value);
1684 }
1685
1686 function nothing() {}
1687
1688 function createObj(base, props) {
1689 var inst;
1690 if (Object.create) {
1691 inst = Object.create(base);
1692 } else {
1693 nothing.prototype = base;
1694 inst = new nothing();
1695 }
1696 if (props) { copyObj(props, inst); }
1697 return inst
1698 }
1699
1700 var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
1701 function isWordCharBasic(ch) {
1702 return /\w/.test(ch) || ch > "\x80" &&
1703 (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))
1704 }
1705 function isWordChar(ch, helper) {
1706 if (!helper) { return isWordCharBasic(ch) }
1707 if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true }
1708 return helper.test(ch)
1709 }
1710
1711 function isEmpty(obj) {
1712 for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }
1713 return true
1714 }
1715
1716 // Extending unicode characters. A series of a non-extending char +
1717 // any number of extending chars is treated as a single unit as far
1718 // as editing and measuring is concerned. This is not fully correct,
1719 // since some scripts/fonts/browsers also treat other configurations
1720 // of code points as a group.
1721 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]/;
1722 function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }
1723
1724 // Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.
1725 function skipExtendingChars(str, pos, dir) {
1726 while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; }
1727 return pos
1728 }
1729
1730 // Returns the value from the range [`from`; `to`] that satisfies
1731 // `pred` and is closest to `from`. Assumes that at least `to`
1732 // satisfies `pred`. Supports `from` being greater than `to`.
1733 function findFirst(pred, from, to) {
1734 // At any point we are certain `to` satisfies `pred`, don't know
1735 // whether `from` does.
1736 var dir = from > to ? -1 : 1;
1737 for (;;) {
1738 if (from == to) { return from }
1739 var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF);
1740 if (mid == from) { return pred(mid) ? from : to }
1741 if (pred(mid)) { to = mid; }
1742 else { from = mid + dir; }
1743 }
1744 }
1745
1746 // The display handles the DOM integration, both for input reading
1747 // and content drawing. It holds references to DOM nodes and
1748 // display-related state.
1749
1750 function Display(place, doc, input) {
1751 var d = this;
1752 this.input = input;
1753
1754 // Covers bottom-right square when both scrollbars are present.
1755 d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
1756 d.scrollbarFiller.setAttribute("cm-not-content", "true");
1757 // Covers bottom of gutter when coverGutterNextToScrollbar is on
1758 // and h scrollbar is present.
1759 d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
1760 d.gutterFiller.setAttribute("cm-not-content", "true");
1761 // Will contain the actual code, positioned to cover the viewport.
1762 d.lineDiv = eltP("div", null, "CodeMirror-code");
1763 // Elements are added to these to represent selection and cursors.
1764 d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
1765 d.cursorDiv = elt("div", null, "CodeMirror-cursors");
1766 // A visibility: hidden element used to find the size of things.
1767 d.measure = elt("div", null, "CodeMirror-measure");
1768 // When lines outside of the viewport are measured, they are drawn in this.
1769 d.lineMeasure = elt("div", null, "CodeMirror-measure");
1770 // Wraps everything that needs to exist inside the vertically-padded coordinate system
1771 d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
1772 null, "position: relative; outline: none");
1773 var lines = eltP("div", [d.lineSpace], "CodeMirror-lines");
1774 // Moved around its parent to cover visible view.
1775 d.mover = elt("div", [lines], null, "position: relative");
1776 // Set to the height of the document, allowing scrolling.
1777 d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
1778 d.sizerWidth = null;
1779 // Behavior of elts with overflow: auto and padding is
1780 // inconsistent across browsers. This is used to ensure the
1781 // scrollable area is big enough.
1782 d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
1783 // Will contain the gutters, if any.
1784 d.gutters = elt("div", null, "CodeMirror-gutters");
1785 d.lineGutter = null;
1786 // Actual scrollable element.
1787 d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
1788 d.scroller.setAttribute("tabIndex", "-1");
1789 // The element in which the editor lives.
1790 d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
1791
1792 // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
1793 if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
1794 if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; }
1795
1796 if (place) {
1797 if (place.appendChild) { place.appendChild(d.wrapper); }
1798 else { place(d.wrapper); }
1799 }
1800
1801 // Current rendered range (may be bigger than the view window).
1802 d.viewFrom = d.viewTo = doc.first;
1803 d.reportedViewFrom = d.reportedViewTo = doc.first;
1804 // Information about the rendered lines.
1805 d.view = [];
1806 d.renderedView = null;
1807 // Holds info about a single rendered line when it was rendered
1808 // for measurement, while not in view.
1809 d.externalMeasured = null;
1810 // Empty space (in pixels) above the view
1811 d.viewOffset = 0;
1812 d.lastWrapHeight = d.lastWrapWidth = 0;
1813 d.updateLineNumbers = null;
1814
1815 d.nativeBarWidth = d.barHeight = d.barWidth = 0;
1816 d.scrollbarsClipped = false;
1817
1818 // Used to only resize the line number gutter when necessary (when
1819 // the amount of lines crosses a boundary that makes its width change)
1820 d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
1821 // Set to true when a non-horizontal-scrolling line widget is
1822 // added. As an optimization, line widget aligning is skipped when
1823 // this is false.
1824 d.alignWidgets = false;
1825
1826 d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
1827
1828 // Tracks the maximum line length so that the horizontal scrollbar
1829 // can be kept static when scrolling.
1830 d.maxLine = null;
1831 d.maxLineLength = 0;
1832 d.maxLineChanged = false;
1833
1834 // Used for measuring wheel scrolling granularity
1835 d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
1836
1837 // True when shift is held down.
1838 d.shift = false;
1839
1840 // Used to track whether anything happened since the context menu
1841 // was opened.
1842 d.selForContextMenu = null;
1843
1844 d.activeTouch = null;
1845
1846 input.init(d);
1847 }
1848
1849 // Find the line object corresponding to the given line number.
1850 function getLine(doc, n) {
1851 n -= doc.first;
1852 if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
1853 var chunk = doc;
1854 while (!chunk.lines) {
1855 for (var i = 0;; ++i) {
1856 var child = chunk.children[i], sz = child.chunkSize();
1857 if (n < sz) { chunk = child; break }
1858 n -= sz;
1859 }
1860 }
1861 return chunk.lines[n]
1862 }
1863
1864 // Get the part of a document between two positions, as an array of
1865 // strings.
1866 function getBetween(doc, start, end) {
1867 var out = [], n = start.line;
1868 doc.iter(start.line, end.line + 1, function (line) {
1869 var text = line.text;
1870 if (n == end.line) { text = text.slice(0, end.ch); }
1871 if (n == start.line) { text = text.slice(start.ch); }
1872 out.push(text);
1873 ++n;
1874 });
1875 return out
1876 }
1877 // Get the lines between from and to, as array of strings.
1878 function getLines(doc, from, to) {
1879 var out = [];
1880 doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value
1881 return out
1882 }
1883
1884 // Update the height of a line, propagating the height change
1885 // upwards to parent nodes.
1886 function updateLineHeight(line, height) {
1887 var diff = height - line.height;
1888 if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } }
1889 }
1890
1891 // Given a line object, find its line number by walking up through
1892 // its parent links.
1893 function lineNo(line) {
1894 if (line.parent == null) { return null }
1895 var cur = line.parent, no = indexOf(cur.lines, line);
1896 for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
1897 for (var i = 0;; ++i) {
1898 if (chunk.children[i] == cur) { break }
1899 no += chunk.children[i].chunkSize();
1900 }
1901 }
1902 return no + cur.first
1903 }
1904
1905 // Find the line at the given vertical position, using the height
1906 // information in the document tree.
1907 function lineAtHeight(chunk, h) {
1908 var n = chunk.first;
1909 outer: do {
1910 for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
1911 var child = chunk.children[i$1], ch = child.height;
1912 if (h < ch) { chunk = child; continue outer }
1913 h -= ch;
1914 n += child.chunkSize();
1915 }
1916 return n
1917 } while (!chunk.lines)
1918 var i = 0;
1919 for (; i < chunk.lines.length; ++i) {
1920 var line = chunk.lines[i], lh = line.height;
1921 if (h < lh) { break }
1922 h -= lh;
1923 }
1924 return n + i
1925 }
1926
1927 function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
1928
1929 function lineNumberFor(options, i) {
1930 return String(options.lineNumberFormatter(i + options.firstLineNumber))
1931 }
1932
1933 // A Pos instance represents a position within the text.
1934 function Pos(line, ch, sticky) {
1935 if ( sticky === void 0 ) sticky = null;
1936
1937 if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }
1938 this.line = line;
1939 this.ch = ch;
1940 this.sticky = sticky;
1941 }
1942
1943 // Compare two positions, return 0 if they are the same, a negative
1944 // number when a is less, and a positive number otherwise.
1945 function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
1946
1947 function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }
1948
1949 function copyPos(x) {return Pos(x.line, x.ch)}
1950 function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
1951 function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
1952
1953 // Most of the external API clips given positions to make sure they
1954 // actually exist within the document.
1955 function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
1956 function clipPos(doc, pos) {
1957 if (pos.line < doc.first) { return Pos(doc.first, 0) }
1958 var last = doc.first + doc.size - 1;
1959 if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
1960 return clipToLen(pos, getLine(doc, pos.line).text.length)
1961 }
1962 function clipToLen(pos, linelen) {
1963 var ch = pos.ch;
1964 if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
1965 else if (ch < 0) { return Pos(pos.line, 0) }
1966 else { return pos }
1967 }
1968 function clipPosArray(doc, array) {
1969 var out = [];
1970 for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); }
1971 return out
1972 }
1973
1974 // Optimize some code when these features are not used.
1975 var sawReadOnlySpans = false;
1976 var sawCollapsedSpans = false;
1977
1978 function seeReadOnlySpans() {
1979 sawReadOnlySpans = true;
1980 }
1981
1982 function seeCollapsedSpans() {
1983 sawCollapsedSpans = true;
1984 }
1985
1986 // TEXTMARKER SPANS
1987
1988 function MarkedSpan(marker, from, to) {
1989 this.marker = marker;
1990 this.from = from; this.to = to;
1991 }
1992
1993 // Search an array of spans for a span matching the given marker.
1994 function getMarkedSpanFor(spans, marker) {
1995 if (spans) { for (var i = 0; i < spans.length; ++i) {
1996 var span = spans[i];
1997 if (span.marker == marker) { return span }
1998 } }
1999 }
2000 // Remove a span from an array, returning undefined if no spans are
2001 // left (we don't store arrays for lines without spans).
2002 function removeMarkedSpan(spans, span) {
2003 var r;
2004 for (var i = 0; i < spans.length; ++i)
2005 { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } }
2006 return r
2007 }
2008 // Add a span to a line.
2009 function addMarkedSpan(line, span) {
2010 line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
2011 span.marker.attachLine(line);
2012 }
2013
2014 // Used for the algorithm that adjusts markers for a change in the
2015 // document. These functions cut an array of spans at a given
2016 // character position, returning an array of remaining chunks (or
2017 // undefined if nothing remains).
2018 function markedSpansBefore(old, startCh, isInsert) {
2019 var nw;
2020 if (old) { for (var i = 0; i < old.length; ++i) {
2021 var span = old[i], marker = span.marker;
2022 var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
2023 if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
2024 var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
2025 }
2026 } }
2027 return nw
2028 }
2029 function markedSpansAfter(old, endCh, isInsert) {
2030 var nw;
2031 if (old) { for (var i = 0; i < old.length; ++i) {
2032 var span = old[i], marker = span.marker;
2033 var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
2034 if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
2035 var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
2036 span.to == null ? null : span.to - endCh));
2037 }
2038 } }
2039 return nw
2040 }
2041
2042 // Given a change object, compute the new set of marker spans that
2043 // cover the line in which the change took place. Removes spans
2044 // entirely within the change, reconnects spans belonging to the
2045 // same marker that appear on both sides of the change, and cuts off
2046 // spans partially within the change. Returns an array of span
2047 // arrays with one element for each line in (after) the change.
2048 function stretchSpansOverChange(doc, change) {
2049 if (change.full) { return null }
2050 var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
2051 var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
2052 if (!oldFirst && !oldLast) { return null }
2053
2054 var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
2055 // Get the spans that 'stick out' on both sides
2056 var first = markedSpansBefore(oldFirst, startCh, isInsert);
2057 var last = markedSpansAfter(oldLast, endCh, isInsert);
2058
2059 // Next, merge those two ends
2060 var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
2061 if (first) {
2062 // Fix up .to properties of first
2063 for (var i = 0; i < first.length; ++i) {
2064 var span = first[i];
2065 if (span.to == null) {
2066 var found = getMarkedSpanFor(last, span.marker);
2067 if (!found) { span.to = startCh; }
2068 else if (sameLine) { span.to = found.to == null ? null : found.to + offset; }
2069 }
2070 }
2071 }
2072 if (last) {
2073 // Fix up .from in last (or move them into first in case of sameLine)
2074 for (var i$1 = 0; i$1 < last.length; ++i$1) {
2075 var span$1 = last[i$1];
2076 if (span$1.to != null) { span$1.to += offset; }
2077 if (span$1.from == null) {
2078 var found$1 = getMarkedSpanFor(first, span$1.marker);
2079 if (!found$1) {
2080 span$1.from = offset;
2081 if (sameLine) { (first || (first = [])).push(span$1); }
2082 }
2083 } else {
2084 span$1.from += offset;
2085 if (sameLine) { (first || (first = [])).push(span$1); }
2086 }
2087 }
2088 }
2089 // Make sure we didn't create any zero-length spans
2090 if (first) { first = clearEmptySpans(first); }
2091 if (last && last != first) { last = clearEmptySpans(last); }
2092
2093 var newMarkers = [first];
2094 if (!sameLine) {
2095 // Fill gap with whole-line-spans
2096 var gap = change.text.length - 2, gapMarkers;
2097 if (gap > 0 && first)
2098 { for (var i$2 = 0; i$2 < first.length; ++i$2)
2099 { if (first[i$2].to == null)
2100 { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } }
2101 for (var i$3 = 0; i$3 < gap; ++i$3)
2102 { newMarkers.push(gapMarkers); }
2103 newMarkers.push(last);
2104 }
2105 return newMarkers
2106 }
2107
2108 // Remove spans that are empty and don't have a clearWhenEmpty
2109 // option of false.
2110 function clearEmptySpans(spans) {
2111 for (var i = 0; i < spans.length; ++i) {
2112 var span = spans[i];
2113 if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
2114 { spans.splice(i--, 1); }
2115 }
2116 if (!spans.length) { return null }
2117 return spans
2118 }
2119
2120 // Used to 'clip' out readOnly ranges when making a change.
2121 function removeReadOnlyRanges(doc, from, to) {
2122 var markers = null;
2123 doc.iter(from.line, to.line + 1, function (line) {
2124 if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
2125 var mark = line.markedSpans[i].marker;
2126 if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
2127 { (markers || (markers = [])).push(mark); }
2128 } }
2129 });
2130 if (!markers) { return null }
2131 var parts = [{from: from, to: to}];
2132 for (var i = 0; i < markers.length; ++i) {
2133 var mk = markers[i], m = mk.find(0);
2134 for (var j = 0; j < parts.length; ++j) {
2135 var p = parts[j];
2136 if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
2137 var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
2138 if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
2139 { newParts.push({from: p.from, to: m.from}); }
2140 if (dto > 0 || !mk.inclusiveRight && !dto)
2141 { newParts.push({from: m.to, to: p.to}); }
2142 parts.splice.apply(parts, newParts);
2143 j += newParts.length - 3;
2144 }
2145 }
2146 return parts
2147 }
2148
2149 // Connect or disconnect spans from a line.
2150 function detachMarkedSpans(line) {
2151 var spans = line.markedSpans;
2152 if (!spans) { return }
2153 for (var i = 0; i < spans.length; ++i)
2154 { spans[i].marker.detachLine(line); }
2155 line.markedSpans = null;
2156 }
2157 function attachMarkedSpans(line, spans) {
2158 if (!spans) { return }
2159 for (var i = 0; i < spans.length; ++i)
2160 { spans[i].marker.attachLine(line); }
2161 line.markedSpans = spans;
2162 }
2163
2164 // Helpers used when computing which overlapping collapsed span
2165 // counts as the larger one.
2166 function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
2167 function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
2168
2169 // Returns a number indicating which of two overlapping collapsed
2170 // spans is larger (and thus includes the other). Falls back to
2171 // comparing ids when the spans cover exactly the same range.
2172 function compareCollapsedMarkers(a, b) {
2173 var lenDiff = a.lines.length - b.lines.length;
2174 if (lenDiff != 0) { return lenDiff }
2175 var aPos = a.find(), bPos = b.find();
2176 var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
2177 if (fromCmp) { return -fromCmp }
2178 var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
2179 if (toCmp) { return toCmp }
2180 return b.id - a.id
2181 }
2182
2183 // Find out whether a line ends or starts in a collapsed span. If
2184 // so, return the marker for that span.
2185 function collapsedSpanAtSide(line, start) {
2186 var sps = sawCollapsedSpans && line.markedSpans, found;
2187 if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
2188 sp = sps[i];
2189 if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
2190 (!found || compareCollapsedMarkers(found, sp.marker) < 0))
2191 { found = sp.marker; }
2192 } }
2193 return found
2194 }
2195 function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
2196 function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
2197
2198 // Test whether there exists a collapsed span that partially
2199 // overlaps (covers the start or end, but not both) of a new span.
2200 // Such overlap is not allowed.
2201 function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) {
2202 var line = getLine(doc, lineNo$$1);
2203 var sps = sawCollapsedSpans && line.markedSpans;
2204 if (sps) { for (var i = 0; i < sps.length; ++i) {
2205 var sp = sps[i];
2206 if (!sp.marker.collapsed) { continue }
2207 var found = sp.marker.find(0);
2208 var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
2209 var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
2210 if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
2211 if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
2212 fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
2213 { return true }
2214 } }
2215 }
2216
2217 // A visual line is a line as drawn on the screen. Folding, for
2218 // example, can cause multiple logical lines to appear on the same
2219 // visual line. This finds the start of the visual line that the
2220 // given line is part of (usually that is the line itself).
2221 function visualLine(line) {
2222 var merged;
2223 while (merged = collapsedSpanAtStart(line))
2224 { line = merged.find(-1, true).line; }
2225 return line
2226 }
2227
2228 function visualLineEnd(line) {
2229 var merged;
2230 while (merged = collapsedSpanAtEnd(line))
2231 { line = merged.find(1, true).line; }
2232 return line
2233 }
2234
2235 // Returns an array of logical lines that continue the visual line
2236 // started by the argument, or undefined if there are no such lines.
2237 function visualLineContinued(line) {
2238 var merged, lines;
2239 while (merged = collapsedSpanAtEnd(line)) {
2240 line = merged.find(1, true).line
2241 ;(lines || (lines = [])).push(line);
2242 }
2243 return lines
2244 }
2245
2246 // Get the line number of the start of the visual line that the
2247 // given line number is part of.
2248 function visualLineNo(doc, lineN) {
2249 var line = getLine(doc, lineN), vis = visualLine(line);
2250 if (line == vis) { return lineN }
2251 return lineNo(vis)
2252 }
2253
2254 // Get the line number of the start of the next visual line after
2255 // the given line.
2256 function visualLineEndNo(doc, lineN) {
2257 if (lineN > doc.lastLine()) { return lineN }
2258 var line = getLine(doc, lineN), merged;
2259 if (!lineIsHidden(doc, line)) { return lineN }
2260 while (merged = collapsedSpanAtEnd(line))
2261 { line = merged.find(1, true).line; }
2262 return lineNo(line) + 1
2263 }
2264
2265 // Compute whether a line is hidden. Lines count as hidden when they
2266 // are part of a visual line that starts with another line, or when
2267 // they are entirely covered by collapsed, non-widget span.
2268 function lineIsHidden(doc, line) {
2269 var sps = sawCollapsedSpans && line.markedSpans;
2270 if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
2271 sp = sps[i];
2272 if (!sp.marker.collapsed) { continue }
2273 if (sp.from == null) { return true }
2274 if (sp.marker.widgetNode) { continue }
2275 if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
2276 { return true }
2277 } }
2278 }
2279 function lineIsHiddenInner(doc, line, span) {
2280 if (span.to == null) {
2281 var end = span.marker.find(1, true);
2282 return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
2283 }
2284 if (span.marker.inclusiveRight && span.to == line.text.length)
2285 { return true }
2286 for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {
2287 sp = line.markedSpans[i];
2288 if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
2289 (sp.to == null || sp.to != span.from) &&
2290 (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
2291 lineIsHiddenInner(doc, line, sp)) { return true }
2292 }
2293 }
2294
2295 // Find the height above the given line.
2296 function heightAtLine(lineObj) {
2297 lineObj = visualLine(lineObj);
2298
2299 var h = 0, chunk = lineObj.parent;
2300 for (var i = 0; i < chunk.lines.length; ++i) {
2301 var line = chunk.lines[i];
2302 if (line == lineObj) { break }
2303 else { h += line.height; }
2304 }
2305 for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
2306 for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
2307 var cur = p.children[i$1];
2308 if (cur == chunk) { break }
2309 else { h += cur.height; }
2310 }
2311 }
2312 return h
2313 }
2314
2315 // Compute the character length of a line, taking into account
2316 // collapsed ranges (see markText) that might hide parts, and join
2317 // other lines onto it.
2318 function lineLength(line) {
2319 if (line.height == 0) { return 0 }
2320 var len = line.text.length, merged, cur = line;
2321 while (merged = collapsedSpanAtStart(cur)) {
2322 var found = merged.find(0, true);
2323 cur = found.from.line;
2324 len += found.from.ch - found.to.ch;
2325 }
2326 cur = line;
2327 while (merged = collapsedSpanAtEnd(cur)) {
2328 var found$1 = merged.find(0, true);
2329 len -= cur.text.length - found$1.from.ch;
2330 cur = found$1.to.line;
2331 len += cur.text.length - found$1.to.ch;
2332 }
2333 return len
2334 }
2335
2336 // Find the longest line in the document.
2337 function findMaxLine(cm) {
2338 var d = cm.display, doc = cm.doc;
2339 d.maxLine = getLine(doc, doc.first);
2340 d.maxLineLength = lineLength(d.maxLine);
2341 d.maxLineChanged = true;
2342 doc.iter(function (line) {
2343 var len = lineLength(line);
2344 if (len > d.maxLineLength) {
2345 d.maxLineLength = len;
2346 d.maxLine = line;
2347 }
2348 });
2349 }
2350
2351 // BIDI HELPERS
2352
2353 function iterateBidiSections(order, from, to, f) {
2354 if (!order) { return f(from, to, "ltr", 0) }
2355 var found = false;
2356 for (var i = 0; i < order.length; ++i) {
2357 var part = order[i];
2358 if (part.from < to && part.to > from || from == to && part.to == from) {
2359 f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i);
2360 found = true;
2361 }
2362 }
2363 if (!found) { f(from, to, "ltr"); }
2364 }
2365
2366 var bidiOther = null;
2367 function getBidiPartAt(order, ch, sticky) {
2368 var found;
2369 bidiOther = null;
2370 for (var i = 0; i < order.length; ++i) {
2371 var cur = order[i];
2372 if (cur.from < ch && cur.to > ch) { return i }
2373 if (cur.to == ch) {
2374 if (cur.from != cur.to && sticky == "before") { found = i; }
2375 else { bidiOther = i; }
2376 }
2377 if (cur.from == ch) {
2378 if (cur.from != cur.to && sticky != "before") { found = i; }
2379 else { bidiOther = i; }
2380 }
2381 }
2382 return found != null ? found : bidiOther
2383 }
2384
2385 // Bidirectional ordering algorithm
2386 // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
2387 // that this (partially) implements.
2388
2389 // One-char codes used for character types:
2390 // L (L): Left-to-Right
2391 // R (R): Right-to-Left
2392 // r (AL): Right-to-Left Arabic
2393 // 1 (EN): European Number
2394 // + (ES): European Number Separator
2395 // % (ET): European Number Terminator
2396 // n (AN): Arabic Number
2397 // , (CS): Common Number Separator
2398 // m (NSM): Non-Spacing Mark
2399 // b (BN): Boundary Neutral
2400 // s (B): Paragraph Separator
2401 // t (S): Segment Separator
2402 // w (WS): Whitespace
2403 // N (ON): Other Neutrals
2404
2405 // Returns null if characters are ordered as they appear
2406 // (left-to-right), or an array of sections ({from, to, level}
2407 // objects) in the order in which they occur visually.
2408 var bidiOrdering = (function() {
2409 // Character types for codepoints 0 to 0xff
2410 var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
2411 // Character types for codepoints 0x600 to 0x6f9
2412 var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";
2413 function charType(code) {
2414 if (code <= 0xf7) { return lowTypes.charAt(code) }
2415 else if (0x590 <= code && code <= 0x5f4) { return "R" }
2416 else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
2417 else if (0x6ee <= code && code <= 0x8ac) { return "r" }
2418 else if (0x2000 <= code && code <= 0x200b) { return "w" }
2419 else if (code == 0x200c) { return "b" }
2420 else { return "L" }
2421 }
2422
2423 var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
2424 var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
2425
2426 function BidiSpan(level, from, to) {
2427 this.level = level;
2428 this.from = from; this.to = to;
2429 }
2430
2431 return function(str, direction) {
2432 var outerType = direction == "ltr" ? "L" : "R";
2433
2434 if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false }
2435 var len = str.length, types = [];
2436 for (var i = 0; i < len; ++i)
2437 { types.push(charType(str.charCodeAt(i))); }
2438
2439 // W1. Examine each non-spacing mark (NSM) in the level run, and
2440 // change the type of the NSM to the type of the previous
2441 // character. If the NSM is at the start of the level run, it will
2442 // get the type of sor.
2443 for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
2444 var type = types[i$1];
2445 if (type == "m") { types[i$1] = prev; }
2446 else { prev = type; }
2447 }
2448
2449 // W2. Search backwards from each instance of a European number
2450 // until the first strong type (R, L, AL, or sor) is found. If an
2451 // AL is found, change the type of the European number to Arabic
2452 // number.
2453 // W3. Change all ALs to R.
2454 for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
2455 var type$1 = types[i$2];
2456 if (type$1 == "1" && cur == "r") { types[i$2] = "n"; }
2457 else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R"; } }
2458 }
2459
2460 // W4. A single European separator between two European numbers
2461 // changes to a European number. A single common separator between
2462 // two numbers of the same type changes to that type.
2463 for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
2464 var type$2 = types[i$3];
2465 if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1"; }
2466 else if (type$2 == "," && prev$1 == types[i$3+1] &&
2467 (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1; }
2468 prev$1 = type$2;
2469 }
2470
2471 // W5. A sequence of European terminators adjacent to European
2472 // numbers changes to all European numbers.
2473 // W6. Otherwise, separators and terminators change to Other
2474 // Neutral.
2475 for (var i$4 = 0; i$4 < len; ++i$4) {
2476 var type$3 = types[i$4];
2477 if (type$3 == ",") { types[i$4] = "N"; }
2478 else if (type$3 == "%") {
2479 var end = (void 0);
2480 for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
2481 var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
2482 for (var j = i$4; j < end; ++j) { types[j] = replace; }
2483 i$4 = end - 1;
2484 }
2485 }
2486
2487 // W7. Search backwards from each instance of a European number
2488 // until the first strong type (R, L, or sor) is found. If an L is
2489 // found, then change the type of the European number to L.
2490 for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
2491 var type$4 = types[i$5];
2492 if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L"; }
2493 else if (isStrong.test(type$4)) { cur$1 = type$4; }
2494 }
2495
2496 // N1. A sequence of neutrals takes the direction of the
2497 // surrounding strong text if the text on both sides has the same
2498 // direction. European and Arabic numbers act as if they were R in
2499 // terms of their influence on neutrals. Start-of-level-run (sor)
2500 // and end-of-level-run (eor) are used at level run boundaries.
2501 // N2. Any remaining neutrals take the embedding direction.
2502 for (var i$6 = 0; i$6 < len; ++i$6) {
2503 if (isNeutral.test(types[i$6])) {
2504 var end$1 = (void 0);
2505 for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
2506 var before = (i$6 ? types[i$6-1] : outerType) == "L";
2507 var after = (end$1 < len ? types[end$1] : outerType) == "L";
2508 var replace$1 = before == after ? (before ? "L" : "R") : outerType;
2509 for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }
2510 i$6 = end$1 - 1;
2511 }
2512 }
2513
2514 // Here we depart from the documented algorithm, in order to avoid
2515 // building up an actual levels array. Since there are only three
2516 // levels (0, 1, 2) in an implementation that doesn't take
2517 // explicit embedding into account, we can build up the order on
2518 // the fly, without following the level-based algorithm.
2519 var order = [], m;
2520 for (var i$7 = 0; i$7 < len;) {
2521 if (countsAsLeft.test(types[i$7])) {
2522 var start = i$7;
2523 for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
2524 order.push(new BidiSpan(0, start, i$7));
2525 } else {
2526 var pos = i$7, at = order.length;
2527 for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
2528 for (var j$2 = pos; j$2 < i$7;) {
2529 if (countsAsNum.test(types[j$2])) {
2530 if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); }
2531 var nstart = j$2;
2532 for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
2533 order.splice(at, 0, new BidiSpan(2, nstart, j$2));
2534 pos = j$2;
2535 } else { ++j$2; }
2536 }
2537 if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }
2538 }
2539 }
2540 if (direction == "ltr") {
2541 if (order[0].level == 1 && (m = str.match(/^\s+/))) {
2542 order[0].from = m[0].length;
2543 order.unshift(new BidiSpan(0, 0, m[0].length));
2544 }
2545 if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
2546 lst(order).to -= m[0].length;
2547 order.push(new BidiSpan(0, len - m[0].length, len));
2548 }
2549 }
2550
2551 return direction == "rtl" ? order.reverse() : order
2552 }
2553 })();
2554
2555 // Get the bidi ordering for the given line (and cache it). Returns
2556 // false for lines that are fully left-to-right, and an array of
2557 // BidiSpan objects otherwise.
2558 function getOrder(line, direction) {
2559 var order = line.order;
2560 if (order == null) { order = line.order = bidiOrdering(line.text, direction); }
2561 return order
2562 }
2563
2564 // EVENT HANDLING
2565
2566 // Lightweight event framework. on/off also work on DOM nodes,
2567 // registering native DOM handlers.
2568
2569 var noHandlers = [];
2570
2571 var on = function(emitter, type, f) {
2572 if (emitter.addEventListener) {
2573 emitter.addEventListener(type, f, false);
2574 } else if (emitter.attachEvent) {
2575 emitter.attachEvent("on" + type, f);
2576 } else {
2577 var map$$1 = emitter._handlers || (emitter._handlers = {});
2578 map$$1[type] = (map$$1[type] || noHandlers).concat(f);
2579 }
2580 };
2581
2582 function getHandlers(emitter, type) {
2583 return emitter._handlers && emitter._handlers[type] || noHandlers
2584 }
2585
2586 function off(emitter, type, f) {
2587 if (emitter.removeEventListener) {
2588 emitter.removeEventListener(type, f, false);
2589 } else if (emitter.detachEvent) {
2590 emitter.detachEvent("on" + type, f);
2591 } else {
2592 var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type];
2593 if (arr) {
2594 var index = indexOf(arr, f);
2595 if (index > -1)
2596 { map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }
2597 }
2598 }
2599 }
2600
2601 function signal(emitter, type /*, values...*/) {
2602 var handlers = getHandlers(emitter, type);
2603 if (!handlers.length) { return }
2604 var args = Array.prototype.slice.call(arguments, 2);
2605 for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }
2606 }
2607
2608 // The DOM events that CodeMirror handles can be overridden by
2609 // registering a (non-DOM) handler on the editor for the event name,
2610 // and preventDefault-ing the event in that handler.
2611 function signalDOMEvent(cm, e, override) {
2612 if (typeof e == "string")
2613 { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }
2614 signal(cm, override || e.type, cm, e);
2615 return e_defaultPrevented(e) || e.codemirrorIgnore
2616 }
2617
2618 function signalCursorActivity(cm) {
2619 var arr = cm._handlers && cm._handlers.cursorActivity;
2620 if (!arr) { return }
2621 var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
2622 for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
2623 { set.push(arr[i]); } }
2624 }
2625
2626 function hasHandler(emitter, type) {
2627 return getHandlers(emitter, type).length > 0
2628 }
2629
2630 // Add on and off methods to a constructor's prototype, to make
2631 // registering events on such objects more convenient.
2632 function eventMixin(ctor) {
2633 ctor.prototype.on = function(type, f) {on(this, type, f);};
2634 ctor.prototype.off = function(type, f) {off(this, type, f);};
2635 }
2636
2637 // Due to the fact that we still support jurassic IE versions, some
2638 // compatibility wrappers are needed.
2639
2640 function e_preventDefault(e) {
2641 if (e.preventDefault) { e.preventDefault(); }
2642 else { e.returnValue = false; }
2643 }
2644 function e_stopPropagation(e) {
2645 if (e.stopPropagation) { e.stopPropagation(); }
2646 else { e.cancelBubble = true; }
2647 }
2648 function e_defaultPrevented(e) {
2649 return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
2650 }
2651 function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
2652
2653 function e_target(e) {return e.target || e.srcElement}
2654 function e_button(e) {
2655 var b = e.which;
2656 if (b == null) {
2657 if (e.button & 1) { b = 1; }
2658 else if (e.button & 2) { b = 3; }
2659 else if (e.button & 4) { b = 2; }
2660 }
2661 if (mac && e.ctrlKey && b == 1) { b = 3; }
2662 return b
2663 }
2664
2665 // Detect drag-and-drop
2666 var dragAndDrop = function() {
2667 // There is *some* kind of drag-and-drop support in IE6-8, but I
2668 // couldn't get it to work yet.
2669 if (ie && ie_version < 9) { return false }
2670 var div = elt('div');
2671 return "draggable" in div || "dragDrop" in div
2672 }();
2673
2674 var zwspSupported;
2675 function zeroWidthElement(measure) {
2676 if (zwspSupported == null) {
2677 var test = elt("span", "\u200b");
2678 removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
2679 if (measure.firstChild.offsetHeight != 0)
2680 { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }
2681 }
2682 var node = zwspSupported ? elt("span", "\u200b") :
2683 elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
2684 node.setAttribute("cm-text", "");
2685 return node
2686 }
2687
2688 // Feature-detect IE's crummy client rect reporting for bidi text
2689 var badBidiRects;
2690 function hasBadBidiRects(measure) {
2691 if (badBidiRects != null) { return badBidiRects }
2692 var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
2693 var r0 = range(txt, 0, 1).getBoundingClientRect();
2694 var r1 = range(txt, 1, 2).getBoundingClientRect();
2695 removeChildren(measure);
2696 if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)
2697 return badBidiRects = (r1.right - r0.right < 3)
2698 }
2699
2700 // See if "".split is the broken IE version, if so, provide an
2701 // alternative way to split lines.
2702 var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) {
2703 var pos = 0, result = [], l = string.length;
2704 while (pos <= l) {
2705 var nl = string.indexOf("\n", pos);
2706 if (nl == -1) { nl = string.length; }
2707 var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
2708 var rt = line.indexOf("\r");
2709 if (rt != -1) {
2710 result.push(line.slice(0, rt));
2711 pos += rt + 1;
2712 } else {
2713 result.push(line);
2714 pos = nl + 1;
2715 }
2716 }
2717 return result
2718 } : function (string) { return string.split(/\r\n?|\n/); };
2719
2720 var hasSelection = window.getSelection ? function (te) {
2721 try { return te.selectionStart != te.selectionEnd }
2722 catch(e) { return false }
2723 } : function (te) {
2724 var range$$1;
2725 try {range$$1 = te.ownerDocument.selection.createRange();}
2726 catch(e) {}
2727 if (!range$$1 || range$$1.parentElement() != te) { return false }
2728 return range$$1.compareEndPoints("StartToEnd", range$$1) != 0
2729 };
2730
2731 var hasCopyEvent = (function () {
2732 var e = elt("div");
2733 if ("oncopy" in e) { return true }
2734 e.setAttribute("oncopy", "return;");
2735 return typeof e.oncopy == "function"
2736 })();
2737
2738 var badZoomedRects = null;
2739 function hasBadZoomedRects(measure) {
2740 if (badZoomedRects != null) { return badZoomedRects }
2741 var node = removeChildrenAndAdd(measure, elt("span", "x"));
2742 var normal = node.getBoundingClientRect();
2743 var fromRange = range(node, 0, 1).getBoundingClientRect();
2744 return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
2745 }
2746
2747 // Known modes, by name and by MIME
2748 var modes = {};
2749 var mimeModes = {};
2750
2751 // Extra arguments are stored as the mode's dependencies, which is
2752 // used by (legacy) mechanisms like loadmode.js to automatically
2753 // load a mode. (Preferred mechanism is the require/define calls.)
2754 function defineMode(name, mode) {
2755 if (arguments.length > 2)
2756 { mode.dependencies = Array.prototype.slice.call(arguments, 2); }
2757 modes[name] = mode;
2758 }
2759
2760 function defineMIME(mime, spec) {
2761 mimeModes[mime] = spec;
2762 }
2763
2764 // Given a MIME type, a {name, ...options} config object, or a name
2765 // string, return a mode config object.
2766 function resolveMode(spec) {
2767 if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
2768 spec = mimeModes[spec];
2769 } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
2770 var found = mimeModes[spec.name];
2771 if (typeof found == "string") { found = {name: found}; }
2772 spec = createObj(found, spec);
2773 spec.name = found.name;
2774 } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
2775 return resolveMode("application/xml")
2776 } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
2777 return resolveMode("application/json")
2778 }
2779 if (typeof spec == "string") { return {name: spec} }
2780 else { return spec || {name: "null"} }
2781 }
2782
2783 // Given a mode spec (anything that resolveMode accepts), find and
2784 // initialize an actual mode object.
2785 function getMode(options, spec) {
2786 spec = resolveMode(spec);
2787 var mfactory = modes[spec.name];
2788 if (!mfactory) { return getMode(options, "text/plain") }
2789 var modeObj = mfactory(options, spec);
2790 if (modeExtensions.hasOwnProperty(spec.name)) {
2791 var exts = modeExtensions[spec.name];
2792 for (var prop in exts) {
2793 if (!exts.hasOwnProperty(prop)) { continue }
2794 if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; }
2795 modeObj[prop] = exts[prop];
2796 }
2797 }
2798 modeObj.name = spec.name;
2799 if (spec.helperType) { modeObj.helperType = spec.helperType; }
2800 if (spec.modeProps) { for (var prop$1 in spec.modeProps)
2801 { modeObj[prop$1] = spec.modeProps[prop$1]; } }
2802
2803 return modeObj
2804 }
2805
2806 // This can be used to attach properties to mode objects from
2807 // outside the actual mode definition.
2808 var modeExtensions = {};
2809 function extendMode(mode, properties) {
2810 var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
2811 copyObj(properties, exts);
2812 }
2813
2814 function copyState(mode, state) {
2815 if (state === true) { return state }
2816 if (mode.copyState) { return mode.copyState(state) }
2817 var nstate = {};
2818 for (var n in state) {
2819 var val = state[n];
2820 if (val instanceof Array) { val = val.concat([]); }
2821 nstate[n] = val;
2822 }
2823 return nstate
2824 }
2825
2826 // Given a mode and a state (for that mode), find the inner mode and
2827 // state at the position that the state refers to.
2828 function innerMode(mode, state) {
2829 var info;
2830 while (mode.innerMode) {
2831 info = mode.innerMode(state);
2832 if (!info || info.mode == mode) { break }
2833 state = info.state;
2834 mode = info.mode;
2835 }
2836 return info || {mode: mode, state: state}
2837 }
2838
2839 function startState(mode, a1, a2) {
2840 return mode.startState ? mode.startState(a1, a2) : true
2841 }
2842
2843 // STRING STREAM
2844
2845 // Fed to the mode parsers, provides helper functions to make
2846 // parsers more succinct.
2847
2848 var StringStream = function(string, tabSize, lineOracle) {
2849 this.pos = this.start = 0;
2850 this.string = string;
2851 this.tabSize = tabSize || 8;
2852 this.lastColumnPos = this.lastColumnValue = 0;
2853 this.lineStart = 0;
2854 this.lineOracle = lineOracle;
2855 };
2856
2857 StringStream.prototype.eol = function () {return this.pos >= this.string.length};
2858 StringStream.prototype.sol = function () {return this.pos == this.lineStart};
2859 StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
2860 StringStream.prototype.next = function () {
2861 if (this.pos < this.string.length)
2862 { return this.string.charAt(this.pos++) }
2863 };
2864 StringStream.prototype.eat = function (match) {
2865 var ch = this.string.charAt(this.pos);
2866 var ok;
2867 if (typeof match == "string") { ok = ch == match; }
2868 else { ok = ch && (match.test ? match.test(ch) : match(ch)); }
2869 if (ok) {++this.pos; return ch}
2870 };
2871 StringStream.prototype.eatWhile = function (match) {
2872 var start = this.pos;
2873 while (this.eat(match)){}
2874 return this.pos > start
2875 };
2876 StringStream.prototype.eatSpace = function () {
2877 var this$1 = this;
2878
2879 var start = this.pos;
2880 while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos; }
2881 return this.pos > start
2882 };
2883 StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};
2884 StringStream.prototype.skipTo = function (ch) {
2885 var found = this.string.indexOf(ch, this.pos);
2886 if (found > -1) {this.pos = found; return true}
2887 };
2888 StringStream.prototype.backUp = function (n) {this.pos -= n;};
2889 StringStream.prototype.column = function () {
2890 if (this.lastColumnPos < this.start) {
2891 this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
2892 this.lastColumnPos = this.start;
2893 }
2894 return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
2895 };
2896 StringStream.prototype.indentation = function () {
2897 return countColumn(this.string, null, this.tabSize) -
2898 (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
2899 };
2900 StringStream.prototype.match = function (pattern, consume, caseInsensitive) {
2901 if (typeof pattern == "string") {
2902 var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };
2903 var substr = this.string.substr(this.pos, pattern.length);
2904 if (cased(substr) == cased(pattern)) {
2905 if (consume !== false) { this.pos += pattern.length; }
2906 return true
2907 }
2908 } else {
2909 var match = this.string.slice(this.pos).match(pattern);
2910 if (match && match.index > 0) { return null }
2911 if (match && consume !== false) { this.pos += match[0].length; }
2912 return match
2913 }
2914 };
2915 StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};
2916 StringStream.prototype.hideFirstChars = function (n, inner) {
2917 this.lineStart += n;
2918 try { return inner() }
2919 finally { this.lineStart -= n; }
2920 };
2921 StringStream.prototype.lookAhead = function (n) {
2922 var oracle = this.lineOracle;
2923 return oracle && oracle.lookAhead(n)
2924 };
2925 StringStream.prototype.baseToken = function () {
2926 var oracle = this.lineOracle;
2927 return oracle && oracle.baseToken(this.pos)
2928 };
2929
2930 var SavedContext = function(state, lookAhead) {
2931 this.state = state;
2932 this.lookAhead = lookAhead;
2933 };
2934
2935 var Context = function(doc, state, line, lookAhead) {
2936 this.state = state;
2937 this.doc = doc;
2938 this.line = line;
2939 this.maxLookAhead = lookAhead || 0;
2940 this.baseTokens = null;
2941 this.baseTokenPos = 1;
2942 };
2943
2944 Context.prototype.lookAhead = function (n) {
2945 var line = this.doc.getLine(this.line + n);
2946 if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; }
2947 return line
2948 };
2949
2950 Context.prototype.baseToken = function (n) {
2951 var this$1 = this;
2952
2953 if (!this.baseTokens) { return null }
2954 while (this.baseTokens[this.baseTokenPos] <= n)
2955 { this$1.baseTokenPos += 2; }
2956 var type = this.baseTokens[this.baseTokenPos + 1];
2957 return {type: type && type.replace(/( |^)overlay .*/, ""),
2958 size: this.baseTokens[this.baseTokenPos] - n}
2959 };
2960
2961 Context.prototype.nextLine = function () {
2962 this.line++;
2963 if (this.maxLookAhead > 0) { this.maxLookAhead--; }
2964 };
2965
2966 Context.fromSaved = function (doc, saved, line) {
2967 if (saved instanceof SavedContext)
2968 { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) }
2969 else
2970 { return new Context(doc, copyState(doc.mode, saved), line) }
2971 };
2972
2973 Context.prototype.save = function (copy) {
2974 var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state;
2975 return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state
2976 };
2977
2978
2979 // Compute a style array (an array starting with a mode generation
2980 // -- for invalidation -- followed by pairs of end positions and
2981 // style strings), which is used to highlight the tokens on the
2982 // line.
2983 function highlightLine(cm, line, context, forceToEnd) {
2984 // A styles array always starts with a number identifying the
2985 // mode/overlays that it is based on (for easy invalidation).
2986 var st = [cm.state.modeGen], lineClasses = {};
2987 // Compute the base array of styles
2988 runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); },
2989 lineClasses, forceToEnd);
2990 var state = context.state;
2991
2992 // Run overlays, adjust style array.
2993 var loop = function ( o ) {
2994 context.baseTokens = st;
2995 var overlay = cm.state.overlays[o], i = 1, at = 0;
2996 context.state = true;
2997 runMode(cm, line.text, overlay.mode, context, function (end, style) {
2998 var start = i;
2999 // Ensure there's a token end at the current position, and that i points at it
3000 while (at < end) {
3001 var i_end = st[i];
3002 if (i_end > end)
3003 { st.splice(i, 1, end, st[i+1], i_end); }
3004 i += 2;
3005 at = Math.min(end, i_end);
3006 }
3007 if (!style) { return }
3008 if (overlay.opaque) {
3009 st.splice(start, i - start, end, "overlay " + style);
3010 i = start + 2;
3011 } else {
3012 for (; start < i; start += 2) {
3013 var cur = st[start+1];
3014 st[start+1] = (cur ? cur + " " : "") + "overlay " + style;
3015 }
3016 }
3017 }, lineClasses);
3018 context.state = state;
3019 context.baseTokens = null;
3020 context.baseTokenPos = 1;
3021 };
3022
3023 for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );
3024
3025 return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
3026 }
3027
3028 function getLineStyles(cm, line, updateFrontier) {
3029 if (!line.styles || line.styles[0] != cm.state.modeGen) {
3030 var context = getContextBefore(cm, lineNo(line));
3031 var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state);
3032 var result = highlightLine(cm, line, context);
3033 if (resetState) { context.state = resetState; }
3034 line.stateAfter = context.save(!resetState);
3035 line.styles = result.styles;
3036 if (result.classes) { line.styleClasses = result.classes; }
3037 else if (line.styleClasses) { line.styleClasses = null; }
3038 if (updateFrontier === cm.doc.highlightFrontier)
3039 { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }
3040 }
3041 return line.styles
3042 }
3043
3044 function getContextBefore(cm, n, precise) {
3045 var doc = cm.doc, display = cm.display;
3046 if (!doc.mode.startState) { return new Context(doc, true, n) }
3047 var start = findStartLine(cm, n, precise);
3048 var saved = start > doc.first && getLine(doc, start - 1).stateAfter;
3049 var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start);
3050
3051 doc.iter(start, n, function (line) {
3052 processLine(cm, line.text, context);
3053 var pos = context.line;
3054 line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null;
3055 context.nextLine();
3056 });
3057 if (precise) { doc.modeFrontier = context.line; }
3058 return context
3059 }
3060
3061 // Lightweight form of highlight -- proceed over this line and
3062 // update state, but don't save a style array. Used for lines that
3063 // aren't currently visible.
3064 function processLine(cm, text, context, startAt) {
3065 var mode = cm.doc.mode;
3066 var stream = new StringStream(text, cm.options.tabSize, context);
3067 stream.start = stream.pos = startAt || 0;
3068 if (text == "") { callBlankLine(mode, context.state); }
3069 while (!stream.eol()) {
3070 readToken(mode, stream, context.state);
3071 stream.start = stream.pos;
3072 }
3073 }
3074
3075 function callBlankLine(mode, state) {
3076 if (mode.blankLine) { return mode.blankLine(state) }
3077 if (!mode.innerMode) { return }
3078 var inner = innerMode(mode, state);
3079 if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
3080 }
3081
3082 function readToken(mode, stream, state, inner) {
3083 for (var i = 0; i < 10; i++) {
3084 if (inner) { inner[0] = innerMode(mode, state).mode; }
3085 var style = mode.token(stream, state);
3086 if (stream.pos > stream.start) { return style }
3087 }
3088 throw new Error("Mode " + mode.name + " failed to advance stream.")
3089 }
3090
3091 var Token = function(stream, type, state) {
3092 this.start = stream.start; this.end = stream.pos;
3093 this.string = stream.current();
3094 this.type = type || null;
3095 this.state = state;
3096 };
3097
3098 // Utility for getTokenAt and getLineTokens
3099 function takeToken(cm, pos, precise, asArray) {
3100 var doc = cm.doc, mode = doc.mode, style;
3101 pos = clipPos(doc, pos);
3102 var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise);
3103 var stream = new StringStream(line.text, cm.options.tabSize, context), tokens;
3104 if (asArray) { tokens = []; }
3105 while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
3106 stream.start = stream.pos;
3107 style = readToken(mode, stream, context.state);
3108 if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); }
3109 }
3110 return asArray ? tokens : new Token(stream, style, context.state)
3111 }
3112
3113 function extractLineClasses(type, output) {
3114 if (type) { for (;;) {
3115 var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
3116 if (!lineClass) { break }
3117 type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
3118 var prop = lineClass[1] ? "bgClass" : "textClass";
3119 if (output[prop] == null)
3120 { output[prop] = lineClass[2]; }
3121 else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
3122 { output[prop] += " " + lineClass[2]; }
3123 } }
3124 return type
3125 }
3126
3127 // Run the given mode's parser over a line, calling f for each token.
3128 function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {
3129 var flattenSpans = mode.flattenSpans;
3130 if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; }
3131 var curStart = 0, curStyle = null;
3132 var stream = new StringStream(text, cm.options.tabSize, context), style;
3133 var inner = cm.options.addModeClass && [null];
3134 if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); }
3135 while (!stream.eol()) {
3136 if (stream.pos > cm.options.maxHighlightLength) {
3137 flattenSpans = false;
3138 if (forceToEnd) { processLine(cm, text, context, stream.pos); }
3139 stream.pos = text.length;
3140 style = null;
3141 } else {
3142 style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses);
3143 }
3144 if (inner) {
3145 var mName = inner[0].name;
3146 if (mName) { style = "m-" + (style ? mName + " " + style : mName); }
3147 }
3148 if (!flattenSpans || curStyle != style) {
3149 while (curStart < stream.start) {
3150 curStart = Math.min(stream.start, curStart + 5000);
3151 f(curStart, curStyle);
3152 }
3153 curStyle = style;
3154 }
3155 stream.start = stream.pos;
3156 }
3157 while (curStart < stream.pos) {
3158 // Webkit seems to refuse to render text nodes longer than 57444
3159 // characters, and returns inaccurate measurements in nodes
3160 // starting around 5000 chars.
3161 var pos = Math.min(stream.pos, curStart + 5000);
3162 f(pos, curStyle);
3163 curStart = pos;
3164 }
3165 }
3166
3167 // Finds the line to start with when starting a parse. Tries to
3168 // find a line with a stateAfter, so that it can start with a
3169 // valid state. If that fails, it returns the line with the
3170 // smallest indentation, which tends to need the least context to
3171 // parse correctly.
3172 function findStartLine(cm, n, precise) {
3173 var minindent, minline, doc = cm.doc;
3174 var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
3175 for (var search = n; search > lim; --search) {
3176 if (search <= doc.first) { return doc.first }
3177 var line = getLine(doc, search - 1), after = line.stateAfter;
3178 if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))
3179 { return search }
3180 var indented = countColumn(line.text, null, cm.options.tabSize);
3181 if (minline == null || minindent > indented) {
3182 minline = search - 1;
3183 minindent = indented;
3184 }
3185 }
3186 return minline
3187 }
3188
3189 function retreatFrontier(doc, n) {
3190 doc.modeFrontier = Math.min(doc.modeFrontier, n);
3191 if (doc.highlightFrontier < n - 10) { return }
3192 var start = doc.first;
3193 for (var line = n - 1; line > start; line--) {
3194 var saved = getLine(doc, line).stateAfter;
3195 // change is on 3
3196 // state on line 1 looked ahead 2 -- so saw 3
3197 // test 1 + 2 < 3 should cover this
3198 if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {
3199 start = line + 1;
3200 break
3201 }
3202 }
3203 doc.highlightFrontier = Math.min(doc.highlightFrontier, start);
3204 }
3205
3206 // LINE DATA STRUCTURE
3207
3208 // Line objects. These hold state related to a line, including
3209 // highlighting info (the styles array).
3210 var Line = function(text, markedSpans, estimateHeight) {
3211 this.text = text;
3212 attachMarkedSpans(this, markedSpans);
3213 this.height = estimateHeight ? estimateHeight(this) : 1;
3214 };
3215
3216 Line.prototype.lineNo = function () { return lineNo(this) };
3217 eventMixin(Line);
3218
3219 // Change the content (text, markers) of a line. Automatically
3220 // invalidates cached information and tries to re-estimate the
3221 // line's height.
3222 function updateLine(line, text, markedSpans, estimateHeight) {
3223 line.text = text;
3224 if (line.stateAfter) { line.stateAfter = null; }
3225 if (line.styles) { line.styles = null; }
3226 if (line.order != null) { line.order = null; }
3227 detachMarkedSpans(line);
3228 attachMarkedSpans(line, markedSpans);
3229 var estHeight = estimateHeight ? estimateHeight(line) : 1;
3230 if (estHeight != line.height) { updateLineHeight(line, estHeight); }
3231 }
3232
3233 // Detach a line from the document tree and its markers.
3234 function cleanUpLine(line) {
3235 line.parent = null;
3236 detachMarkedSpans(line);
3237 }
3238
3239 // Convert a style as returned by a mode (either null, or a string
3240 // containing one or more styles) to a CSS style. This is cached,
3241 // and also looks for line-wide styles.
3242 var styleToClassCache = {};
3243 var styleToClassCacheWithMode = {};
3244 function interpretTokenStyle(style, options) {
3245 if (!style || /^\s*$/.test(style)) { return null }
3246 var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
3247 return cache[style] ||
3248 (cache[style] = style.replace(/\S+/g, "cm-$&"))
3249 }
3250
3251 // Render the DOM representation of the text of a line. Also builds
3252 // up a 'line map', which points at the DOM nodes that represent
3253 // specific stretches of text, and is used by the measuring code.
3254 // The returned object contains the DOM node, this map, and
3255 // information about line-wide styles that were set by the mode.
3256 function buildLineContent(cm, lineView) {
3257 // The padding-right forces the element to have a 'border', which
3258 // is needed on Webkit to be able to get line-level bounding
3259 // rectangles for it (in measureChar).
3260 var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null);
3261 var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content,
3262 col: 0, pos: 0, cm: cm,
3263 trailingSpace: false,
3264 splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")};
3265 lineView.measure = {};
3266
3267 // Iterate over the logical lines that make up this visual line.
3268 for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
3269 var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0);
3270 builder.pos = 0;
3271 builder.addToken = buildToken;
3272 // Optionally wire in some hacks into the token-rendering
3273 // algorithm, to deal with browser quirks.
3274 if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction)))
3275 { builder.addToken = buildTokenBadBidi(builder.addToken, order); }
3276 builder.map = [];
3277 var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
3278 insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
3279 if (line.styleClasses) {
3280 if (line.styleClasses.bgClass)
3281 { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); }
3282 if (line.styleClasses.textClass)
3283 { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); }
3284 }
3285
3286 // Ensure at least a single node is present, for measuring.
3287 if (builder.map.length == 0)
3288 { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); }
3289
3290 // Store the map and a cache object for the current logical line
3291 if (i == 0) {
3292 lineView.measure.map = builder.map;
3293 lineView.measure.cache = {};
3294 } else {
3295 (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)
3296 ;(lineView.measure.caches || (lineView.measure.caches = [])).push({});
3297 }
3298 }
3299
3300 // See issue #2901
3301 if (webkit) {
3302 var last = builder.content.lastChild;
3303 if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
3304 { builder.content.className = "cm-tab-wrap-hack"; }
3305 }
3306
3307 signal(cm, "renderLine", cm, lineView.line, builder.pre);
3308 if (builder.pre.className)
3309 { builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); }
3310
3311 return builder
3312 }
3313
3314 function defaultSpecialCharPlaceholder(ch) {
3315 var token = elt("span", "\u2022", "cm-invalidchar");
3316 token.title = "\\u" + ch.charCodeAt(0).toString(16);
3317 token.setAttribute("aria-label", token.title);
3318 return token
3319 }
3320
3321 // Build up the DOM representation for a single token, and add it to
3322 // the line map. Takes care to render special characters separately.
3323 function buildToken(builder, text, style, startStyle, endStyle, title, css) {
3324 if (!text) { return }
3325 var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;
3326 var special = builder.cm.state.specialChars, mustWrap = false;
3327 var content;
3328 if (!special.test(text)) {
3329 builder.col += text.length;
3330 content = document.createTextNode(displayText);
3331 builder.map.push(builder.pos, builder.pos + text.length, content);
3332 if (ie && ie_version < 9) { mustWrap = true; }
3333 builder.pos += text.length;
3334 } else {
3335 content = document.createDocumentFragment();
3336 var pos = 0;
3337 while (true) {
3338 special.lastIndex = pos;
3339 var m = special.exec(text);
3340 var skipped = m ? m.index - pos : text.length - pos;
3341 if (skipped) {
3342 var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
3343 if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])); }
3344 else { content.appendChild(txt); }
3345 builder.map.push(builder.pos, builder.pos + skipped, txt);
3346 builder.col += skipped;
3347 builder.pos += skipped;
3348 }
3349 if (!m) { break }
3350 pos += skipped + 1;
3351 var txt$1 = (void 0);
3352 if (m[0] == "\t") {
3353 var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
3354 txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
3355 txt$1.setAttribute("role", "presentation");
3356 txt$1.setAttribute("cm-text", "\t");
3357 builder.col += tabWidth;
3358 } else if (m[0] == "\r" || m[0] == "\n") {
3359 txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
3360 txt$1.setAttribute("cm-text", m[0]);
3361 builder.col += 1;
3362 } else {
3363 txt$1 = builder.cm.options.specialCharPlaceholder(m[0]);
3364 txt$1.setAttribute("cm-text", m[0]);
3365 if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])); }
3366 else { content.appendChild(txt$1); }
3367 builder.col += 1;
3368 }
3369 builder.map.push(builder.pos, builder.pos + 1, txt$1);
3370 builder.pos++;
3371 }
3372 }
3373 builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32;
3374 if (style || startStyle || endStyle || mustWrap || css) {
3375 var fullStyle = style || "";
3376 if (startStyle) { fullStyle += startStyle; }
3377 if (endStyle) { fullStyle += endStyle; }
3378 var token = elt("span", [content], fullStyle, css);
3379 if (title) { token.title = title; }
3380 return builder.content.appendChild(token)
3381 }
3382 builder.content.appendChild(content);
3383 }
3384
3385 function splitSpaces(text, trailingBefore) {
3386 if (text.length > 1 && !/ /.test(text)) { return text }
3387 var spaceBefore = trailingBefore, result = "";
3388 for (var i = 0; i < text.length; i++) {
3389 var ch = text.charAt(i);
3390 if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))
3391 { ch = "\u00a0"; }
3392 result += ch;
3393 spaceBefore = ch == " ";
3394 }
3395 return result
3396 }
3397
3398 // Work around nonsense dimensions being reported for stretches of
3399 // right-to-left text.
3400 function buildTokenBadBidi(inner, order) {
3401 return function (builder, text, style, startStyle, endStyle, title, css) {
3402 style = style ? style + " cm-force-border" : "cm-force-border";
3403 var start = builder.pos, end = start + text.length;
3404 for (;;) {
3405 // Find the part that overlaps with the start of this text
3406 var part = (void 0);
3407 for (var i = 0; i < order.length; i++) {
3408 part = order[i];
3409 if (part.to > start && part.from <= start) { break }
3410 }
3411 if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) }
3412 inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);
3413 startStyle = null;
3414 text = text.slice(part.to - start);
3415 start = part.to;
3416 }
3417 }
3418 }
3419
3420 function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
3421 var widget = !ignoreWidget && marker.widgetNode;
3422 if (widget) { builder.map.push(builder.pos, builder.pos + size, widget); }
3423 if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
3424 if (!widget)
3425 { widget = builder.content.appendChild(document.createElement("span")); }
3426 widget.setAttribute("cm-marker", marker.id);
3427 }
3428 if (widget) {
3429 builder.cm.display.input.setUneditable(widget);
3430 builder.content.appendChild(widget);
3431 }
3432 builder.pos += size;
3433 builder.trailingSpace = false;
3434 }
3435
3436 // Outputs a number of spans to make up a line, taking highlighting
3437 // and marked text into account.
3438 function insertLineContent(line, builder, styles) {
3439 var spans = line.markedSpans, allText = line.text, at = 0;
3440 if (!spans) {
3441 for (var i$1 = 1; i$1 < styles.length; i$1+=2)
3442 { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); }
3443 return
3444 }
3445
3446 var len = allText.length, pos = 0, i = 1, text = "", style, css;
3447 var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
3448 for (;;) {
3449 if (nextChange == pos) { // Update current marker set
3450 spanStyle = spanEndStyle = spanStartStyle = title = css = "";
3451 collapsed = null; nextChange = Infinity;
3452 var foundBookmarks = [], endStyles = (void 0);
3453 for (var j = 0; j < spans.length; ++j) {
3454 var sp = spans[j], m = sp.marker;
3455 if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
3456 foundBookmarks.push(m);
3457 } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
3458 if (sp.to != null && sp.to != pos && nextChange > sp.to) {
3459 nextChange = sp.to;
3460 spanEndStyle = "";
3461 }
3462 if (m.className) { spanStyle += " " + m.className; }
3463 if (m.css) { css = (css ? css + ";" : "") + m.css; }
3464 if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle; }
3465 if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); }
3466 if (m.title && !title) { title = m.title; }
3467 if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
3468 { collapsed = sp; }
3469 } else if (sp.from > pos && nextChange > sp.from) {
3470 nextChange = sp.from;
3471 }
3472 }
3473 if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)
3474 { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1]; } } }
3475
3476 if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)
3477 { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]); } }
3478 if (collapsed && (collapsed.from || 0) == pos) {
3479 buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
3480 collapsed.marker, collapsed.from == null);
3481 if (collapsed.to == null) { return }
3482 if (collapsed.to == pos) { collapsed = false; }
3483 }
3484 }
3485 if (pos >= len) { break }
3486
3487 var upto = Math.min(len, nextChange);
3488 while (true) {
3489 if (text) {
3490 var end = pos + text.length;
3491 if (!collapsed) {
3492 var tokenText = end > upto ? text.slice(0, upto - pos) : text;
3493 builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
3494 spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
3495 }
3496 if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
3497 pos = end;
3498 spanStartStyle = "";
3499 }
3500 text = allText.slice(at, at = styles[i++]);
3501 style = interpretTokenStyle(styles[i++], builder.cm.options);
3502 }
3503 }
3504 }
3505
3506
3507 // These objects are used to represent the visible (currently drawn)
3508 // part of the document. A LineView may correspond to multiple
3509 // logical lines, if those are connected by collapsed ranges.
3510 function LineView(doc, line, lineN) {
3511 // The starting line
3512 this.line = line;
3513 // Continuing lines, if any
3514 this.rest = visualLineContinued(line);
3515 // Number of logical lines in this visual line
3516 this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
3517 this.node = this.text = null;
3518 this.hidden = lineIsHidden(doc, line);
3519 }
3520
3521 // Create a range of LineView objects for the given lines.
3522 function buildViewArray(cm, from, to) {
3523 var array = [], nextPos;
3524 for (var pos = from; pos < to; pos = nextPos) {
3525 var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
3526 nextPos = pos + view.size;
3527 array.push(view);
3528 }
3529 return array
3530 }
3531
3532 var operationGroup = null;
3533
3534 function pushOperation(op) {
3535 if (operationGroup) {
3536 operationGroup.ops.push(op);
3537 } else {
3538 op.ownsGroup = operationGroup = {
3539 ops: [op],
3540 delayedCallbacks: []
3541 };
3542 }
3543 }
3544
3545 function fireCallbacksForOps(group) {
3546 // Calls delayed callbacks and cursorActivity handlers until no
3547 // new ones appear
3548 var callbacks = group.delayedCallbacks, i = 0;
3549 do {
3550 for (; i < callbacks.length; i++)
3551 { callbacks[i].call(null); }
3552 for (var j = 0; j < group.ops.length; j++) {
3553 var op = group.ops[j];
3554 if (op.cursorActivityHandlers)
3555 { while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
3556 { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } }
3557 }
3558 } while (i < callbacks.length)
3559 }
3560
3561 function finishOperation(op, endCb) {
3562 var group = op.ownsGroup;
3563 if (!group) { return }
3564
3565 try { fireCallbacksForOps(group); }
3566 finally {
3567 operationGroup = null;
3568 endCb(group);
3569 }
3570 }
3571
3572 var orphanDelayedCallbacks = null;
3573
3574 // Often, we want to signal events at a point where we are in the
3575 // middle of some work, but don't want the handler to start calling
3576 // other methods on the editor, which might be in an inconsistent
3577 // state or simply not expect any other events to happen.
3578 // signalLater looks whether there are any handlers, and schedules
3579 // them to be executed when the last operation ends, or, if no
3580 // operation is active, when a timeout fires.
3581 function signalLater(emitter, type /*, values...*/) {
3582 var arr = getHandlers(emitter, type);
3583 if (!arr.length) { return }
3584 var args = Array.prototype.slice.call(arguments, 2), list;
3585 if (operationGroup) {
3586 list = operationGroup.delayedCallbacks;
3587 } else if (orphanDelayedCallbacks) {
3588 list = orphanDelayedCallbacks;
3589 } else {
3590 list = orphanDelayedCallbacks = [];
3591 setTimeout(fireOrphanDelayed, 0);
3592 }
3593 var loop = function ( i ) {
3594 list.push(function () { return arr[i].apply(null, args); });
3595 };
3596
3597 for (var i = 0; i < arr.length; ++i)
3598 loop( i );
3599 }
3600
3601 function fireOrphanDelayed() {
3602 var delayed = orphanDelayedCallbacks;
3603 orphanDelayedCallbacks = null;
3604 for (var i = 0; i < delayed.length; ++i) { delayed[i](); }
3605 }
3606
3607 // When an aspect of a line changes, a string is added to
3608 // lineView.changes. This updates the relevant part of the line's
3609 // DOM structure.
3610 function updateLineForChanges(cm, lineView, lineN, dims) {
3611 for (var j = 0; j < lineView.changes.length; j++) {
3612 var type = lineView.changes[j];
3613 if (type == "text") { updateLineText(cm, lineView); }
3614 else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims); }
3615 else if (type == "class") { updateLineClasses(cm, lineView); }
3616 else if (type == "widget") { updateLineWidgets(cm, lineView, dims); }
3617 }
3618 lineView.changes = null;
3619 }
3620
3621 // Lines with gutter elements, widgets or a background class need to
3622 // be wrapped, and have the extra elements added to the wrapper div
3623 function ensureLineWrapped(lineView) {
3624 if (lineView.node == lineView.text) {
3625 lineView.node = elt("div", null, null, "position: relative");
3626 if (lineView.text.parentNode)
3627 { lineView.text.parentNode.replaceChild(lineView.node, lineView.text); }
3628 lineView.node.appendChild(lineView.text);
3629 if (ie && ie_version < 8) { lineView.node.style.zIndex = 2; }
3630 }
3631 return lineView.node
3632 }
3633
3634 function updateLineBackground(cm, lineView) {
3635 var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
3636 if (cls) { cls += " CodeMirror-linebackground"; }
3637 if (lineView.background) {
3638 if (cls) { lineView.background.className = cls; }
3639 else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
3640 } else if (cls) {
3641 var wrap = ensureLineWrapped(lineView);
3642 lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
3643 cm.display.input.setUneditable(lineView.background);
3644 }
3645 }
3646
3647 // Wrapper around buildLineContent which will reuse the structure
3648 // in display.externalMeasured when possible.
3649 function getLineContent(cm, lineView) {
3650 var ext = cm.display.externalMeasured;
3651 if (ext && ext.line == lineView.line) {
3652 cm.display.externalMeasured = null;
3653 lineView.measure = ext.measure;
3654 return ext.built
3655 }
3656 return buildLineContent(cm, lineView)
3657 }
3658
3659 // Redraw the line's text. Interacts with the background and text
3660 // classes because the mode may output tokens that influence these
3661 // classes.
3662 function updateLineText(cm, lineView) {
3663 var cls = lineView.text.className;
3664 var built = getLineContent(cm, lineView);
3665 if (lineView.text == lineView.node) { lineView.node = built.pre; }
3666 lineView.text.parentNode.replaceChild(built.pre, lineView.text);
3667 lineView.text = built.pre;
3668 if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
3669 lineView.bgClass = built.bgClass;
3670 lineView.textClass = built.textClass;
3671 updateLineClasses(cm, lineView);
3672 } else if (cls) {
3673 lineView.text.className = cls;
3674 }
3675 }
3676
3677 function updateLineClasses(cm, lineView) {
3678 updateLineBackground(cm, lineView);
3679 if (lineView.line.wrapClass)
3680 { ensureLineWrapped(lineView).className = lineView.line.wrapClass; }
3681 else if (lineView.node != lineView.text)
3682 { lineView.node.className = ""; }
3683 var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
3684 lineView.text.className = textClass || "";
3685 }
3686
3687 function updateLineGutter(cm, lineView, lineN, dims) {
3688 if (lineView.gutter) {
3689 lineView.node.removeChild(lineView.gutter);
3690 lineView.gutter = null;
3691 }
3692 if (lineView.gutterBackground) {
3693 lineView.node.removeChild(lineView.gutterBackground);
3694 lineView.gutterBackground = null;
3695 }
3696 if (lineView.line.gutterClass) {
3697 var wrap = ensureLineWrapped(lineView);
3698 lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
3699 ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px"));
3700 cm.display.input.setUneditable(lineView.gutterBackground);
3701 wrap.insertBefore(lineView.gutterBackground, lineView.text);
3702 }
3703 var markers = lineView.line.gutterMarkers;
3704 if (cm.options.lineNumbers || markers) {
3705 var wrap$1 = ensureLineWrapped(lineView);
3706 var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"));
3707 cm.display.input.setUneditable(gutterWrap);
3708 wrap$1.insertBefore(gutterWrap, lineView.text);
3709 if (lineView.line.gutterClass)
3710 { gutterWrap.className += " " + lineView.line.gutterClass; }
3711 if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
3712 { lineView.lineNumber = gutterWrap.appendChild(
3713 elt("div", lineNumberFor(cm.options, lineN),
3714 "CodeMirror-linenumber CodeMirror-gutter-elt",
3715 ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))); }
3716 if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) {
3717 var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
3718 if (found)
3719 { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
3720 ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))); }
3721 } }
3722 }
3723 }
3724
3725 function updateLineWidgets(cm, lineView, dims) {
3726 if (lineView.alignable) { lineView.alignable = null; }
3727 for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {
3728 next = node.nextSibling;
3729 if (node.className == "CodeMirror-linewidget")
3730 { lineView.node.removeChild(node); }
3731 }
3732 insertLineWidgets(cm, lineView, dims);
3733 }
3734
3735 // Build a line's DOM representation from scratch
3736 function buildLineElement(cm, lineView, lineN, dims) {
3737 var built = getLineContent(cm, lineView);
3738 lineView.text = lineView.node = built.pre;
3739 if (built.bgClass) { lineView.bgClass = built.bgClass; }
3740 if (built.textClass) { lineView.textClass = built.textClass; }
3741
3742 updateLineClasses(cm, lineView);
3743 updateLineGutter(cm, lineView, lineN, dims);
3744 insertLineWidgets(cm, lineView, dims);
3745 return lineView.node
3746 }
3747
3748 // A lineView may contain multiple logical lines (when merged by
3749 // collapsed spans). The widgets for all of them need to be drawn.
3750 function insertLineWidgets(cm, lineView, dims) {
3751 insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
3752 if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
3753 { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } }
3754 }
3755
3756 function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
3757 if (!line.widgets) { return }
3758 var wrap = ensureLineWrapped(lineView);
3759 for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
3760 var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
3761 if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); }
3762 positionLineWidget(widget, node, lineView, dims);
3763 cm.display.input.setUneditable(node);
3764 if (allowAbove && widget.above)
3765 { wrap.insertBefore(node, lineView.gutter || lineView.text); }
3766 else
3767 { wrap.appendChild(node); }
3768 signalLater(widget, "redraw");
3769 }
3770 }
3771
3772 function positionLineWidget(widget, node, lineView, dims) {
3773 if (widget.noHScroll) {
3774 (lineView.alignable || (lineView.alignable = [])).push(node);
3775 var width = dims.wrapperWidth;
3776 node.style.left = dims.fixedPos + "px";
3777 if (!widget.coverGutter) {
3778 width -= dims.gutterTotalWidth;
3779 node.style.paddingLeft = dims.gutterTotalWidth + "px";
3780 }
3781 node.style.width = width + "px";
3782 }
3783 if (widget.coverGutter) {
3784 node.style.zIndex = 5;
3785 node.style.position = "relative";
3786 if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px"; }
3787 }
3788 }
3789
3790 function widgetHeight(widget) {
3791 if (widget.height != null) { return widget.height }
3792 var cm = widget.doc.cm;
3793 if (!cm) { return 0 }
3794 if (!contains(document.body, widget.node)) {
3795 var parentStyle = "position: relative;";
3796 if (widget.coverGutter)
3797 { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; }
3798 if (widget.noHScroll)
3799 { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; }
3800 removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
3801 }
3802 return widget.height = widget.node.parentNode.offsetHeight
3803 }
3804
3805 // Return true when the given mouse event happened in a widget
3806 function eventInWidget(display, e) {
3807 for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
3808 if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
3809 (n.parentNode == display.sizer && n != display.mover))
3810 { return true }
3811 }
3812 }
3813
3814 // POSITION MEASUREMENT
3815
3816 function paddingTop(display) {return display.lineSpace.offsetTop}
3817 function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}
3818 function paddingH(display) {
3819 if (display.cachedPaddingH) { return display.cachedPaddingH }
3820 var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
3821 var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
3822 var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
3823 if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; }
3824 return data
3825 }
3826
3827 function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
3828 function displayWidth(cm) {
3829 return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth
3830 }
3831 function displayHeight(cm) {
3832 return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight
3833 }
3834
3835 // Ensure the lineView.wrapping.heights array is populated. This is
3836 // an array of bottom offsets for the lines that make up a drawn
3837 // line. When lineWrapping is on, there might be more than one
3838 // height.
3839 function ensureLineHeights(cm, lineView, rect) {
3840 var wrapping = cm.options.lineWrapping;
3841 var curWidth = wrapping && displayWidth(cm);
3842 if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
3843 var heights = lineView.measure.heights = [];
3844 if (wrapping) {
3845 lineView.measure.width = curWidth;
3846 var rects = lineView.text.firstChild.getClientRects();
3847 for (var i = 0; i < rects.length - 1; i++) {
3848 var cur = rects[i], next = rects[i + 1];
3849 if (Math.abs(cur.bottom - next.bottom) > 2)
3850 { heights.push((cur.bottom + next.top) / 2 - rect.top); }
3851 }
3852 }
3853 heights.push(rect.bottom - rect.top);
3854 }
3855 }
3856
3857 // Find a line map (mapping character offsets to text nodes) and a
3858 // measurement cache for the given line number. (A line view might
3859 // contain multiple lines when collapsed ranges are present.)
3860 function mapFromLineView(lineView, line, lineN) {
3861 if (lineView.line == line)
3862 { return {map: lineView.measure.map, cache: lineView.measure.cache} }
3863 for (var i = 0; i < lineView.rest.length; i++)
3864 { if (lineView.rest[i] == line)
3865 { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
3866 for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
3867 { if (lineNo(lineView.rest[i$1]) > lineN)
3868 { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
3869 }
3870
3871 // Render a line into the hidden node display.externalMeasured. Used
3872 // when measurement is needed for a line that's not in the viewport.
3873 function updateExternalMeasurement(cm, line) {
3874 line = visualLine(line);
3875 var lineN = lineNo(line);
3876 var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
3877 view.lineN = lineN;
3878 var built = view.built = buildLineContent(cm, view);
3879 view.text = built.pre;
3880 removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
3881 return view
3882 }
3883
3884 // Get a {top, bottom, left, right} box (in line-local coordinates)
3885 // for a given character.
3886 function measureChar(cm, line, ch, bias) {
3887 return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)
3888 }
3889
3890 // Find a line view that corresponds to the given line number.
3891 function findViewForLine(cm, lineN) {
3892 if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
3893 { return cm.display.view[findViewIndex(cm, lineN)] }
3894 var ext = cm.display.externalMeasured;
3895 if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
3896 { return ext }
3897 }
3898
3899 // Measurement can be split in two steps, the set-up work that
3900 // applies to the whole line, and the measurement of the actual
3901 // character. Functions like coordsChar, that need to do a lot of
3902 // measurements in a row, can thus ensure that the set-up work is
3903 // only done once.
3904 function prepareMeasureForLine(cm, line) {
3905 var lineN = lineNo(line);
3906 var view = findViewForLine(cm, lineN);
3907 if (view && !view.text) {
3908 view = null;
3909 } else if (view && view.changes) {
3910 updateLineForChanges(cm, view, lineN, getDimensions(cm));
3911 cm.curOp.forceUpdate = true;
3912 }
3913 if (!view)
3914 { view = updateExternalMeasurement(cm, line); }
3915
3916 var info = mapFromLineView(view, line, lineN);
3917 return {
3918 line: line, view: view, rect: null,
3919 map: info.map, cache: info.cache, before: info.before,
3920 hasHeights: false
3921 }
3922 }
3923
3924 // Given a prepared measurement object, measures the position of an
3925 // actual character (or fetches it from the cache).
3926 function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
3927 if (prepared.before) { ch = -1; }
3928 var key = ch + (bias || ""), found;
3929 if (prepared.cache.hasOwnProperty(key)) {
3930 found = prepared.cache[key];
3931 } else {
3932 if (!prepared.rect)
3933 { prepared.rect = prepared.view.text.getBoundingClientRect(); }
3934 if (!prepared.hasHeights) {
3935 ensureLineHeights(cm, prepared.view, prepared.rect);
3936 prepared.hasHeights = true;
3937 }
3938 found = measureCharInner(cm, prepared, ch, bias);
3939 if (!found.bogus) { prepared.cache[key] = found; }
3940 }
3941 return {left: found.left, right: found.right,
3942 top: varHeight ? found.rtop : found.top,
3943 bottom: varHeight ? found.rbottom : found.bottom}
3944 }
3945
3946 var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
3947
3948 function nodeAndOffsetInLineMap(map$$1, ch, bias) {
3949 var node, start, end, collapse, mStart, mEnd;
3950 // First, search the line map for the text node corresponding to,
3951 // or closest to, the target character.
3952 for (var i = 0; i < map$$1.length; i += 3) {
3953 mStart = map$$1[i];
3954 mEnd = map$$1[i + 1];
3955 if (ch < mStart) {
3956 start = 0; end = 1;
3957 collapse = "left";
3958 } else if (ch < mEnd) {
3959 start = ch - mStart;
3960 end = start + 1;
3961 } else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) {
3962 end = mEnd - mStart;
3963 start = end - 1;
3964 if (ch >= mEnd) { collapse = "right"; }
3965 }
3966 if (start != null) {
3967 node = map$$1[i + 2];
3968 if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
3969 { collapse = bias; }
3970 if (bias == "left" && start == 0)
3971 { while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) {
3972 node = map$$1[(i -= 3) + 2];
3973 collapse = "left";
3974 } }
3975 if (bias == "right" && start == mEnd - mStart)
3976 { while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) {
3977 node = map$$1[(i += 3) + 2];
3978 collapse = "right";
3979 } }
3980 break
3981 }
3982 }
3983 return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}
3984 }
3985
3986 function getUsefulRect(rects, bias) {
3987 var rect = nullRect;
3988 if (bias == "left") { for (var i = 0; i < rects.length; i++) {
3989 if ((rect = rects[i]).left != rect.right) { break }
3990 } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {
3991 if ((rect = rects[i$1]).left != rect.right) { break }
3992 } }
3993 return rect
3994 }
3995
3996 function measureCharInner(cm, prepared, ch, bias) {
3997 var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
3998 var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
3999
4000 var rect;
4001 if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
4002 for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned
4003 while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start; }
4004 while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end; }
4005 if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)
4006 { rect = node.parentNode.getBoundingClientRect(); }
4007 else
4008 { rect = getUsefulRect(range(node, start, end).getClientRects(), bias); }
4009 if (rect.left || rect.right || start == 0) { break }
4010 end = start;
4011 start = start - 1;
4012 collapse = "right";
4013 }
4014 if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect); }
4015 } else { // If it is a widget, simply get the box for the whole widget.
4016 if (start > 0) { collapse = bias = "right"; }
4017 var rects;
4018 if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
4019 { rect = rects[bias == "right" ? rects.length - 1 : 0]; }
4020 else
4021 { rect = node.getBoundingClientRect(); }
4022 }
4023 if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
4024 var rSpan = node.parentNode.getClientRects()[0];
4025 if (rSpan)
4026 { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; }
4027 else
4028 { rect = nullRect; }
4029 }
4030
4031 var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
4032 var mid = (rtop + rbot) / 2;
4033 var heights = prepared.view.measure.heights;
4034 var i = 0;
4035 for (; i < heights.length - 1; i++)
4036 { if (mid < heights[i]) { break } }
4037 var top = i ? heights[i - 1] : 0, bot = heights[i];
4038 var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
4039 right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
4040 top: top, bottom: bot};
4041 if (!rect.left && !rect.right) { result.bogus = true; }
4042 if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
4043
4044 return result
4045 }
4046
4047 // Work around problem with bounding client rects on ranges being
4048 // returned incorrectly when zoomed on IE10 and below.
4049 function maybeUpdateRectForZooming(measure, rect) {
4050 if (!window.screen || screen.logicalXDPI == null ||
4051 screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
4052 { return rect }
4053 var scaleX = screen.logicalXDPI / screen.deviceXDPI;
4054 var scaleY = screen.logicalYDPI / screen.deviceYDPI;
4055 return {left: rect.left * scaleX, right: rect.right * scaleX,
4056 top: rect.top * scaleY, bottom: rect.bottom * scaleY}
4057 }
4058
4059 function clearLineMeasurementCacheFor(lineView) {
4060 if (lineView.measure) {
4061 lineView.measure.cache = {};
4062 lineView.measure.heights = null;
4063 if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
4064 { lineView.measure.caches[i] = {}; } }
4065 }
4066 }
4067
4068 function clearLineMeasurementCache(cm) {
4069 cm.display.externalMeasure = null;
4070 removeChildren(cm.display.lineMeasure);
4071 for (var i = 0; i < cm.display.view.length; i++)
4072 { clearLineMeasurementCacheFor(cm.display.view[i]); }
4073 }
4074
4075 function clearCaches(cm) {
4076 clearLineMeasurementCache(cm);
4077 cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
4078 if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true; }
4079 cm.display.lineNumChars = null;
4080 }
4081
4082 function pageScrollX() {
4083 // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206
4084 // which causes page_Offset and bounding client rects to use
4085 // different reference viewports and invalidate our calculations.
4086 if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }
4087 return window.pageXOffset || (document.documentElement || document.body).scrollLeft
4088 }
4089 function pageScrollY() {
4090 if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }
4091 return window.pageYOffset || (document.documentElement || document.body).scrollTop
4092 }
4093
4094 function widgetTopHeight(lineObj) {
4095 var height = 0;
4096 if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
4097 { height += widgetHeight(lineObj.widgets[i]); } } }
4098 return height
4099 }
4100
4101 // Converts a {top, bottom, left, right} box from line-local
4102 // coordinates into another coordinate system. Context may be one of
4103 // "line", "div" (display.lineDiv), "local"./null (editor), "window",
4104 // or "page".
4105 function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
4106 if (!includeWidgets) {
4107 var height = widgetTopHeight(lineObj);
4108 rect.top += height; rect.bottom += height;
4109 }
4110 if (context == "line") { return rect }
4111 if (!context) { context = "local"; }
4112 var yOff = heightAtLine(lineObj);
4113 if (context == "local") { yOff += paddingTop(cm.display); }
4114 else { yOff -= cm.display.viewOffset; }
4115 if (context == "page" || context == "window") {
4116 var lOff = cm.display.lineSpace.getBoundingClientRect();
4117 yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
4118 var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
4119 rect.left += xOff; rect.right += xOff;
4120 }
4121 rect.top += yOff; rect.bottom += yOff;
4122 return rect
4123 }
4124
4125 // Coverts a box from "div" coords to another coordinate system.
4126 // Context may be "window", "page", "div", or "local"./null.
4127 function fromCoordSystem(cm, coords, context) {
4128 if (context == "div") { return coords }
4129 var left = coords.left, top = coords.top;
4130 // First move into "page" coordinate system
4131 if (context == "page") {
4132 left -= pageScrollX();
4133 top -= pageScrollY();
4134 } else if (context == "local" || !context) {
4135 var localBox = cm.display.sizer.getBoundingClientRect();
4136 left += localBox.left;
4137 top += localBox.top;
4138 }
4139
4140 var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
4141 return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}
4142 }
4143
4144 function charCoords(cm, pos, context, lineObj, bias) {
4145 if (!lineObj) { lineObj = getLine(cm.doc, pos.line); }
4146 return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)
4147 }
4148
4149 // Returns a box for a given cursor position, which may have an
4150 // 'other' property containing the position of the secondary cursor
4151 // on a bidi boundary.
4152 // A cursor Pos(line, char, "before") is on the same visual line as `char - 1`
4153 // and after `char - 1` in writing order of `char - 1`
4154 // A cursor Pos(line, char, "after") is on the same visual line as `char`
4155 // and before `char` in writing order of `char`
4156 // Examples (upper-case letters are RTL, lower-case are LTR):
4157 // Pos(0, 1, ...)
4158 // before after
4159 // ab a|b a|b
4160 // aB a|B aB|
4161 // Ab |Ab A|b
4162 // AB B|A B|A
4163 // Every position after the last character on a line is considered to stick
4164 // to the last character on the line.
4165 function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
4166 lineObj = lineObj || getLine(cm.doc, pos.line);
4167 if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
4168 function get(ch, right) {
4169 var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
4170 if (right) { m.left = m.right; } else { m.right = m.left; }
4171 return intoCoordSystem(cm, lineObj, m, context)
4172 }
4173 var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky;
4174 if (ch >= lineObj.text.length) {
4175 ch = lineObj.text.length;
4176 sticky = "before";
4177 } else if (ch <= 0) {
4178 ch = 0;
4179 sticky = "after";
4180 }
4181 if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") }
4182
4183 function getBidi(ch, partPos, invert) {
4184 var part = order[partPos], right = part.level == 1;
4185 return get(invert ? ch - 1 : ch, right != invert)
4186 }
4187 var partPos = getBidiPartAt(order, ch, sticky);
4188 var other = bidiOther;
4189 var val = getBidi(ch, partPos, sticky == "before");
4190 if (other != null) { val.other = getBidi(ch, other, sticky != "before"); }
4191 return val
4192 }
4193
4194 // Used to cheaply estimate the coordinates for a position. Used for
4195 // intermediate scroll updates.
4196 function estimateCoords(cm, pos) {
4197 var left = 0;
4198 pos = clipPos(cm.doc, pos);
4199 if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch; }
4200 var lineObj = getLine(cm.doc, pos.line);
4201 var top = heightAtLine(lineObj) + paddingTop(cm.display);
4202 return {left: left, right: left, top: top, bottom: top + lineObj.height}
4203 }
4204
4205 // Positions returned by coordsChar contain some extra information.
4206 // xRel is the relative x position of the input coordinates compared
4207 // to the found position (so xRel > 0 means the coordinates are to
4208 // the right of the character position, for example). When outside
4209 // is true, that means the coordinates lie outside the line's
4210 // vertical range.
4211 function PosWithInfo(line, ch, sticky, outside, xRel) {
4212 var pos = Pos(line, ch, sticky);
4213 pos.xRel = xRel;
4214 if (outside) { pos.outside = true; }
4215 return pos
4216 }
4217
4218 // Compute the character position closest to the given coordinates.
4219 // Input must be lineSpace-local ("div" coordinate system).
4220 function coordsChar(cm, x, y) {
4221 var doc = cm.doc;
4222 y += cm.display.viewOffset;
4223 if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) }
4224 var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
4225 if (lineN > last)
4226 { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) }
4227 if (x < 0) { x = 0; }
4228
4229 var lineObj = getLine(doc, lineN);
4230 for (;;) {
4231 var found = coordsCharInner(cm, lineObj, lineN, x, y);
4232 var merged = collapsedSpanAtEnd(lineObj);
4233 var mergedPos = merged && merged.find(0, true);
4234 if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
4235 { lineN = lineNo(lineObj = mergedPos.to.line); }
4236 else
4237 { return found }
4238 }
4239 }
4240
4241 function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
4242 y -= widgetTopHeight(lineObj);
4243 var end = lineObj.text.length;
4244 var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0);
4245 end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end);
4246 return {begin: begin, end: end}
4247 }
4248
4249 function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
4250 if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
4251 var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top;
4252 return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)
4253 }
4254
4255 // Returns true if the given side of a box is after the given
4256 // coordinates, in top-to-bottom, left-to-right order.
4257 function boxIsAfter(box, x, y, left) {
4258 return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
4259 }
4260
4261 function coordsCharInner(cm, lineObj, lineNo$$1, x, y) {
4262 // Move y into line-local coordinate space
4263 y -= heightAtLine(lineObj);
4264 var preparedMeasure = prepareMeasureForLine(cm, lineObj);
4265 // When directly calling `measureCharPrepared`, we have to adjust
4266 // for the widgets at this line.
4267 var widgetHeight$$1 = widgetTopHeight(lineObj);
4268 var begin = 0, end = lineObj.text.length, ltr = true;
4269
4270 var order = getOrder(lineObj, cm.doc.direction);
4271 // If the line isn't plain left-to-right text, first figure out
4272 // which bidi section the coordinates fall into.
4273 if (order) {
4274 var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
4275 (cm, lineObj, lineNo$$1, preparedMeasure, order, x, y);
4276 ltr = part.level != 1;
4277 // The awkward -1 offsets are needed because findFirst (called
4278 // on these below) will treat its first bound as inclusive,
4279 // second as exclusive, but we want to actually address the
4280 // characters in the part's range
4281 begin = ltr ? part.from : part.to - 1;
4282 end = ltr ? part.to : part.from - 1;
4283 }
4284
4285 // A binary search to find the first character whose bounding box
4286 // starts after the coordinates. If we run across any whose box wrap
4287 // the coordinates, store that.
4288 var chAround = null, boxAround = null;
4289 var ch = findFirst(function (ch) {
4290 var box = measureCharPrepared(cm, preparedMeasure, ch);
4291 box.top += widgetHeight$$1; box.bottom += widgetHeight$$1;
4292 if (!boxIsAfter(box, x, y, false)) { return false }
4293 if (box.top <= y && box.left <= x) {
4294 chAround = ch;
4295 boxAround = box;
4296 }
4297 return true
4298 }, begin, end);
4299
4300 var baseX, sticky, outside = false;
4301 // If a box around the coordinates was found, use that
4302 if (boxAround) {
4303 // Distinguish coordinates nearer to the left or right side of the box
4304 var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr;
4305 ch = chAround + (atStart ? 0 : 1);
4306 sticky = atStart ? "after" : "before";
4307 baseX = atLeft ? boxAround.left : boxAround.right;
4308 } else {
4309 // (Adjust for extended bound, if necessary.)
4310 if (!ltr && (ch == end || ch == begin)) { ch++; }
4311 // To determine which side to associate with, get the box to the
4312 // left of the character and compare it's vertical position to the
4313 // coordinates
4314 sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
4315 (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight$$1 <= y) == ltr ?
4316 "after" : "before";
4317 // Now get accurate coordinates for this place, in order to get a
4318 // base X position
4319 var coords = cursorCoords(cm, Pos(lineNo$$1, ch, sticky), "line", lineObj, preparedMeasure);
4320 baseX = coords.left;
4321 outside = y < coords.top || y >= coords.bottom;
4322 }
4323
4324 ch = skipExtendingChars(lineObj.text, ch, 1);
4325 return PosWithInfo(lineNo$$1, ch, sticky, outside, x - baseX)
4326 }
4327
4328 function coordsBidiPart(cm, lineObj, lineNo$$1, preparedMeasure, order, x, y) {
4329 // Bidi parts are sorted left-to-right, and in a non-line-wrapping
4330 // situation, we can take this ordering to correspond to the visual
4331 // ordering. This finds the first part whose end is after the given
4332 // coordinates.
4333 var index = findFirst(function (i) {
4334 var part = order[i], ltr = part.level != 1;
4335 return boxIsAfter(cursorCoords(cm, Pos(lineNo$$1, ltr ? part.to : part.from, ltr ? "before" : "after"),
4336 "line", lineObj, preparedMeasure), x, y, true)
4337 }, 0, order.length - 1);
4338 var part = order[index];
4339 // If this isn't the first part, the part's start is also after
4340 // the coordinates, and the coordinates aren't on the same line as
4341 // that start, move one part back.
4342 if (index > 0) {
4343 var ltr = part.level != 1;
4344 var start = cursorCoords(cm, Pos(lineNo$$1, ltr ? part.from : part.to, ltr ? "after" : "before"),
4345 "line", lineObj, preparedMeasure);
4346 if (boxIsAfter(start, x, y, true) && start.top > y)
4347 { part = order[index - 1]; }
4348 }
4349 return part
4350 }
4351
4352 function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {
4353 // In a wrapped line, rtl text on wrapping boundaries can do things
4354 // that don't correspond to the ordering in our `order` array at
4355 // all, so a binary search doesn't work, and we want to return a
4356 // part that only spans one line so that the binary search in
4357 // coordsCharInner is safe. As such, we first find the extent of the
4358 // wrapped line, and then do a flat search in which we discard any
4359 // spans that aren't on the line.
4360 var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);
4361 var begin = ref.begin;
4362 var end = ref.end;
4363 if (/\s/.test(lineObj.text.charAt(end - 1))) { end--; }
4364 var part = null, closestDist = null;
4365 for (var i = 0; i < order.length; i++) {
4366 var p = order[i];
4367 if (p.from >= end || p.to <= begin) { continue }
4368 var ltr = p.level != 1;
4369 var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right;
4370 // Weigh against spans ending before this, so that they are only
4371 // picked if nothing ends after
4372 var dist = endX < x ? x - endX + 1e9 : endX - x;
4373 if (!part || closestDist > dist) {
4374 part = p;
4375 closestDist = dist;
4376 }
4377 }
4378 if (!part) { part = order[order.length - 1]; }
4379 // Clip the part to the wrapped line.
4380 if (part.from < begin) { part = {from: begin, to: part.to, level: part.level}; }
4381 if (part.to > end) { part = {from: part.from, to: end, level: part.level}; }
4382 return part
4383 }
4384
4385 var measureText;
4386 // Compute the default text height.
4387 function textHeight(display) {
4388 if (display.cachedTextHeight != null) { return display.cachedTextHeight }
4389 if (measureText == null) {
4390 measureText = elt("pre");
4391 // Measure a bunch of lines, for browsers that compute
4392 // fractional heights.
4393 for (var i = 0; i < 49; ++i) {
4394 measureText.appendChild(document.createTextNode("x"));
4395 measureText.appendChild(elt("br"));
4396 }
4397 measureText.appendChild(document.createTextNode("x"));
4398 }
4399 removeChildrenAndAdd(display.measure, measureText);
4400 var height = measureText.offsetHeight / 50;
4401 if (height > 3) { display.cachedTextHeight = height; }
4402 removeChildren(display.measure);
4403 return height || 1
4404 }
4405
4406 // Compute the default character width.
4407 function charWidth(display) {
4408 if (display.cachedCharWidth != null) { return display.cachedCharWidth }
4409 var anchor = elt("span", "xxxxxxxxxx");
4410 var pre = elt("pre", [anchor]);
4411 removeChildrenAndAdd(display.measure, pre);
4412 var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
4413 if (width > 2) { display.cachedCharWidth = width; }
4414 return width || 10
4415 }
4416
4417 // Do a bulk-read of the DOM positions and sizes needed to draw the
4418 // view, so that we don't interleave reading and writing to the DOM.
4419 function getDimensions(cm) {
4420 var d = cm.display, left = {}, width = {};
4421 var gutterLeft = d.gutters.clientLeft;
4422 for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
4423 left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
4424 width[cm.options.gutters[i]] = n.clientWidth;
4425 }
4426 return {fixedPos: compensateForHScroll(d),
4427 gutterTotalWidth: d.gutters.offsetWidth,
4428 gutterLeft: left,
4429 gutterWidth: width,
4430 wrapperWidth: d.wrapper.clientWidth}
4431 }
4432
4433 // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
4434 // but using getBoundingClientRect to get a sub-pixel-accurate
4435 // result.
4436 function compensateForHScroll(display) {
4437 return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left
4438 }
4439
4440 // Returns a function that estimates the height of a line, to use as
4441 // first approximation until the line becomes visible (and is thus
4442 // properly measurable).
4443 function estimateHeight(cm) {
4444 var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
4445 var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
4446 return function (line) {
4447 if (lineIsHidden(cm.doc, line)) { return 0 }
4448
4449 var widgetsHeight = 0;
4450 if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {
4451 if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height; }
4452 } }
4453
4454 if (wrapping)
4455 { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }
4456 else
4457 { return widgetsHeight + th }
4458 }
4459 }
4460
4461 function estimateLineHeights(cm) {
4462 var doc = cm.doc, est = estimateHeight(cm);
4463 doc.iter(function (line) {
4464 var estHeight = est(line);
4465 if (estHeight != line.height) { updateLineHeight(line, estHeight); }
4466 });
4467 }
4468
4469 // Given a mouse event, find the corresponding position. If liberal
4470 // is false, it checks whether a gutter or scrollbar was clicked,
4471 // and returns null if it was. forRect is used by rectangular
4472 // selections, and tries to estimate a character position even for
4473 // coordinates beyond the right of the text.
4474 function posFromMouse(cm, e, liberal, forRect) {
4475 var display = cm.display;
4476 if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null }
4477
4478 var x, y, space = display.lineSpace.getBoundingClientRect();
4479 // Fails unpredictably on IE[67] when mouse is dragged around quickly.
4480 try { x = e.clientX - space.left; y = e.clientY - space.top; }
4481 catch (e) { return null }
4482 var coords = coordsChar(cm, x, y), line;
4483 if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
4484 var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
4485 coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
4486 }
4487 return coords
4488 }
4489
4490 // Find the view element corresponding to a given line. Return null
4491 // when the line isn't visible.
4492 function findViewIndex(cm, n) {
4493 if (n >= cm.display.viewTo) { return null }
4494 n -= cm.display.viewFrom;
4495 if (n < 0) { return null }
4496 var view = cm.display.view;
4497 for (var i = 0; i < view.length; i++) {
4498 n -= view[i].size;
4499 if (n < 0) { return i }
4500 }
4501 }
4502
4503 function updateSelection(cm) {
4504 cm.display.input.showSelection(cm.display.input.prepareSelection());
4505 }
4506
4507 function prepareSelection(cm, primary) {
4508 if ( primary === void 0 ) primary = true;
4509
4510 var doc = cm.doc, result = {};
4511 var curFragment = result.cursors = document.createDocumentFragment();
4512 var selFragment = result.selection = document.createDocumentFragment();
4513
4514 for (var i = 0; i < doc.sel.ranges.length; i++) {
4515 if (!primary && i == doc.sel.primIndex) { continue }
4516 var range$$1 = doc.sel.ranges[i];
4517 if (range$$1.from().line >= cm.display.viewTo || range$$1.to().line < cm.display.viewFrom) { continue }
4518 var collapsed = range$$1.empty();
4519 if (collapsed || cm.options.showCursorWhenSelecting)
4520 { drawSelectionCursor(cm, range$$1.head, curFragment); }
4521 if (!collapsed)
4522 { drawSelectionRange(cm, range$$1, selFragment); }
4523 }
4524 return result
4525 }
4526
4527 // Draws a cursor for the given range
4528 function drawSelectionCursor(cm, head, output) {
4529 var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine);
4530
4531 var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
4532 cursor.style.left = pos.left + "px";
4533 cursor.style.top = pos.top + "px";
4534 cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
4535
4536 if (pos.other) {
4537 // Secondary cursor, shown when on a 'jump' in bi-directional text
4538 var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
4539 otherCursor.style.display = "";
4540 otherCursor.style.left = pos.other.left + "px";
4541 otherCursor.style.top = pos.other.top + "px";
4542 otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
4543 }
4544 }
4545
4546 function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
4547
4548 // Draws the given range as a highlighted selection
4549 function drawSelectionRange(cm, range$$1, output) {
4550 var display = cm.display, doc = cm.doc;
4551 var fragment = document.createDocumentFragment();
4552 var padding = paddingH(cm.display), leftSide = padding.left;
4553 var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
4554 var docLTR = doc.direction == "ltr";
4555
4556 function add(left, top, width, bottom) {
4557 if (top < 0) { top = 0; }
4558 top = Math.round(top);
4559 bottom = Math.round(bottom);
4560 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")));
4561 }
4562
4563 function drawForLine(line, fromArg, toArg) {
4564 var lineObj = getLine(doc, line);
4565 var lineLen = lineObj.text.length;
4566 var start, end;
4567 function coords(ch, bias) {
4568 return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
4569 }
4570
4571 function wrapX(pos, dir, side) {
4572 var extent = wrappedLineExtentChar(cm, lineObj, null, pos);
4573 var prop = (dir == "ltr") == (side == "after") ? "left" : "right";
4574 var ch = side == "after" ? extent.begin : extent.end - (/\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1);
4575 return coords(ch, prop)[prop]
4576 }
4577
4578 var order = getOrder(lineObj, doc.direction);
4579 iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {
4580 var ltr = dir == "ltr";
4581 var fromPos = coords(from, ltr ? "left" : "right");
4582 var toPos = coords(to - 1, ltr ? "right" : "left");
4583
4584 var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen;
4585 var first = i == 0, last = !order || i == order.length - 1;
4586 if (toPos.top - fromPos.top <= 3) { // Single line
4587 var openLeft = (docLTR ? openStart : openEnd) && first;
4588 var openRight = (docLTR ? openEnd : openStart) && last;
4589 var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left;
4590 var right = openRight ? rightSide : (ltr ? toPos : fromPos).right;
4591 add(left, fromPos.top, right - left, fromPos.bottom);
4592 } else { // Multiple lines
4593 var topLeft, topRight, botLeft, botRight;
4594 if (ltr) {
4595 topLeft = docLTR && openStart && first ? leftSide : fromPos.left;
4596 topRight = docLTR ? rightSide : wrapX(from, dir, "before");
4597 botLeft = docLTR ? leftSide : wrapX(to, dir, "after");
4598 botRight = docLTR && openEnd && last ? rightSide : toPos.right;
4599 } else {
4600 topLeft = !docLTR ? leftSide : wrapX(from, dir, "before");
4601 topRight = !docLTR && openStart && first ? rightSide : fromPos.right;
4602 botLeft = !docLTR && openEnd && last ? leftSide : toPos.left;
4603 botRight = !docLTR ? rightSide : wrapX(to, dir, "after");
4604 }
4605 add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom);
4606 if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top); }
4607 add(botLeft, toPos.top, botRight - botLeft, toPos.bottom);
4608 }
4609
4610 if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos; }
4611 if (cmpCoords(toPos, start) < 0) { start = toPos; }
4612 if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos; }
4613 if (cmpCoords(toPos, end) < 0) { end = toPos; }
4614 });
4615 return {start: start, end: end}
4616 }
4617
4618 var sFrom = range$$1.from(), sTo = range$$1.to();
4619 if (sFrom.line == sTo.line) {
4620 drawForLine(sFrom.line, sFrom.ch, sTo.ch);
4621 } else {
4622 var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
4623 var singleVLine = visualLine(fromLine) == visualLine(toLine);
4624 var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
4625 var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
4626 if (singleVLine) {
4627 if (leftEnd.top < rightStart.top - 2) {
4628 add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
4629 add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
4630 } else {
4631 add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
4632 }
4633 }
4634 if (leftEnd.bottom < rightStart.top)
4635 { add(leftSide, leftEnd.bottom, null, rightStart.top); }
4636 }
4637
4638 output.appendChild(fragment);
4639 }
4640
4641 // Cursor-blinking
4642 function restartBlink(cm) {
4643 if (!cm.state.focused) { return }
4644 var display = cm.display;
4645 clearInterval(display.blinker);
4646 var on = true;
4647 display.cursorDiv.style.visibility = "";
4648 if (cm.options.cursorBlinkRate > 0)
4649 { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; },
4650 cm.options.cursorBlinkRate); }
4651 else if (cm.options.cursorBlinkRate < 0)
4652 { display.cursorDiv.style.visibility = "hidden"; }
4653 }
4654
4655 function ensureFocus(cm) {
4656 if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
4657 }
4658
4659 function delayBlurEvent(cm) {
4660 cm.state.delayingBlurEvent = true;
4661 setTimeout(function () { if (cm.state.delayingBlurEvent) {
4662 cm.state.delayingBlurEvent = false;
4663 onBlur(cm);
4664 } }, 100);
4665 }
4666
4667 function onFocus(cm, e) {
4668 if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; }
4669
4670 if (cm.options.readOnly == "nocursor") { return }
4671 if (!cm.state.focused) {
4672 signal(cm, "focus", cm, e);
4673 cm.state.focused = true;
4674 addClass(cm.display.wrapper, "CodeMirror-focused");
4675 // This test prevents this from firing when a context
4676 // menu is closed (since the input reset would kill the
4677 // select-all detection hack)
4678 if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
4679 cm.display.input.reset();
4680 if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730
4681 }
4682 cm.display.input.receivedFocus();
4683 }
4684 restartBlink(cm);
4685 }
4686 function onBlur(cm, e) {
4687 if (cm.state.delayingBlurEvent) { return }
4688
4689 if (cm.state.focused) {
4690 signal(cm, "blur", cm, e);
4691 cm.state.focused = false;
4692 rmClass(cm.display.wrapper, "CodeMirror-focused");
4693 }
4694 clearInterval(cm.display.blinker);
4695 setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false; } }, 150);
4696 }
4697
4698 // Read the actual heights of the rendered lines, and update their
4699 // stored heights to match.
4700 function updateHeightsInViewport(cm) {
4701 var display = cm.display;
4702 var prevBottom = display.lineDiv.offsetTop;
4703 for (var i = 0; i < display.view.length; i++) {
4704 var cur = display.view[i], height = (void 0);
4705 if (cur.hidden) { continue }
4706 if (ie && ie_version < 8) {
4707 var bot = cur.node.offsetTop + cur.node.offsetHeight;
4708 height = bot - prevBottom;
4709 prevBottom = bot;
4710 } else {
4711 var box = cur.node.getBoundingClientRect();
4712 height = box.bottom - box.top;
4713 }
4714 var diff = cur.line.height - height;
4715 if (height < 2) { height = textHeight(display); }
4716 if (diff > .005 || diff < -.005) {
4717 updateLineHeight(cur.line, height);
4718 updateWidgetHeight(cur.line);
4719 if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
4720 { updateWidgetHeight(cur.rest[j]); } }
4721 }
4722 }
4723 }
4724
4725 // Read and store the height of line widgets associated with the
4726 // given line.
4727 function updateWidgetHeight(line) {
4728 if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) {
4729 var w = line.widgets[i], parent = w.node.parentNode;
4730 if (parent) { w.height = parent.offsetHeight; }
4731 } }
4732 }
4733
4734 // Compute the lines that are visible in a given viewport (defaults
4735 // the the current scroll position). viewport may contain top,
4736 // height, and ensure (see op.scrollToPos) properties.
4737 function visibleLines(display, doc, viewport) {
4738 var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
4739 top = Math.floor(top - paddingTop(display));
4740 var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
4741
4742 var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
4743 // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
4744 // forces those lines into the viewport (if possible).
4745 if (viewport && viewport.ensure) {
4746 var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
4747 if (ensureFrom < from) {
4748 from = ensureFrom;
4749 to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
4750 } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
4751 from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
4752 to = ensureTo;
4753 }
4754 }
4755 return {from: from, to: Math.max(to, from + 1)}
4756 }
4757
4758 // Re-align line numbers and gutter marks to compensate for
4759 // horizontal scrolling.
4760 function alignHorizontally(cm) {
4761 var display = cm.display, view = display.view;
4762 if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
4763 var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
4764 var gutterW = display.gutters.offsetWidth, left = comp + "px";
4765 for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {
4766 if (cm.options.fixedGutter) {
4767 if (view[i].gutter)
4768 { view[i].gutter.style.left = left; }
4769 if (view[i].gutterBackground)
4770 { view[i].gutterBackground.style.left = left; }
4771 }
4772 var align = view[i].alignable;
4773 if (align) { for (var j = 0; j < align.length; j++)
4774 { align[j].style.left = left; } }
4775 } }
4776 if (cm.options.fixedGutter)
4777 { display.gutters.style.left = (comp + gutterW) + "px"; }
4778 }
4779
4780 // Used to ensure that the line number gutter is still the right
4781 // size for the current document size. Returns true when an update
4782 // is needed.
4783 function maybeUpdateLineNumberWidth(cm) {
4784 if (!cm.options.lineNumbers) { return false }
4785 var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
4786 if (last.length != display.lineNumChars) {
4787 var test = display.measure.appendChild(elt("div", [elt("div", last)],
4788 "CodeMirror-linenumber CodeMirror-gutter-elt"));
4789 var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
4790 display.lineGutter.style.width = "";
4791 display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
4792 display.lineNumWidth = display.lineNumInnerWidth + padding;
4793 display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
4794 display.lineGutter.style.width = display.lineNumWidth + "px";
4795 updateGutterSpace(cm);
4796 return true
4797 }
4798 return false
4799 }
4800
4801 // SCROLLING THINGS INTO VIEW
4802
4803 // If an editor sits on the top or bottom of the window, partially
4804 // scrolled out of view, this ensures that the cursor is visible.
4805 function maybeScrollWindow(cm, rect) {
4806 if (signalDOMEvent(cm, "scrollCursorIntoView")) { return }
4807
4808 var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
4809 if (rect.top + box.top < 0) { doScroll = true; }
4810 else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; }
4811 if (doScroll != null && !phantom) {
4812 var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n top: " + (rect.top - display.viewOffset - paddingTop(cm.display)) + "px;\n height: " + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + "px;\n left: " + (rect.left) + "px; width: " + (Math.max(2, rect.right - rect.left)) + "px;"));
4813 cm.display.lineSpace.appendChild(scrollNode);
4814 scrollNode.scrollIntoView(doScroll);
4815 cm.display.lineSpace.removeChild(scrollNode);
4816 }
4817 }
4818
4819 // Scroll a given position into view (immediately), verifying that
4820 // it actually became visible (as line heights are accurately
4821 // measured, the position of something may 'drift' during drawing).
4822 function scrollPosIntoView(cm, pos, end, margin) {
4823 if (margin == null) { margin = 0; }
4824 var rect;
4825 if (!cm.options.lineWrapping && pos == end) {
4826 // Set pos and end to the cursor positions around the character pos sticks to
4827 // If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch
4828 // If pos == Pos(_, 0, "before"), pos and end are unchanged
4829 pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos;
4830 end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos;
4831 }
4832 for (var limit = 0; limit < 5; limit++) {
4833 var changed = false;
4834 var coords = cursorCoords(cm, pos);
4835 var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
4836 rect = {left: Math.min(coords.left, endCoords.left),
4837 top: Math.min(coords.top, endCoords.top) - margin,
4838 right: Math.max(coords.left, endCoords.left),
4839 bottom: Math.max(coords.bottom, endCoords.bottom) + margin};
4840 var scrollPos = calculateScrollPos(cm, rect);
4841 var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
4842 if (scrollPos.scrollTop != null) {
4843 updateScrollTop(cm, scrollPos.scrollTop);
4844 if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true; }
4845 }
4846 if (scrollPos.scrollLeft != null) {
4847 setScrollLeft(cm, scrollPos.scrollLeft);
4848 if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true; }
4849 }
4850 if (!changed) { break }
4851 }
4852 return rect
4853 }
4854
4855 // Scroll a given set of coordinates into view (immediately).
4856 function scrollIntoView(cm, rect) {
4857 var scrollPos = calculateScrollPos(cm, rect);
4858 if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop); }
4859 if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); }
4860 }
4861
4862 // Calculate a new scroll position needed to scroll the given
4863 // rectangle into view. Returns an object with scrollTop and
4864 // scrollLeft properties. When these are undefined, the
4865 // vertical/horizontal position does not need to be adjusted.
4866 function calculateScrollPos(cm, rect) {
4867 var display = cm.display, snapMargin = textHeight(cm.display);
4868 if (rect.top < 0) { rect.top = 0; }
4869 var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
4870 var screen = displayHeight(cm), result = {};
4871 if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen; }
4872 var docBottom = cm.doc.height + paddingVert(display);
4873 var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin;
4874 if (rect.top < screentop) {
4875 result.scrollTop = atTop ? 0 : rect.top;
4876 } else if (rect.bottom > screentop + screen) {
4877 var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen);
4878 if (newTop != screentop) { result.scrollTop = newTop; }
4879 }
4880
4881 var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
4882 var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
4883 var tooWide = rect.right - rect.left > screenw;
4884 if (tooWide) { rect.right = rect.left + screenw; }
4885 if (rect.left < 10)
4886 { result.scrollLeft = 0; }
4887 else if (rect.left < screenleft)
4888 { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); }
4889 else if (rect.right > screenw + screenleft - 3)
4890 { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }
4891 return result
4892 }
4893
4894 // Store a relative adjustment to the scroll position in the current
4895 // operation (to be applied when the operation finishes).
4896 function addToScrollTop(cm, top) {
4897 if (top == null) { return }
4898 resolveScrollToPos(cm);
4899 cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
4900 }
4901
4902 // Make sure that at the end of the operation the current cursor is
4903 // shown.
4904 function ensureCursorVisible(cm) {
4905 resolveScrollToPos(cm);
4906 var cur = cm.getCursor();
4907 cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin};
4908 }
4909
4910 function scrollToCoords(cm, x, y) {
4911 if (x != null || y != null) { resolveScrollToPos(cm); }
4912 if (x != null) { cm.curOp.scrollLeft = x; }
4913 if (y != null) { cm.curOp.scrollTop = y; }
4914 }
4915
4916 function scrollToRange(cm, range$$1) {
4917 resolveScrollToPos(cm);
4918 cm.curOp.scrollToPos = range$$1;
4919 }
4920
4921 // When an operation has its scrollToPos property set, and another
4922 // scroll action is applied before the end of the operation, this
4923 // 'simulates' scrolling that position into view in a cheap way, so
4924 // that the effect of intermediate scroll commands is not ignored.
4925 function resolveScrollToPos(cm) {
4926 var range$$1 = cm.curOp.scrollToPos;
4927 if (range$$1) {
4928 cm.curOp.scrollToPos = null;
4929 var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to);
4930 scrollToCoordsRange(cm, from, to, range$$1.margin);
4931 }
4932 }
4933
4934 function scrollToCoordsRange(cm, from, to, margin) {
4935 var sPos = calculateScrollPos(cm, {
4936 left: Math.min(from.left, to.left),
4937 top: Math.min(from.top, to.top) - margin,
4938 right: Math.max(from.right, to.right),
4939 bottom: Math.max(from.bottom, to.bottom) + margin
4940 });
4941 scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop);
4942 }
4943
4944 // Sync the scrollable area and scrollbars, ensure the viewport
4945 // covers the visible area.
4946 function updateScrollTop(cm, val) {
4947 if (Math.abs(cm.doc.scrollTop - val) < 2) { return }
4948 if (!gecko) { updateDisplaySimple(cm, {top: val}); }
4949 setScrollTop(cm, val, true);
4950 if (gecko) { updateDisplaySimple(cm); }
4951 startWorker(cm, 100);
4952 }
4953
4954 function setScrollTop(cm, val, forceScroll) {
4955 val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val);
4956 if (cm.display.scroller.scrollTop == val && !forceScroll) { return }
4957 cm.doc.scrollTop = val;
4958 cm.display.scrollbars.setScrollTop(val);
4959 if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val; }
4960 }
4961
4962 // Sync scroller and scrollbar, ensure the gutter elements are
4963 // aligned.
4964 function setScrollLeft(cm, val, isScroller, forceScroll) {
4965 val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
4966 if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }
4967 cm.doc.scrollLeft = val;
4968 alignHorizontally(cm);
4969 if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val; }
4970 cm.display.scrollbars.setScrollLeft(val);
4971 }
4972
4973 // SCROLLBARS
4974
4975 // Prepare DOM reads needed to update the scrollbars. Done in one
4976 // shot to minimize update/measure roundtrips.
4977 function measureForScrollbars(cm) {
4978 var d = cm.display, gutterW = d.gutters.offsetWidth;
4979 var docH = Math.round(cm.doc.height + paddingVert(cm.display));
4980 return {
4981 clientHeight: d.scroller.clientHeight,
4982 viewHeight: d.wrapper.clientHeight,
4983 scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
4984 viewWidth: d.wrapper.clientWidth,
4985 barLeft: cm.options.fixedGutter ? gutterW : 0,
4986 docHeight: docH,
4987 scrollHeight: docH + scrollGap(cm) + d.barHeight,
4988 nativeBarWidth: d.nativeBarWidth,
4989 gutterWidth: gutterW
4990 }
4991 }
4992
4993 var NativeScrollbars = function(place, scroll, cm) {
4994 this.cm = cm;
4995 var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
4996 var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
4997 place(vert); place(horiz);
4998
4999 on(vert, "scroll", function () {
5000 if (vert.clientHeight) { scroll(vert.scrollTop, "vertical"); }
5001 });
5002 on(horiz, "scroll", function () {
5003 if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal"); }
5004 });
5005
5006 this.checkedZeroWidth = false;
5007 // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
5008 if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; }
5009 };
5010
5011 NativeScrollbars.prototype.update = function (measure) {
5012 var needsH = measure.scrollWidth > measure.clientWidth + 1;
5013 var needsV = measure.scrollHeight > measure.clientHeight + 1;
5014 var sWidth = measure.nativeBarWidth;
5015
5016 if (needsV) {
5017 this.vert.style.display = "block";
5018 this.vert.style.bottom = needsH ? sWidth + "px" : "0";
5019 var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
5020 // A bug in IE8 can cause this value to be negative, so guard it.
5021 this.vert.firstChild.style.height =
5022 Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
5023 } else {
5024 this.vert.style.display = "";
5025 this.vert.firstChild.style.height = "0";
5026 }
5027
5028 if (needsH) {
5029 this.horiz.style.display = "block";
5030 this.horiz.style.right = needsV ? sWidth + "px" : "0";
5031 this.horiz.style.left = measure.barLeft + "px";
5032 var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
5033 this.horiz.firstChild.style.width =
5034 Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
5035 } else {
5036 this.horiz.style.display = "";
5037 this.horiz.firstChild.style.width = "0";
5038 }
5039
5040 if (!this.checkedZeroWidth && measure.clientHeight > 0) {
5041 if (sWidth == 0) { this.zeroWidthHack(); }
5042 this.checkedZeroWidth = true;
5043 }
5044
5045 return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
5046 };
5047
5048 NativeScrollbars.prototype.setScrollLeft = function (pos) {
5049 if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos; }
5050 if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz"); }
5051 };
5052
5053 NativeScrollbars.prototype.setScrollTop = function (pos) {
5054 if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos; }
5055 if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, "vert"); }
5056 };
5057
5058 NativeScrollbars.prototype.zeroWidthHack = function () {
5059 var w = mac && !mac_geMountainLion ? "12px" : "18px";
5060 this.horiz.style.height = this.vert.style.width = w;
5061 this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
5062 this.disableHoriz = new Delayed;
5063 this.disableVert = new Delayed;
5064 };
5065
5066 NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) {
5067 bar.style.pointerEvents = "auto";
5068 function maybeDisable() {
5069 // To find out whether the scrollbar is still visible, we
5070 // check whether the element under the pixel in the bottom
5071 // right corner of the scrollbar box is the scrollbar box
5072 // itself (when the bar is still visible) or its filler child
5073 // (when the bar is hidden). If it is still visible, we keep
5074 // it enabled, if it's hidden, we disable pointer events.
5075 var box = bar.getBoundingClientRect();
5076 var elt$$1 = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)
5077 : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1);
5078 if (elt$$1 != bar) { bar.style.pointerEvents = "none"; }
5079 else { delay.set(1000, maybeDisable); }
5080 }
5081 delay.set(1000, maybeDisable);
5082 };
5083
5084 NativeScrollbars.prototype.clear = function () {
5085 var parent = this.horiz.parentNode;
5086 parent.removeChild(this.horiz);
5087 parent.removeChild(this.vert);
5088 };
5089
5090 var NullScrollbars = function () {};
5091
5092 NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} };
5093 NullScrollbars.prototype.setScrollLeft = function () {};
5094 NullScrollbars.prototype.setScrollTop = function () {};
5095 NullScrollbars.prototype.clear = function () {};
5096
5097 function updateScrollbars(cm, measure) {
5098 if (!measure) { measure = measureForScrollbars(cm); }
5099 var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
5100 updateScrollbarsInner(cm, measure);
5101 for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
5102 if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
5103 { updateHeightsInViewport(cm); }
5104 updateScrollbarsInner(cm, measureForScrollbars(cm));
5105 startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
5106 }
5107 }
5108
5109 // Re-synchronize the fake scrollbars with the actual size of the
5110 // content.
5111 function updateScrollbarsInner(cm, measure) {
5112 var d = cm.display;
5113 var sizes = d.scrollbars.update(measure);
5114
5115 d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
5116 d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
5117 d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent";
5118
5119 if (sizes.right && sizes.bottom) {
5120 d.scrollbarFiller.style.display = "block";
5121 d.scrollbarFiller.style.height = sizes.bottom + "px";
5122 d.scrollbarFiller.style.width = sizes.right + "px";
5123 } else { d.scrollbarFiller.style.display = ""; }
5124 if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
5125 d.gutterFiller.style.display = "block";
5126 d.gutterFiller.style.height = sizes.bottom + "px";
5127 d.gutterFiller.style.width = measure.gutterWidth + "px";
5128 } else { d.gutterFiller.style.display = ""; }
5129 }
5130
5131 var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
5132
5133 function initScrollbars(cm) {
5134 if (cm.display.scrollbars) {
5135 cm.display.scrollbars.clear();
5136 if (cm.display.scrollbars.addClass)
5137 { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
5138 }
5139
5140 cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {
5141 cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
5142 // Prevent clicks in the scrollbars from killing focus
5143 on(node, "mousedown", function () {
5144 if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); }
5145 });
5146 node.setAttribute("cm-not-content", "true");
5147 }, function (pos, axis) {
5148 if (axis == "horizontal") { setScrollLeft(cm, pos); }
5149 else { updateScrollTop(cm, pos); }
5150 }, cm);
5151 if (cm.display.scrollbars.addClass)
5152 { addClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
5153 }
5154
5155 // Operations are used to wrap a series of changes to the editor
5156 // state in such a way that each change won't have to update the
5157 // cursor and display (which would be awkward, slow, and
5158 // error-prone). Instead, display updates are batched and then all
5159 // combined and executed at once.
5160
5161 var nextOpId = 0;
5162 // Start a new operation.
5163 function startOperation(cm) {
5164 cm.curOp = {
5165 cm: cm,
5166 viewChanged: false, // Flag that indicates that lines might need to be redrawn
5167 startHeight: cm.doc.height, // Used to detect need to update scrollbar
5168 forceUpdate: false, // Used to force a redraw
5169 updateInput: null, // Whether to reset the input textarea
5170 typing: false, // Whether this reset should be careful to leave existing text (for compositing)
5171 changeObjs: null, // Accumulated changes, for firing change events
5172 cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
5173 cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
5174 selectionChanged: false, // Whether the selection needs to be redrawn
5175 updateMaxLine: false, // Set when the widest line needs to be determined anew
5176 scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
5177 scrollToPos: null, // Used to scroll to a specific position
5178 focus: false,
5179 id: ++nextOpId // Unique ID
5180 };
5181 pushOperation(cm.curOp);
5182 }
5183
5184 // Finish an operation, updating the display and signalling delayed events
5185 function endOperation(cm) {
5186 var op = cm.curOp;
5187 finishOperation(op, function (group) {
5188 for (var i = 0; i < group.ops.length; i++)
5189 { group.ops[i].cm.curOp = null; }
5190 endOperations(group);
5191 });
5192 }
5193
5194 // The DOM updates done when an operation finishes are batched so
5195 // that the minimum number of relayouts are required.
5196 function endOperations(group) {
5197 var ops = group.ops;
5198 for (var i = 0; i < ops.length; i++) // Read DOM
5199 { endOperation_R1(ops[i]); }
5200 for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)
5201 { endOperation_W1(ops[i$1]); }
5202 for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM
5203 { endOperation_R2(ops[i$2]); }
5204 for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)
5205 { endOperation_W2(ops[i$3]); }
5206 for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM
5207 { endOperation_finish(ops[i$4]); }
5208 }
5209
5210 function endOperation_R1(op) {
5211 var cm = op.cm, display = cm.display;
5212 maybeClipScrollbars(cm);
5213 if (op.updateMaxLine) { findMaxLine(cm); }
5214
5215 op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
5216 op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
5217 op.scrollToPos.to.line >= display.viewTo) ||
5218 display.maxLineChanged && cm.options.lineWrapping;
5219 op.update = op.mustUpdate &&
5220 new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
5221 }
5222
5223 function endOperation_W1(op) {
5224 op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
5225 }
5226
5227 function endOperation_R2(op) {
5228 var cm = op.cm, display = cm.display;
5229 if (op.updatedDisplay) { updateHeightsInViewport(cm); }
5230
5231 op.barMeasure = measureForScrollbars(cm);
5232
5233 // If the max line changed since it was last measured, measure it,
5234 // and ensure the document's width matches it.
5235 // updateDisplay_W2 will use these properties to do the actual resizing
5236 if (display.maxLineChanged && !cm.options.lineWrapping) {
5237 op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
5238 cm.display.sizerWidth = op.adjustWidthTo;
5239 op.barMeasure.scrollWidth =
5240 Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
5241 op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
5242 }
5243
5244 if (op.updatedDisplay || op.selectionChanged)
5245 { op.preparedSelection = display.input.prepareSelection(); }
5246 }
5247
5248 function endOperation_W2(op) {
5249 var cm = op.cm;
5250
5251 if (op.adjustWidthTo != null) {
5252 cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
5253 if (op.maxScrollLeft < cm.doc.scrollLeft)
5254 { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); }
5255 cm.display.maxLineChanged = false;
5256 }
5257
5258 var takeFocus = op.focus && op.focus == activeElt();
5259 if (op.preparedSelection)
5260 { cm.display.input.showSelection(op.preparedSelection, takeFocus); }
5261 if (op.updatedDisplay || op.startHeight != cm.doc.height)
5262 { updateScrollbars(cm, op.barMeasure); }
5263 if (op.updatedDisplay)
5264 { setDocumentHeight(cm, op.barMeasure); }
5265
5266 if (op.selectionChanged) { restartBlink(cm); }
5267
5268 if (cm.state.focused && op.updateInput)
5269 { cm.display.input.reset(op.typing); }
5270 if (takeFocus) { ensureFocus(op.cm); }
5271 }
5272
5273 function endOperation_finish(op) {
5274 var cm = op.cm, display = cm.display, doc = cm.doc;
5275
5276 if (op.updatedDisplay) { postUpdateDisplay(cm, op.update); }
5277
5278 // Abort mouse wheel delta measurement, when scrolling explicitly
5279 if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
5280 { display.wheelStartX = display.wheelStartY = null; }
5281
5282 // Propagate the scroll position to the actual DOM scroller
5283 if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll); }
5284
5285 if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true); }
5286 // If we need to scroll a specific position into view, do so.
5287 if (op.scrollToPos) {
5288 var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
5289 clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
5290 maybeScrollWindow(cm, rect);
5291 }
5292
5293 // Fire events for markers that are hidden/unidden by editing or
5294 // undoing
5295 var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
5296 if (hidden) { for (var i = 0; i < hidden.length; ++i)
5297 { if (!hidden[i].lines.length) { signal(hidden[i], "hide"); } } }
5298 if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1)
5299 { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide"); } } }
5300
5301 if (display.wrapper.offsetHeight)
5302 { doc.scrollTop = cm.display.scroller.scrollTop; }
5303
5304 // Fire change events, and delayed event handlers
5305 if (op.changeObjs)
5306 { signal(cm, "changes", cm, op.changeObjs); }
5307 if (op.update)
5308 { op.update.finish(); }
5309 }
5310
5311 // Run the given function in an operation
5312 function runInOp(cm, f) {
5313 if (cm.curOp) { return f() }
5314 startOperation(cm);
5315 try { return f() }
5316 finally { endOperation(cm); }
5317 }
5318 // Wraps a function in an operation. Returns the wrapped function.
5319 function operation(cm, f) {
5320 return function() {
5321 if (cm.curOp) { return f.apply(cm, arguments) }
5322 startOperation(cm);
5323 try { return f.apply(cm, arguments) }
5324 finally { endOperation(cm); }
5325 }
5326 }
5327 // Used to add methods to editor and doc instances, wrapping them in
5328 // operations.
5329 function methodOp(f) {
5330 return function() {
5331 if (this.curOp) { return f.apply(this, arguments) }
5332 startOperation(this);
5333 try { return f.apply(this, arguments) }
5334 finally { endOperation(this); }
5335 }
5336 }
5337 function docMethodOp(f) {
5338 return function() {
5339 var cm = this.cm;
5340 if (!cm || cm.curOp) { return f.apply(this, arguments) }
5341 startOperation(cm);
5342 try { return f.apply(this, arguments) }
5343 finally { endOperation(cm); }
5344 }
5345 }
5346
5347 // Updates the display.view data structure for a given change to the
5348 // document. From and to are in pre-change coordinates. Lendiff is
5349 // the amount of lines added or subtracted by the change. This is
5350 // used for changes that span multiple lines, or change the way
5351 // lines are divided into visual lines. regLineChange (below)
5352 // registers single-line changes.
5353 function regChange(cm, from, to, lendiff) {
5354 if (from == null) { from = cm.doc.first; }
5355 if (to == null) { to = cm.doc.first + cm.doc.size; }
5356 if (!lendiff) { lendiff = 0; }
5357
5358 var display = cm.display;
5359 if (lendiff && to < display.viewTo &&
5360 (display.updateLineNumbers == null || display.updateLineNumbers > from))
5361 { display.updateLineNumbers = from; }
5362
5363 cm.curOp.viewChanged = true;
5364
5365 if (from >= display.viewTo) { // Change after
5366 if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
5367 { resetView(cm); }
5368 } else if (to <= display.viewFrom) { // Change before
5369 if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
5370 resetView(cm);
5371 } else {
5372 display.viewFrom += lendiff;
5373 display.viewTo += lendiff;
5374 }
5375 } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
5376 resetView(cm);
5377 } else if (from <= display.viewFrom) { // Top overlap
5378 var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
5379 if (cut) {
5380 display.view = display.view.slice(cut.index);
5381 display.viewFrom = cut.lineN;
5382 display.viewTo += lendiff;
5383 } else {
5384 resetView(cm);
5385 }
5386 } else if (to >= display.viewTo) { // Bottom overlap
5387 var cut$1 = viewCuttingPoint(cm, from, from, -1);
5388 if (cut$1) {
5389 display.view = display.view.slice(0, cut$1.index);
5390 display.viewTo = cut$1.lineN;
5391 } else {
5392 resetView(cm);
5393 }
5394 } else { // Gap in the middle
5395 var cutTop = viewCuttingPoint(cm, from, from, -1);
5396 var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
5397 if (cutTop && cutBot) {
5398 display.view = display.view.slice(0, cutTop.index)
5399 .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
5400 .concat(display.view.slice(cutBot.index));
5401 display.viewTo += lendiff;
5402 } else {
5403 resetView(cm);
5404 }
5405 }
5406
5407 var ext = display.externalMeasured;
5408 if (ext) {
5409 if (to < ext.lineN)
5410 { ext.lineN += lendiff; }
5411 else if (from < ext.lineN + ext.size)
5412 { display.externalMeasured = null; }
5413 }
5414 }
5415
5416 // Register a change to a single line. Type must be one of "text",
5417 // "gutter", "class", "widget"
5418 function regLineChange(cm, line, type) {
5419 cm.curOp.viewChanged = true;
5420 var display = cm.display, ext = cm.display.externalMeasured;
5421 if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
5422 { display.externalMeasured = null; }
5423
5424 if (line < display.viewFrom || line >= display.viewTo) { return }
5425 var lineView = display.view[findViewIndex(cm, line)];
5426 if (lineView.node == null) { return }
5427 var arr = lineView.changes || (lineView.changes = []);
5428 if (indexOf(arr, type) == -1) { arr.push(type); }
5429 }
5430
5431 // Clear the view.
5432 function resetView(cm) {
5433 cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
5434 cm.display.view = [];
5435 cm.display.viewOffset = 0;
5436 }
5437
5438 function viewCuttingPoint(cm, oldN, newN, dir) {
5439 var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
5440 if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
5441 { return {index: index, lineN: newN} }
5442 var n = cm.display.viewFrom;
5443 for (var i = 0; i < index; i++)
5444 { n += view[i].size; }
5445 if (n != oldN) {
5446 if (dir > 0) {
5447 if (index == view.length - 1) { return null }
5448 diff = (n + view[index].size) - oldN;
5449 index++;
5450 } else {
5451 diff = n - oldN;
5452 }
5453 oldN += diff; newN += diff;
5454 }
5455 while (visualLineNo(cm.doc, newN) != newN) {
5456 if (index == (dir < 0 ? 0 : view.length - 1)) { return null }
5457 newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
5458 index += dir;
5459 }
5460 return {index: index, lineN: newN}
5461 }
5462
5463 // Force the view to cover a given range, adding empty view element
5464 // or clipping off existing ones as needed.
5465 function adjustView(cm, from, to) {
5466 var display = cm.display, view = display.view;
5467 if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
5468 display.view = buildViewArray(cm, from, to);
5469 display.viewFrom = from;
5470 } else {
5471 if (display.viewFrom > from)
5472 { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); }
5473 else if (display.viewFrom < from)
5474 { display.view = display.view.slice(findViewIndex(cm, from)); }
5475 display.viewFrom = from;
5476 if (display.viewTo < to)
5477 { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); }
5478 else if (display.viewTo > to)
5479 { display.view = display.view.slice(0, findViewIndex(cm, to)); }
5480 }
5481 display.viewTo = to;
5482 }
5483
5484 // Count the number of lines in the view whose DOM representation is
5485 // out of date (or nonexistent).
5486 function countDirtyView(cm) {
5487 var view = cm.display.view, dirty = 0;
5488 for (var i = 0; i < view.length; i++) {
5489 var lineView = view[i];
5490 if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }
5491 }
5492 return dirty
5493 }
5494
5495 // HIGHLIGHT WORKER
5496
5497 function startWorker(cm, time) {
5498 if (cm.doc.highlightFrontier < cm.display.viewTo)
5499 { cm.state.highlight.set(time, bind(highlightWorker, cm)); }
5500 }
5501
5502 function highlightWorker(cm) {
5503 var doc = cm.doc;
5504 if (doc.highlightFrontier >= cm.display.viewTo) { return }
5505 var end = +new Date + cm.options.workTime;
5506 var context = getContextBefore(cm, doc.highlightFrontier);
5507 var changedLines = [];
5508
5509 doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {
5510 if (context.line >= cm.display.viewFrom) { // Visible
5511 var oldStyles = line.styles;
5512 var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null;
5513 var highlighted = highlightLine(cm, line, context, true);
5514 if (resetState) { context.state = resetState; }
5515 line.styles = highlighted.styles;
5516 var oldCls = line.styleClasses, newCls = highlighted.classes;
5517 if (newCls) { line.styleClasses = newCls; }
5518 else if (oldCls) { line.styleClasses = null; }
5519 var ischange = !oldStyles || oldStyles.length != line.styles.length ||
5520 oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
5521 for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i]; }
5522 if (ischange) { changedLines.push(context.line); }
5523 line.stateAfter = context.save();
5524 context.nextLine();
5525 } else {
5526 if (line.text.length <= cm.options.maxHighlightLength)
5527 { processLine(cm, line.text, context); }
5528 line.stateAfter = context.line % 5 == 0 ? context.save() : null;
5529 context.nextLine();
5530 }
5531 if (+new Date > end) {
5532 startWorker(cm, cm.options.workDelay);
5533 return true
5534 }
5535 });
5536 doc.highlightFrontier = context.line;
5537 doc.modeFrontier = Math.max(doc.modeFrontier, context.line);
5538 if (changedLines.length) { runInOp(cm, function () {
5539 for (var i = 0; i < changedLines.length; i++)
5540 { regLineChange(cm, changedLines[i], "text"); }
5541 }); }
5542 }
5543
5544 // DISPLAY DRAWING
5545
5546 var DisplayUpdate = function(cm, viewport, force) {
5547 var display = cm.display;
5548
5549 this.viewport = viewport;
5550 // Store some values that we'll need later (but don't want to force a relayout for)
5551 this.visible = visibleLines(display, cm.doc, viewport);
5552 this.editorIsHidden = !display.wrapper.offsetWidth;
5553 this.wrapperHeight = display.wrapper.clientHeight;
5554 this.wrapperWidth = display.wrapper.clientWidth;
5555 this.oldDisplayWidth = displayWidth(cm);
5556 this.force = force;
5557 this.dims = getDimensions(cm);
5558 this.events = [];
5559 };
5560
5561 DisplayUpdate.prototype.signal = function (emitter, type) {
5562 if (hasHandler(emitter, type))
5563 { this.events.push(arguments); }
5564 };
5565 DisplayUpdate.prototype.finish = function () {
5566 var this$1 = this;
5567
5568 for (var i = 0; i < this.events.length; i++)
5569 { signal.apply(null, this$1.events[i]); }
5570 };
5571
5572 function maybeClipScrollbars(cm) {
5573 var display = cm.display;
5574 if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
5575 display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
5576 display.heightForcer.style.height = scrollGap(cm) + "px";
5577 display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
5578 display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
5579 display.scrollbarsClipped = true;
5580 }
5581 }
5582
5583 function selectionSnapshot(cm) {
5584 if (cm.hasFocus()) { return null }
5585 var active = activeElt();
5586 if (!active || !contains(cm.display.lineDiv, active)) { return null }
5587 var result = {activeElt: active};
5588 if (window.getSelection) {
5589 var sel = window.getSelection();
5590 if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) {
5591 result.anchorNode = sel.anchorNode;
5592 result.anchorOffset = sel.anchorOffset;
5593 result.focusNode = sel.focusNode;
5594 result.focusOffset = sel.focusOffset;
5595 }
5596 }
5597 return result
5598 }
5599
5600 function restoreSelection(snapshot) {
5601 if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }
5602 snapshot.activeElt.focus();
5603 if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {
5604 var sel = window.getSelection(), range$$1 = document.createRange();
5605 range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset);
5606 range$$1.collapse(false);
5607 sel.removeAllRanges();
5608 sel.addRange(range$$1);
5609 sel.extend(snapshot.focusNode, snapshot.focusOffset);
5610 }
5611 }
5612
5613 // Does the actual updating of the line display. Bails out
5614 // (returning false) when there is nothing to be done and forced is
5615 // false.
5616 function updateDisplayIfNeeded(cm, update) {
5617 var display = cm.display, doc = cm.doc;
5618
5619 if (update.editorIsHidden) {
5620 resetView(cm);
5621 return false
5622 }
5623
5624 // Bail out if the visible area is already rendered and nothing changed.
5625 if (!update.force &&
5626 update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
5627 (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
5628 display.renderedView == display.view && countDirtyView(cm) == 0)
5629 { return false }
5630
5631 if (maybeUpdateLineNumberWidth(cm)) {
5632 resetView(cm);
5633 update.dims = getDimensions(cm);
5634 }
5635
5636 // Compute a suitable new viewport (from & to)
5637 var end = doc.first + doc.size;
5638 var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
5639 var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
5640 if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom); }
5641 if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo); }
5642 if (sawCollapsedSpans) {
5643 from = visualLineNo(cm.doc, from);
5644 to = visualLineEndNo(cm.doc, to);
5645 }
5646
5647 var different = from != display.viewFrom || to != display.viewTo ||
5648 display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
5649 adjustView(cm, from, to);
5650
5651 display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
5652 // Position the mover div to align with the current scroll position
5653 cm.display.mover.style.top = display.viewOffset + "px";
5654
5655 var toUpdate = countDirtyView(cm);
5656 if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
5657 (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
5658 { return false }
5659
5660 // For big changes, we hide the enclosing element during the
5661 // update, since that speeds up the operations on most browsers.
5662 var selSnapshot = selectionSnapshot(cm);
5663 if (toUpdate > 4) { display.lineDiv.style.display = "none"; }
5664 patchDisplay(cm, display.updateLineNumbers, update.dims);
5665 if (toUpdate > 4) { display.lineDiv.style.display = ""; }
5666 display.renderedView = display.view;
5667 // There might have been a widget with a focused element that got
5668 // hidden or updated, if so re-focus it.
5669 restoreSelection(selSnapshot);
5670
5671 // Prevent selection and cursors from interfering with the scroll
5672 // width and height.
5673 removeChildren(display.cursorDiv);
5674 removeChildren(display.selectionDiv);
5675 display.gutters.style.height = display.sizer.style.minHeight = 0;
5676
5677 if (different) {
5678 display.lastWrapHeight = update.wrapperHeight;
5679 display.lastWrapWidth = update.wrapperWidth;
5680 startWorker(cm, 400);
5681 }
5682
5683 display.updateLineNumbers = null;
5684
5685 return true
5686 }
5687
5688 function postUpdateDisplay(cm, update) {
5689 var viewport = update.viewport;
5690
5691 for (var first = true;; first = false) {
5692 if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
5693 // Clip forced viewport to actual scrollable area.
5694 if (viewport && viewport.top != null)
5695 { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; }
5696 // Updated line heights might result in the drawn area not
5697 // actually covering the viewport. Keep looping until it does.
5698 update.visible = visibleLines(cm.display, cm.doc, viewport);
5699 if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
5700 { break }
5701 }
5702 if (!updateDisplayIfNeeded(cm, update)) { break }
5703 updateHeightsInViewport(cm);
5704 var barMeasure = measureForScrollbars(cm);
5705 updateSelection(cm);
5706 updateScrollbars(cm, barMeasure);
5707 setDocumentHeight(cm, barMeasure);
5708 update.force = false;
5709 }
5710
5711 update.signal(cm, "update", cm);
5712 if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
5713 update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
5714 cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
5715 }
5716 }
5717
5718 function updateDisplaySimple(cm, viewport) {
5719 var update = new DisplayUpdate(cm, viewport);
5720 if (updateDisplayIfNeeded(cm, update)) {
5721 updateHeightsInViewport(cm);
5722 postUpdateDisplay(cm, update);
5723 var barMeasure = measureForScrollbars(cm);
5724 updateSelection(cm);
5725 updateScrollbars(cm, barMeasure);
5726 setDocumentHeight(cm, barMeasure);
5727 update.finish();
5728 }
5729 }
5730
5731 // Sync the actual display DOM structure with display.view, removing
5732 // nodes for lines that are no longer in view, and creating the ones
5733 // that are not there yet, and updating the ones that are out of
5734 // date.
5735 function patchDisplay(cm, updateNumbersFrom, dims) {
5736 var display = cm.display, lineNumbers = cm.options.lineNumbers;
5737 var container = display.lineDiv, cur = container.firstChild;
5738
5739 function rm(node) {
5740 var next = node.nextSibling;
5741 // Works around a throw-scroll bug in OS X Webkit
5742 if (webkit && mac && cm.display.currentWheelTarget == node)
5743 { node.style.display = "none"; }
5744 else
5745 { node.parentNode.removeChild(node); }
5746 return next
5747 }
5748
5749 var view = display.view, lineN = display.viewFrom;
5750 // Loop over the elements in the view, syncing cur (the DOM nodes
5751 // in display.lineDiv) with the view as we go.
5752 for (var i = 0; i < view.length; i++) {
5753 var lineView = view[i];
5754 if (lineView.hidden) {
5755 } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
5756 var node = buildLineElement(cm, lineView, lineN, dims);
5757 container.insertBefore(node, cur);
5758 } else { // Already drawn
5759 while (cur != lineView.node) { cur = rm(cur); }
5760 var updateNumber = lineNumbers && updateNumbersFrom != null &&
5761 updateNumbersFrom <= lineN && lineView.lineNumber;
5762 if (lineView.changes) {
5763 if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false; }
5764 updateLineForChanges(cm, lineView, lineN, dims);
5765 }
5766 if (updateNumber) {
5767 removeChildren(lineView.lineNumber);
5768 lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
5769 }
5770 cur = lineView.node.nextSibling;
5771 }
5772 lineN += lineView.size;
5773 }
5774 while (cur) { cur = rm(cur); }
5775 }
5776
5777 function updateGutterSpace(cm) {
5778 var width = cm.display.gutters.offsetWidth;
5779 cm.display.sizer.style.marginLeft = width + "px";
5780 }
5781
5782 function setDocumentHeight(cm, measure) {
5783 cm.display.sizer.style.minHeight = measure.docHeight + "px";
5784 cm.display.heightForcer.style.top = measure.docHeight + "px";
5785 cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
5786 }
5787
5788 // Rebuild the gutter elements, ensure the margin to the left of the
5789 // code matches their width.
5790 function updateGutters(cm) {
5791 var gutters = cm.display.gutters, specs = cm.options.gutters;
5792 removeChildren(gutters);
5793 var i = 0;
5794 for (; i < specs.length; ++i) {
5795 var gutterClass = specs[i];
5796 var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
5797 if (gutterClass == "CodeMirror-linenumbers") {
5798 cm.display.lineGutter = gElt;
5799 gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
5800 }
5801 }
5802 gutters.style.display = i ? "" : "none";
5803 updateGutterSpace(cm);
5804 }
5805
5806 // Make sure the gutters options contains the element
5807 // "CodeMirror-linenumbers" when the lineNumbers option is true.
5808 function setGuttersForLineNumbers(options) {
5809 var found = indexOf(options.gutters, "CodeMirror-linenumbers");
5810 if (found == -1 && options.lineNumbers) {
5811 options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
5812 } else if (found > -1 && !options.lineNumbers) {
5813 options.gutters = options.gutters.slice(0);
5814 options.gutters.splice(found, 1);
5815 }
5816 }
5817
5818 // Since the delta values reported on mouse wheel events are
5819 // unstandardized between browsers and even browser versions, and
5820 // generally horribly unpredictable, this code starts by measuring
5821 // the scroll effect that the first few mouse wheel events have,
5822 // and, from that, detects the way it can convert deltas to pixel
5823 // offsets afterwards.
5824 //
5825 // The reason we want to know the amount a wheel event will scroll
5826 // is that it gives us a chance to update the display before the
5827 // actual scrolling happens, reducing flickering.
5828
5829 var wheelSamples = 0;
5830 var wheelPixelsPerUnit = null;
5831 // Fill in a browser-detected starting value on browsers where we
5832 // know one. These don't have to be accurate -- the result of them
5833 // being wrong would just be a slight flicker on the first wheel
5834 // scroll (if it is large enough).
5835 if (ie) { wheelPixelsPerUnit = -.53; }
5836 else if (gecko) { wheelPixelsPerUnit = 15; }
5837 else if (chrome) { wheelPixelsPerUnit = -.7; }
5838 else if (safari) { wheelPixelsPerUnit = -1/3; }
5839
5840 function wheelEventDelta(e) {
5841 var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
5842 if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail; }
5843 if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail; }
5844 else if (dy == null) { dy = e.wheelDelta; }
5845 return {x: dx, y: dy}
5846 }
5847 function wheelEventPixels(e) {
5848 var delta = wheelEventDelta(e);
5849 delta.x *= wheelPixelsPerUnit;
5850 delta.y *= wheelPixelsPerUnit;
5851 return delta
5852 }
5853
5854 function onScrollWheel(cm, e) {
5855 var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
5856
5857 var display = cm.display, scroll = display.scroller;
5858 // Quit if there's nothing to scroll here
5859 var canScrollX = scroll.scrollWidth > scroll.clientWidth;
5860 var canScrollY = scroll.scrollHeight > scroll.clientHeight;
5861 if (!(dx && canScrollX || dy && canScrollY)) { return }
5862
5863 // Webkit browsers on OS X abort momentum scrolls when the target
5864 // of the scroll event is removed from the scrollable element.
5865 // This hack (see related code in patchDisplay) makes sure the
5866 // element is kept around.
5867 if (dy && mac && webkit) {
5868 outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
5869 for (var i = 0; i < view.length; i++) {
5870 if (view[i].node == cur) {
5871 cm.display.currentWheelTarget = cur;
5872 break outer
5873 }
5874 }
5875 }
5876 }
5877
5878 // On some browsers, horizontal scrolling will cause redraws to
5879 // happen before the gutter has been realigned, causing it to
5880 // wriggle around in a most unseemly way. When we have an
5881 // estimated pixels/delta value, we just handle horizontal
5882 // scrolling entirely here. It'll be slightly off from native, but
5883 // better than glitching out.
5884 if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
5885 if (dy && canScrollY)
5886 { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); }
5887 setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit));
5888 // Only prevent default scrolling if vertical scrolling is
5889 // actually possible. Otherwise, it causes vertical scroll
5890 // jitter on OSX trackpads when deltaX is small and deltaY
5891 // is large (issue #3579)
5892 if (!dy || (dy && canScrollY))
5893 { e_preventDefault(e); }
5894 display.wheelStartX = null; // Abort measurement, if in progress
5895 return
5896 }
5897
5898 // 'Project' the visible viewport to cover the area that is being
5899 // scrolled into view (if we know enough to estimate it).
5900 if (dy && wheelPixelsPerUnit != null) {
5901 var pixels = dy * wheelPixelsPerUnit;
5902 var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
5903 if (pixels < 0) { top = Math.max(0, top + pixels - 50); }
5904 else { bot = Math.min(cm.doc.height, bot + pixels + 50); }
5905 updateDisplaySimple(cm, {top: top, bottom: bot});
5906 }
5907
5908 if (wheelSamples < 20) {
5909 if (display.wheelStartX == null) {
5910 display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
5911 display.wheelDX = dx; display.wheelDY = dy;
5912 setTimeout(function () {
5913 if (display.wheelStartX == null) { return }
5914 var movedX = scroll.scrollLeft - display.wheelStartX;
5915 var movedY = scroll.scrollTop - display.wheelStartY;
5916 var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
5917 (movedX && display.wheelDX && movedX / display.wheelDX);
5918 display.wheelStartX = display.wheelStartY = null;
5919 if (!sample) { return }
5920 wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
5921 ++wheelSamples;
5922 }, 200);
5923 } else {
5924 display.wheelDX += dx; display.wheelDY += dy;
5925 }
5926 }
5927 }
5928
5929 // Selection objects are immutable. A new one is created every time
5930 // the selection changes. A selection is one or more non-overlapping
5931 // (and non-touching) ranges, sorted, and an integer that indicates
5932 // which one is the primary selection (the one that's scrolled into
5933 // view, that getCursor returns, etc).
5934 var Selection = function(ranges, primIndex) {
5935 this.ranges = ranges;
5936 this.primIndex = primIndex;
5937 };
5938
5939 Selection.prototype.primary = function () { return this.ranges[this.primIndex] };
5940
5941 Selection.prototype.equals = function (other) {
5942 var this$1 = this;
5943
5944 if (other == this) { return true }
5945 if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }
5946 for (var i = 0; i < this.ranges.length; i++) {
5947 var here = this$1.ranges[i], there = other.ranges[i];
5948 if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false }
5949 }
5950 return true
5951 };
5952
5953 Selection.prototype.deepCopy = function () {
5954 var this$1 = this;
5955
5956 var out = [];
5957 for (var i = 0; i < this.ranges.length; i++)
5958 { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)); }
5959 return new Selection(out, this.primIndex)
5960 };
5961
5962 Selection.prototype.somethingSelected = function () {
5963 var this$1 = this;
5964
5965 for (var i = 0; i < this.ranges.length; i++)
5966 { if (!this$1.ranges[i].empty()) { return true } }
5967 return false
5968 };
5969
5970 Selection.prototype.contains = function (pos, end) {
5971 var this$1 = this;
5972
5973 if (!end) { end = pos; }
5974 for (var i = 0; i < this.ranges.length; i++) {
5975 var range = this$1.ranges[i];
5976 if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
5977 { return i }
5978 }
5979 return -1
5980 };
5981
5982 var Range = function(anchor, head) {
5983 this.anchor = anchor; this.head = head;
5984 };
5985
5986 Range.prototype.from = function () { return minPos(this.anchor, this.head) };
5987 Range.prototype.to = function () { return maxPos(this.anchor, this.head) };
5988 Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch };
5989
5990 // Take an unsorted, potentially overlapping set of ranges, and
5991 // build a selection out of it. 'Consumes' ranges array (modifying
5992 // it).
5993 function normalizeSelection(ranges, primIndex) {
5994 var prim = ranges[primIndex];
5995 ranges.sort(function (a, b) { return cmp(a.from(), b.from()); });
5996 primIndex = indexOf(ranges, prim);
5997 for (var i = 1; i < ranges.length; i++) {
5998 var cur = ranges[i], prev = ranges[i - 1];
5999 if (cmp(prev.to(), cur.from()) >= 0) {
6000 var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
6001 var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
6002 if (i <= primIndex) { --primIndex; }
6003 ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
6004 }
6005 }
6006 return new Selection(ranges, primIndex)
6007 }
6008
6009 function simpleSelection(anchor, head) {
6010 return new Selection([new Range(anchor, head || anchor)], 0)
6011 }
6012
6013 // Compute the position of the end of a change (its 'to' property
6014 // refers to the pre-change end).
6015 function changeEnd(change) {
6016 if (!change.text) { return change.to }
6017 return Pos(change.from.line + change.text.length - 1,
6018 lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0))
6019 }
6020
6021 // Adjust a position to refer to the post-change position of the
6022 // same text, or the end of the change if the change covers it.
6023 function adjustForChange(pos, change) {
6024 if (cmp(pos, change.from) < 0) { return pos }
6025 if (cmp(pos, change.to) <= 0) { return changeEnd(change) }
6026
6027 var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
6028 if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch; }
6029 return Pos(line, ch)
6030 }
6031
6032 function computeSelAfterChange(doc, change) {
6033 var out = [];
6034 for (var i = 0; i < doc.sel.ranges.length; i++) {
6035 var range = doc.sel.ranges[i];
6036 out.push(new Range(adjustForChange(range.anchor, change),
6037 adjustForChange(range.head, change)));
6038 }
6039 return normalizeSelection(out, doc.sel.primIndex)
6040 }
6041
6042 function offsetPos(pos, old, nw) {
6043 if (pos.line == old.line)
6044 { return Pos(nw.line, pos.ch - old.ch + nw.ch) }
6045 else
6046 { return Pos(nw.line + (pos.line - old.line), pos.ch) }
6047 }
6048
6049 // Used by replaceSelections to allow moving the selection to the
6050 // start or around the replaced test. Hint may be "start" or "around".
6051 function computeReplacedSel(doc, changes, hint) {
6052 var out = [];
6053 var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
6054 for (var i = 0; i < changes.length; i++) {
6055 var change = changes[i];
6056 var from = offsetPos(change.from, oldPrev, newPrev);
6057 var to = offsetPos(changeEnd(change), oldPrev, newPrev);
6058 oldPrev = change.to;
6059 newPrev = to;
6060 if (hint == "around") {
6061 var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
6062 out[i] = new Range(inv ? to : from, inv ? from : to);
6063 } else {
6064 out[i] = new Range(from, from);
6065 }
6066 }
6067 return new Selection(out, doc.sel.primIndex)
6068 }
6069
6070 // Used to get the editor into a consistent state again when options change.
6071
6072 function loadMode(cm) {
6073 cm.doc.mode = getMode(cm.options, cm.doc.modeOption);
6074 resetModeState(cm);
6075 }
6076
6077 function resetModeState(cm) {
6078 cm.doc.iter(function (line) {
6079 if (line.stateAfter) { line.stateAfter = null; }
6080 if (line.styles) { line.styles = null; }
6081 });
6082 cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first;
6083 startWorker(cm, 100);
6084 cm.state.modeGen++;
6085 if (cm.curOp) { regChange(cm); }
6086 }
6087
6088 // DOCUMENT DATA STRUCTURE
6089
6090 // By default, updates that start and end at the beginning of a line
6091 // are treated specially, in order to make the association of line
6092 // widgets and marker elements with the text behave more intuitive.
6093 function isWholeLineUpdate(doc, change) {
6094 return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
6095 (!doc.cm || doc.cm.options.wholeLineUpdateBefore)
6096 }
6097
6098 // Perform a change on the document data structure.
6099 function updateDoc(doc, change, markedSpans, estimateHeight$$1) {
6100 function spansFor(n) {return markedSpans ? markedSpans[n] : null}
6101 function update(line, text, spans) {
6102 updateLine(line, text, spans, estimateHeight$$1);
6103 signalLater(line, "change", line, change);
6104 }
6105 function linesFor(start, end) {
6106 var result = [];
6107 for (var i = start; i < end; ++i)
6108 { result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); }
6109 return result
6110 }
6111
6112 var from = change.from, to = change.to, text = change.text;
6113 var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
6114 var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
6115
6116 // Adjust the line structure
6117 if (change.full) {
6118 doc.insert(0, linesFor(0, text.length));
6119 doc.remove(text.length, doc.size - text.length);
6120 } else if (isWholeLineUpdate(doc, change)) {
6121 // This is a whole-line replace. Treated specially to make
6122 // sure line objects move the way they are supposed to.
6123 var added = linesFor(0, text.length - 1);
6124 update(lastLine, lastLine.text, lastSpans);
6125 if (nlines) { doc.remove(from.line, nlines); }
6126 if (added.length) { doc.insert(from.line, added); }
6127 } else if (firstLine == lastLine) {
6128 if (text.length == 1) {
6129 update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
6130 } else {
6131 var added$1 = linesFor(1, text.length - 1);
6132 added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1));
6133 update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
6134 doc.insert(from.line + 1, added$1);
6135 }
6136 } else if (text.length == 1) {
6137 update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
6138 doc.remove(from.line + 1, nlines);
6139 } else {
6140 update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
6141 update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
6142 var added$2 = linesFor(1, text.length - 1);
6143 if (nlines > 1) { doc.remove(from.line + 1, nlines - 1); }
6144 doc.insert(from.line + 1, added$2);
6145 }
6146
6147 signalLater(doc, "change", doc, change);
6148 }
6149
6150 // Call f for all linked documents.
6151 function linkedDocs(doc, f, sharedHistOnly) {
6152 function propagate(doc, skip, sharedHist) {
6153 if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) {
6154 var rel = doc.linked[i];
6155 if (rel.doc == skip) { continue }
6156 var shared = sharedHist && rel.sharedHist;
6157 if (sharedHistOnly && !shared) { continue }
6158 f(rel.doc, shared);
6159 propagate(rel.doc, doc, shared);
6160 } }
6161 }
6162 propagate(doc, null, true);
6163 }
6164
6165 // Attach a document to an editor.
6166 function attachDoc(cm, doc) {
6167 if (doc.cm) { throw new Error("This document is already in use.") }
6168 cm.doc = doc;
6169 doc.cm = cm;
6170 estimateLineHeights(cm);
6171 loadMode(cm);
6172 setDirectionClass(cm);
6173 if (!cm.options.lineWrapping) { findMaxLine(cm); }
6174 cm.options.mode = doc.modeOption;
6175 regChange(cm);
6176 }
6177
6178 function setDirectionClass(cm) {
6179 (cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl");
6180 }
6181
6182 function directionChanged(cm) {
6183 runInOp(cm, function () {
6184 setDirectionClass(cm);
6185 regChange(cm);
6186 });
6187 }
6188
6189 function History(startGen) {
6190 // Arrays of change events and selections. Doing something adds an
6191 // event to done and clears undo. Undoing moves events from done
6192 // to undone, redoing moves them in the other direction.
6193 this.done = []; this.undone = [];
6194 this.undoDepth = Infinity;
6195 // Used to track when changes can be merged into a single undo
6196 // event
6197 this.lastModTime = this.lastSelTime = 0;
6198 this.lastOp = this.lastSelOp = null;
6199 this.lastOrigin = this.lastSelOrigin = null;
6200 // Used by the isClean() method
6201 this.generation = this.maxGeneration = startGen || 1;
6202 }
6203
6204 // Create a history change event from an updateDoc-style change
6205 // object.
6206 function historyChangeFromChange(doc, change) {
6207 var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
6208 attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
6209 linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true);
6210 return histChange
6211 }
6212
6213 // Pop all selection events off the end of a history array. Stop at
6214 // a change event.
6215 function clearSelectionEvents(array) {
6216 while (array.length) {
6217 var last = lst(array);
6218 if (last.ranges) { array.pop(); }
6219 else { break }
6220 }
6221 }
6222
6223 // Find the top change event in the history. Pop off selection
6224 // events that are in the way.
6225 function lastChangeEvent(hist, force) {
6226 if (force) {
6227 clearSelectionEvents(hist.done);
6228 return lst(hist.done)
6229 } else if (hist.done.length && !lst(hist.done).ranges) {
6230 return lst(hist.done)
6231 } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
6232 hist.done.pop();
6233 return lst(hist.done)
6234 }
6235 }
6236
6237 // Register a change in the history. Merges changes that are within
6238 // a single operation, or are close together with an origin that
6239 // allows merging (starting with "+") into a single event.
6240 function addChangeToHistory(doc, change, selAfter, opId) {
6241 var hist = doc.history;
6242 hist.undone.length = 0;
6243 var time = +new Date, cur;
6244 var last;
6245
6246 if ((hist.lastOp == opId ||
6247 hist.lastOrigin == change.origin && change.origin &&
6248 ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
6249 change.origin.charAt(0) == "*")) &&
6250 (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
6251 // Merge this change into the last event
6252 last = lst(cur.changes);
6253 if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
6254 // Optimized case for simple insertion -- don't want to add
6255 // new changesets for every character typed
6256 last.to = changeEnd(change);
6257 } else {
6258 // Add new sub-event
6259 cur.changes.push(historyChangeFromChange(doc, change));
6260 }
6261 } else {
6262 // Can not be merged, start a new event.
6263 var before = lst(hist.done);
6264 if (!before || !before.ranges)
6265 { pushSelectionToHistory(doc.sel, hist.done); }
6266 cur = {changes: [historyChangeFromChange(doc, change)],
6267 generation: hist.generation};
6268 hist.done.push(cur);
6269 while (hist.done.length > hist.undoDepth) {
6270 hist.done.shift();
6271 if (!hist.done[0].ranges) { hist.done.shift(); }
6272 }
6273 }
6274 hist.done.push(selAfter);
6275 hist.generation = ++hist.maxGeneration;
6276 hist.lastModTime = hist.lastSelTime = time;
6277 hist.lastOp = hist.lastSelOp = opId;
6278 hist.lastOrigin = hist.lastSelOrigin = change.origin;
6279
6280 if (!last) { signal(doc, "historyAdded"); }
6281 }
6282
6283 function selectionEventCanBeMerged(doc, origin, prev, sel) {
6284 var ch = origin.charAt(0);
6285 return ch == "*" ||
6286 ch == "+" &&
6287 prev.ranges.length == sel.ranges.length &&
6288 prev.somethingSelected() == sel.somethingSelected() &&
6289 new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500)
6290 }
6291
6292 // Called whenever the selection changes, sets the new selection as
6293 // the pending selection in the history, and pushes the old pending
6294 // selection into the 'done' array when it was significantly
6295 // different (in number of selected ranges, emptiness, or time).
6296 function addSelectionToHistory(doc, sel, opId, options) {
6297 var hist = doc.history, origin = options && options.origin;
6298
6299 // A new event is started when the previous origin does not match
6300 // the current, or the origins don't allow matching. Origins
6301 // starting with * are always merged, those starting with + are
6302 // merged when similar and close together in time.
6303 if (opId == hist.lastSelOp ||
6304 (origin && hist.lastSelOrigin == origin &&
6305 (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
6306 selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
6307 { hist.done[hist.done.length - 1] = sel; }
6308 else
6309 { pushSelectionToHistory(sel, hist.done); }
6310
6311 hist.lastSelTime = +new Date;
6312 hist.lastSelOrigin = origin;
6313 hist.lastSelOp = opId;
6314 if (options && options.clearRedo !== false)
6315 { clearSelectionEvents(hist.undone); }
6316 }
6317
6318 function pushSelectionToHistory(sel, dest) {
6319 var top = lst(dest);
6320 if (!(top && top.ranges && top.equals(sel)))
6321 { dest.push(sel); }
6322 }
6323
6324 // Used to store marked span information in the history.
6325 function attachLocalSpans(doc, change, from, to) {
6326 var existing = change["spans_" + doc.id], n = 0;
6327 doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) {
6328 if (line.markedSpans)
6329 { (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; }
6330 ++n;
6331 });
6332 }
6333
6334 // When un/re-doing restores text containing marked spans, those
6335 // that have been explicitly cleared should not be restored.
6336 function removeClearedSpans(spans) {
6337 if (!spans) { return null }
6338 var out;
6339 for (var i = 0; i < spans.length; ++i) {
6340 if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i); } }
6341 else if (out) { out.push(spans[i]); }
6342 }
6343 return !out ? spans : out.length ? out : null
6344 }
6345
6346 // Retrieve and filter the old marked spans stored in a change event.
6347 function getOldSpans(doc, change) {
6348 var found = change["spans_" + doc.id];
6349 if (!found) { return null }
6350 var nw = [];
6351 for (var i = 0; i < change.text.length; ++i)
6352 { nw.push(removeClearedSpans(found[i])); }
6353 return nw
6354 }
6355
6356 // Used for un/re-doing changes from the history. Combines the
6357 // result of computing the existing spans with the set of spans that
6358 // existed in the history (so that deleting around a span and then
6359 // undoing brings back the span).
6360 function mergeOldSpans(doc, change) {
6361 var old = getOldSpans(doc, change);
6362 var stretched = stretchSpansOverChange(doc, change);
6363 if (!old) { return stretched }
6364 if (!stretched) { return old }
6365
6366 for (var i = 0; i < old.length; ++i) {
6367 var oldCur = old[i], stretchCur = stretched[i];
6368 if (oldCur && stretchCur) {
6369 spans: for (var j = 0; j < stretchCur.length; ++j) {
6370 var span = stretchCur[j];
6371 for (var k = 0; k < oldCur.length; ++k)
6372 { if (oldCur[k].marker == span.marker) { continue spans } }
6373 oldCur.push(span);
6374 }
6375 } else if (stretchCur) {
6376 old[i] = stretchCur;
6377 }
6378 }
6379 return old
6380 }
6381
6382 // Used both to provide a JSON-safe object in .getHistory, and, when
6383 // detaching a document, to split the history in two
6384 function copyHistoryArray(events, newGroup, instantiateSel) {
6385 var copy = [];
6386 for (var i = 0; i < events.length; ++i) {
6387 var event = events[i];
6388 if (event.ranges) {
6389 copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
6390 continue
6391 }
6392 var changes = event.changes, newChanges = [];
6393 copy.push({changes: newChanges});
6394 for (var j = 0; j < changes.length; ++j) {
6395 var change = changes[j], m = (void 0);
6396 newChanges.push({from: change.from, to: change.to, text: change.text});
6397 if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) {
6398 if (indexOf(newGroup, Number(m[1])) > -1) {
6399 lst(newChanges)[prop] = change[prop];
6400 delete change[prop];
6401 }
6402 } } }
6403 }
6404 }
6405 return copy
6406 }
6407
6408 // The 'scroll' parameter given to many of these indicated whether
6409 // the new cursor position should be scrolled into view after
6410 // modifying the selection.
6411
6412 // If shift is held or the extend flag is set, extends a range to
6413 // include a given position (and optionally a second position).
6414 // Otherwise, simply returns the range between the given positions.
6415 // Used for cursor motion and such.
6416 function extendRange(range, head, other, extend) {
6417 if (extend) {
6418 var anchor = range.anchor;
6419 if (other) {
6420 var posBefore = cmp(head, anchor) < 0;
6421 if (posBefore != (cmp(other, anchor) < 0)) {
6422 anchor = head;
6423 head = other;
6424 } else if (posBefore != (cmp(head, other) < 0)) {
6425 head = other;
6426 }
6427 }
6428 return new Range(anchor, head)
6429 } else {
6430 return new Range(other || head, head)
6431 }
6432 }
6433
6434 // Extend the primary selection range, discard the rest.
6435 function extendSelection(doc, head, other, options, extend) {
6436 if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend); }
6437 setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options);
6438 }
6439
6440 // Extend all selections (pos is an array of selections with length
6441 // equal the number of selections)
6442 function extendSelections(doc, heads, options) {
6443 var out = [];
6444 var extend = doc.cm && (doc.cm.display.shift || doc.extend);
6445 for (var i = 0; i < doc.sel.ranges.length; i++)
6446 { out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend); }
6447 var newSel = normalizeSelection(out, doc.sel.primIndex);
6448 setSelection(doc, newSel, options);
6449 }
6450
6451 // Updates a single range in the selection.
6452 function replaceOneSelection(doc, i, range, options) {
6453 var ranges = doc.sel.ranges.slice(0);
6454 ranges[i] = range;
6455 setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
6456 }
6457
6458 // Reset the selection to a single range.
6459 function setSimpleSelection(doc, anchor, head, options) {
6460 setSelection(doc, simpleSelection(anchor, head), options);
6461 }
6462
6463 // Give beforeSelectionChange handlers a change to influence a
6464 // selection update.
6465 function filterSelectionChange(doc, sel, options) {
6466 var obj = {
6467 ranges: sel.ranges,
6468 update: function(ranges) {
6469 var this$1 = this;
6470
6471 this.ranges = [];
6472 for (var i = 0; i < ranges.length; i++)
6473 { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
6474 clipPos(doc, ranges[i].head)); }
6475 },
6476 origin: options && options.origin
6477 };
6478 signal(doc, "beforeSelectionChange", doc, obj);
6479 if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj); }
6480 if (obj.ranges != sel.ranges) { return normalizeSelection(obj.ranges, obj.ranges.length - 1) }
6481 else { return sel }
6482 }
6483
6484 function setSelectionReplaceHistory(doc, sel, options) {
6485 var done = doc.history.done, last = lst(done);
6486 if (last && last.ranges) {
6487 done[done.length - 1] = sel;
6488 setSelectionNoUndo(doc, sel, options);
6489 } else {
6490 setSelection(doc, sel, options);
6491 }
6492 }
6493
6494 // Set a new selection.
6495 function setSelection(doc, sel, options) {
6496 setSelectionNoUndo(doc, sel, options);
6497 addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
6498 }
6499
6500 function setSelectionNoUndo(doc, sel, options) {
6501 if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
6502 { sel = filterSelectionChange(doc, sel, options); }
6503
6504 var bias = options && options.bias ||
6505 (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
6506 setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
6507
6508 if (!(options && options.scroll === false) && doc.cm)
6509 { ensureCursorVisible(doc.cm); }
6510 }
6511
6512 function setSelectionInner(doc, sel) {
6513 if (sel.equals(doc.sel)) { return }
6514
6515 doc.sel = sel;
6516
6517 if (doc.cm) {
6518 doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
6519 signalCursorActivity(doc.cm);
6520 }
6521 signalLater(doc, "cursorActivity", doc);
6522 }
6523
6524 // Verify that the selection does not partially select any atomic
6525 // marked ranges.
6526 function reCheckSelection(doc) {
6527 setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false));
6528 }
6529
6530 // Return a selection that does not partially select any atomic
6531 // ranges.
6532 function skipAtomicInSelection(doc, sel, bias, mayClear) {
6533 var out;
6534 for (var i = 0; i < sel.ranges.length; i++) {
6535 var range = sel.ranges[i];
6536 var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
6537 var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
6538 var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
6539 if (out || newAnchor != range.anchor || newHead != range.head) {
6540 if (!out) { out = sel.ranges.slice(0, i); }
6541 out[i] = new Range(newAnchor, newHead);
6542 }
6543 }
6544 return out ? normalizeSelection(out, sel.primIndex) : sel
6545 }
6546
6547 function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
6548 var line = getLine(doc, pos.line);
6549 if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
6550 var sp = line.markedSpans[i], m = sp.marker;
6551 if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
6552 (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
6553 if (mayClear) {
6554 signal(m, "beforeCursorEnter");
6555 if (m.explicitlyCleared) {
6556 if (!line.markedSpans) { break }
6557 else {--i; continue}
6558 }
6559 }
6560 if (!m.atomic) { continue }
6561
6562 if (oldPos) {
6563 var near = m.find(dir < 0 ? 1 : -1), diff = (void 0);
6564 if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)
6565 { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); }
6566 if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
6567 { return skipAtomicInner(doc, near, pos, dir, mayClear) }
6568 }
6569
6570 var far = m.find(dir < 0 ? -1 : 1);
6571 if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)
6572 { far = movePos(doc, far, dir, far.line == pos.line ? line : null); }
6573 return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null
6574 }
6575 } }
6576 return pos
6577 }
6578
6579 // Ensure a given position is not inside an atomic range.
6580 function skipAtomic(doc, pos, oldPos, bias, mayClear) {
6581 var dir = bias || 1;
6582 var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
6583 (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
6584 skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
6585 (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
6586 if (!found) {
6587 doc.cantEdit = true;
6588 return Pos(doc.first, 0)
6589 }
6590 return found
6591 }
6592
6593 function movePos(doc, pos, dir, line) {
6594 if (dir < 0 && pos.ch == 0) {
6595 if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) }
6596 else { return null }
6597 } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
6598 if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) }
6599 else { return null }
6600 } else {
6601 return new Pos(pos.line, pos.ch + dir)
6602 }
6603 }
6604
6605 function selectAll(cm) {
6606 cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);
6607 }
6608
6609 // UPDATING
6610
6611 // Allow "beforeChange" event handlers to influence a change
6612 function filterChange(doc, change, update) {
6613 var obj = {
6614 canceled: false,
6615 from: change.from,
6616 to: change.to,
6617 text: change.text,
6618 origin: change.origin,
6619 cancel: function () { return obj.canceled = true; }
6620 };
6621 if (update) { obj.update = function (from, to, text, origin) {
6622 if (from) { obj.from = clipPos(doc, from); }
6623 if (to) { obj.to = clipPos(doc, to); }
6624 if (text) { obj.text = text; }
6625 if (origin !== undefined) { obj.origin = origin; }
6626 }; }
6627 signal(doc, "beforeChange", doc, obj);
6628 if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj); }
6629
6630 if (obj.canceled) { return null }
6631 return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}
6632 }
6633
6634 // Apply a change to a document, and add it to the document's
6635 // history, and propagating it to all linked documents.
6636 function makeChange(doc, change, ignoreReadOnly) {
6637 if (doc.cm) {
6638 if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) }
6639 if (doc.cm.state.suppressEdits) { return }
6640 }
6641
6642 if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
6643 change = filterChange(doc, change, true);
6644 if (!change) { return }
6645 }
6646
6647 // Possibly split or suppress the update based on the presence
6648 // of read-only spans in its range.
6649 var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
6650 if (split) {
6651 for (var i = split.length - 1; i >= 0; --i)
6652 { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}); }
6653 } else {
6654 makeChangeInner(doc, change);
6655 }
6656 }
6657
6658 function makeChangeInner(doc, change) {
6659 if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return }
6660 var selAfter = computeSelAfterChange(doc, change);
6661 addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
6662
6663 makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
6664 var rebased = [];
6665
6666 linkedDocs(doc, function (doc, sharedHist) {
6667 if (!sharedHist && indexOf(rebased, doc.history) == -1) {
6668 rebaseHist(doc.history, change);
6669 rebased.push(doc.history);
6670 }
6671 makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
6672 });
6673 }
6674
6675 // Revert a change stored in a document's history.
6676 function makeChangeFromHistory(doc, type, allowSelectionOnly) {
6677 if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) { return }
6678
6679 var hist = doc.history, event, selAfter = doc.sel;
6680 var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
6681
6682 // Verify that there is a useable event (so that ctrl-z won't
6683 // needlessly clear selection events)
6684 var i = 0;
6685 for (; i < source.length; i++) {
6686 event = source[i];
6687 if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
6688 { break }
6689 }
6690 if (i == source.length) { return }
6691 hist.lastOrigin = hist.lastSelOrigin = null;
6692
6693 for (;;) {
6694 event = source.pop();
6695 if (event.ranges) {
6696 pushSelectionToHistory(event, dest);
6697 if (allowSelectionOnly && !event.equals(doc.sel)) {
6698 setSelection(doc, event, {clearRedo: false});
6699 return
6700 }
6701 selAfter = event;
6702 }
6703 else { break }
6704 }
6705
6706 // Build up a reverse change object to add to the opposite history
6707 // stack (redo when undoing, and vice versa).
6708 var antiChanges = [];
6709 pushSelectionToHistory(selAfter, dest);
6710 dest.push({changes: antiChanges, generation: hist.generation});
6711 hist.generation = event.generation || ++hist.maxGeneration;
6712
6713 var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
6714
6715 var loop = function ( i ) {
6716 var change = event.changes[i];
6717 change.origin = type;
6718 if (filter && !filterChange(doc, change, false)) {
6719 source.length = 0;
6720 return {}
6721 }
6722
6723 antiChanges.push(historyChangeFromChange(doc, change));
6724
6725 var after = i ? computeSelAfterChange(doc, change) : lst(source);
6726 makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
6727 if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); }
6728 var rebased = [];
6729
6730 // Propagate to the linked documents
6731 linkedDocs(doc, function (doc, sharedHist) {
6732 if (!sharedHist && indexOf(rebased, doc.history) == -1) {
6733 rebaseHist(doc.history, change);
6734 rebased.push(doc.history);
6735 }
6736 makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
6737 });
6738 };
6739
6740 for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) {
6741 var returned = loop( i$1 );
6742
6743 if ( returned ) return returned.v;
6744 }
6745 }
6746
6747 // Sub-views need their line numbers shifted when text is added
6748 // above or below them in the parent document.
6749 function shiftDoc(doc, distance) {
6750 if (distance == 0) { return }
6751 doc.first += distance;
6752 doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range(
6753 Pos(range.anchor.line + distance, range.anchor.ch),
6754 Pos(range.head.line + distance, range.head.ch)
6755 ); }), doc.sel.primIndex);
6756 if (doc.cm) {
6757 regChange(doc.cm, doc.first, doc.first - distance, distance);
6758 for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
6759 { regLineChange(doc.cm, l, "gutter"); }
6760 }
6761 }
6762
6763 // More lower-level change function, handling only a single document
6764 // (not linked ones).
6765 function makeChangeSingleDoc(doc, change, selAfter, spans) {
6766 if (doc.cm && !doc.cm.curOp)
6767 { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) }
6768
6769 if (change.to.line < doc.first) {
6770 shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
6771 return
6772 }
6773 if (change.from.line > doc.lastLine()) { return }
6774
6775 // Clip the change to the size of this doc
6776 if (change.from.line < doc.first) {
6777 var shift = change.text.length - 1 - (doc.first - change.from.line);
6778 shiftDoc(doc, shift);
6779 change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
6780 text: [lst(change.text)], origin: change.origin};
6781 }
6782 var last = doc.lastLine();
6783 if (change.to.line > last) {
6784 change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
6785 text: [change.text[0]], origin: change.origin};
6786 }
6787
6788 change.removed = getBetween(doc, change.from, change.to);
6789
6790 if (!selAfter) { selAfter = computeSelAfterChange(doc, change); }
6791 if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); }
6792 else { updateDoc(doc, change, spans); }
6793 setSelectionNoUndo(doc, selAfter, sel_dontScroll);
6794 }
6795
6796 // Handle the interaction of a change to a document with the editor
6797 // that this document is part of.
6798 function makeChangeSingleDocInEditor(cm, change, spans) {
6799 var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
6800
6801 var recomputeMaxLength = false, checkWidthStart = from.line;
6802 if (!cm.options.lineWrapping) {
6803 checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
6804 doc.iter(checkWidthStart, to.line + 1, function (line) {
6805 if (line == display.maxLine) {
6806 recomputeMaxLength = true;
6807 return true
6808 }
6809 });
6810 }
6811
6812 if (doc.sel.contains(change.from, change.to) > -1)
6813 { signalCursorActivity(cm); }
6814
6815 updateDoc(doc, change, spans, estimateHeight(cm));
6816
6817 if (!cm.options.lineWrapping) {
6818 doc.iter(checkWidthStart, from.line + change.text.length, function (line) {
6819 var len = lineLength(line);
6820 if (len > display.maxLineLength) {
6821 display.maxLine = line;
6822 display.maxLineLength = len;
6823 display.maxLineChanged = true;
6824 recomputeMaxLength = false;
6825 }
6826 });
6827 if (recomputeMaxLength) { cm.curOp.updateMaxLine = true; }
6828 }
6829
6830 retreatFrontier(doc, from.line);
6831 startWorker(cm, 400);
6832
6833 var lendiff = change.text.length - (to.line - from.line) - 1;
6834 // Remember that these lines changed, for updating the display
6835 if (change.full)
6836 { regChange(cm); }
6837 else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
6838 { regLineChange(cm, from.line, "text"); }
6839 else
6840 { regChange(cm, from.line, to.line + 1, lendiff); }
6841
6842 var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
6843 if (changeHandler || changesHandler) {
6844 var obj = {
6845 from: from, to: to,
6846 text: change.text,
6847 removed: change.removed,
6848 origin: change.origin
6849 };
6850 if (changeHandler) { signalLater(cm, "change", cm, obj); }
6851 if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); }
6852 }
6853 cm.display.selForContextMenu = null;
6854 }
6855
6856 function replaceRange(doc, code, from, to, origin) {
6857 if (!to) { to = from; }
6858 if (cmp(to, from) < 0) { var assign;
6859 (assign = [to, from], from = assign[0], to = assign[1], assign); }
6860 if (typeof code == "string") { code = doc.splitLines(code); }
6861 makeChange(doc, {from: from, to: to, text: code, origin: origin});
6862 }
6863
6864 // Rebasing/resetting history to deal with externally-sourced changes
6865
6866 function rebaseHistSelSingle(pos, from, to, diff) {
6867 if (to < pos.line) {
6868 pos.line += diff;
6869 } else if (from < pos.line) {
6870 pos.line = from;
6871 pos.ch = 0;
6872 }
6873 }
6874
6875 // Tries to rebase an array of history events given a change in the
6876 // document. If the change touches the same lines as the event, the
6877 // event, and everything 'behind' it, is discarded. If the change is
6878 // before the event, the event's positions are updated. Uses a
6879 // copy-on-write scheme for the positions, to avoid having to
6880 // reallocate them all on every rebase, but also avoid problems with
6881 // shared position objects being unsafely updated.
6882 function rebaseHistArray(array, from, to, diff) {
6883 for (var i = 0; i < array.length; ++i) {
6884 var sub = array[i], ok = true;
6885 if (sub.ranges) {
6886 if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
6887 for (var j = 0; j < sub.ranges.length; j++) {
6888 rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
6889 rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
6890 }
6891 continue
6892 }
6893 for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) {
6894 var cur = sub.changes[j$1];
6895 if (to < cur.from.line) {
6896 cur.from = Pos(cur.from.line + diff, cur.from.ch);
6897 cur.to = Pos(cur.to.line + diff, cur.to.ch);
6898 } else if (from <= cur.to.line) {
6899 ok = false;
6900 break
6901 }
6902 }
6903 if (!ok) {
6904 array.splice(0, i + 1);
6905 i = 0;
6906 }
6907 }
6908 }
6909
6910 function rebaseHist(hist, change) {
6911 var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
6912 rebaseHistArray(hist.done, from, to, diff);
6913 rebaseHistArray(hist.undone, from, to, diff);
6914 }
6915
6916 // Utility for applying a change to a line by handle or number,
6917 // returning the number and optionally registering the line as
6918 // changed.
6919 function changeLine(doc, handle, changeType, op) {
6920 var no = handle, line = handle;
6921 if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)); }
6922 else { no = lineNo(handle); }
6923 if (no == null) { return null }
6924 if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType); }
6925 return line
6926 }
6927
6928 // The document is represented as a BTree consisting of leaves, with
6929 // chunk of lines in them, and branches, with up to ten leaves or
6930 // other branch nodes below them. The top node is always a branch
6931 // node, and is the document object itself (meaning it has
6932 // additional methods and properties).
6933 //
6934 // All nodes have parent links. The tree is used both to go from
6935 // line numbers to line objects, and to go from objects to numbers.
6936 // It also indexes by height, and is used to convert between height
6937 // and line object, and to find the total height of the document.
6938 //
6939 // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
6940
6941 function LeafChunk(lines) {
6942 var this$1 = this;
6943
6944 this.lines = lines;
6945 this.parent = null;
6946 var height = 0;
6947 for (var i = 0; i < lines.length; ++i) {
6948 lines[i].parent = this$1;
6949 height += lines[i].height;
6950 }
6951 this.height = height;
6952 }
6953
6954 LeafChunk.prototype = {
6955 chunkSize: function chunkSize() { return this.lines.length },
6956
6957 // Remove the n lines at offset 'at'.
6958 removeInner: function removeInner(at, n) {
6959 var this$1 = this;
6960
6961 for (var i = at, e = at + n; i < e; ++i) {
6962 var line = this$1.lines[i];
6963 this$1.height -= line.height;
6964 cleanUpLine(line);
6965 signalLater(line, "delete");
6966 }
6967 this.lines.splice(at, n);
6968 },
6969
6970 // Helper used to collapse a small branch into a single leaf.
6971 collapse: function collapse(lines) {
6972 lines.push.apply(lines, this.lines);
6973 },
6974
6975 // Insert the given array of lines at offset 'at', count them as
6976 // having the given height.
6977 insertInner: function insertInner(at, lines, height) {
6978 var this$1 = this;
6979
6980 this.height += height;
6981 this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
6982 for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1; }
6983 },
6984
6985 // Used to iterate over a part of the tree.
6986 iterN: function iterN(at, n, op) {
6987 var this$1 = this;
6988
6989 for (var e = at + n; at < e; ++at)
6990 { if (op(this$1.lines[at])) { return true } }
6991 }
6992 };
6993
6994 function BranchChunk(children) {
6995 var this$1 = this;
6996
6997 this.children = children;
6998 var size = 0, height = 0;
6999 for (var i = 0; i < children.length; ++i) {
7000 var ch = children[i];
7001 size += ch.chunkSize(); height += ch.height;
7002 ch.parent = this$1;
7003 }
7004 this.size = size;
7005 this.height = height;
7006 this.parent = null;
7007 }
7008
7009 BranchChunk.prototype = {
7010 chunkSize: function chunkSize() { return this.size },
7011
7012 removeInner: function removeInner(at, n) {
7013 var this$1 = this;
7014
7015 this.size -= n;
7016 for (var i = 0; i < this.children.length; ++i) {
7017 var child = this$1.children[i], sz = child.chunkSize();
7018 if (at < sz) {
7019 var rm = Math.min(n, sz - at), oldHeight = child.height;
7020 child.removeInner(at, rm);
7021 this$1.height -= oldHeight - child.height;
7022 if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null; }
7023 if ((n -= rm) == 0) { break }
7024 at = 0;
7025 } else { at -= sz; }
7026 }
7027 // If the result is smaller than 25 lines, ensure that it is a
7028 // single leaf node.
7029 if (this.size - n < 25 &&
7030 (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
7031 var lines = [];
7032 this.collapse(lines);
7033 this.children = [new LeafChunk(lines)];
7034 this.children[0].parent = this;
7035 }
7036 },
7037
7038 collapse: function collapse(lines) {
7039 var this$1 = this;
7040
7041 for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines); }
7042 },
7043
7044 insertInner: function insertInner(at, lines, height) {
7045 var this$1 = this;
7046
7047 this.size += lines.length;
7048 this.height += height;
7049 for (var i = 0; i < this.children.length; ++i) {
7050 var child = this$1.children[i], sz = child.chunkSize();
7051 if (at <= sz) {
7052 child.insertInner(at, lines, height);
7053 if (child.lines && child.lines.length > 50) {
7054 // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.
7055 // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.
7056 var remaining = child.lines.length % 25 + 25;
7057 for (var pos = remaining; pos < child.lines.length;) {
7058 var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));
7059 child.height -= leaf.height;
7060 this$1.children.splice(++i, 0, leaf);
7061 leaf.parent = this$1;
7062 }
7063 child.lines = child.lines.slice(0, remaining);
7064 this$1.maybeSpill();
7065 }
7066 break
7067 }
7068 at -= sz;
7069 }
7070 },
7071
7072 // When a node has grown, check whether it should be split.
7073 maybeSpill: function maybeSpill() {
7074 if (this.children.length <= 10) { return }
7075 var me = this;
7076 do {
7077 var spilled = me.children.splice(me.children.length - 5, 5);
7078 var sibling = new BranchChunk(spilled);
7079 if (!me.parent) { // Become the parent node
7080 var copy = new BranchChunk(me.children);
7081 copy.parent = me;
7082 me.children = [copy, sibling];
7083 me = copy;
7084 } else {
7085 me.size -= sibling.size;
7086 me.height -= sibling.height;
7087 var myIndex = indexOf(me.parent.children, me);
7088 me.parent.children.splice(myIndex + 1, 0, sibling);
7089 }
7090 sibling.parent = me.parent;
7091 } while (me.children.length > 10)
7092 me.parent.maybeSpill();
7093 },
7094
7095 iterN: function iterN(at, n, op) {
7096 var this$1 = this;
7097
7098 for (var i = 0; i < this.children.length; ++i) {
7099 var child = this$1.children[i], sz = child.chunkSize();
7100 if (at < sz) {
7101 var used = Math.min(n, sz - at);
7102 if (child.iterN(at, used, op)) { return true }
7103 if ((n -= used) == 0) { break }
7104 at = 0;
7105 } else { at -= sz; }
7106 }
7107 }
7108 };
7109
7110 // Line widgets are block elements displayed above or below a line.
7111
7112 var LineWidget = function(doc, node, options) {
7113 var this$1 = this;
7114
7115 if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))
7116 { this$1[opt] = options[opt]; } } }
7117 this.doc = doc;
7118 this.node = node;
7119 };
7120
7121 LineWidget.prototype.clear = function () {
7122 var this$1 = this;
7123
7124 var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
7125 if (no == null || !ws) { return }
7126 for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1); } }
7127 if (!ws.length) { line.widgets = null; }
7128 var height = widgetHeight(this);
7129 updateLineHeight(line, Math.max(0, line.height - height));
7130 if (cm) {
7131 runInOp(cm, function () {
7132 adjustScrollWhenAboveVisible(cm, line, -height);
7133 regLineChange(cm, no, "widget");
7134 });
7135 signalLater(cm, "lineWidgetCleared", cm, this, no);
7136 }
7137 };
7138
7139 LineWidget.prototype.changed = function () {
7140 var this$1 = this;
7141
7142 var oldH = this.height, cm = this.doc.cm, line = this.line;
7143 this.height = null;
7144 var diff = widgetHeight(this) - oldH;
7145 if (!diff) { return }
7146 updateLineHeight(line, line.height + diff);
7147 if (cm) {
7148 runInOp(cm, function () {
7149 cm.curOp.forceUpdate = true;
7150 adjustScrollWhenAboveVisible(cm, line, diff);
7151 signalLater(cm, "lineWidgetChanged", cm, this$1, lineNo(line));
7152 });
7153 }
7154 };
7155 eventMixin(LineWidget);
7156
7157 function adjustScrollWhenAboveVisible(cm, line, diff) {
7158 if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
7159 { addToScrollTop(cm, diff); }
7160 }
7161
7162 function addLineWidget(doc, handle, node, options) {
7163 var widget = new LineWidget(doc, node, options);
7164 var cm = doc.cm;
7165 if (cm && widget.noHScroll) { cm.display.alignWidgets = true; }
7166 changeLine(doc, handle, "widget", function (line) {
7167 var widgets = line.widgets || (line.widgets = []);
7168 if (widget.insertAt == null) { widgets.push(widget); }
7169 else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); }
7170 widget.line = line;
7171 if (cm && !lineIsHidden(doc, line)) {
7172 var aboveVisible = heightAtLine(line) < doc.scrollTop;
7173 updateLineHeight(line, line.height + widgetHeight(widget));
7174 if (aboveVisible) { addToScrollTop(cm, widget.height); }
7175 cm.curOp.forceUpdate = true;
7176 }
7177 return true
7178 });
7179 signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle));
7180 return widget
7181 }
7182
7183 // TEXTMARKERS
7184
7185 // Created with markText and setBookmark methods. A TextMarker is a
7186 // handle that can be used to clear or find a marked position in the
7187 // document. Line objects hold arrays (markedSpans) containing
7188 // {from, to, marker} object pointing to such marker objects, and
7189 // indicating that such a marker is present on that line. Multiple
7190 // lines may point to the same marker when it spans across lines.
7191 // The spans will have null for their from/to properties when the
7192 // marker continues beyond the start/end of the line. Markers have
7193 // links back to the lines they currently touch.
7194
7195 // Collapsed markers have unique ids, in order to be able to order
7196 // them, which is needed for uniquely determining an outer marker
7197 // when they overlap (they may nest, but not partially overlap).
7198 var nextMarkerId = 0;
7199
7200 var TextMarker = function(doc, type) {
7201 this.lines = [];
7202 this.type = type;
7203 this.doc = doc;
7204 this.id = ++nextMarkerId;
7205 };
7206
7207 // Clear the marker.
7208 TextMarker.prototype.clear = function () {
7209 var this$1 = this;
7210
7211 if (this.explicitlyCleared) { return }
7212 var cm = this.doc.cm, withOp = cm && !cm.curOp;
7213 if (withOp) { startOperation(cm); }
7214 if (hasHandler(this, "clear")) {
7215 var found = this.find();
7216 if (found) { signalLater(this, "clear", found.from, found.to); }
7217 }
7218 var min = null, max = null;
7219 for (var i = 0; i < this.lines.length; ++i) {
7220 var line = this$1.lines[i];
7221 var span = getMarkedSpanFor(line.markedSpans, this$1);
7222 if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text"); }
7223 else if (cm) {
7224 if (span.to != null) { max = lineNo(line); }
7225 if (span.from != null) { min = lineNo(line); }
7226 }
7227 line.markedSpans = removeMarkedSpan(line.markedSpans, span);
7228 if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm)
7229 { updateLineHeight(line, textHeight(cm.display)); }
7230 }
7231 if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {
7232 var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual);
7233 if (len > cm.display.maxLineLength) {
7234 cm.display.maxLine = visual;
7235 cm.display.maxLineLength = len;
7236 cm.display.maxLineChanged = true;
7237 }
7238 } }
7239
7240 if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1); }
7241 this.lines.length = 0;
7242 this.explicitlyCleared = true;
7243 if (this.atomic && this.doc.cantEdit) {
7244 this.doc.cantEdit = false;
7245 if (cm) { reCheckSelection(cm.doc); }
7246 }
7247 if (cm) { signalLater(cm, "markerCleared", cm, this, min, max); }
7248 if (withOp) { endOperation(cm); }
7249 if (this.parent) { this.parent.clear(); }
7250 };
7251
7252 // Find the position of the marker in the document. Returns a {from,
7253 // to} object by default. Side can be passed to get a specific side
7254 // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
7255 // Pos objects returned contain a line object, rather than a line
7256 // number (used to prevent looking up the same line twice).
7257 TextMarker.prototype.find = function (side, lineObj) {
7258 var this$1 = this;
7259
7260 if (side == null && this.type == "bookmark") { side = 1; }
7261 var from, to;
7262 for (var i = 0; i < this.lines.length; ++i) {
7263 var line = this$1.lines[i];
7264 var span = getMarkedSpanFor(line.markedSpans, this$1);
7265 if (span.from != null) {
7266 from = Pos(lineObj ? line : lineNo(line), span.from);
7267 if (side == -1) { return from }
7268 }
7269 if (span.to != null) {
7270 to = Pos(lineObj ? line : lineNo(line), span.to);
7271 if (side == 1) { return to }
7272 }
7273 }
7274 return from && {from: from, to: to}
7275 };
7276
7277 // Signals that the marker's widget changed, and surrounding layout
7278 // should be recomputed.
7279 TextMarker.prototype.changed = function () {
7280 var this$1 = this;
7281
7282 var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
7283 if (!pos || !cm) { return }
7284 runInOp(cm, function () {
7285 var line = pos.line, lineN = lineNo(pos.line);
7286 var view = findViewForLine(cm, lineN);
7287 if (view) {
7288 clearLineMeasurementCacheFor(view);
7289 cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
7290 }
7291 cm.curOp.updateMaxLine = true;
7292 if (!lineIsHidden(widget.doc, line) && widget.height != null) {
7293 var oldHeight = widget.height;
7294 widget.height = null;
7295 var dHeight = widgetHeight(widget) - oldHeight;
7296 if (dHeight)
7297 { updateLineHeight(line, line.height + dHeight); }
7298 }
7299 signalLater(cm, "markerChanged", cm, this$1);
7300 });
7301 };
7302
7303 TextMarker.prototype.attachLine = function (line) {
7304 if (!this.lines.length && this.doc.cm) {
7305 var op = this.doc.cm.curOp;
7306 if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
7307 { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); }
7308 }
7309 this.lines.push(line);
7310 };
7311
7312 TextMarker.prototype.detachLine = function (line) {
7313 this.lines.splice(indexOf(this.lines, line), 1);
7314 if (!this.lines.length && this.doc.cm) {
7315 var op = this.doc.cm.curOp;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
7316 }
7317 };
7318 eventMixin(TextMarker);
7319
7320 // Create a marker, wire it up to the right lines, and
7321 function markText(doc, from, to, options, type) {
7322 // Shared markers (across linked documents) are handled separately
7323 // (markTextShared will call out to this again, once per
7324 // document).
7325 if (options && options.shared) { return markTextShared(doc, from, to, options, type) }
7326 // Ensure we are in an operation.
7327 if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) }
7328
7329 var marker = new TextMarker(doc, type), diff = cmp(from, to);
7330 if (options) { copyObj(options, marker, false); }
7331 // Don't connect empty markers unless clearWhenEmpty is false
7332 if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
7333 { return marker }
7334 if (marker.replacedWith) {
7335 // Showing up as a widget implies collapsed (widget replaces text)
7336 marker.collapsed = true;
7337 marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget");
7338 if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true"); }
7339 if (options.insertLeft) { marker.widgetNode.insertLeft = true; }
7340 }
7341 if (marker.collapsed) {
7342 if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
7343 from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
7344 { throw new Error("Inserting collapsed marker partially overlapping an existing one") }
7345 seeCollapsedSpans();
7346 }
7347
7348 if (marker.addToHistory)
7349 { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); }
7350
7351 var curLine = from.line, cm = doc.cm, updateMaxLine;
7352 doc.iter(curLine, to.line + 1, function (line) {
7353 if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
7354 { updateMaxLine = true; }
7355 if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); }
7356 addMarkedSpan(line, new MarkedSpan(marker,
7357 curLine == from.line ? from.ch : null,
7358 curLine == to.line ? to.ch : null));
7359 ++curLine;
7360 });
7361 // lineIsHidden depends on the presence of the spans, so needs a second pass
7362 if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) {
7363 if (lineIsHidden(doc, line)) { updateLineHeight(line, 0); }
7364 }); }
7365
7366 if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }); }
7367
7368 if (marker.readOnly) {
7369 seeReadOnlySpans();
7370 if (doc.history.done.length || doc.history.undone.length)
7371 { doc.clearHistory(); }
7372 }
7373 if (marker.collapsed) {
7374 marker.id = ++nextMarkerId;
7375 marker.atomic = true;
7376 }
7377 if (cm) {
7378 // Sync editor state
7379 if (updateMaxLine) { cm.curOp.updateMaxLine = true; }
7380 if (marker.collapsed)
7381 { regChange(cm, from.line, to.line + 1); }
7382 else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
7383 { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text"); } }
7384 if (marker.atomic) { reCheckSelection(cm.doc); }
7385 signalLater(cm, "markerAdded", cm, marker);
7386 }
7387 return marker
7388 }
7389
7390 // SHARED TEXTMARKERS
7391
7392 // A shared marker spans multiple linked documents. It is
7393 // implemented as a meta-marker-object controlling multiple normal
7394 // markers.
7395 var SharedTextMarker = function(markers, primary) {
7396 var this$1 = this;
7397
7398 this.markers = markers;
7399 this.primary = primary;
7400 for (var i = 0; i < markers.length; ++i)
7401 { markers[i].parent = this$1; }
7402 };
7403
7404 SharedTextMarker.prototype.clear = function () {
7405 var this$1 = this;
7406
7407 if (this.explicitlyCleared) { return }
7408 this.explicitlyCleared = true;
7409 for (var i = 0; i < this.markers.length; ++i)
7410 { this$1.markers[i].clear(); }
7411 signalLater(this, "clear");
7412 };
7413
7414 SharedTextMarker.prototype.find = function (side, lineObj) {
7415 return this.primary.find(side, lineObj)
7416 };
7417 eventMixin(SharedTextMarker);
7418
7419 function markTextShared(doc, from, to, options, type) {
7420 options = copyObj(options);
7421 options.shared = false;
7422 var markers = [markText(doc, from, to, options, type)], primary = markers[0];
7423 var widget = options.widgetNode;
7424 linkedDocs(doc, function (doc) {
7425 if (widget) { options.widgetNode = widget.cloneNode(true); }
7426 markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
7427 for (var i = 0; i < doc.linked.length; ++i)
7428 { if (doc.linked[i].isParent) { return } }
7429 primary = lst(markers);
7430 });
7431 return new SharedTextMarker(markers, primary)
7432 }
7433
7434 function findSharedMarkers(doc) {
7435 return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; })
7436 }
7437
7438 function copySharedMarkers(doc, markers) {
7439 for (var i = 0; i < markers.length; i++) {
7440 var marker = markers[i], pos = marker.find();
7441 var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
7442 if (cmp(mFrom, mTo)) {
7443 var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
7444 marker.markers.push(subMark);
7445 subMark.parent = marker;
7446 }
7447 }
7448 }
7449
7450 function detachSharedMarkers(markers) {
7451 var loop = function ( i ) {
7452 var marker = markers[i], linked = [marker.primary.doc];
7453 linkedDocs(marker.primary.doc, function (d) { return linked.push(d); });
7454 for (var j = 0; j < marker.markers.length; j++) {
7455 var subMarker = marker.markers[j];
7456 if (indexOf(linked, subMarker.doc) == -1) {
7457 subMarker.parent = null;
7458 marker.markers.splice(j--, 1);
7459 }
7460 }
7461 };
7462
7463 for (var i = 0; i < markers.length; i++) loop( i );
7464 }
7465
7466 var nextDocId = 0;
7467 var Doc = function(text, mode, firstLine, lineSep, direction) {
7468 if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) }
7469 if (firstLine == null) { firstLine = 0; }
7470
7471 BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
7472 this.first = firstLine;
7473 this.scrollTop = this.scrollLeft = 0;
7474 this.cantEdit = false;
7475 this.cleanGeneration = 1;
7476 this.modeFrontier = this.highlightFrontier = firstLine;
7477 var start = Pos(firstLine, 0);
7478 this.sel = simpleSelection(start);
7479 this.history = new History(null);
7480 this.id = ++nextDocId;
7481 this.modeOption = mode;
7482 this.lineSep = lineSep;
7483 this.direction = (direction == "rtl") ? "rtl" : "ltr";
7484 this.extend = false;
7485
7486 if (typeof text == "string") { text = this.splitLines(text); }
7487 updateDoc(this, {from: start, to: start, text: text});
7488 setSelection(this, simpleSelection(start), sel_dontScroll);
7489 };
7490
7491 Doc.prototype = createObj(BranchChunk.prototype, {
7492 constructor: Doc,
7493 // Iterate over the document. Supports two forms -- with only one
7494 // argument, it calls that for each line in the document. With
7495 // three, it iterates over the range given by the first two (with
7496 // the second being non-inclusive).
7497 iter: function(from, to, op) {
7498 if (op) { this.iterN(from - this.first, to - from, op); }
7499 else { this.iterN(this.first, this.first + this.size, from); }
7500 },
7501
7502 // Non-public interface for adding and removing lines.
7503 insert: function(at, lines) {
7504 var height = 0;
7505 for (var i = 0; i < lines.length; ++i) { height += lines[i].height; }
7506 this.insertInner(at - this.first, lines, height);
7507 },
7508 remove: function(at, n) { this.removeInner(at - this.first, n); },
7509
7510 // From here, the methods are part of the public interface. Most
7511 // are also available from CodeMirror (editor) instances.
7512
7513 getValue: function(lineSep) {
7514 var lines = getLines(this, this.first, this.first + this.size);
7515 if (lineSep === false) { return lines }
7516 return lines.join(lineSep || this.lineSeparator())
7517 },
7518 setValue: docMethodOp(function(code) {
7519 var top = Pos(this.first, 0), last = this.first + this.size - 1;
7520 makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
7521 text: this.splitLines(code), origin: "setValue", full: true}, true);
7522 if (this.cm) { scrollToCoords(this.cm, 0, 0); }
7523 setSelection(this, simpleSelection(top), sel_dontScroll);
7524 }),
7525 replaceRange: function(code, from, to, origin) {
7526 from = clipPos(this, from);
7527 to = to ? clipPos(this, to) : from;
7528 replaceRange(this, code, from, to, origin);
7529 },
7530 getRange: function(from, to, lineSep) {
7531 var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
7532 if (lineSep === false) { return lines }
7533 return lines.join(lineSep || this.lineSeparator())
7534 },
7535
7536 getLine: function(line) {var l = this.getLineHandle(line); return l && l.text},
7537
7538 getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }},
7539 getLineNumber: function(line) {return lineNo(line)},
7540
7541 getLineHandleVisualStart: function(line) {
7542 if (typeof line == "number") { line = getLine(this, line); }
7543 return visualLine(line)
7544 },
7545
7546 lineCount: function() {return this.size},
7547 firstLine: function() {return this.first},
7548 lastLine: function() {return this.first + this.size - 1},
7549
7550 clipPos: function(pos) {return clipPos(this, pos)},
7551
7552 getCursor: function(start) {
7553 var range$$1 = this.sel.primary(), pos;
7554 if (start == null || start == "head") { pos = range$$1.head; }
7555 else if (start == "anchor") { pos = range$$1.anchor; }
7556 else if (start == "end" || start == "to" || start === false) { pos = range$$1.to(); }
7557 else { pos = range$$1.from(); }
7558 return pos
7559 },
7560 listSelections: function() { return this.sel.ranges },
7561 somethingSelected: function() {return this.sel.somethingSelected()},
7562
7563 setCursor: docMethodOp(function(line, ch, options) {
7564 setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
7565 }),
7566 setSelection: docMethodOp(function(anchor, head, options) {
7567 setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
7568 }),
7569 extendSelection: docMethodOp(function(head, other, options) {
7570 extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
7571 }),
7572 extendSelections: docMethodOp(function(heads, options) {
7573 extendSelections(this, clipPosArray(this, heads), options);
7574 }),
7575 extendSelectionsBy: docMethodOp(function(f, options) {
7576 var heads = map(this.sel.ranges, f);
7577 extendSelections(this, clipPosArray(this, heads), options);
7578 }),
7579 setSelections: docMethodOp(function(ranges, primary, options) {
7580 var this$1 = this;
7581
7582 if (!ranges.length) { return }
7583 var out = [];
7584 for (var i = 0; i < ranges.length; i++)
7585 { out[i] = new Range(clipPos(this$1, ranges[i].anchor),
7586 clipPos(this$1, ranges[i].head)); }
7587 if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); }
7588 setSelection(this, normalizeSelection(out, primary), options);
7589 }),
7590 addSelection: docMethodOp(function(anchor, head, options) {
7591 var ranges = this.sel.ranges.slice(0);
7592 ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
7593 setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
7594 }),
7595
7596 getSelection: function(lineSep) {
7597 var this$1 = this;
7598
7599 var ranges = this.sel.ranges, lines;
7600 for (var i = 0; i < ranges.length; i++) {
7601 var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
7602 lines = lines ? lines.concat(sel) : sel;
7603 }
7604 if (lineSep === false) { return lines }
7605 else { return lines.join(lineSep || this.lineSeparator()) }
7606 },
7607 getSelections: function(lineSep) {
7608 var this$1 = this;
7609
7610 var parts = [], ranges = this.sel.ranges;
7611 for (var i = 0; i < ranges.length; i++) {
7612 var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
7613 if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()); }
7614 parts[i] = sel;
7615 }
7616 return parts
7617 },
7618 replaceSelection: function(code, collapse, origin) {
7619 var dup = [];
7620 for (var i = 0; i < this.sel.ranges.length; i++)
7621 { dup[i] = code; }
7622 this.replaceSelections(dup, collapse, origin || "+input");
7623 },
7624 replaceSelections: docMethodOp(function(code, collapse, origin) {
7625 var this$1 = this;
7626
7627 var changes = [], sel = this.sel;
7628 for (var i = 0; i < sel.ranges.length; i++) {
7629 var range$$1 = sel.ranges[i];
7630 changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this$1.splitLines(code[i]), origin: origin};
7631 }
7632 var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
7633 for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)
7634 { makeChange(this$1, changes[i$1]); }
7635 if (newSel) { setSelectionReplaceHistory(this, newSel); }
7636 else if (this.cm) { ensureCursorVisible(this.cm); }
7637 }),
7638 undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
7639 redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
7640 undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
7641 redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
7642
7643 setExtending: function(val) {this.extend = val;},
7644 getExtending: function() {return this.extend},
7645
7646 historySize: function() {
7647 var hist = this.history, done = 0, undone = 0;
7648 for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done; } }
7649 for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }
7650 return {undo: done, redo: undone}
7651 },
7652 clearHistory: function() {this.history = new History(this.history.maxGeneration);},
7653
7654 markClean: function() {
7655 this.cleanGeneration = this.changeGeneration(true);
7656 },
7657 changeGeneration: function(forceSplit) {
7658 if (forceSplit)
7659 { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; }
7660 return this.history.generation
7661 },
7662 isClean: function (gen) {
7663 return this.history.generation == (gen || this.cleanGeneration)
7664 },
7665
7666 getHistory: function() {
7667 return {done: copyHistoryArray(this.history.done),
7668 undone: copyHistoryArray(this.history.undone)}
7669 },
7670 setHistory: function(histData) {
7671 var hist = this.history = new History(this.history.maxGeneration);
7672 hist.done = copyHistoryArray(histData.done.slice(0), null, true);
7673 hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
7674 },
7675
7676 setGutterMarker: docMethodOp(function(line, gutterID, value) {
7677 return changeLine(this, line, "gutter", function (line) {
7678 var markers = line.gutterMarkers || (line.gutterMarkers = {});
7679 markers[gutterID] = value;
7680 if (!value && isEmpty(markers)) { line.gutterMarkers = null; }
7681 return true
7682 })
7683 }),
7684
7685 clearGutter: docMethodOp(function(gutterID) {
7686 var this$1 = this;
7687
7688 this.iter(function (line) {
7689 if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
7690 changeLine(this$1, line, "gutter", function () {
7691 line.gutterMarkers[gutterID] = null;
7692 if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null; }
7693 return true
7694 });
7695 }
7696 });
7697 }),
7698
7699 lineInfo: function(line) {
7700 var n;
7701 if (typeof line == "number") {
7702 if (!isLine(this, line)) { return null }
7703 n = line;
7704 line = getLine(this, line);
7705 if (!line) { return null }
7706 } else {
7707 n = lineNo(line);
7708 if (n == null) { return null }
7709 }
7710 return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
7711 textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
7712 widgets: line.widgets}
7713 },
7714
7715 addLineClass: docMethodOp(function(handle, where, cls) {
7716 return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
7717 var prop = where == "text" ? "textClass"
7718 : where == "background" ? "bgClass"
7719 : where == "gutter" ? "gutterClass" : "wrapClass";
7720 if (!line[prop]) { line[prop] = cls; }
7721 else if (classTest(cls).test(line[prop])) { return false }
7722 else { line[prop] += " " + cls; }
7723 return true
7724 })
7725 }),
7726 removeLineClass: docMethodOp(function(handle, where, cls) {
7727 return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
7728 var prop = where == "text" ? "textClass"
7729 : where == "background" ? "bgClass"
7730 : where == "gutter" ? "gutterClass" : "wrapClass";
7731 var cur = line[prop];
7732 if (!cur) { return false }
7733 else if (cls == null) { line[prop] = null; }
7734 else {
7735 var found = cur.match(classTest(cls));
7736 if (!found) { return false }
7737 var end = found.index + found[0].length;
7738 line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
7739 }
7740 return true
7741 })
7742 }),
7743
7744 addLineWidget: docMethodOp(function(handle, node, options) {
7745 return addLineWidget(this, handle, node, options)
7746 }),
7747 removeLineWidget: function(widget) { widget.clear(); },
7748
7749 markText: function(from, to, options) {
7750 return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range")
7751 },
7752 setBookmark: function(pos, options) {
7753 var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
7754 insertLeft: options && options.insertLeft,
7755 clearWhenEmpty: false, shared: options && options.shared,
7756 handleMouseEvents: options && options.handleMouseEvents};
7757 pos = clipPos(this, pos);
7758 return markText(this, pos, pos, realOpts, "bookmark")
7759 },
7760 findMarksAt: function(pos) {
7761 pos = clipPos(this, pos);
7762 var markers = [], spans = getLine(this, pos.line).markedSpans;
7763 if (spans) { for (var i = 0; i < spans.length; ++i) {
7764 var span = spans[i];
7765 if ((span.from == null || span.from <= pos.ch) &&
7766 (span.to == null || span.to >= pos.ch))
7767 { markers.push(span.marker.parent || span.marker); }
7768 } }
7769 return markers
7770 },
7771 findMarks: function(from, to, filter) {
7772 from = clipPos(this, from); to = clipPos(this, to);
7773 var found = [], lineNo$$1 = from.line;
7774 this.iter(from.line, to.line + 1, function (line) {
7775 var spans = line.markedSpans;
7776 if (spans) { for (var i = 0; i < spans.length; i++) {
7777 var span = spans[i];
7778 if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to ||
7779 span.from == null && lineNo$$1 != from.line ||
7780 span.from != null && lineNo$$1 == to.line && span.from >= to.ch) &&
7781 (!filter || filter(span.marker)))
7782 { found.push(span.marker.parent || span.marker); }
7783 } }
7784 ++lineNo$$1;
7785 });
7786 return found
7787 },
7788 getAllMarks: function() {
7789 var markers = [];
7790 this.iter(function (line) {
7791 var sps = line.markedSpans;
7792 if (sps) { for (var i = 0; i < sps.length; ++i)
7793 { if (sps[i].from != null) { markers.push(sps[i].marker); } } }
7794 });
7795 return markers
7796 },
7797
7798 posFromIndex: function(off) {
7799 var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length;
7800 this.iter(function (line) {
7801 var sz = line.text.length + sepSize;
7802 if (sz > off) { ch = off; return true }
7803 off -= sz;
7804 ++lineNo$$1;
7805 });
7806 return clipPos(this, Pos(lineNo$$1, ch))
7807 },
7808 indexFromPos: function (coords) {
7809 coords = clipPos(this, coords);
7810 var index = coords.ch;
7811 if (coords.line < this.first || coords.ch < 0) { return 0 }
7812 var sepSize = this.lineSeparator().length;
7813 this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value
7814 index += line.text.length + sepSize;
7815 });
7816 return index
7817 },
7818
7819 copy: function(copyHistory) {
7820 var doc = new Doc(getLines(this, this.first, this.first + this.size),
7821 this.modeOption, this.first, this.lineSep, this.direction);
7822 doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
7823 doc.sel = this.sel;
7824 doc.extend = false;
7825 if (copyHistory) {
7826 doc.history.undoDepth = this.history.undoDepth;
7827 doc.setHistory(this.getHistory());
7828 }
7829 return doc
7830 },
7831
7832 linkedDoc: function(options) {
7833 if (!options) { options = {}; }
7834 var from = this.first, to = this.first + this.size;
7835 if (options.from != null && options.from > from) { from = options.from; }
7836 if (options.to != null && options.to < to) { to = options.to; }
7837 var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction);
7838 if (options.sharedHist) { copy.history = this.history
7839 ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
7840 copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
7841 copySharedMarkers(copy, findSharedMarkers(this));
7842 return copy
7843 },
7844 unlinkDoc: function(other) {
7845 var this$1 = this;
7846
7847 if (other instanceof CodeMirror$1) { other = other.doc; }
7848 if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {
7849 var link = this$1.linked[i];
7850 if (link.doc != other) { continue }
7851 this$1.linked.splice(i, 1);
7852 other.unlinkDoc(this$1);
7853 detachSharedMarkers(findSharedMarkers(this$1));
7854 break
7855 } }
7856 // If the histories were shared, split them again
7857 if (other.history == this.history) {
7858 var splitIds = [other.id];
7859 linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true);
7860 other.history = new History(null);
7861 other.history.done = copyHistoryArray(this.history.done, splitIds);
7862 other.history.undone = copyHistoryArray(this.history.undone, splitIds);
7863 }
7864 },
7865 iterLinkedDocs: function(f) {linkedDocs(this, f);},
7866
7867 getMode: function() {return this.mode},
7868 getEditor: function() {return this.cm},
7869
7870 splitLines: function(str) {
7871 if (this.lineSep) { return str.split(this.lineSep) }
7872 return splitLinesAuto(str)
7873 },
7874 lineSeparator: function() { return this.lineSep || "\n" },
7875
7876 setDirection: docMethodOp(function (dir) {
7877 if (dir != "rtl") { dir = "ltr"; }
7878 if (dir == this.direction) { return }
7879 this.direction = dir;
7880 this.iter(function (line) { return line.order = null; });
7881 if (this.cm) { directionChanged(this.cm); }
7882 })
7883 });
7884
7885 // Public alias.
7886 Doc.prototype.eachLine = Doc.prototype.iter;
7887
7888 // Kludge to work around strange IE behavior where it'll sometimes
7889 // re-fire a series of drag-related events right after the drop (#1551)
7890 var lastDrop = 0;
7891
7892 function onDrop(e) {
7893 var cm = this;
7894 clearDragCursor(cm);
7895 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
7896 { return }
7897 e_preventDefault(e);
7898 if (ie) { lastDrop = +new Date; }
7899 var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
7900 if (!pos || cm.isReadOnly()) { return }
7901 // Might be a file drop, in which case we simply extract the text
7902 // and insert it.
7903 if (files && files.length && window.FileReader && window.File) {
7904 var n = files.length, text = Array(n), read = 0;
7905 var loadFile = function (file, i) {
7906 if (cm.options.allowDropFileTypes &&
7907 indexOf(cm.options.allowDropFileTypes, file.type) == -1)
7908 { return }
7909
7910 var reader = new FileReader;
7911 reader.onload = operation(cm, function () {
7912 var content = reader.result;
7913 if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = ""; }
7914 text[i] = content;
7915 if (++read == n) {
7916 pos = clipPos(cm.doc, pos);
7917 var change = {from: pos, to: pos,
7918 text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
7919 origin: "paste"};
7920 makeChange(cm.doc, change);
7921 setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
7922 }
7923 });
7924 reader.readAsText(file);
7925 };
7926 for (var i = 0; i < n; ++i) { loadFile(files[i], i); }
7927 } else { // Normal drop
7928 // Don't do a replace if the drop happened inside of the selected text.
7929 if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
7930 cm.state.draggingText(e);
7931 // Ensure the editor is re-focused
7932 setTimeout(function () { return cm.display.input.focus(); }, 20);
7933 return
7934 }
7935 try {
7936 var text$1 = e.dataTransfer.getData("Text");
7937 if (text$1) {
7938 var selected;
7939 if (cm.state.draggingText && !cm.state.draggingText.copy)
7940 { selected = cm.listSelections(); }
7941 setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
7942 if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1)
7943 { replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag"); } }
7944 cm.replaceSelection(text$1, "around", "paste");
7945 cm.display.input.focus();
7946 }
7947 }
7948 catch(e){}
7949 }
7950 }
7951
7952 function onDragStart(cm, e) {
7953 if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return }
7954 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return }
7955
7956 e.dataTransfer.setData("Text", cm.getSelection());
7957 e.dataTransfer.effectAllowed = "copyMove";
7958
7959 // Use dummy image instead of default browsers image.
7960 // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
7961 if (e.dataTransfer.setDragImage && !safari) {
7962 var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
7963 img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
7964 if (presto) {
7965 img.width = img.height = 1;
7966 cm.display.wrapper.appendChild(img);
7967 // Force a relayout, or Opera won't use our image for some obscure reason
7968 img._top = img.offsetTop;
7969 }
7970 e.dataTransfer.setDragImage(img, 0, 0);
7971 if (presto) { img.parentNode.removeChild(img); }
7972 }
7973 }
7974
7975 function onDragOver(cm, e) {
7976 var pos = posFromMouse(cm, e);
7977 if (!pos) { return }
7978 var frag = document.createDocumentFragment();
7979 drawSelectionCursor(cm, pos, frag);
7980 if (!cm.display.dragCursor) {
7981 cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
7982 cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
7983 }
7984 removeChildrenAndAdd(cm.display.dragCursor, frag);
7985 }
7986
7987 function clearDragCursor(cm) {
7988 if (cm.display.dragCursor) {
7989 cm.display.lineSpace.removeChild(cm.display.dragCursor);
7990 cm.display.dragCursor = null;
7991 }
7992 }
7993
7994 // These must be handled carefully, because naively registering a
7995 // handler for each editor will cause the editors to never be
7996 // garbage collected.
7997
7998 function forEachCodeMirror(f) {
7999 if (!document.getElementsByClassName) { return }
8000 var byClass = document.getElementsByClassName("CodeMirror");
8001 for (var i = 0; i < byClass.length; i++) {
8002 var cm = byClass[i].CodeMirror;
8003 if (cm) { f(cm); }
8004 }
8005 }
8006
8007 var globalsRegistered = false;
8008 function ensureGlobalHandlers() {
8009 if (globalsRegistered) { return }
8010 registerGlobalHandlers();
8011 globalsRegistered = true;
8012 }
8013 function registerGlobalHandlers() {
8014 // When the window resizes, we need to refresh active editors.
8015 var resizeTimer;
8016 on(window, "resize", function () {
8017 if (resizeTimer == null) { resizeTimer = setTimeout(function () {
8018 resizeTimer = null;
8019 forEachCodeMirror(onResize);
8020 }, 100); }
8021 });
8022 // When the window loses focus, we want to show the editor as blurred
8023 on(window, "blur", function () { return forEachCodeMirror(onBlur); });
8024 }
8025 // Called when the window resizes
8026 function onResize(cm) {
8027 var d = cm.display;
8028 if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)
8029 { return }
8030 // Might be a text scaling operation, clear size caches.
8031 d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
8032 d.scrollbarsClipped = false;
8033 cm.setSize();
8034 }
8035
8036 var keyNames = {
8037 3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
8038 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
8039 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
8040 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
8041 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete",
8042 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
8043 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
8044 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
8045 };
8046
8047 // Number keys
8048 for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); }
8049 // Alphabetic keys
8050 for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); }
8051 // Function keys
8052 for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2; }
8053
8054 var keyMap = {};
8055
8056 keyMap.basic = {
8057 "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
8058 "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
8059 "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
8060 "Tab": "defaultTab", "Shift-Tab": "indentAuto",
8061 "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
8062 "Esc": "singleSelection"
8063 };
8064 // Note that the save and find-related commands aren't defined by
8065 // default. User code or addons can define them. Unknown commands
8066 // are simply ignored.
8067 keyMap.pcDefault = {
8068 "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
8069 "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
8070 "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
8071 "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
8072 "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
8073 "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
8074 "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
8075 fallthrough: "basic"
8076 };
8077 // Very basic readline/emacs-style bindings, which are standard on Mac.
8078 keyMap.emacsy = {
8079 "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
8080 "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
8081 "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
8082 "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars",
8083 "Ctrl-O": "openLine"
8084 };
8085 keyMap.macDefault = {
8086 "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
8087 "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
8088 "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
8089 "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
8090 "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
8091 "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
8092 "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
8093 fallthrough: ["basic", "emacsy"]
8094 };
8095 keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
8096
8097 // KEYMAP DISPATCH
8098
8099 function normalizeKeyName(name) {
8100 var parts = name.split(/-(?!$)/);
8101 name = parts[parts.length - 1];
8102 var alt, ctrl, shift, cmd;
8103 for (var i = 0; i < parts.length - 1; i++) {
8104 var mod = parts[i];
8105 if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true; }
8106 else if (/^a(lt)?$/i.test(mod)) { alt = true; }
8107 else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; }
8108 else if (/^s(hift)?$/i.test(mod)) { shift = true; }
8109 else { throw new Error("Unrecognized modifier name: " + mod) }
8110 }
8111 if (alt) { name = "Alt-" + name; }
8112 if (ctrl) { name = "Ctrl-" + name; }
8113 if (cmd) { name = "Cmd-" + name; }
8114 if (shift) { name = "Shift-" + name; }
8115 return name
8116 }
8117
8118 // This is a kludge to keep keymaps mostly working as raw objects
8119 // (backwards compatibility) while at the same time support features
8120 // like normalization and multi-stroke key bindings. It compiles a
8121 // new normalized keymap, and then updates the old object to reflect
8122 // this.
8123 function normalizeKeyMap(keymap) {
8124 var copy = {};
8125 for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) {
8126 var value = keymap[keyname];
8127 if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue }
8128 if (value == "...") { delete keymap[keyname]; continue }
8129
8130 var keys = map(keyname.split(" "), normalizeKeyName);
8131 for (var i = 0; i < keys.length; i++) {
8132 var val = (void 0), name = (void 0);
8133 if (i == keys.length - 1) {
8134 name = keys.join(" ");
8135 val = value;
8136 } else {
8137 name = keys.slice(0, i + 1).join(" ");
8138 val = "...";
8139 }
8140 var prev = copy[name];
8141 if (!prev) { copy[name] = val; }
8142 else if (prev != val) { throw new Error("Inconsistent bindings for " + name) }
8143 }
8144 delete keymap[keyname];
8145 } }
8146 for (var prop in copy) { keymap[prop] = copy[prop]; }
8147 return keymap
8148 }
8149
8150 function lookupKey(key, map$$1, handle, context) {
8151 map$$1 = getKeyMap(map$$1);
8152 var found = map$$1.call ? map$$1.call(key, context) : map$$1[key];
8153 if (found === false) { return "nothing" }
8154 if (found === "...") { return "multi" }
8155 if (found != null && handle(found)) { return "handled" }
8156
8157 if (map$$1.fallthrough) {
8158 if (Object.prototype.toString.call(map$$1.fallthrough) != "[object Array]")
8159 { return lookupKey(key, map$$1.fallthrough, handle, context) }
8160 for (var i = 0; i < map$$1.fallthrough.length; i++) {
8161 var result = lookupKey(key, map$$1.fallthrough[i], handle, context);
8162 if (result) { return result }
8163 }
8164 }
8165 }
8166
8167 // Modifier key presses don't count as 'real' key presses for the
8168 // purpose of keymap fallthrough.
8169 function isModifierKey(value) {
8170 var name = typeof value == "string" ? value : keyNames[value.keyCode];
8171 return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"
8172 }
8173
8174 function addModifierNames(name, event, noShift) {
8175 var base = name;
8176 if (event.altKey && base != "Alt") { name = "Alt-" + name; }
8177 if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; }
8178 if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name; }
8179 if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; }
8180 return name
8181 }
8182
8183 // Look up the name of a key as indicated by an event object.
8184 function keyName(event, noShift) {
8185 if (presto && event.keyCode == 34 && event["char"]) { return false }
8186 var name = keyNames[event.keyCode];
8187 if (name == null || event.altGraphKey) { return false }
8188 return addModifierNames(name, event, noShift)
8189 }
8190
8191 function getKeyMap(val) {
8192 return typeof val == "string" ? keyMap[val] : val
8193 }
8194
8195 // Helper for deleting text near the selection(s), used to implement
8196 // backspace, delete, and similar functionality.
8197 function deleteNearSelection(cm, compute) {
8198 var ranges = cm.doc.sel.ranges, kill = [];
8199 // Build up a set of ranges to kill first, merging overlapping
8200 // ranges.
8201 for (var i = 0; i < ranges.length; i++) {
8202 var toKill = compute(ranges[i]);
8203 while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
8204 var replaced = kill.pop();
8205 if (cmp(replaced.from, toKill.from) < 0) {
8206 toKill.from = replaced.from;
8207 break
8208 }
8209 }
8210 kill.push(toKill);
8211 }
8212 // Next, remove those actual ranges.
8213 runInOp(cm, function () {
8214 for (var i = kill.length - 1; i >= 0; i--)
8215 { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); }
8216 ensureCursorVisible(cm);
8217 });
8218 }
8219
8220 function moveCharLogically(line, ch, dir) {
8221 var target = skipExtendingChars(line.text, ch + dir, dir);
8222 return target < 0 || target > line.text.length ? null : target
8223 }
8224
8225 function moveLogically(line, start, dir) {
8226 var ch = moveCharLogically(line, start.ch, dir);
8227 return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
8228 }
8229
8230 function endOfLine(visually, cm, lineObj, lineNo, dir) {
8231 if (visually) {
8232 var order = getOrder(lineObj, cm.doc.direction);
8233 if (order) {
8234 var part = dir < 0 ? lst(order) : order[0];
8235 var moveInStorageOrder = (dir < 0) == (part.level == 1);
8236 var sticky = moveInStorageOrder ? "after" : "before";
8237 var ch;
8238 // With a wrapped rtl chunk (possibly spanning multiple bidi parts),
8239 // it could be that the last bidi part is not on the last visual line,
8240 // since visual lines contain content order-consecutive chunks.
8241 // Thus, in rtl, we are looking for the first (content-order) character
8242 // in the rtl chunk that is on the last line (that is, the same line
8243 // as the last (content-order) character).
8244 if (part.level > 0 || cm.doc.direction == "rtl") {
8245 var prep = prepareMeasureForLine(cm, lineObj);
8246 ch = dir < 0 ? lineObj.text.length - 1 : 0;
8247 var targetTop = measureCharPrepared(cm, prep, ch).top;
8248 ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch);
8249 if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1); }
8250 } else { ch = dir < 0 ? part.to : part.from; }
8251 return new Pos(lineNo, ch, sticky)
8252 }
8253 }
8254 return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
8255 }
8256
8257 function moveVisually(cm, line, start, dir) {
8258 var bidi = getOrder(line, cm.doc.direction);
8259 if (!bidi) { return moveLogically(line, start, dir) }
8260 if (start.ch >= line.text.length) {
8261 start.ch = line.text.length;
8262 start.sticky = "before";
8263 } else if (start.ch <= 0) {
8264 start.ch = 0;
8265 start.sticky = "after";
8266 }
8267 var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos];
8268 if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
8269 // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
8270 // nothing interesting happens.
8271 return moveLogically(line, start, dir)
8272 }
8273
8274 var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); };
8275 var prep;
8276 var getWrappedLineExtent = function (ch) {
8277 if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
8278 prep = prep || prepareMeasureForLine(cm, line);
8279 return wrappedLineExtentChar(cm, line, prep, ch)
8280 };
8281 var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch);
8282
8283 if (cm.doc.direction == "rtl" || part.level == 1) {
8284 var moveInStorageOrder = (part.level == 1) == (dir < 0);
8285 var ch = mv(start, moveInStorageOrder ? 1 : -1);
8286 if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
8287 // Case 2: We move within an rtl part or in an rtl editor on the same visual line
8288 var sticky = moveInStorageOrder ? "before" : "after";
8289 return new Pos(start.line, ch, sticky)
8290 }
8291 }
8292
8293 // Case 3: Could not move within this bidi part in this visual line, so leave
8294 // the current bidi part
8295
8296 var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
8297 var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
8298 ? new Pos(start.line, mv(ch, 1), "before")
8299 : new Pos(start.line, ch, "after"); };
8300
8301 for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
8302 var part = bidi[partPos];
8303 var moveInStorageOrder = (dir > 0) == (part.level != 1);
8304 var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1);
8305 if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
8306 ch = moveInStorageOrder ? part.from : mv(part.to, -1);
8307 if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
8308 }
8309 };
8310
8311 // Case 3a: Look for other bidi parts on the same visual line
8312 var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent);
8313 if (res) { return res }
8314
8315 // Case 3b: Look for other bidi parts on the next visual line
8316 var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1);
8317 if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
8318 res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh));
8319 if (res) { return res }
8320 }
8321
8322 // Case 4: Nowhere to move
8323 return null
8324 }
8325
8326 // Commands are parameter-less actions that can be performed on an
8327 // editor, mostly used for keybindings.
8328 var commands = {
8329 selectAll: selectAll,
8330 singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); },
8331 killLine: function (cm) { return deleteNearSelection(cm, function (range) {
8332 if (range.empty()) {
8333 var len = getLine(cm.doc, range.head.line).text.length;
8334 if (range.head.ch == len && range.head.line < cm.lastLine())
8335 { return {from: range.head, to: Pos(range.head.line + 1, 0)} }
8336 else
8337 { return {from: range.head, to: Pos(range.head.line, len)} }
8338 } else {
8339 return {from: range.from(), to: range.to()}
8340 }
8341 }); },
8342 deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({
8343 from: Pos(range.from().line, 0),
8344 to: clipPos(cm.doc, Pos(range.to().line + 1, 0))
8345 }); }); },
8346 delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({
8347 from: Pos(range.from().line, 0), to: range.from()
8348 }); }); },
8349 delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) {
8350 var top = cm.charCoords(range.head, "div").top + 5;
8351 var leftPos = cm.coordsChar({left: 0, top: top}, "div");
8352 return {from: leftPos, to: range.from()}
8353 }); },
8354 delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) {
8355 var top = cm.charCoords(range.head, "div").top + 5;
8356 var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
8357 return {from: range.from(), to: rightPos }
8358 }); },
8359 undo: function (cm) { return cm.undo(); },
8360 redo: function (cm) { return cm.redo(); },
8361 undoSelection: function (cm) { return cm.undoSelection(); },
8362 redoSelection: function (cm) { return cm.redoSelection(); },
8363 goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); },
8364 goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); },
8365 goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); },
8366 {origin: "+move", bias: 1}
8367 ); },
8368 goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); },
8369 {origin: "+move", bias: 1}
8370 ); },
8371 goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); },
8372 {origin: "+move", bias: -1}
8373 ); },
8374 goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) {
8375 var top = cm.cursorCoords(range.head, "div").top + 5;
8376 return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")
8377 }, sel_move); },
8378 goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) {
8379 var top = cm.cursorCoords(range.head, "div").top + 5;
8380 return cm.coordsChar({left: 0, top: top}, "div")
8381 }, sel_move); },
8382 goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) {
8383 var top = cm.cursorCoords(range.head, "div").top + 5;
8384 var pos = cm.coordsChar({left: 0, top: top}, "div");
8385 if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) }
8386 return pos
8387 }, sel_move); },
8388 goLineUp: function (cm) { return cm.moveV(-1, "line"); },
8389 goLineDown: function (cm) { return cm.moveV(1, "line"); },
8390 goPageUp: function (cm) { return cm.moveV(-1, "page"); },
8391 goPageDown: function (cm) { return cm.moveV(1, "page"); },
8392 goCharLeft: function (cm) { return cm.moveH(-1, "char"); },
8393 goCharRight: function (cm) { return cm.moveH(1, "char"); },
8394 goColumnLeft: function (cm) { return cm.moveH(-1, "column"); },
8395 goColumnRight: function (cm) { return cm.moveH(1, "column"); },
8396 goWordLeft: function (cm) { return cm.moveH(-1, "word"); },
8397 goGroupRight: function (cm) { return cm.moveH(1, "group"); },
8398 goGroupLeft: function (cm) { return cm.moveH(-1, "group"); },
8399 goWordRight: function (cm) { return cm.moveH(1, "word"); },
8400 delCharBefore: function (cm) { return cm.deleteH(-1, "char"); },
8401 delCharAfter: function (cm) { return cm.deleteH(1, "char"); },
8402 delWordBefore: function (cm) { return cm.deleteH(-1, "word"); },
8403 delWordAfter: function (cm) { return cm.deleteH(1, "word"); },
8404 delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); },
8405 delGroupAfter: function (cm) { return cm.deleteH(1, "group"); },
8406 indentAuto: function (cm) { return cm.indentSelection("smart"); },
8407 indentMore: function (cm) { return cm.indentSelection("add"); },
8408 indentLess: function (cm) { return cm.indentSelection("subtract"); },
8409 insertTab: function (cm) { return cm.replaceSelection("\t"); },
8410 insertSoftTab: function (cm) {
8411 var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
8412 for (var i = 0; i < ranges.length; i++) {
8413 var pos = ranges[i].from();
8414 var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
8415 spaces.push(spaceStr(tabSize - col % tabSize));
8416 }
8417 cm.replaceSelections(spaces);
8418 },
8419 defaultTab: function (cm) {
8420 if (cm.somethingSelected()) { cm.indentSelection("add"); }
8421 else { cm.execCommand("insertTab"); }
8422 },
8423 // Swap the two chars left and right of each selection's head.
8424 // Move cursor behind the two swapped characters afterwards.
8425 //
8426 // Doesn't consider line feeds a character.
8427 // Doesn't scan more than one line above to find a character.
8428 // Doesn't do anything on an empty line.
8429 // Doesn't do anything with non-empty selections.
8430 transposeChars: function (cm) { return runInOp(cm, function () {
8431 var ranges = cm.listSelections(), newSel = [];
8432 for (var i = 0; i < ranges.length; i++) {
8433 if (!ranges[i].empty()) { continue }
8434 var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
8435 if (line) {
8436 if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); }
8437 if (cur.ch > 0) {
8438 cur = new Pos(cur.line, cur.ch + 1);
8439 cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
8440 Pos(cur.line, cur.ch - 2), cur, "+transpose");
8441 } else if (cur.line > cm.doc.first) {
8442 var prev = getLine(cm.doc, cur.line - 1).text;
8443 if (prev) {
8444 cur = new Pos(cur.line, 1);
8445 cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
8446 prev.charAt(prev.length - 1),
8447 Pos(cur.line - 1, prev.length - 1), cur, "+transpose");
8448 }
8449 }
8450 }
8451 newSel.push(new Range(cur, cur));
8452 }
8453 cm.setSelections(newSel);
8454 }); },
8455 newlineAndIndent: function (cm) { return runInOp(cm, function () {
8456 var sels = cm.listSelections();
8457 for (var i = sels.length - 1; i >= 0; i--)
8458 { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input"); }
8459 sels = cm.listSelections();
8460 for (var i$1 = 0; i$1 < sels.length; i$1++)
8461 { cm.indentLine(sels[i$1].from().line, null, true); }
8462 ensureCursorVisible(cm);
8463 }); },
8464 openLine: function (cm) { return cm.replaceSelection("\n", "start"); },
8465 toggleOverwrite: function (cm) { return cm.toggleOverwrite(); }
8466 };
8467
8468
8469 function lineStart(cm, lineN) {
8470 var line = getLine(cm.doc, lineN);
8471 var visual = visualLine(line);
8472 if (visual != line) { lineN = lineNo(visual); }
8473 return endOfLine(true, cm, visual, lineN, 1)
8474 }
8475 function lineEnd(cm, lineN) {
8476 var line = getLine(cm.doc, lineN);
8477 var visual = visualLineEnd(line);
8478 if (visual != line) { lineN = lineNo(visual); }
8479 return endOfLine(true, cm, line, lineN, -1)
8480 }
8481 function lineStartSmart(cm, pos) {
8482 var start = lineStart(cm, pos.line);
8483 var line = getLine(cm.doc, start.line);
8484 var order = getOrder(line, cm.doc.direction);
8485 if (!order || order[0].level == 0) {
8486 var firstNonWS = Math.max(0, line.text.search(/\S/));
8487 var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
8488 return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)
8489 }
8490 return start
8491 }
8492
8493 // Run a handler that was bound to a key.
8494 function doHandleBinding(cm, bound, dropShift) {
8495 if (typeof bound == "string") {
8496 bound = commands[bound];
8497 if (!bound) { return false }
8498 }
8499 // Ensure previous input has been read, so that the handler sees a
8500 // consistent view of the document
8501 cm.display.input.ensurePolled();
8502 var prevShift = cm.display.shift, done = false;
8503 try {
8504 if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
8505 if (dropShift) { cm.display.shift = false; }
8506 done = bound(cm) != Pass;
8507 } finally {
8508 cm.display.shift = prevShift;
8509 cm.state.suppressEdits = false;
8510 }
8511 return done
8512 }
8513
8514 function lookupKeyForEditor(cm, name, handle) {
8515 for (var i = 0; i < cm.state.keyMaps.length; i++) {
8516 var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
8517 if (result) { return result }
8518 }
8519 return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
8520 || lookupKey(name, cm.options.keyMap, handle, cm)
8521 }
8522
8523 // Note that, despite the name, this function is also used to check
8524 // for bound mouse clicks.
8525
8526 var stopSeq = new Delayed;
8527
8528 function dispatchKey(cm, name, e, handle) {
8529 var seq = cm.state.keySeq;
8530 if (seq) {
8531 if (isModifierKey(name)) { return "handled" }
8532 if (/\'$/.test(name))
8533 { cm.state.keySeq = null; }
8534 else
8535 { stopSeq.set(50, function () {
8536 if (cm.state.keySeq == seq) {
8537 cm.state.keySeq = null;
8538 cm.display.input.reset();
8539 }
8540 }); }
8541 if (dispatchKeyInner(cm, seq + " " + name, e, handle)) { return true }
8542 }
8543 return dispatchKeyInner(cm, name, e, handle)
8544 }
8545
8546 function dispatchKeyInner(cm, name, e, handle) {
8547 var result = lookupKeyForEditor(cm, name, handle);
8548
8549 if (result == "multi")
8550 { cm.state.keySeq = name; }
8551 if (result == "handled")
8552 { signalLater(cm, "keyHandled", cm, name, e); }
8553
8554 if (result == "handled" || result == "multi") {
8555 e_preventDefault(e);
8556 restartBlink(cm);
8557 }
8558
8559 return !!result
8560 }
8561
8562 // Handle a key from the keydown event.
8563 function handleKeyBinding(cm, e) {
8564 var name = keyName(e, true);
8565 if (!name) { return false }
8566
8567 if (e.shiftKey && !cm.state.keySeq) {
8568 // First try to resolve full name (including 'Shift-'). Failing
8569 // that, see if there is a cursor-motion command (starting with
8570 // 'go') bound to the keyname without 'Shift-'.
8571 return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); })
8572 || dispatchKey(cm, name, e, function (b) {
8573 if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
8574 { return doHandleBinding(cm, b) }
8575 })
8576 } else {
8577 return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); })
8578 }
8579 }
8580
8581 // Handle a key from the keypress event
8582 function handleCharBinding(cm, e, ch) {
8583 return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); })
8584 }
8585
8586 var lastStoppedKey = null;
8587 function onKeyDown(e) {
8588 var cm = this;
8589 cm.curOp.focus = activeElt();
8590 if (signalDOMEvent(cm, e)) { return }
8591 // IE does strange things with escape.
8592 if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; }
8593 var code = e.keyCode;
8594 cm.display.shift = code == 16 || e.shiftKey;
8595 var handled = handleKeyBinding(cm, e);
8596 if (presto) {
8597 lastStoppedKey = handled ? code : null;
8598 // Opera has no cut event... we try to at least catch the key combo
8599 if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
8600 { cm.replaceSelection("", null, "cut"); }
8601 }
8602
8603 // Turn mouse into crosshair when Alt is held on Mac.
8604 if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
8605 { showCrossHair(cm); }
8606 }
8607
8608 function showCrossHair(cm) {
8609 var lineDiv = cm.display.lineDiv;
8610 addClass(lineDiv, "CodeMirror-crosshair");
8611
8612 function up(e) {
8613 if (e.keyCode == 18 || !e.altKey) {
8614 rmClass(lineDiv, "CodeMirror-crosshair");
8615 off(document, "keyup", up);
8616 off(document, "mouseover", up);
8617 }
8618 }
8619 on(document, "keyup", up);
8620 on(document, "mouseover", up);
8621 }
8622
8623 function onKeyUp(e) {
8624 if (e.keyCode == 16) { this.doc.sel.shift = false; }
8625 signalDOMEvent(this, e);
8626 }
8627
8628 function onKeyPress(e) {
8629 var cm = this;
8630 if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }
8631 var keyCode = e.keyCode, charCode = e.charCode;
8632 if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}
8633 if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return }
8634 var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
8635 // Some browsers fire keypress events for backspace
8636 if (ch == "\x08") { return }
8637 if (handleCharBinding(cm, e, ch)) { return }
8638 cm.display.input.onKeyPress(e);
8639 }
8640
8641 var DOUBLECLICK_DELAY = 400;
8642
8643 var PastClick = function(time, pos, button) {
8644 this.time = time;
8645 this.pos = pos;
8646 this.button = button;
8647 };
8648
8649 PastClick.prototype.compare = function (time, pos, button) {
8650 return this.time + DOUBLECLICK_DELAY > time &&
8651 cmp(pos, this.pos) == 0 && button == this.button
8652 };
8653
8654 var lastClick;
8655 var lastDoubleClick;
8656 function clickRepeat(pos, button) {
8657 var now = +new Date;
8658 if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) {
8659 lastClick = lastDoubleClick = null;
8660 return "triple"
8661 } else if (lastClick && lastClick.compare(now, pos, button)) {
8662 lastDoubleClick = new PastClick(now, pos, button);
8663 lastClick = null;
8664 return "double"
8665 } else {
8666 lastClick = new PastClick(now, pos, button);
8667 lastDoubleClick = null;
8668 return "single"
8669 }
8670 }
8671
8672 // A mouse down can be a single click, double click, triple click,
8673 // start of selection drag, start of text drag, new cursor
8674 // (ctrl-click), rectangle drag (alt-drag), or xwin
8675 // middle-click-paste. Or it might be a click on something we should
8676 // not interfere with, such as a scrollbar or widget.
8677 function onMouseDown(e) {
8678 var cm = this, display = cm.display;
8679 if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return }
8680 display.input.ensurePolled();
8681 display.shift = e.shiftKey;
8682
8683 if (eventInWidget(display, e)) {
8684 if (!webkit) {
8685 // Briefly turn off draggability, to allow widgets to do
8686 // normal dragging things.
8687 display.scroller.draggable = false;
8688 setTimeout(function () { return display.scroller.draggable = true; }, 100);
8689 }
8690 return
8691 }
8692 if (clickInGutter(cm, e)) { return }
8693 var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single";
8694 window.focus();
8695
8696 // #3261: make sure, that we're not starting a second selection
8697 if (button == 1 && cm.state.selectingText)
8698 { cm.state.selectingText(e); }
8699
8700 if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return }
8701
8702 if (button == 1) {
8703 if (pos) { leftButtonDown(cm, pos, repeat, e); }
8704 else if (e_target(e) == display.scroller) { e_preventDefault(e); }
8705 } else if (button == 2) {
8706 if (pos) { extendSelection(cm.doc, pos); }
8707 setTimeout(function () { return display.input.focus(); }, 20);
8708 } else if (button == 3) {
8709 if (captureRightClick) { onContextMenu(cm, e); }
8710 else { delayBlurEvent(cm); }
8711 }
8712 }
8713
8714 function handleMappedButton(cm, button, pos, repeat, event) {
8715 var name = "Click";
8716 if (repeat == "double") { name = "Double" + name; }
8717 else if (repeat == "triple") { name = "Triple" + name; }
8718 name = (button == 1 ? "Left" : button == 2 ? "Middle" : "Right") + name;
8719
8720 return dispatchKey(cm, addModifierNames(name, event), event, function (bound) {
8721 if (typeof bound == "string") { bound = commands[bound]; }
8722 if (!bound) { return false }
8723 var done = false;
8724 try {
8725 if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
8726 done = bound(cm, pos) != Pass;
8727 } finally {
8728 cm.state.suppressEdits = false;
8729 }
8730 return done
8731 })
8732 }
8733
8734 function configureMouse(cm, repeat, event) {
8735 var option = cm.getOption("configureMouse");
8736 var value = option ? option(cm, repeat, event) : {};
8737 if (value.unit == null) {
8738 var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey;
8739 value.unit = rect ? "rectangle" : repeat == "single" ? "char" : repeat == "double" ? "word" : "line";
8740 }
8741 if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey; }
8742 if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey; }
8743 if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey); }
8744 return value
8745 }
8746
8747 function leftButtonDown(cm, pos, repeat, event) {
8748 if (ie) { setTimeout(bind(ensureFocus, cm), 0); }
8749 else { cm.curOp.focus = activeElt(); }
8750
8751 var behavior = configureMouse(cm, repeat, event);
8752
8753 var sel = cm.doc.sel, contained;
8754 if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
8755 repeat == "single" && (contained = sel.contains(pos)) > -1 &&
8756 (cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) &&
8757 (cmp(contained.to(), pos) > 0 || pos.xRel < 0))
8758 { leftButtonStartDrag(cm, event, pos, behavior); }
8759 else
8760 { leftButtonSelect(cm, event, pos, behavior); }
8761 }
8762
8763 // Start a text drag. When it ends, see if any dragging actually
8764 // happen, and treat as a click if it didn't.
8765 function leftButtonStartDrag(cm, event, pos, behavior) {
8766 var display = cm.display, moved = false;
8767 var dragEnd = operation(cm, function (e) {
8768 if (webkit) { display.scroller.draggable = false; }
8769 cm.state.draggingText = false;
8770 off(document, "mouseup", dragEnd);
8771 off(document, "mousemove", mouseMove);
8772 off(display.scroller, "dragstart", dragStart);
8773 off(display.scroller, "drop", dragEnd);
8774 if (!moved) {
8775 e_preventDefault(e);
8776 if (!behavior.addNew)
8777 { extendSelection(cm.doc, pos, null, null, behavior.extend); }
8778 // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
8779 if (webkit || ie && ie_version == 9)
8780 { setTimeout(function () {document.body.focus(); display.input.focus();}, 20); }
8781 else
8782 { display.input.focus(); }
8783 }
8784 });
8785 var mouseMove = function(e2) {
8786 moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10;
8787 };
8788 var dragStart = function () { return moved = true; };
8789 // Let the drag handler handle this.
8790 if (webkit) { display.scroller.draggable = true; }
8791 cm.state.draggingText = dragEnd;
8792 dragEnd.copy = !behavior.moveOnDrag;
8793 // IE's approach to draggable
8794 if (display.scroller.dragDrop) { display.scroller.dragDrop(); }
8795 on(document, "mouseup", dragEnd);
8796 on(document, "mousemove", mouseMove);
8797 on(display.scroller, "dragstart", dragStart);
8798 on(display.scroller, "drop", dragEnd);
8799
8800 delayBlurEvent(cm);
8801 setTimeout(function () { return display.input.focus(); }, 20);
8802 }
8803
8804 function rangeForUnit(cm, pos, unit) {
8805 if (unit == "char") { return new Range(pos, pos) }
8806 if (unit == "word") { return cm.findWordAt(pos) }
8807 if (unit == "line") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) }
8808 var result = unit(cm, pos);
8809 return new Range(result.from, result.to)
8810 }
8811
8812 // Normal selection, as opposed to text dragging.
8813 function leftButtonSelect(cm, event, start, behavior) {
8814 var display = cm.display, doc = cm.doc;
8815 e_preventDefault(event);
8816
8817 var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
8818 if (behavior.addNew && !behavior.extend) {
8819 ourIndex = doc.sel.contains(start);
8820 if (ourIndex > -1)
8821 { ourRange = ranges[ourIndex]; }
8822 else
8823 { ourRange = new Range(start, start); }
8824 } else {
8825 ourRange = doc.sel.primary();
8826 ourIndex = doc.sel.primIndex;
8827 }
8828
8829 if (behavior.unit == "rectangle") {
8830 if (!behavior.addNew) { ourRange = new Range(start, start); }
8831 start = posFromMouse(cm, event, true, true);
8832 ourIndex = -1;
8833 } else {
8834 var range$$1 = rangeForUnit(cm, start, behavior.unit);
8835 if (behavior.extend)
8836 { ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); }
8837 else
8838 { ourRange = range$$1; }
8839 }
8840
8841 if (!behavior.addNew) {
8842 ourIndex = 0;
8843 setSelection(doc, new Selection([ourRange], 0), sel_mouse);
8844 startSel = doc.sel;
8845 } else if (ourIndex == -1) {
8846 ourIndex = ranges.length;
8847 setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
8848 {scroll: false, origin: "*mouse"});
8849 } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) {
8850 setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
8851 {scroll: false, origin: "*mouse"});
8852 startSel = doc.sel;
8853 } else {
8854 replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
8855 }
8856
8857 var lastPos = start;
8858 function extendTo(pos) {
8859 if (cmp(lastPos, pos) == 0) { return }
8860 lastPos = pos;
8861
8862 if (behavior.unit == "rectangle") {
8863 var ranges = [], tabSize = cm.options.tabSize;
8864 var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
8865 var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
8866 var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
8867 for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
8868 line <= end; line++) {
8869 var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
8870 if (left == right)
8871 { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); }
8872 else if (text.length > leftPos)
8873 { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); }
8874 }
8875 if (!ranges.length) { ranges.push(new Range(start, start)); }
8876 setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
8877 {origin: "*mouse", scroll: false});
8878 cm.scrollIntoView(pos);
8879 } else {
8880 var oldRange = ourRange;
8881 var range$$1 = rangeForUnit(cm, pos, behavior.unit);
8882 var anchor = oldRange.anchor, head;
8883 if (cmp(range$$1.anchor, anchor) > 0) {
8884 head = range$$1.head;
8885 anchor = minPos(oldRange.from(), range$$1.anchor);
8886 } else {
8887 head = range$$1.anchor;
8888 anchor = maxPos(oldRange.to(), range$$1.head);
8889 }
8890 var ranges$1 = startSel.ranges.slice(0);
8891 ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head));
8892 setSelection(doc, normalizeSelection(ranges$1, ourIndex), sel_mouse);
8893 }
8894 }
8895
8896 var editorSize = display.wrapper.getBoundingClientRect();
8897 // Used to ensure timeout re-tries don't fire when another extend
8898 // happened in the meantime (clearTimeout isn't reliable -- at
8899 // least on Chrome, the timeouts still happen even when cleared,
8900 // if the clear happens after their scheduled firing time).
8901 var counter = 0;
8902
8903 function extend(e) {
8904 var curCount = ++counter;
8905 var cur = posFromMouse(cm, e, true, behavior.unit == "rectangle");
8906 if (!cur) { return }
8907 if (cmp(cur, lastPos) != 0) {
8908 cm.curOp.focus = activeElt();
8909 extendTo(cur);
8910 var visible = visibleLines(display, doc);
8911 if (cur.line >= visible.to || cur.line < visible.from)
8912 { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); }
8913 } else {
8914 var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
8915 if (outside) { setTimeout(operation(cm, function () {
8916 if (counter != curCount) { return }
8917 display.scroller.scrollTop += outside;
8918 extend(e);
8919 }), 50); }
8920 }
8921 }
8922
8923 function done(e) {
8924 cm.state.selectingText = false;
8925 counter = Infinity;
8926 e_preventDefault(e);
8927 display.input.focus();
8928 off(document, "mousemove", move);
8929 off(document, "mouseup", up);
8930 doc.history.lastSelOrigin = null;
8931 }
8932
8933 var move = operation(cm, function (e) {
8934 if (!e_button(e)) { done(e); }
8935 else { extend(e); }
8936 });
8937 var up = operation(cm, done);
8938 cm.state.selectingText = up;
8939 on(document, "mousemove", move);
8940 on(document, "mouseup", up);
8941 }
8942
8943 // Used when mouse-selecting to adjust the anchor to the proper side
8944 // of a bidi jump depending on the visual position of the head.
8945 function bidiSimplify(cm, range$$1) {
8946 var anchor = range$$1.anchor;
8947 var head = range$$1.head;
8948 var anchorLine = getLine(cm.doc, anchor.line);
8949 if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range$$1 }
8950 var order = getOrder(anchorLine);
8951 if (!order) { return range$$1 }
8952 var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index];
8953 if (part.from != anchor.ch && part.to != anchor.ch) { return range$$1 }
8954 var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1);
8955 if (boundary == 0 || boundary == order.length) { return range$$1 }
8956
8957 // Compute the relative visual position of the head compared to the
8958 // anchor (<0 is to the left, >0 to the right)
8959 var leftSide;
8960 if (head.line != anchor.line) {
8961 leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0;
8962 } else {
8963 var headIndex = getBidiPartAt(order, head.ch, head.sticky);
8964 var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1);
8965 if (headIndex == boundary - 1 || headIndex == boundary)
8966 { leftSide = dir < 0; }
8967 else
8968 { leftSide = dir > 0; }
8969 }
8970
8971 var usePart = order[boundary + (leftSide ? -1 : 0)];
8972 var from = leftSide == (usePart.level == 1);
8973 var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before";
8974 return anchor.ch == ch && anchor.sticky == sticky ? range$$1 : new Range(new Pos(anchor.line, ch, sticky), head)
8975 }
8976
8977
8978 // Determines whether an event happened in the gutter, and fires the
8979 // handlers for the corresponding event.
8980 function gutterEvent(cm, e, type, prevent) {
8981 var mX, mY;
8982 if (e.touches) {
8983 mX = e.touches[0].clientX;
8984 mY = e.touches[0].clientY;
8985 } else {
8986 try { mX = e.clientX; mY = e.clientY; }
8987 catch(e) { return false }
8988 }
8989 if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
8990 if (prevent) { e_preventDefault(e); }
8991
8992 var display = cm.display;
8993 var lineBox = display.lineDiv.getBoundingClientRect();
8994
8995 if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }
8996 mY -= lineBox.top - display.viewOffset;
8997
8998 for (var i = 0; i < cm.options.gutters.length; ++i) {
8999 var g = display.gutters.childNodes[i];
9000 if (g && g.getBoundingClientRect().right >= mX) {
9001 var line = lineAtHeight(cm.doc, mY);
9002 var gutter = cm.options.gutters[i];
9003 signal(cm, type, cm, line, gutter, e);
9004 return e_defaultPrevented(e)
9005 }
9006 }
9007 }
9008
9009 function clickInGutter(cm, e) {
9010 return gutterEvent(cm, e, "gutterClick", true)
9011 }
9012
9013 // CONTEXT MENU HANDLING
9014
9015 // To make the context menu work, we need to briefly unhide the
9016 // textarea (making it as unobtrusive as possible) to let the
9017 // right-click take effect on it.
9018 function onContextMenu(cm, e) {
9019 if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return }
9020 if (signalDOMEvent(cm, e, "contextmenu")) { return }
9021 cm.display.input.onContextMenu(e);
9022 }
9023
9024 function contextMenuInGutter(cm, e) {
9025 if (!hasHandler(cm, "gutterContextMenu")) { return false }
9026 return gutterEvent(cm, e, "gutterContextMenu", false)
9027 }
9028
9029 function themeChanged(cm) {
9030 cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
9031 cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
9032 clearCaches(cm);
9033 }
9034
9035 var Init = {toString: function(){return "CodeMirror.Init"}};
9036
9037 var defaults = {};
9038 var optionHandlers = {};
9039
9040 function defineOptions(CodeMirror) {
9041 var optionHandlers = CodeMirror.optionHandlers;
9042
9043 function option(name, deflt, handle, notOnInit) {
9044 CodeMirror.defaults[name] = deflt;
9045 if (handle) { optionHandlers[name] =
9046 notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old); }} : handle; }
9047 }
9048
9049 CodeMirror.defineOption = option;
9050
9051 // Passed to option handlers when there is no old value.
9052 CodeMirror.Init = Init;
9053
9054 // These two are, on init, called from the constructor because they
9055 // have to be initialized before the editor can start at all.
9056 option("value", "", function (cm, val) { return cm.setValue(val); }, true);
9057 option("mode", null, function (cm, val) {
9058 cm.doc.modeOption = val;
9059 loadMode(cm);
9060 }, true);
9061
9062 option("indentUnit", 2, loadMode, true);
9063 option("indentWithTabs", false);
9064 option("smartIndent", true);
9065 option("tabSize", 4, function (cm) {
9066 resetModeState(cm);
9067 clearCaches(cm);
9068 regChange(cm);
9069 }, true);
9070
9071 option("lineSeparator", null, function (cm, val) {
9072 cm.doc.lineSep = val;
9073 if (!val) { return }
9074 var newBreaks = [], lineNo = cm.doc.first;
9075 cm.doc.iter(function (line) {
9076 for (var pos = 0;;) {
9077 var found = line.text.indexOf(val, pos);
9078 if (found == -1) { break }
9079 pos = found + val.length;
9080 newBreaks.push(Pos(lineNo, found));
9081 }
9082 lineNo++;
9083 });
9084 for (var i = newBreaks.length - 1; i >= 0; i--)
9085 { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }
9086 });
9087 option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) {
9088 cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
9089 if (old != Init) { cm.refresh(); }
9090 });
9091 option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true);
9092 option("electricChars", true);
9093 option("inputStyle", mobile ? "contenteditable" : "textarea", function () {
9094 throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME
9095 }, true);
9096 option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true);
9097 option("rtlMoveVisually", !windows);
9098 option("wholeLineUpdateBefore", true);
9099
9100 option("theme", "default", function (cm) {
9101 themeChanged(cm);
9102 guttersChanged(cm);
9103 }, true);
9104 option("keyMap", "default", function (cm, val, old) {
9105 var next = getKeyMap(val);
9106 var prev = old != Init && getKeyMap(old);
9107 if (prev && prev.detach) { prev.detach(cm, next); }
9108 if (next.attach) { next.attach(cm, prev || null); }
9109 });
9110 option("extraKeys", null);
9111 option("configureMouse", null);
9112
9113 option("lineWrapping", false, wrappingChanged, true);
9114 option("gutters", [], function (cm) {
9115 setGuttersForLineNumbers(cm.options);
9116 guttersChanged(cm);
9117 }, true);
9118 option("fixedGutter", true, function (cm, val) {
9119 cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
9120 cm.refresh();
9121 }, true);
9122 option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true);
9123 option("scrollbarStyle", "native", function (cm) {
9124 initScrollbars(cm);
9125 updateScrollbars(cm);
9126 cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
9127 cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
9128 }, true);
9129 option("lineNumbers", false, function (cm) {
9130 setGuttersForLineNumbers(cm.options);
9131 guttersChanged(cm);
9132 }, true);
9133 option("firstLineNumber", 1, guttersChanged, true);
9134 option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true);
9135 option("showCursorWhenSelecting", false, updateSelection, true);
9136
9137 option("resetSelectionOnContextMenu", true);
9138 option("lineWiseCopyCut", true);
9139 option("pasteLinesPerSelection", true);
9140
9141 option("readOnly", false, function (cm, val) {
9142 if (val == "nocursor") {
9143 onBlur(cm);
9144 cm.display.input.blur();
9145 }
9146 cm.display.input.readOnlyChanged(val);
9147 });
9148 option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);
9149 option("dragDrop", true, dragDropChanged);
9150 option("allowDropFileTypes", null);
9151
9152 option("cursorBlinkRate", 530);
9153 option("cursorScrollMargin", 0);
9154 option("cursorHeight", 1, updateSelection, true);
9155 option("singleCursorHeightPerLine", true, updateSelection, true);
9156 option("workTime", 100);
9157 option("workDelay", 100);
9158 option("flattenSpans", true, resetModeState, true);
9159 option("addModeClass", false, resetModeState, true);
9160 option("pollInterval", 100);
9161 option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; });
9162 option("historyEventDelay", 1250);
9163 option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true);
9164 option("maxHighlightLength", 10000, resetModeState, true);
9165 option("moveInputWithCursor", true, function (cm, val) {
9166 if (!val) { cm.display.input.resetPosition(); }
9167 });
9168
9169 option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; });
9170 option("autofocus", null);
9171 option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true);
9172 }
9173
9174 function guttersChanged(cm) {
9175 updateGutters(cm);
9176 regChange(cm);
9177 alignHorizontally(cm);
9178 }
9179
9180 function dragDropChanged(cm, value, old) {
9181 var wasOn = old && old != Init;
9182 if (!value != !wasOn) {
9183 var funcs = cm.display.dragFunctions;
9184 var toggle = value ? on : off;
9185 toggle(cm.display.scroller, "dragstart", funcs.start);
9186 toggle(cm.display.scroller, "dragenter", funcs.enter);
9187 toggle(cm.display.scroller, "dragover", funcs.over);
9188 toggle(cm.display.scroller, "dragleave", funcs.leave);
9189 toggle(cm.display.scroller, "drop", funcs.drop);
9190 }
9191 }
9192
9193 function wrappingChanged(cm) {
9194 if (cm.options.lineWrapping) {
9195 addClass(cm.display.wrapper, "CodeMirror-wrap");
9196 cm.display.sizer.style.minWidth = "";
9197 cm.display.sizerWidth = null;
9198 } else {
9199 rmClass(cm.display.wrapper, "CodeMirror-wrap");
9200 findMaxLine(cm);
9201 }
9202 estimateLineHeights(cm);
9203 regChange(cm);
9204 clearCaches(cm);
9205 setTimeout(function () { return updateScrollbars(cm); }, 100);
9206 }
9207
9208 // A CodeMirror instance represents an editor. This is the object
9209 // that user code is usually dealing with.
9210
9211 function CodeMirror$1(place, options) {
9212 var this$1 = this;
9213
9214 if (!(this instanceof CodeMirror$1)) { return new CodeMirror$1(place, options) }
9215
9216 this.options = options = options ? copyObj(options) : {};
9217 // Determine effective options based on given values and defaults.
9218 copyObj(defaults, options, false);
9219 setGuttersForLineNumbers(options);
9220
9221 var doc = options.value;
9222 if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); }
9223 this.doc = doc;
9224
9225 var input = new CodeMirror$1.inputStyles[options.inputStyle](this);
9226 var display = this.display = new Display(place, doc, input);
9227 display.wrapper.CodeMirror = this;
9228 updateGutters(this);
9229 themeChanged(this);
9230 if (options.lineWrapping)
9231 { this.display.wrapper.className += " CodeMirror-wrap"; }
9232 initScrollbars(this);
9233
9234 this.state = {
9235 keyMaps: [], // stores maps added by addKeyMap
9236 overlays: [], // highlighting overlays, as added by addOverlay
9237 modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
9238 overwrite: false,
9239 delayingBlurEvent: false,
9240 focused: false,
9241 suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
9242 pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
9243 selectingText: false,
9244 draggingText: false,
9245 highlight: new Delayed(), // stores highlight worker timeout
9246 keySeq: null, // Unfinished key sequence
9247 specialChars: null
9248 };
9249
9250 if (options.autofocus && !mobile) { display.input.focus(); }
9251
9252 // Override magic textarea content restore that IE sometimes does
9253 // on our hidden textarea on reload
9254 if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); }
9255
9256 registerEventHandlers(this);
9257 ensureGlobalHandlers();
9258
9259 startOperation(this);
9260 this.curOp.forceUpdate = true;
9261 attachDoc(this, doc);
9262
9263 if ((options.autofocus && !mobile) || this.hasFocus())
9264 { setTimeout(bind(onFocus, this), 20); }
9265 else
9266 { onBlur(this); }
9267
9268 for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))
9269 { optionHandlers[opt](this$1, options[opt], Init); } }
9270 maybeUpdateLineNumberWidth(this);
9271 if (options.finishInit) { options.finishInit(this); }
9272 for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1); }
9273 endOperation(this);
9274 // Suppress optimizelegibility in Webkit, since it breaks text
9275 // measuring on line wrapping boundaries.
9276 if (webkit && options.lineWrapping &&
9277 getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
9278 { display.lineDiv.style.textRendering = "auto"; }
9279 }
9280
9281 // The default configuration options.
9282 CodeMirror$1.defaults = defaults;
9283 // Functions to run when options are changed.
9284 CodeMirror$1.optionHandlers = optionHandlers;
9285
9286 // Attach the necessary event handlers when initializing the editor
9287 function registerEventHandlers(cm) {
9288 var d = cm.display;
9289 on(d.scroller, "mousedown", operation(cm, onMouseDown));
9290 // Older IE's will not fire a second mousedown for a double click
9291 if (ie && ie_version < 11)
9292 { on(d.scroller, "dblclick", operation(cm, function (e) {
9293 if (signalDOMEvent(cm, e)) { return }
9294 var pos = posFromMouse(cm, e);
9295 if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return }
9296 e_preventDefault(e);
9297 var word = cm.findWordAt(pos);
9298 extendSelection(cm.doc, word.anchor, word.head);
9299 })); }
9300 else
9301 { on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }); }
9302 // Some browsers fire contextmenu *after* opening the menu, at
9303 // which point we can't mess with it anymore. Context menu is
9304 // handled in onMouseDown for these browsers.
9305 if (!captureRightClick) { on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); }); }
9306
9307 // Used to suppress mouse event handling when a touch happens
9308 var touchFinished, prevTouch = {end: 0};
9309 function finishTouch() {
9310 if (d.activeTouch) {
9311 touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000);
9312 prevTouch = d.activeTouch;
9313 prevTouch.end = +new Date;
9314 }
9315 }
9316 function isMouseLikeTouchEvent(e) {
9317 if (e.touches.length != 1) { return false }
9318 var touch = e.touches[0];
9319 return touch.radiusX <= 1 && touch.radiusY <= 1
9320 }
9321 function farAway(touch, other) {
9322 if (other.left == null) { return true }
9323 var dx = other.left - touch.left, dy = other.top - touch.top;
9324 return dx * dx + dy * dy > 20 * 20
9325 }
9326 on(d.scroller, "touchstart", function (e) {
9327 if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {
9328 d.input.ensurePolled();
9329 clearTimeout(touchFinished);
9330 var now = +new Date;
9331 d.activeTouch = {start: now, moved: false,
9332 prev: now - prevTouch.end <= 300 ? prevTouch : null};
9333 if (e.touches.length == 1) {
9334 d.activeTouch.left = e.touches[0].pageX;
9335 d.activeTouch.top = e.touches[0].pageY;
9336 }
9337 }
9338 });
9339 on(d.scroller, "touchmove", function () {
9340 if (d.activeTouch) { d.activeTouch.moved = true; }
9341 });
9342 on(d.scroller, "touchend", function (e) {
9343 var touch = d.activeTouch;
9344 if (touch && !eventInWidget(d, e) && touch.left != null &&
9345 !touch.moved && new Date - touch.start < 300) {
9346 var pos = cm.coordsChar(d.activeTouch, "page"), range;
9347 if (!touch.prev || farAway(touch, touch.prev)) // Single tap
9348 { range = new Range(pos, pos); }
9349 else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
9350 { range = cm.findWordAt(pos); }
9351 else // Triple tap
9352 { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); }
9353 cm.setSelection(range.anchor, range.head);
9354 cm.focus();
9355 e_preventDefault(e);
9356 }
9357 finishTouch();
9358 });
9359 on(d.scroller, "touchcancel", finishTouch);
9360
9361 // Sync scrolling between fake scrollbars and real scrollable
9362 // area, ensure viewport is updated when scrolling.
9363 on(d.scroller, "scroll", function () {
9364 if (d.scroller.clientHeight) {
9365 updateScrollTop(cm, d.scroller.scrollTop);
9366 setScrollLeft(cm, d.scroller.scrollLeft, true);
9367 signal(cm, "scroll", cm);
9368 }
9369 });
9370
9371 // Listen to wheel events in order to try and update the viewport on time.
9372 on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); });
9373 on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); });
9374
9375 // Prevent wrapper from ever scrolling
9376 on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
9377
9378 d.dragFunctions = {
9379 enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e); }},
9380 over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
9381 start: function (e) { return onDragStart(cm, e); },
9382 drop: operation(cm, onDrop),
9383 leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}
9384 };
9385
9386 var inp = d.input.getField();
9387 on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); });
9388 on(inp, "keydown", operation(cm, onKeyDown));
9389 on(inp, "keypress", operation(cm, onKeyPress));
9390 on(inp, "focus", function (e) { return onFocus(cm, e); });
9391 on(inp, "blur", function (e) { return onBlur(cm, e); });
9392 }
9393
9394 var initHooks = [];
9395 CodeMirror$1.defineInitHook = function (f) { return initHooks.push(f); };
9396
9397 // Indent the given line. The how parameter can be "smart",
9398 // "add"/null, "subtract", or "prev". When aggressive is false
9399 // (typically set to true for forced single-line indents), empty
9400 // lines are not indented, and places where the mode returns Pass
9401 // are left alone.
9402 function indentLine(cm, n, how, aggressive) {
9403 var doc = cm.doc, state;
9404 if (how == null) { how = "add"; }
9405 if (how == "smart") {
9406 // Fall back to "prev" when the mode doesn't have an indentation
9407 // method.
9408 if (!doc.mode.indent) { how = "prev"; }
9409 else { state = getContextBefore(cm, n).state; }
9410 }
9411
9412 var tabSize = cm.options.tabSize;
9413 var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
9414 if (line.stateAfter) { line.stateAfter = null; }
9415 var curSpaceString = line.text.match(/^\s*/)[0], indentation;
9416 if (!aggressive && !/\S/.test(line.text)) {
9417 indentation = 0;
9418 how = "not";
9419 } else if (how == "smart") {
9420 indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
9421 if (indentation == Pass || indentation > 150) {
9422 if (!aggressive) { return }
9423 how = "prev";
9424 }
9425 }
9426 if (how == "prev") {
9427 if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize); }
9428 else { indentation = 0; }
9429 } else if (how == "add") {
9430 indentation = curSpace + cm.options.indentUnit;
9431 } else if (how == "subtract") {
9432 indentation = curSpace - cm.options.indentUnit;
9433 } else if (typeof how == "number") {
9434 indentation = curSpace + how;
9435 }
9436 indentation = Math.max(0, indentation);
9437
9438 var indentString = "", pos = 0;
9439 if (cm.options.indentWithTabs)
9440 { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} }
9441 if (pos < indentation) { indentString += spaceStr(indentation - pos); }
9442
9443 if (indentString != curSpaceString) {
9444 replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
9445 line.stateAfter = null;
9446 return true
9447 } else {
9448 // Ensure that, if the cursor was in the whitespace at the start
9449 // of the line, it is moved to the end of that space.
9450 for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) {
9451 var range = doc.sel.ranges[i$1];
9452 if (range.head.line == n && range.head.ch < curSpaceString.length) {
9453 var pos$1 = Pos(n, curSpaceString.length);
9454 replaceOneSelection(doc, i$1, new Range(pos$1, pos$1));
9455 break
9456 }
9457 }
9458 }
9459 }
9460
9461 // This will be set to a {lineWise: bool, text: [string]} object, so
9462 // that, when pasting, we know what kind of selections the copied
9463 // text was made out of.
9464 var lastCopied = null;
9465
9466 function setLastCopied(newLastCopied) {
9467 lastCopied = newLastCopied;
9468 }
9469
9470 function applyTextInput(cm, inserted, deleted, sel, origin) {
9471 var doc = cm.doc;
9472 cm.display.shift = false;
9473 if (!sel) { sel = doc.sel; }
9474
9475 var paste = cm.state.pasteIncoming || origin == "paste";
9476 var textLines = splitLinesAuto(inserted), multiPaste = null;
9477 // When pasing N lines into N selections, insert one line per selection
9478 if (paste && sel.ranges.length > 1) {
9479 if (lastCopied && lastCopied.text.join("\n") == inserted) {
9480 if (sel.ranges.length % lastCopied.text.length == 0) {
9481 multiPaste = [];
9482 for (var i = 0; i < lastCopied.text.length; i++)
9483 { multiPaste.push(doc.splitLines(lastCopied.text[i])); }
9484 }
9485 } else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) {
9486 multiPaste = map(textLines, function (l) { return [l]; });
9487 }
9488 }
9489
9490 var updateInput;
9491 // Normal behavior is to insert the new text into every selection
9492 for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {
9493 var range$$1 = sel.ranges[i$1];
9494 var from = range$$1.from(), to = range$$1.to();
9495 if (range$$1.empty()) {
9496 if (deleted && deleted > 0) // Handle deletion
9497 { from = Pos(from.line, from.ch - deleted); }
9498 else if (cm.state.overwrite && !paste) // Handle overwrite
9499 { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }
9500 else if (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted)
9501 { from = to = Pos(from.line, 0); }
9502 }
9503 updateInput = cm.curOp.updateInput;
9504 var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,
9505 origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")};
9506 makeChange(cm.doc, changeEvent);
9507 signalLater(cm, "inputRead", cm, changeEvent);
9508 }
9509 if (inserted && !paste)
9510 { triggerElectric(cm, inserted); }
9511
9512 ensureCursorVisible(cm);
9513 cm.curOp.updateInput = updateInput;
9514 cm.curOp.typing = true;
9515 cm.state.pasteIncoming = cm.state.cutIncoming = false;
9516 }
9517
9518 function handlePaste(e, cm) {
9519 var pasted = e.clipboardData && e.clipboardData.getData("Text");
9520 if (pasted) {
9521 e.preventDefault();
9522 if (!cm.isReadOnly() && !cm.options.disableInput)
9523 { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }); }
9524 return true
9525 }
9526 }
9527
9528 function triggerElectric(cm, inserted) {
9529 // When an 'electric' character is inserted, immediately trigger a reindent
9530 if (!cm.options.electricChars || !cm.options.smartIndent) { return }
9531 var sel = cm.doc.sel;
9532
9533 for (var i = sel.ranges.length - 1; i >= 0; i--) {
9534 var range$$1 = sel.ranges[i];
9535 if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue }
9536 var mode = cm.getModeAt(range$$1.head);
9537 var indented = false;
9538 if (mode.electricChars) {
9539 for (var j = 0; j < mode.electricChars.length; j++)
9540 { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
9541 indented = indentLine(cm, range$$1.head.line, "smart");
9542 break
9543 } }
9544 } else if (mode.electricInput) {
9545 if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch)))
9546 { indented = indentLine(cm, range$$1.head.line, "smart"); }
9547 }
9548 if (indented) { signalLater(cm, "electricInput", cm, range$$1.head.line); }
9549 }
9550 }
9551
9552 function copyableRanges(cm) {
9553 var text = [], ranges = [];
9554 for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
9555 var line = cm.doc.sel.ranges[i].head.line;
9556 var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
9557 ranges.push(lineRange);
9558 text.push(cm.getRange(lineRange.anchor, lineRange.head));
9559 }
9560 return {text: text, ranges: ranges}
9561 }
9562
9563 function disableBrowserMagic(field, spellcheck) {
9564 field.setAttribute("autocorrect", "off");
9565 field.setAttribute("autocapitalize", "off");
9566 field.setAttribute("spellcheck", !!spellcheck);
9567 }
9568
9569 function hiddenTextarea() {
9570 var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none");
9571 var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
9572 // The textarea is kept positioned near the cursor to prevent the
9573 // fact that it'll be scrolled into view on input from scrolling
9574 // our fake cursor out of view. On webkit, when wrap=off, paste is
9575 // very slow. So make the area wide instead.
9576 if (webkit) { te.style.width = "1000px"; }
9577 else { te.setAttribute("wrap", "off"); }
9578 // If border: 0; -- iOS fails to open keyboard (issue #1287)
9579 if (ios) { te.style.border = "1px solid black"; }
9580 disableBrowserMagic(te);
9581 return div
9582 }
9583
9584 // The publicly visible API. Note that methodOp(f) means
9585 // 'wrap f in an operation, performed on its `this` parameter'.
9586
9587 // This is not the complete set of editor methods. Most of the
9588 // methods defined on the Doc type are also injected into
9589 // CodeMirror.prototype, for backwards compatibility and
9590 // convenience.
9591
9592 var addEditorMethods = function(CodeMirror) {
9593 var optionHandlers = CodeMirror.optionHandlers;
9594
9595 var helpers = CodeMirror.helpers = {};
9596
9597 CodeMirror.prototype = {
9598 constructor: CodeMirror,
9599 focus: function(){window.focus(); this.display.input.focus();},
9600
9601 setOption: function(option, value) {
9602 var options = this.options, old = options[option];
9603 if (options[option] == value && option != "mode") { return }
9604 options[option] = value;
9605 if (optionHandlers.hasOwnProperty(option))
9606 { operation(this, optionHandlers[option])(this, value, old); }
9607 signal(this, "optionChange", this, option);
9608 },
9609
9610 getOption: function(option) {return this.options[option]},
9611 getDoc: function() {return this.doc},
9612
9613 addKeyMap: function(map$$1, bottom) {
9614 this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map$$1));
9615 },
9616 removeKeyMap: function(map$$1) {
9617 var maps = this.state.keyMaps;
9618 for (var i = 0; i < maps.length; ++i)
9619 { if (maps[i] == map$$1 || maps[i].name == map$$1) {
9620 maps.splice(i, 1);
9621 return true
9622 } }
9623 },
9624
9625 addOverlay: methodOp(function(spec, options) {
9626 var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
9627 if (mode.startState) { throw new Error("Overlays may not be stateful.") }
9628 insertSorted(this.state.overlays,
9629 {mode: mode, modeSpec: spec, opaque: options && options.opaque,
9630 priority: (options && options.priority) || 0},
9631 function (overlay) { return overlay.priority; });
9632 this.state.modeGen++;
9633 regChange(this);
9634 }),
9635 removeOverlay: methodOp(function(spec) {
9636 var this$1 = this;
9637
9638 var overlays = this.state.overlays;
9639 for (var i = 0; i < overlays.length; ++i) {
9640 var cur = overlays[i].modeSpec;
9641 if (cur == spec || typeof spec == "string" && cur.name == spec) {
9642 overlays.splice(i, 1);
9643 this$1.state.modeGen++;
9644 regChange(this$1);
9645 return
9646 }
9647 }
9648 }),
9649
9650 indentLine: methodOp(function(n, dir, aggressive) {
9651 if (typeof dir != "string" && typeof dir != "number") {
9652 if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev"; }
9653 else { dir = dir ? "add" : "subtract"; }
9654 }
9655 if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); }
9656 }),
9657 indentSelection: methodOp(function(how) {
9658 var this$1 = this;
9659
9660 var ranges = this.doc.sel.ranges, end = -1;
9661 for (var i = 0; i < ranges.length; i++) {
9662 var range$$1 = ranges[i];
9663 if (!range$$1.empty()) {
9664 var from = range$$1.from(), to = range$$1.to();
9665 var start = Math.max(end, from.line);
9666 end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
9667 for (var j = start; j < end; ++j)
9668 { indentLine(this$1, j, how); }
9669 var newRanges = this$1.doc.sel.ranges;
9670 if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
9671 { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); }
9672 } else if (range$$1.head.line > end) {
9673 indentLine(this$1, range$$1.head.line, how, true);
9674 end = range$$1.head.line;
9675 if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1); }
9676 }
9677 }
9678 }),
9679
9680 // Fetch the parser token for a given character. Useful for hacks
9681 // that want to inspect the mode state (say, for completion).
9682 getTokenAt: function(pos, precise) {
9683 return takeToken(this, pos, precise)
9684 },
9685
9686 getLineTokens: function(line, precise) {
9687 return takeToken(this, Pos(line), precise, true)
9688 },
9689
9690 getTokenTypeAt: function(pos) {
9691 pos = clipPos(this.doc, pos);
9692 var styles = getLineStyles(this, getLine(this.doc, pos.line));
9693 var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
9694 var type;
9695 if (ch == 0) { type = styles[2]; }
9696 else { for (;;) {
9697 var mid = (before + after) >> 1;
9698 if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid; }
9699 else if (styles[mid * 2 + 1] < ch) { before = mid + 1; }
9700 else { type = styles[mid * 2 + 2]; break }
9701 } }
9702 var cut = type ? type.indexOf("overlay ") : -1;
9703 return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1)
9704 },
9705
9706 getModeAt: function(pos) {
9707 var mode = this.doc.mode;
9708 if (!mode.innerMode) { return mode }
9709 return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode
9710 },
9711
9712 getHelper: function(pos, type) {
9713 return this.getHelpers(pos, type)[0]
9714 },
9715
9716 getHelpers: function(pos, type) {
9717 var this$1 = this;
9718
9719 var found = [];
9720 if (!helpers.hasOwnProperty(type)) { return found }
9721 var help = helpers[type], mode = this.getModeAt(pos);
9722 if (typeof mode[type] == "string") {
9723 if (help[mode[type]]) { found.push(help[mode[type]]); }
9724 } else if (mode[type]) {
9725 for (var i = 0; i < mode[type].length; i++) {
9726 var val = help[mode[type][i]];
9727 if (val) { found.push(val); }
9728 }
9729 } else if (mode.helperType && help[mode.helperType]) {
9730 found.push(help[mode.helperType]);
9731 } else if (help[mode.name]) {
9732 found.push(help[mode.name]);
9733 }
9734 for (var i$1 = 0; i$1 < help._global.length; i$1++) {
9735 var cur = help._global[i$1];
9736 if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1)
9737 { found.push(cur.val); }
9738 }
9739 return found
9740 },
9741
9742 getStateAfter: function(line, precise) {
9743 var doc = this.doc;
9744 line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
9745 return getContextBefore(this, line + 1, precise).state
9746 },
9747
9748 cursorCoords: function(start, mode) {
9749 var pos, range$$1 = this.doc.sel.primary();
9750 if (start == null) { pos = range$$1.head; }
9751 else if (typeof start == "object") { pos = clipPos(this.doc, start); }
9752 else { pos = start ? range$$1.from() : range$$1.to(); }
9753 return cursorCoords(this, pos, mode || "page")
9754 },
9755
9756 charCoords: function(pos, mode) {
9757 return charCoords(this, clipPos(this.doc, pos), mode || "page")
9758 },
9759
9760 coordsChar: function(coords, mode) {
9761 coords = fromCoordSystem(this, coords, mode || "page");
9762 return coordsChar(this, coords.left, coords.top)
9763 },
9764
9765 lineAtHeight: function(height, mode) {
9766 height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
9767 return lineAtHeight(this.doc, height + this.display.viewOffset)
9768 },
9769 heightAtLine: function(line, mode, includeWidgets) {
9770 var end = false, lineObj;
9771 if (typeof line == "number") {
9772 var last = this.doc.first + this.doc.size - 1;
9773 if (line < this.doc.first) { line = this.doc.first; }
9774 else if (line > last) { line = last; end = true; }
9775 lineObj = getLine(this.doc, line);
9776 } else {
9777 lineObj = line;
9778 }
9779 return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets || end).top +
9780 (end ? this.doc.height - heightAtLine(lineObj) : 0)
9781 },
9782
9783 defaultTextHeight: function() { return textHeight(this.display) },
9784 defaultCharWidth: function() { return charWidth(this.display) },
9785
9786 getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}},
9787
9788 addWidget: function(pos, node, scroll, vert, horiz) {
9789 var display = this.display;
9790 pos = cursorCoords(this, clipPos(this.doc, pos));
9791 var top = pos.bottom, left = pos.left;
9792 node.style.position = "absolute";
9793 node.setAttribute("cm-ignore-events", "true");
9794 this.display.input.setUneditable(node);
9795 display.sizer.appendChild(node);
9796 if (vert == "over") {
9797 top = pos.top;
9798 } else if (vert == "above" || vert == "near") {
9799 var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
9800 hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
9801 // Default to positioning above (if specified and possible); otherwise default to positioning below
9802 if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
9803 { top = pos.top - node.offsetHeight; }
9804 else if (pos.bottom + node.offsetHeight <= vspace)
9805 { top = pos.bottom; }
9806 if (left + node.offsetWidth > hspace)
9807 { left = hspace - node.offsetWidth; }
9808 }
9809 node.style.top = top + "px";
9810 node.style.left = node.style.right = "";
9811 if (horiz == "right") {
9812 left = display.sizer.clientWidth - node.offsetWidth;
9813 node.style.right = "0px";
9814 } else {
9815 if (horiz == "left") { left = 0; }
9816 else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2; }
9817 node.style.left = left + "px";
9818 }
9819 if (scroll)
9820 { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}); }
9821 },
9822
9823 triggerOnKeyDown: methodOp(onKeyDown),
9824 triggerOnKeyPress: methodOp(onKeyPress),
9825 triggerOnKeyUp: onKeyUp,
9826 triggerOnMouseDown: methodOp(onMouseDown),
9827
9828 execCommand: function(cmd) {
9829 if (commands.hasOwnProperty(cmd))
9830 { return commands[cmd].call(null, this) }
9831 },
9832
9833 triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
9834
9835 findPosH: function(from, amount, unit, visually) {
9836 var this$1 = this;
9837
9838 var dir = 1;
9839 if (amount < 0) { dir = -1; amount = -amount; }
9840 var cur = clipPos(this.doc, from);
9841 for (var i = 0; i < amount; ++i) {
9842 cur = findPosH(this$1.doc, cur, dir, unit, visually);
9843 if (cur.hitSide) { break }
9844 }
9845 return cur
9846 },
9847
9848 moveH: methodOp(function(dir, unit) {
9849 var this$1 = this;
9850
9851 this.extendSelectionsBy(function (range$$1) {
9852 if (this$1.display.shift || this$1.doc.extend || range$$1.empty())
9853 { return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) }
9854 else
9855 { return dir < 0 ? range$$1.from() : range$$1.to() }
9856 }, sel_move);
9857 }),
9858
9859 deleteH: methodOp(function(dir, unit) {
9860 var sel = this.doc.sel, doc = this.doc;
9861 if (sel.somethingSelected())
9862 { doc.replaceSelection("", null, "+delete"); }
9863 else
9864 { deleteNearSelection(this, function (range$$1) {
9865 var other = findPosH(doc, range$$1.head, dir, unit, false);
9866 return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other}
9867 }); }
9868 }),
9869
9870 findPosV: function(from, amount, unit, goalColumn) {
9871 var this$1 = this;
9872
9873 var dir = 1, x = goalColumn;
9874 if (amount < 0) { dir = -1; amount = -amount; }
9875 var cur = clipPos(this.doc, from);
9876 for (var i = 0; i < amount; ++i) {
9877 var coords = cursorCoords(this$1, cur, "div");
9878 if (x == null) { x = coords.left; }
9879 else { coords.left = x; }
9880 cur = findPosV(this$1, coords, dir, unit);
9881 if (cur.hitSide) { break }
9882 }
9883 return cur
9884 },
9885
9886 moveV: methodOp(function(dir, unit) {
9887 var this$1 = this;
9888
9889 var doc = this.doc, goals = [];
9890 var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();
9891 doc.extendSelectionsBy(function (range$$1) {
9892 if (collapse)
9893 { return dir < 0 ? range$$1.from() : range$$1.to() }
9894 var headPos = cursorCoords(this$1, range$$1.head, "div");
9895 if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; }
9896 goals.push(headPos.left);
9897 var pos = findPosV(this$1, headPos, dir, unit);
9898 if (unit == "page" && range$$1 == doc.sel.primary())
9899 { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); }
9900 return pos
9901 }, sel_move);
9902 if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++)
9903 { doc.sel.ranges[i].goalColumn = goals[i]; } }
9904 }),
9905
9906 // Find the word at the given position (as returned by coordsChar).
9907 findWordAt: function(pos) {
9908 var doc = this.doc, line = getLine(doc, pos.line).text;
9909 var start = pos.ch, end = pos.ch;
9910 if (line) {
9911 var helper = this.getHelper(pos, "wordChars");
9912 if ((pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end; }
9913 var startChar = line.charAt(start);
9914 var check = isWordChar(startChar, helper)
9915 ? function (ch) { return isWordChar(ch, helper); }
9916 : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); }
9917 : function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); };
9918 while (start > 0 && check(line.charAt(start - 1))) { --start; }
9919 while (end < line.length && check(line.charAt(end))) { ++end; }
9920 }
9921 return new Range(Pos(pos.line, start), Pos(pos.line, end))
9922 },
9923
9924 toggleOverwrite: function(value) {
9925 if (value != null && value == this.state.overwrite) { return }
9926 if (this.state.overwrite = !this.state.overwrite)
9927 { addClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
9928 else
9929 { rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
9930
9931 signal(this, "overwriteToggle", this, this.state.overwrite);
9932 },
9933 hasFocus: function() { return this.display.input.getField() == activeElt() },
9934 isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) },
9935
9936 scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }),
9937 getScrollInfo: function() {
9938 var scroller = this.display.scroller;
9939 return {left: scroller.scrollLeft, top: scroller.scrollTop,
9940 height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
9941 width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
9942 clientHeight: displayHeight(this), clientWidth: displayWidth(this)}
9943 },
9944
9945 scrollIntoView: methodOp(function(range$$1, margin) {
9946 if (range$$1 == null) {
9947 range$$1 = {from: this.doc.sel.primary().head, to: null};
9948 if (margin == null) { margin = this.options.cursorScrollMargin; }
9949 } else if (typeof range$$1 == "number") {
9950 range$$1 = {from: Pos(range$$1, 0), to: null};
9951 } else if (range$$1.from == null) {
9952 range$$1 = {from: range$$1, to: null};
9953 }
9954 if (!range$$1.to) { range$$1.to = range$$1.from; }
9955 range$$1.margin = margin || 0;
9956
9957 if (range$$1.from.line != null) {
9958 scrollToRange(this, range$$1);
9959 } else {
9960 scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin);
9961 }
9962 }),
9963
9964 setSize: methodOp(function(width, height) {
9965 var this$1 = this;
9966
9967 var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; };
9968 if (width != null) { this.display.wrapper.style.width = interpret(width); }
9969 if (height != null) { this.display.wrapper.style.height = interpret(height); }
9970 if (this.options.lineWrapping) { clearLineMeasurementCache(this); }
9971 var lineNo$$1 = this.display.viewFrom;
9972 this.doc.iter(lineNo$$1, this.display.viewTo, function (line) {
9973 if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)
9974 { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, "widget"); break } } }
9975 ++lineNo$$1;
9976 });
9977 this.curOp.forceUpdate = true;
9978 signal(this, "refresh", this);
9979 }),
9980
9981 operation: function(f){return runInOp(this, f)},
9982 startOperation: function(){return startOperation(this)},
9983 endOperation: function(){return endOperation(this)},
9984
9985 refresh: methodOp(function() {
9986 var oldHeight = this.display.cachedTextHeight;
9987 regChange(this);
9988 this.curOp.forceUpdate = true;
9989 clearCaches(this);
9990 scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);
9991 updateGutterSpace(this);
9992 if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
9993 { estimateLineHeights(this); }
9994 signal(this, "refresh", this);
9995 }),
9996
9997 swapDoc: methodOp(function(doc) {
9998 var old = this.doc;
9999 old.cm = null;
10000 attachDoc(this, doc);
10001 clearCaches(this);
10002 this.display.input.reset();
10003 scrollToCoords(this, doc.scrollLeft, doc.scrollTop);
10004 this.curOp.forceScroll = true;
10005 signalLater(this, "swapDoc", this, old);
10006 return old
10007 }),
10008
10009 getInputField: function(){return this.display.input.getField()},
10010 getWrapperElement: function(){return this.display.wrapper},
10011 getScrollerElement: function(){return this.display.scroller},
10012 getGutterElement: function(){return this.display.gutters}
10013 };
10014 eventMixin(CodeMirror);
10015
10016 CodeMirror.registerHelper = function(type, name, value) {
10017 if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; }
10018 helpers[type][name] = value;
10019 };
10020 CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
10021 CodeMirror.registerHelper(type, name, value);
10022 helpers[type]._global.push({pred: predicate, val: value});
10023 };
10024 };
10025
10026 // Used for horizontal relative motion. Dir is -1 or 1 (left or
10027 // right), unit can be "char", "column" (like char, but doesn't
10028 // cross line boundaries), "word" (across next word), or "group" (to
10029 // the start of next group of word or non-word-non-whitespace
10030 // chars). The visually param controls whether, in right-to-left
10031 // text, direction 1 means to move towards the next index in the
10032 // string, or towards the character to the right of the current
10033 // position. The resulting position will have a hitSide=true
10034 // property if it reached the end of the document.
10035 function findPosH(doc, pos, dir, unit, visually) {
10036 var oldPos = pos;
10037 var origDir = dir;
10038 var lineObj = getLine(doc, pos.line);
10039 function findNextLine() {
10040 var l = pos.line + dir;
10041 if (l < doc.first || l >= doc.first + doc.size) { return false }
10042 pos = new Pos(l, pos.ch, pos.sticky);
10043 return lineObj = getLine(doc, l)
10044 }
10045 function moveOnce(boundToLine) {
10046 var next;
10047 if (visually) {
10048 next = moveVisually(doc.cm, lineObj, pos, dir);
10049 } else {
10050 next = moveLogically(lineObj, pos, dir);
10051 }
10052 if (next == null) {
10053 if (!boundToLine && findNextLine())
10054 { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir); }
10055 else
10056 { return false }
10057 } else {
10058 pos = next;
10059 }
10060 return true
10061 }
10062
10063 if (unit == "char") {
10064 moveOnce();
10065 } else if (unit == "column") {
10066 moveOnce(true);
10067 } else if (unit == "word" || unit == "group") {
10068 var sawType = null, group = unit == "group";
10069 var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
10070 for (var first = true;; first = false) {
10071 if (dir < 0 && !moveOnce(!first)) { break }
10072 var cur = lineObj.text.charAt(pos.ch) || "\n";
10073 var type = isWordChar(cur, helper) ? "w"
10074 : group && cur == "\n" ? "n"
10075 : !group || /\s/.test(cur) ? null
10076 : "p";
10077 if (group && !first && !type) { type = "s"; }
10078 if (sawType && sawType != type) {
10079 if (dir < 0) {dir = 1; moveOnce(); pos.sticky = "after";}
10080 break
10081 }
10082
10083 if (type) { sawType = type; }
10084 if (dir > 0 && !moveOnce(!first)) { break }
10085 }
10086 }
10087 var result = skipAtomic(doc, pos, oldPos, origDir, true);
10088 if (equalCursorPos(oldPos, result)) { result.hitSide = true; }
10089 return result
10090 }
10091
10092 // For relative vertical movement. Dir may be -1 or 1. Unit can be
10093 // "page" or "line". The resulting position will have a hitSide=true
10094 // property if it reached the end of the document.
10095 function findPosV(cm, pos, dir, unit) {
10096 var doc = cm.doc, x = pos.left, y;
10097 if (unit == "page") {
10098 var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
10099 var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3);
10100 y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount;
10101
10102 } else if (unit == "line") {
10103 y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
10104 }
10105 var target;
10106 for (;;) {
10107 target = coordsChar(cm, x, y);
10108 if (!target.outside) { break }
10109 if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break }
10110 y += dir * 5;
10111 }
10112 return target
10113 }
10114
10115 // CONTENTEDITABLE INPUT STYLE
10116
10117 var ContentEditableInput = function(cm) {
10118 this.cm = cm;
10119 this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
10120 this.polling = new Delayed();
10121 this.composing = null;
10122 this.gracePeriod = false;
10123 this.readDOMTimeout = null;
10124 };
10125
10126 ContentEditableInput.prototype.init = function (display) {
10127 var this$1 = this;
10128
10129 var input = this, cm = input.cm;
10130 var div = input.div = display.lineDiv;
10131 disableBrowserMagic(div, cm.options.spellcheck);
10132
10133 on(div, "paste", function (e) {
10134 if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
10135 // IE doesn't fire input events, so we schedule a read for the pasted content in this way
10136 if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }
10137 });
10138
10139 on(div, "compositionstart", function (e) {
10140 this$1.composing = {data: e.data, done: false};
10141 });
10142 on(div, "compositionupdate", function (e) {
10143 if (!this$1.composing) { this$1.composing = {data: e.data, done: false}; }
10144 });
10145 on(div, "compositionend", function (e) {
10146 if (this$1.composing) {
10147 if (e.data != this$1.composing.data) { this$1.readFromDOMSoon(); }
10148 this$1.composing.done = true;
10149 }
10150 });
10151
10152 on(div, "touchstart", function () { return input.forceCompositionEnd(); });
10153
10154 on(div, "input", function () {
10155 if (!this$1.composing) { this$1.readFromDOMSoon(); }
10156 });
10157
10158 function onCopyCut(e) {
10159 if (signalDOMEvent(cm, e)) { return }
10160 if (cm.somethingSelected()) {
10161 setLastCopied({lineWise: false, text: cm.getSelections()});
10162 if (e.type == "cut") { cm.replaceSelection("", null, "cut"); }
10163 } else if (!cm.options.lineWiseCopyCut) {
10164 return
10165 } else {
10166 var ranges = copyableRanges(cm);
10167 setLastCopied({lineWise: true, text: ranges.text});
10168 if (e.type == "cut") {
10169 cm.operation(function () {
10170 cm.setSelections(ranges.ranges, 0, sel_dontScroll);
10171 cm.replaceSelection("", null, "cut");
10172 });
10173 }
10174 }
10175 if (e.clipboardData) {
10176 e.clipboardData.clearData();
10177 var content = lastCopied.text.join("\n");
10178 // iOS exposes the clipboard API, but seems to discard content inserted into it
10179 e.clipboardData.setData("Text", content);
10180 if (e.clipboardData.getData("Text") == content) {
10181 e.preventDefault();
10182 return
10183 }
10184 }
10185 // Old-fashioned briefly-focus-a-textarea hack
10186 var kludge = hiddenTextarea(), te = kludge.firstChild;
10187 cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
10188 te.value = lastCopied.text.join("\n");
10189 var hadFocus = document.activeElement;
10190 selectInput(te);
10191 setTimeout(function () {
10192 cm.display.lineSpace.removeChild(kludge);
10193 hadFocus.focus();
10194 if (hadFocus == div) { input.showPrimarySelection(); }
10195 }, 50);
10196 }
10197 on(div, "copy", onCopyCut);
10198 on(div, "cut", onCopyCut);
10199 };
10200
10201 ContentEditableInput.prototype.prepareSelection = function () {
10202 var result = prepareSelection(this.cm, false);
10203 result.focus = this.cm.state.focused;
10204 return result
10205 };
10206
10207 ContentEditableInput.prototype.showSelection = function (info, takeFocus) {
10208 if (!info || !this.cm.display.view.length) { return }
10209 if (info.focus || takeFocus) { this.showPrimarySelection(); }
10210 this.showMultipleSelections(info);
10211 };
10212
10213 ContentEditableInput.prototype.showPrimarySelection = function () {
10214 var sel = window.getSelection(), cm = this.cm, prim = cm.doc.sel.primary();
10215 var from = prim.from(), to = prim.to();
10216
10217 if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {
10218 sel.removeAllRanges();
10219 return
10220 }
10221
10222 var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
10223 var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset);
10224 if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
10225 cmp(minPos(curAnchor, curFocus), from) == 0 &&
10226 cmp(maxPos(curAnchor, curFocus), to) == 0)
10227 { return }
10228
10229 var view = cm.display.view;
10230 var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) ||
10231 {node: view[0].measure.map[2], offset: 0};
10232 var end = to.line < cm.display.viewTo && posToDOM(cm, to);
10233 if (!end) {
10234 var measure = view[view.length - 1].measure;
10235 var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
10236 end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]};
10237 }
10238
10239 if (!start || !end) {
10240 sel.removeAllRanges();
10241 return
10242 }
10243
10244 var old = sel.rangeCount && sel.getRangeAt(0), rng;
10245 try { rng = range(start.node, start.offset, end.offset, end.node); }
10246 catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
10247 if (rng) {
10248 if (!gecko && cm.state.focused) {
10249 sel.collapse(start.node, start.offset);
10250 if (!rng.collapsed) {
10251 sel.removeAllRanges();
10252 sel.addRange(rng);
10253 }
10254 } else {
10255 sel.removeAllRanges();
10256 sel.addRange(rng);
10257 }
10258 if (old && sel.anchorNode == null) { sel.addRange(old); }
10259 else if (gecko) { this.startGracePeriod(); }
10260 }
10261 this.rememberSelection();
10262 };
10263
10264 ContentEditableInput.prototype.startGracePeriod = function () {
10265 var this$1 = this;
10266
10267 clearTimeout(this.gracePeriod);
10268 this.gracePeriod = setTimeout(function () {
10269 this$1.gracePeriod = false;
10270 if (this$1.selectionChanged())
10271 { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }); }
10272 }, 20);
10273 };
10274
10275 ContentEditableInput.prototype.showMultipleSelections = function (info) {
10276 removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
10277 removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
10278 };
10279
10280 ContentEditableInput.prototype.rememberSelection = function () {
10281 var sel = window.getSelection();
10282 this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
10283 this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
10284 };
10285
10286 ContentEditableInput.prototype.selectionInEditor = function () {
10287 var sel = window.getSelection();
10288 if (!sel.rangeCount) { return false }
10289 var node = sel.getRangeAt(0).commonAncestorContainer;
10290 return contains(this.div, node)
10291 };
10292
10293 ContentEditableInput.prototype.focus = function () {
10294 if (this.cm.options.readOnly != "nocursor") {
10295 if (!this.selectionInEditor())
10296 { this.showSelection(this.prepareSelection(), true); }
10297 this.div.focus();
10298 }
10299 };
10300 ContentEditableInput.prototype.blur = function () { this.div.blur(); };
10301 ContentEditableInput.prototype.getField = function () { return this.div };
10302
10303 ContentEditableInput.prototype.supportsTouch = function () { return true };
10304
10305 ContentEditableInput.prototype.receivedFocus = function () {
10306 var input = this;
10307 if (this.selectionInEditor())
10308 { this.pollSelection(); }
10309 else
10310 { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); }
10311
10312 function poll() {
10313 if (input.cm.state.focused) {
10314 input.pollSelection();
10315 input.polling.set(input.cm.options.pollInterval, poll);
10316 }
10317 }
10318 this.polling.set(this.cm.options.pollInterval, poll);
10319 };
10320
10321 ContentEditableInput.prototype.selectionChanged = function () {
10322 var sel = window.getSelection();
10323 return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
10324 sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
10325 };
10326
10327 ContentEditableInput.prototype.pollSelection = function () {
10328 if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return }
10329 var sel = window.getSelection(), cm = this.cm;
10330 // On Android Chrome (version 56, at least), backspacing into an
10331 // uneditable block element will put the cursor in that element,
10332 // and then, because it's not editable, hide the virtual keyboard.
10333 // Because Android doesn't allow us to actually detect backspace
10334 // presses in a sane way, this code checks for when that happens
10335 // and simulates a backspace press in this case.
10336 if (android && chrome && this.cm.options.gutters.length && isInGutter(sel.anchorNode)) {
10337 this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs});
10338 this.blur();
10339 this.focus();
10340 return
10341 }
10342 if (this.composing) { return }
10343 this.rememberSelection();
10344 var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
10345 var head = domToPos(cm, sel.focusNode, sel.focusOffset);
10346 if (anchor && head) { runInOp(cm, function () {
10347 setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
10348 if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true; }
10349 }); }
10350 };
10351
10352 ContentEditableInput.prototype.pollContent = function () {
10353 if (this.readDOMTimeout != null) {
10354 clearTimeout(this.readDOMTimeout);
10355 this.readDOMTimeout = null;
10356 }
10357
10358 var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
10359 var from = sel.from(), to = sel.to();
10360 if (from.ch == 0 && from.line > cm.firstLine())
10361 { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); }
10362 if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())
10363 { to = Pos(to.line + 1, 0); }
10364 if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }
10365
10366 var fromIndex, fromLine, fromNode;
10367 if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
10368 fromLine = lineNo(display.view[0].line);
10369 fromNode = display.view[0].node;
10370 } else {
10371 fromLine = lineNo(display.view[fromIndex].line);
10372 fromNode = display.view[fromIndex - 1].node.nextSibling;
10373 }
10374 var toIndex = findViewIndex(cm, to.line);
10375 var toLine, toNode;
10376 if (toIndex == display.view.length - 1) {
10377 toLine = display.viewTo - 1;
10378 toNode = display.lineDiv.lastChild;
10379 } else {
10380 toLine = lineNo(display.view[toIndex + 1].line) - 1;
10381 toNode = display.view[toIndex + 1].node.previousSibling;
10382 }
10383
10384 if (!fromNode) { return false }
10385 var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
10386 var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
10387 while (newText.length > 1 && oldText.length > 1) {
10388 if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
10389 else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
10390 else { break }
10391 }
10392
10393 var cutFront = 0, cutEnd = 0;
10394 var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
10395 while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
10396 { ++cutFront; }
10397 var newBot = lst(newText), oldBot = lst(oldText);
10398 var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
10399 oldBot.length - (oldText.length == 1 ? cutFront : 0));
10400 while (cutEnd < maxCutEnd &&
10401 newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
10402 { ++cutEnd; }
10403 // Try to move start of change to start of selection if ambiguous
10404 if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) {
10405 while (cutFront && cutFront > from.ch &&
10406 newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) {
10407 cutFront--;
10408 cutEnd++;
10409 }
10410 }
10411
10412 newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "");
10413 newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "");
10414
10415 var chFrom = Pos(fromLine, cutFront);
10416 var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
10417 if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
10418 replaceRange(cm.doc, newText, chFrom, chTo, "+input");
10419 return true
10420 }
10421 };
10422
10423 ContentEditableInput.prototype.ensurePolled = function () {
10424 this.forceCompositionEnd();
10425 };
10426 ContentEditableInput.prototype.reset = function () {
10427 this.forceCompositionEnd();
10428 };
10429 ContentEditableInput.prototype.forceCompositionEnd = function () {
10430 if (!this.composing) { return }
10431 clearTimeout(this.readDOMTimeout);
10432 this.composing = null;
10433 this.updateFromDOM();
10434 this.div.blur();
10435 this.div.focus();
10436 };
10437 ContentEditableInput.prototype.readFromDOMSoon = function () {
10438 var this$1 = this;
10439
10440 if (this.readDOMTimeout != null) { return }
10441 this.readDOMTimeout = setTimeout(function () {
10442 this$1.readDOMTimeout = null;
10443 if (this$1.composing) {
10444 if (this$1.composing.done) { this$1.composing = null; }
10445 else { return }
10446 }
10447 this$1.updateFromDOM();
10448 }, 80);
10449 };
10450
10451 ContentEditableInput.prototype.updateFromDOM = function () {
10452 var this$1 = this;
10453
10454 if (this.cm.isReadOnly() || !this.pollContent())
10455 { runInOp(this.cm, function () { return regChange(this$1.cm); }); }
10456 };
10457
10458 ContentEditableInput.prototype.setUneditable = function (node) {
10459 node.contentEditable = "false";
10460 };
10461
10462 ContentEditableInput.prototype.onKeyPress = function (e) {
10463 if (e.charCode == 0) { return }
10464 e.preventDefault();
10465 if (!this.cm.isReadOnly())
10466 { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); }
10467 };
10468
10469 ContentEditableInput.prototype.readOnlyChanged = function (val) {
10470 this.div.contentEditable = String(val != "nocursor");
10471 };
10472
10473 ContentEditableInput.prototype.onContextMenu = function () {};
10474 ContentEditableInput.prototype.resetPosition = function () {};
10475
10476 ContentEditableInput.prototype.needsContentAttribute = true;
10477
10478 function posToDOM(cm, pos) {
10479 var view = findViewForLine(cm, pos.line);
10480 if (!view || view.hidden) { return null }
10481 var line = getLine(cm.doc, pos.line);
10482 var info = mapFromLineView(view, line, pos.line);
10483
10484 var order = getOrder(line, cm.doc.direction), side = "left";
10485 if (order) {
10486 var partPos = getBidiPartAt(order, pos.ch);
10487 side = partPos % 2 ? "right" : "left";
10488 }
10489 var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
10490 result.offset = result.collapse == "right" ? result.end : result.start;
10491 return result
10492 }
10493
10494 function isInGutter(node) {
10495 for (var scan = node; scan; scan = scan.parentNode)
10496 { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } }
10497 return false
10498 }
10499
10500 function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
10501
10502 function domTextBetween(cm, from, to, fromLine, toLine) {
10503 var text = "", closing = false, lineSep = cm.doc.lineSeparator();
10504 function recognizeMarker(id) { return function (marker) { return marker.id == id; } }
10505 function close() {
10506 if (closing) {
10507 text += lineSep;
10508 closing = false;
10509 }
10510 }
10511 function addText(str) {
10512 if (str) {
10513 close();
10514 text += str;
10515 }
10516 }
10517 function walk(node) {
10518 if (node.nodeType == 1) {
10519 var cmText = node.getAttribute("cm-text");
10520 if (cmText != null) {
10521 addText(cmText || node.textContent.replace(/\u200b/g, ""));
10522 return
10523 }
10524 var markerID = node.getAttribute("cm-marker"), range$$1;
10525 if (markerID) {
10526 var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
10527 if (found.length && (range$$1 = found[0].find(0)))
10528 { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); }
10529 return
10530 }
10531 if (node.getAttribute("contenteditable") == "false") { return }
10532 var isBlock = /^(pre|div|p)$/i.test(node.nodeName);
10533 if (isBlock) { close(); }
10534 for (var i = 0; i < node.childNodes.length; i++)
10535 { walk(node.childNodes[i]); }
10536 if (isBlock) { closing = true; }
10537 } else if (node.nodeType == 3) {
10538 addText(node.nodeValue);
10539 }
10540 }
10541 for (;;) {
10542 walk(from);
10543 if (from == to) { break }
10544 from = from.nextSibling;
10545 }
10546 return text
10547 }
10548
10549 function domToPos(cm, node, offset) {
10550 var lineNode;
10551 if (node == cm.display.lineDiv) {
10552 lineNode = cm.display.lineDiv.childNodes[offset];
10553 if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) }
10554 node = null; offset = 0;
10555 } else {
10556 for (lineNode = node;; lineNode = lineNode.parentNode) {
10557 if (!lineNode || lineNode == cm.display.lineDiv) { return null }
10558 if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break }
10559 }
10560 }
10561 for (var i = 0; i < cm.display.view.length; i++) {
10562 var lineView = cm.display.view[i];
10563 if (lineView.node == lineNode)
10564 { return locateNodeInLineView(lineView, node, offset) }
10565 }
10566 }
10567
10568 function locateNodeInLineView(lineView, node, offset) {
10569 var wrapper = lineView.text.firstChild, bad = false;
10570 if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) }
10571 if (node == wrapper) {
10572 bad = true;
10573 node = wrapper.childNodes[offset];
10574 offset = 0;
10575 if (!node) {
10576 var line = lineView.rest ? lst(lineView.rest) : lineView.line;
10577 return badPos(Pos(lineNo(line), line.text.length), bad)
10578 }
10579 }
10580
10581 var textNode = node.nodeType == 3 ? node : null, topNode = node;
10582 if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
10583 textNode = node.firstChild;
10584 if (offset) { offset = textNode.nodeValue.length; }
10585 }
10586 while (topNode.parentNode != wrapper) { topNode = topNode.parentNode; }
10587 var measure = lineView.measure, maps = measure.maps;
10588
10589 function find(textNode, topNode, offset) {
10590 for (var i = -1; i < (maps ? maps.length : 0); i++) {
10591 var map$$1 = i < 0 ? measure.map : maps[i];
10592 for (var j = 0; j < map$$1.length; j += 3) {
10593 var curNode = map$$1[j + 2];
10594 if (curNode == textNode || curNode == topNode) {
10595 var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
10596 var ch = map$$1[j] + offset;
10597 if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; }
10598 return Pos(line, ch)
10599 }
10600 }
10601 }
10602 }
10603 var found = find(textNode, topNode, offset);
10604 if (found) { return badPos(found, bad) }
10605
10606 // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
10607 for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
10608 found = find(after, after.firstChild, 0);
10609 if (found)
10610 { return badPos(Pos(found.line, found.ch - dist), bad) }
10611 else
10612 { dist += after.textContent.length; }
10613 }
10614 for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) {
10615 found = find(before, before.firstChild, -1);
10616 if (found)
10617 { return badPos(Pos(found.line, found.ch + dist$1), bad) }
10618 else
10619 { dist$1 += before.textContent.length; }
10620 }
10621 }
10622
10623 // TEXTAREA INPUT STYLE
10624
10625 var TextareaInput = function(cm) {
10626 this.cm = cm;
10627 // See input.poll and input.reset
10628 this.prevInput = "";
10629
10630 // Flag that indicates whether we expect input to appear real soon
10631 // now (after some event like 'keypress' or 'input') and are
10632 // polling intensively.
10633 this.pollingFast = false;
10634 // Self-resetting timeout for the poller
10635 this.polling = new Delayed();
10636 // Used to work around IE issue with selection being forgotten when focus moves away from textarea
10637 this.hasSelection = false;
10638 this.composing = null;
10639 };
10640
10641 TextareaInput.prototype.init = function (display) {
10642 var this$1 = this;
10643
10644 var input = this, cm = this.cm;
10645
10646 // Wraps and hides input textarea
10647 var div = this.wrapper = hiddenTextarea();
10648 // The semihidden textarea that is focused when the editor is
10649 // focused, and receives input.
10650 var te = this.textarea = div.firstChild;
10651 display.wrapper.insertBefore(div, display.wrapper.firstChild);
10652
10653 // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
10654 if (ios) { te.style.width = "0px"; }
10655
10656 on(te, "input", function () {
10657 if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null; }
10658 input.poll();
10659 });
10660
10661 on(te, "paste", function (e) {
10662 if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
10663
10664 cm.state.pasteIncoming = true;
10665 input.fastPoll();
10666 });
10667
10668 function prepareCopyCut(e) {
10669 if (signalDOMEvent(cm, e)) { return }
10670 if (cm.somethingSelected()) {
10671 setLastCopied({lineWise: false, text: cm.getSelections()});
10672 } else if (!cm.options.lineWiseCopyCut) {
10673 return
10674 } else {
10675 var ranges = copyableRanges(cm);
10676 setLastCopied({lineWise: true, text: ranges.text});
10677 if (e.type == "cut") {
10678 cm.setSelections(ranges.ranges, null, sel_dontScroll);
10679 } else {
10680 input.prevInput = "";
10681 te.value = ranges.text.join("\n");
10682 selectInput(te);
10683 }
10684 }
10685 if (e.type == "cut") { cm.state.cutIncoming = true; }
10686 }
10687 on(te, "cut", prepareCopyCut);
10688 on(te, "copy", prepareCopyCut);
10689
10690 on(display.scroller, "paste", function (e) {
10691 if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }
10692 cm.state.pasteIncoming = true;
10693 input.focus();
10694 });
10695
10696 // Prevent normal selection in the editor (we handle our own)
10697 on(display.lineSpace, "selectstart", function (e) {
10698 if (!eventInWidget(display, e)) { e_preventDefault(e); }
10699 });
10700
10701 on(te, "compositionstart", function () {
10702 var start = cm.getCursor("from");
10703 if (input.composing) { input.composing.range.clear(); }
10704 input.composing = {
10705 start: start,
10706 range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
10707 };
10708 });
10709 on(te, "compositionend", function () {
10710 if (input.composing) {
10711 input.poll();
10712 input.composing.range.clear();
10713 input.composing = null;
10714 }
10715 });
10716 };
10717
10718 TextareaInput.prototype.prepareSelection = function () {
10719 // Redraw the selection and/or cursor
10720 var cm = this.cm, display = cm.display, doc = cm.doc;
10721 var result = prepareSelection(cm);
10722
10723 // Move the hidden textarea near the cursor to prevent scrolling artifacts
10724 if (cm.options.moveInputWithCursor) {
10725 var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
10726 var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
10727 result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
10728 headPos.top + lineOff.top - wrapOff.top));
10729 result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
10730 headPos.left + lineOff.left - wrapOff.left));
10731 }
10732
10733 return result
10734 };
10735
10736 TextareaInput.prototype.showSelection = function (drawn) {
10737 var cm = this.cm, display = cm.display;
10738 removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
10739 removeChildrenAndAdd(display.selectionDiv, drawn.selection);
10740 if (drawn.teTop != null) {
10741 this.wrapper.style.top = drawn.teTop + "px";
10742 this.wrapper.style.left = drawn.teLeft + "px";
10743 }
10744 };
10745
10746 // Reset the input to correspond to the selection (or to be empty,
10747 // when not typing and nothing is selected)
10748 TextareaInput.prototype.reset = function (typing) {
10749 if (this.contextMenuPending || this.composing) { return }
10750 var cm = this.cm;
10751 if (cm.somethingSelected()) {
10752 this.prevInput = "";
10753 var content = cm.getSelection();
10754 this.textarea.value = content;
10755 if (cm.state.focused) { selectInput(this.textarea); }
10756 if (ie && ie_version >= 9) { this.hasSelection = content; }
10757 } else if (!typing) {
10758 this.prevInput = this.textarea.value = "";
10759 if (ie && ie_version >= 9) { this.hasSelection = null; }
10760 }
10761 };
10762
10763 TextareaInput.prototype.getField = function () { return this.textarea };
10764
10765 TextareaInput.prototype.supportsTouch = function () { return false };
10766
10767 TextareaInput.prototype.focus = function () {
10768 if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
10769 try { this.textarea.focus(); }
10770 catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
10771 }
10772 };
10773
10774 TextareaInput.prototype.blur = function () { this.textarea.blur(); };
10775
10776 TextareaInput.prototype.resetPosition = function () {
10777 this.wrapper.style.top = this.wrapper.style.left = 0;
10778 };
10779
10780 TextareaInput.prototype.receivedFocus = function () { this.slowPoll(); };
10781
10782 // Poll for input changes, using the normal rate of polling. This
10783 // runs as long as the editor is focused.
10784 TextareaInput.prototype.slowPoll = function () {
10785 var this$1 = this;
10786
10787 if (this.pollingFast) { return }
10788 this.polling.set(this.cm.options.pollInterval, function () {
10789 this$1.poll();
10790 if (this$1.cm.state.focused) { this$1.slowPoll(); }
10791 });
10792 };
10793
10794 // When an event has just come in that is likely to add or change
10795 // something in the input textarea, we poll faster, to ensure that
10796 // the change appears on the screen quickly.
10797 TextareaInput.prototype.fastPoll = function () {
10798 var missed = false, input = this;
10799 input.pollingFast = true;
10800 function p() {
10801 var changed = input.poll();
10802 if (!changed && !missed) {missed = true; input.polling.set(60, p);}
10803 else {input.pollingFast = false; input.slowPoll();}
10804 }
10805 input.polling.set(20, p);
10806 };
10807
10808 // Read input from the textarea, and update the document to match.
10809 // When something is selected, it is present in the textarea, and
10810 // selected (unless it is huge, in which case a placeholder is
10811 // used). When nothing is selected, the cursor sits after previously
10812 // seen text (can be empty), which is stored in prevInput (we must
10813 // not reset the textarea when typing, because that breaks IME).
10814 TextareaInput.prototype.poll = function () {
10815 var this$1 = this;
10816
10817 var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
10818 // Since this is called a *lot*, try to bail out as cheaply as
10819 // possible when it is clear that nothing happened. hasSelection
10820 // will be the case when there is a lot of text in the textarea,
10821 // in which case reading its value would be expensive.
10822 if (this.contextMenuPending || !cm.state.focused ||
10823 (hasSelection(input) && !prevInput && !this.composing) ||
10824 cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
10825 { return false }
10826
10827 var text = input.value;
10828 // If nothing changed, bail.
10829 if (text == prevInput && !cm.somethingSelected()) { return false }
10830 // Work around nonsensical selection resetting in IE9/10, and
10831 // inexplicable appearance of private area unicode characters on
10832 // some key combos in Mac (#2689).
10833 if (ie && ie_version >= 9 && this.hasSelection === text ||
10834 mac && /[\uf700-\uf7ff]/.test(text)) {
10835 cm.display.input.reset();
10836 return false
10837 }
10838
10839 if (cm.doc.sel == cm.display.selForContextMenu) {
10840 var first = text.charCodeAt(0);
10841 if (first == 0x200b && !prevInput) { prevInput = "\u200b"; }
10842 if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") }
10843 }
10844 // Find the part of the input that is actually new
10845 var same = 0, l = Math.min(prevInput.length, text.length);
10846 while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; }
10847
10848 runInOp(cm, function () {
10849 applyTextInput(cm, text.slice(same), prevInput.length - same,
10850 null, this$1.composing ? "*compose" : null);
10851
10852 // Don't leave long text in the textarea, since it makes further polling slow
10853 if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = ""; }
10854 else { this$1.prevInput = text; }
10855
10856 if (this$1.composing) {
10857 this$1.composing.range.clear();
10858 this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"),
10859 {className: "CodeMirror-composing"});
10860 }
10861 });
10862 return true
10863 };
10864
10865 TextareaInput.prototype.ensurePolled = function () {
10866 if (this.pollingFast && this.poll()) { this.pollingFast = false; }
10867 };
10868
10869 TextareaInput.prototype.onKeyPress = function () {
10870 if (ie && ie_version >= 9) { this.hasSelection = null; }
10871 this.fastPoll();
10872 };
10873
10874 TextareaInput.prototype.onContextMenu = function (e) {
10875 var input = this, cm = input.cm, display = cm.display, te = input.textarea;
10876 var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
10877 if (!pos || presto) { return } // Opera is difficult.
10878
10879 // Reset the current text selection only if the click is done outside of the selection
10880 // and 'resetSelectionOnContextMenu' option is true.
10881 var reset = cm.options.resetSelectionOnContextMenu;
10882 if (reset && cm.doc.sel.contains(pos) == -1)
10883 { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); }
10884
10885 var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;
10886 input.wrapper.style.cssText = "position: absolute";
10887 var wrapperBox = input.wrapper.getBoundingClientRect();
10888 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);";
10889 var oldScrollY;
10890 if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712)
10891 display.input.focus();
10892 if (webkit) { window.scrollTo(null, oldScrollY); }
10893 display.input.reset();
10894 // Adds "Select all" to context menu in FF
10895 if (!cm.somethingSelected()) { te.value = input.prevInput = " "; }
10896 input.contextMenuPending = true;
10897 display.selForContextMenu = cm.doc.sel;
10898 clearTimeout(display.detectingSelectAll);
10899
10900 // Select-all will be greyed out if there's nothing to select, so
10901 // this adds a zero-width space so that we can later check whether
10902 // it got selected.
10903 function prepareSelectAllHack() {
10904 if (te.selectionStart != null) {
10905 var selected = cm.somethingSelected();
10906 var extval = "\u200b" + (selected ? te.value : "");
10907 te.value = "\u21da"; // Used to catch context-menu undo
10908 te.value = extval;
10909 input.prevInput = selected ? "" : "\u200b";
10910 te.selectionStart = 1; te.selectionEnd = extval.length;
10911 // Re-set this, in case some other handler touched the
10912 // selection in the meantime.
10913 display.selForContextMenu = cm.doc.sel;
10914 }
10915 }
10916 function rehide() {
10917 input.contextMenuPending = false;
10918 input.wrapper.style.cssText = oldWrapperCSS;
10919 te.style.cssText = oldCSS;
10920 if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); }
10921
10922 // Try to detect the user choosing select-all
10923 if (te.selectionStart != null) {
10924 if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack(); }
10925 var i = 0, poll = function () {
10926 if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
10927 te.selectionEnd > 0 && input.prevInput == "\u200b") {
10928 operation(cm, selectAll)(cm);
10929 } else if (i++ < 10) {
10930 display.detectingSelectAll = setTimeout(poll, 500);
10931 } else {
10932 display.selForContextMenu = null;
10933 display.input.reset();
10934 }
10935 };
10936 display.detectingSelectAll = setTimeout(poll, 200);
10937 }
10938 }
10939
10940 if (ie && ie_version >= 9) { prepareSelectAllHack(); }
10941 if (captureRightClick) {
10942 e_stop(e);
10943 var mouseup = function () {
10944 off(window, "mouseup", mouseup);
10945 setTimeout(rehide, 20);
10946 };
10947 on(window, "mouseup", mouseup);
10948 } else {
10949 setTimeout(rehide, 50);
10950 }
10951 };
10952
10953 TextareaInput.prototype.readOnlyChanged = function (val) {
10954 if (!val) { this.reset(); }
10955 this.textarea.disabled = val == "nocursor";
10956 };
10957
10958 TextareaInput.prototype.setUneditable = function () {};
10959
10960 TextareaInput.prototype.needsContentAttribute = false;
10961
10962 function fromTextArea(textarea, options) {
10963 options = options ? copyObj(options) : {};
10964 options.value = textarea.value;
10965 if (!options.tabindex && textarea.tabIndex)
10966 { options.tabindex = textarea.tabIndex; }
10967 if (!options.placeholder && textarea.placeholder)
10968 { options.placeholder = textarea.placeholder; }
10969 // Set autofocus to true if this textarea is focused, or if it has
10970 // autofocus and no other element is focused.
10971 if (options.autofocus == null) {
10972 var hasFocus = activeElt();
10973 options.autofocus = hasFocus == textarea ||
10974 textarea.getAttribute("autofocus") != null && hasFocus == document.body;
10975 }
10976
10977 function save() {textarea.value = cm.getValue();}
10978
10979 var realSubmit;
10980 if (textarea.form) {
10981 on(textarea.form, "submit", save);
10982 // Deplorable hack to make the submit method do the right thing.
10983 if (!options.leaveSubmitMethodAlone) {
10984 var form = textarea.form;
10985 realSubmit = form.submit;
10986 try {
10987 var wrappedSubmit = form.submit = function () {
10988 save();
10989 form.submit = realSubmit;
10990 form.submit();
10991 form.submit = wrappedSubmit;
10992 };
10993 } catch(e) {}
10994 }
10995 }
10996
10997 options.finishInit = function (cm) {
10998 cm.save = save;
10999 cm.getTextArea = function () { return textarea; };
11000 cm.toTextArea = function () {
11001 cm.toTextArea = isNaN; // Prevent this from being ran twice
11002 save();
11003 textarea.parentNode.removeChild(cm.getWrapperElement());
11004 textarea.style.display = "";
11005 if (textarea.form) {
11006 off(textarea.form, "submit", save);
11007 if (typeof textarea.form.submit == "function")
11008 { textarea.form.submit = realSubmit; }
11009 }
11010 };
11011 };
11012
11013 textarea.style.display = "none";
11014 var cm = CodeMirror$1(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); },
11015 options);
11016 return cm
11017 }
11018
11019 function addLegacyProps(CodeMirror) {
11020 CodeMirror.off = off;
11021 CodeMirror.on = on;
11022 CodeMirror.wheelEventPixels = wheelEventPixels;
11023 CodeMirror.Doc = Doc;
11024 CodeMirror.splitLines = splitLinesAuto;
11025 CodeMirror.countColumn = countColumn;
11026 CodeMirror.findColumn = findColumn;
11027 CodeMirror.isWordChar = isWordCharBasic;
11028 CodeMirror.Pass = Pass;
11029 CodeMirror.signal = signal;
11030 CodeMirror.Line = Line;
11031 CodeMirror.changeEnd = changeEnd;
11032 CodeMirror.scrollbarModel = scrollbarModel;
11033 CodeMirror.Pos = Pos;
11034 CodeMirror.cmpPos = cmp;
11035 CodeMirror.modes = modes;
11036 CodeMirror.mimeModes = mimeModes;
11037 CodeMirror.resolveMode = resolveMode;
11038 CodeMirror.getMode = getMode;
11039 CodeMirror.modeExtensions = modeExtensions;
11040 CodeMirror.extendMode = extendMode;
11041 CodeMirror.copyState = copyState;
11042 CodeMirror.startState = startState;
11043 CodeMirror.innerMode = innerMode;
11044 CodeMirror.commands = commands;
11045 CodeMirror.keyMap = keyMap;
11046 CodeMirror.keyName = keyName;
11047 CodeMirror.isModifierKey = isModifierKey;
11048 CodeMirror.lookupKey = lookupKey;
11049 CodeMirror.normalizeKeyMap = normalizeKeyMap;
11050 CodeMirror.StringStream = StringStream;
11051 CodeMirror.SharedTextMarker = SharedTextMarker;
11052 CodeMirror.TextMarker = TextMarker;
11053 CodeMirror.LineWidget = LineWidget;
11054 CodeMirror.e_preventDefault = e_preventDefault;
11055 CodeMirror.e_stopPropagation = e_stopPropagation;
11056 CodeMirror.e_stop = e_stop;
11057 CodeMirror.addClass = addClass;
11058 CodeMirror.contains = contains;
11059 CodeMirror.rmClass = rmClass;
11060 CodeMirror.keyNames = keyNames;
11061 }
11062
11063 // EDITOR CONSTRUCTOR
11064
11065 defineOptions(CodeMirror$1);
11066
11067 addEditorMethods(CodeMirror$1);
11068
11069 // Set up methods on CodeMirror's prototype to redirect to the editor's document.
11070 var dontDelegate = "iter insert remove copy getEditor constructor".split(" ");
11071 for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
11072 { CodeMirror$1.prototype[prop] = (function(method) {
11073 return function() {return method.apply(this.doc, arguments)}
11074 })(Doc.prototype[prop]); } }
11075
11076 eventMixin(Doc);
11077
11078 // INPUT HANDLING
11079
11080 CodeMirror$1.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
11081
11082 // MODE DEFINITION AND QUERYING
11083
11084 // Extra arguments are stored as the mode's dependencies, which is
11085 // used by (legacy) mechanisms like loadmode.js to automatically
11086 // load a mode. (Preferred mechanism is the require/define calls.)
11087 CodeMirror$1.defineMode = function(name/*, mode, …*/) {
11088 if (!CodeMirror$1.defaults.mode && name != "null") { CodeMirror$1.defaults.mode = name; }
11089 defineMode.apply(this, arguments);
11090 };
11091
11092 CodeMirror$1.defineMIME = defineMIME;
11093
11094 // Minimal default mode.
11095 CodeMirror$1.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });
11096 CodeMirror$1.defineMIME("text/plain", "null");
11097
11098 // EXTENSIONS
11099
11100 CodeMirror$1.defineExtension = function (name, func) {
11101 CodeMirror$1.prototype[name] = func;
11102 };
11103 CodeMirror$1.defineDocExtension = function (name, func) {
11104 Doc.prototype[name] = func;
11105 };
11106
11107 CodeMirror$1.fromTextArea = fromTextArea;
11108
11109 addLegacyProps(CodeMirror$1);
11110
11111 CodeMirror$1.version = "5.33.0";
11112
11113 return CodeMirror$1;
11114
11115 })));
11116
11117 },{}],13:[function(require,module,exports){
11118 // CodeMirror, copyright (c) by Marijn Haverbeke and others
11119 // Distributed under an MIT license: http://codemirror.net/LICENSE
11120
11121 (function(mod) {
11122 if (typeof exports == "object" && typeof module == "object") // CommonJS
11123 mod(require("../../lib/codemirror"));
11124 else if (typeof define == "function" && define.amd) // AMD
11125 define(["../../lib/codemirror"], mod);
11126 else // Plain browser env
11127 mod(CodeMirror);
11128 })(function(CodeMirror) {
11129 "use strict";
11130
11131 CodeMirror.defineMode("css", function(config, parserConfig) {
11132 var inline = parserConfig.inline
11133 if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
11134
11135 var indentUnit = config.indentUnit,
11136 tokenHooks = parserConfig.tokenHooks,
11137 documentTypes = parserConfig.documentTypes || {},
11138 mediaTypes = parserConfig.mediaTypes || {},
11139 mediaFeatures = parserConfig.mediaFeatures || {},
11140 mediaValueKeywords = parserConfig.mediaValueKeywords || {},
11141 propertyKeywords = parserConfig.propertyKeywords || {},
11142 nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
11143 fontProperties = parserConfig.fontProperties || {},
11144 counterDescriptors = parserConfig.counterDescriptors || {},
11145 colorKeywords = parserConfig.colorKeywords || {},
11146 valueKeywords = parserConfig.valueKeywords || {},
11147 allowNested = parserConfig.allowNested,
11148 lineComment = parserConfig.lineComment,
11149 supportsAtComponent = parserConfig.supportsAtComponent === true;
11150
11151 var type, override;
11152 function ret(style, tp) { type = tp; return style; }
11153
11154 // Tokenizers
11155
11156 function tokenBase(stream, state) {
11157 var ch = stream.next();
11158 if (tokenHooks[ch]) {
11159 var result = tokenHooks[ch](stream, state);
11160 if (result !== false) return result;
11161 }
11162 if (ch == "@") {
11163 stream.eatWhile(/[\w\\\-]/);
11164 return ret("def", stream.current());
11165 } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
11166 return ret(null, "compare");
11167 } else if (ch == "\"" || ch == "'") {
11168 state.tokenize = tokenString(ch);
11169 return state.tokenize(stream, state);
11170 } else if (ch == "#") {
11171 stream.eatWhile(/[\w\\\-]/);
11172 return ret("atom", "hash");
11173 } else if (ch == "!") {
11174 stream.match(/^\s*\w*/);
11175 return ret("keyword", "important");
11176 } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
11177 stream.eatWhile(/[\w.%]/);
11178 return ret("number", "unit");
11179 } else if (ch === "-") {
11180 if (/[\d.]/.test(stream.peek())) {
11181 stream.eatWhile(/[\w.%]/);
11182 return ret("number", "unit");
11183 } else if (stream.match(/^-[\w\\\-]+/)) {
11184 stream.eatWhile(/[\w\\\-]/);
11185 if (stream.match(/^\s*:/, false))
11186 return ret("variable-2", "variable-definition");
11187 return ret("variable-2", "variable");
11188 } else if (stream.match(/^\w+-/)) {
11189 return ret("meta", "meta");
11190 }
11191 } else if (/[,+>*\/]/.test(ch)) {
11192 return ret(null, "select-op");
11193 } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
11194 return ret("qualifier", "qualifier");
11195 } else if (/[:;{}\[\]\(\)]/.test(ch)) {
11196 return ret(null, ch);
11197 } else if (((ch == "u" || ch == "U") && stream.match(/rl(-prefix)?\(/i)) ||
11198 ((ch == "d" || ch == "D") && stream.match("omain(", true, true)) ||
11199 ((ch == "r" || ch == "R") && stream.match("egexp(", true, true))) {
11200 stream.backUp(1);
11201 state.tokenize = tokenParenthesized;
11202 return ret("property", "word");
11203 } else if (/[\w\\\-]/.test(ch)) {
11204 stream.eatWhile(/[\w\\\-]/);
11205 return ret("property", "word");
11206 } else {
11207 return ret(null, null);
11208 }
11209 }
11210
11211 function tokenString(quote) {
11212 return function(stream, state) {
11213 var escaped = false, ch;
11214 while ((ch = stream.next()) != null) {
11215 if (ch == quote && !escaped) {
11216 if (quote == ")") stream.backUp(1);
11217 break;
11218 }
11219 escaped = !escaped && ch == "\\";
11220 }
11221 if (ch == quote || !escaped && quote != ")") state.tokenize = null;
11222 return ret("string", "string");
11223 };
11224 }
11225
11226 function tokenParenthesized(stream, state) {
11227 stream.next(); // Must be '('
11228 if (!stream.match(/\s*[\"\')]/, false))
11229 state.tokenize = tokenString(")");
11230 else
11231 state.tokenize = null;
11232 return ret(null, "(");
11233 }
11234
11235 // Context management
11236
11237 function Context(type, indent, prev) {
11238 this.type = type;
11239 this.indent = indent;
11240 this.prev = prev;
11241 }
11242
11243 function pushContext(state, stream, type, indent) {
11244 state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context);
11245 return type;
11246 }
11247
11248 function popContext(state) {
11249 if (state.context.prev)
11250 state.context = state.context.prev;
11251 return state.context.type;
11252 }
11253
11254 function pass(type, stream, state) {
11255 return states[state.context.type](type, stream, state);
11256 }
11257 function popAndPass(type, stream, state, n) {
11258 for (var i = n || 1; i > 0; i--)
11259 state.context = state.context.prev;
11260 return pass(type, stream, state);
11261 }
11262
11263 // Parser
11264
11265 function wordAsValue(stream) {
11266 var word = stream.current().toLowerCase();
11267 if (valueKeywords.hasOwnProperty(word))
11268 override = "atom";
11269 else if (colorKeywords.hasOwnProperty(word))
11270 override = "keyword";
11271 else
11272 override = "variable";
11273 }
11274
11275 var states = {};
11276
11277 states.top = function(type, stream, state) {
11278 if (type == "{") {
11279 return pushContext(state, stream, "block");
11280 } else if (type == "}" && state.context.prev) {
11281 return popContext(state);
11282 } else if (supportsAtComponent && /@component/i.test(type)) {
11283 return pushContext(state, stream, "atComponentBlock");
11284 } else if (/^@(-moz-)?document$/i.test(type)) {
11285 return pushContext(state, stream, "documentTypes");
11286 } else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) {
11287 return pushContext(state, stream, "atBlock");
11288 } else if (/^@(font-face|counter-style)/i.test(type)) {
11289 state.stateArg = type;
11290 return "restricted_atBlock_before";
11291 } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) {
11292 return "keyframes";
11293 } else if (type && type.charAt(0) == "@") {
11294 return pushContext(state, stream, "at");
11295 } else if (type == "hash") {
11296 override = "builtin";
11297 } else if (type == "word") {
11298 override = "tag";
11299 } else if (type == "variable-definition") {
11300 return "maybeprop";
11301 } else if (type == "interpolation") {
11302 return pushContext(state, stream, "interpolation");
11303 } else if (type == ":") {
11304 return "pseudo";
11305 } else if (allowNested && type == "(") {
11306 return pushContext(state, stream, "parens");
11307 }
11308 return state.context.type;
11309 };
11310
11311 states.block = function(type, stream, state) {
11312 if (type == "word") {
11313 var word = stream.current().toLowerCase();
11314 if (propertyKeywords.hasOwnProperty(word)) {
11315 override = "property";
11316 return "maybeprop";
11317 } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
11318 override = "string-2";
11319 return "maybeprop";
11320 } else if (allowNested) {
11321 override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag";
11322 return "block";
11323 } else {
11324 override += " error";
11325 return "maybeprop";
11326 }
11327 } else if (type == "meta") {
11328 return "block";
11329 } else if (!allowNested && (type == "hash" || type == "qualifier")) {
11330 override = "error";
11331 return "block";
11332 } else {
11333 return states.top(type, stream, state);
11334 }
11335 };
11336
11337 states.maybeprop = function(type, stream, state) {
11338 if (type == ":") return pushContext(state, stream, "prop");
11339 return pass(type, stream, state);
11340 };
11341
11342 states.prop = function(type, stream, state) {
11343 if (type == ";") return popContext(state);
11344 if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
11345 if (type == "}" || type == "{") return popAndPass(type, stream, state);
11346 if (type == "(") return pushContext(state, stream, "parens");
11347
11348 if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) {
11349 override += " error";
11350 } else if (type == "word") {
11351 wordAsValue(stream);
11352 } else if (type == "interpolation") {
11353 return pushContext(state, stream, "interpolation");
11354 }
11355 return "prop";
11356 };
11357
11358 states.propBlock = function(type, _stream, state) {
11359 if (type == "}") return popContext(state);
11360 if (type == "word") { override = "property"; return "maybeprop"; }
11361 return state.context.type;
11362 };
11363
11364 states.parens = function(type, stream, state) {
11365 if (type == "{" || type == "}") return popAndPass(type, stream, state);
11366 if (type == ")") return popContext(state);
11367 if (type == "(") return pushContext(state, stream, "parens");
11368 if (type == "interpolation") return pushContext(state, stream, "interpolation");
11369 if (type == "word") wordAsValue(stream);
11370 return "parens";
11371 };
11372
11373 states.pseudo = function(type, stream, state) {
11374 if (type == "meta") return "pseudo";
11375
11376 if (type == "word") {
11377 override = "variable-3";
11378 return state.context.type;
11379 }
11380 return pass(type, stream, state);
11381 };
11382
11383 states.documentTypes = function(type, stream, state) {
11384 if (type == "word" && documentTypes.hasOwnProperty(stream.current())) {
11385 override = "tag";
11386 return state.context.type;
11387 } else {
11388 return states.atBlock(type, stream, state);
11389 }
11390 };
11391
11392 states.atBlock = function(type, stream, state) {
11393 if (type == "(") return pushContext(state, stream, "atBlock_parens");
11394 if (type == "}" || type == ";") return popAndPass(type, stream, state);
11395 if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
11396
11397 if (type == "interpolation") return pushContext(state, stream, "interpolation");
11398
11399 if (type == "word") {
11400 var word = stream.current().toLowerCase();
11401 if (word == "only" || word == "not" || word == "and" || word == "or")
11402 override = "keyword";
11403 else if (mediaTypes.hasOwnProperty(word))
11404 override = "attribute";
11405 else if (mediaFeatures.hasOwnProperty(word))
11406 override = "property";
11407 else if (mediaValueKeywords.hasOwnProperty(word))
11408 override = "keyword";
11409 else if (propertyKeywords.hasOwnProperty(word))
11410 override = "property";
11411 else if (nonStandardPropertyKeywords.hasOwnProperty(word))
11412 override = "string-2";
11413 else if (valueKeywords.hasOwnProperty(word))
11414 override = "atom";
11415 else if (colorKeywords.hasOwnProperty(word))
11416 override = "keyword";
11417 else
11418 override = "error";
11419 }
11420 return state.context.type;
11421 };
11422
11423 states.atComponentBlock = function(type, stream, state) {
11424 if (type == "}")
11425 return popAndPass(type, stream, state);
11426 if (type == "{")
11427 return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false);
11428 if (type == "word")
11429 override = "error";
11430 return state.context.type;
11431 };
11432
11433 states.atBlock_parens = function(type, stream, state) {
11434 if (type == ")") return popContext(state);
11435 if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
11436 return states.atBlock(type, stream, state);
11437 };
11438
11439 states.restricted_atBlock_before = function(type, stream, state) {
11440 if (type == "{")
11441 return pushContext(state, stream, "restricted_atBlock");
11442 if (type == "word" && state.stateArg == "@counter-style") {
11443 override = "variable";
11444 return "restricted_atBlock_before";
11445 }
11446 return pass(type, stream, state);
11447 };
11448
11449 states.restricted_atBlock = function(type, stream, state) {
11450 if (type == "}") {
11451 state.stateArg = null;
11452 return popContext(state);
11453 }
11454 if (type == "word") {
11455 if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) ||
11456 (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase())))
11457 override = "error";
11458 else
11459 override = "property";
11460 return "maybeprop";
11461 }
11462 return "restricted_atBlock";
11463 };
11464
11465 states.keyframes = function(type, stream, state) {
11466 if (type == "word") { override = "variable"; return "keyframes"; }
11467 if (type == "{") return pushContext(state, stream, "top");
11468 return pass(type, stream, state);
11469 };
11470
11471 states.at = function(type, stream, state) {
11472 if (type == ";") return popContext(state);
11473 if (type == "{" || type == "}") return popAndPass(type, stream, state);
11474 if (type == "word") override = "tag";
11475 else if (type == "hash") override = "builtin";
11476 return "at";
11477 };
11478
11479 states.interpolation = function(type, stream, state) {
11480 if (type == "}") return popContext(state);
11481 if (type == "{" || type == ";") return popAndPass(type, stream, state);
11482 if (type == "word") override = "variable";
11483 else if (type != "variable" && type != "(" && type != ")") override = "error";
11484 return "interpolation";
11485 };
11486
11487 return {
11488 startState: function(base) {
11489 return {tokenize: null,
11490 state: inline ? "block" : "top",
11491 stateArg: null,
11492 context: new Context(inline ? "block" : "top", base || 0, null)};
11493 },
11494
11495 token: function(stream, state) {
11496 if (!state.tokenize && stream.eatSpace()) return null;
11497 var style = (state.tokenize || tokenBase)(stream, state);
11498 if (style && typeof style == "object") {
11499 type = style[1];
11500 style = style[0];
11501 }
11502 override = style;
11503 if (type != "comment")
11504 state.state = states[state.state](type, stream, state);
11505 return override;
11506 },
11507
11508 indent: function(state, textAfter) {
11509 var cx = state.context, ch = textAfter && textAfter.charAt(0);
11510 var indent = cx.indent;
11511 if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev;
11512 if (cx.prev) {
11513 if (ch == "}" && (cx.type == "block" || cx.type == "top" ||
11514 cx.type == "interpolation" || cx.type == "restricted_atBlock")) {
11515 // Resume indentation from parent context.
11516 cx = cx.prev;
11517 indent = cx.indent;
11518 } else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") ||
11519 ch == "{" && (cx.type == "at" || cx.type == "atBlock")) {
11520 // Dedent relative to current context.
11521 indent = Math.max(0, cx.indent - indentUnit);
11522 }
11523 }
11524 return indent;
11525 },
11526
11527 electricChars: "}",
11528 blockCommentStart: "/*",
11529 blockCommentEnd: "*/",
11530 blockCommentContinue: " * ",
11531 lineComment: lineComment,
11532 fold: "brace"
11533 };
11534 });
11535
11536 function keySet(array) {
11537 var keys = {};
11538 for (var i = 0; i < array.length; ++i) {
11539 keys[array[i].toLowerCase()] = true;
11540 }
11541 return keys;
11542 }
11543
11544 var documentTypes_ = [
11545 "domain", "regexp", "url", "url-prefix"
11546 ], documentTypes = keySet(documentTypes_);
11547
11548 var mediaTypes_ = [
11549 "all", "aural", "braille", "handheld", "print", "projection", "screen",
11550 "tty", "tv", "embossed"
11551 ], mediaTypes = keySet(mediaTypes_);
11552
11553 var mediaFeatures_ = [
11554 "width", "min-width", "max-width", "height", "min-height", "max-height",
11555 "device-width", "min-device-width", "max-device-width", "device-height",
11556 "min-device-height", "max-device-height", "aspect-ratio",
11557 "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
11558 "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
11559 "max-color", "color-index", "min-color-index", "max-color-index",
11560 "monochrome", "min-monochrome", "max-monochrome", "resolution",
11561 "min-resolution", "max-resolution", "scan", "grid", "orientation",
11562 "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio",
11563 "pointer", "any-pointer", "hover", "any-hover"
11564 ], mediaFeatures = keySet(mediaFeatures_);
11565
11566 var mediaValueKeywords_ = [
11567 "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover",
11568 "interlace", "progressive"
11569 ], mediaValueKeywords = keySet(mediaValueKeywords_);
11570
11571 var propertyKeywords_ = [
11572 "align-content", "align-items", "align-self", "alignment-adjust",
11573 "alignment-baseline", "anchor-point", "animation", "animation-delay",
11574 "animation-direction", "animation-duration", "animation-fill-mode",
11575 "animation-iteration-count", "animation-name", "animation-play-state",
11576 "animation-timing-function", "appearance", "azimuth", "backface-visibility",
11577 "background", "background-attachment", "background-blend-mode", "background-clip",
11578 "background-color", "background-image", "background-origin", "background-position",
11579 "background-repeat", "background-size", "baseline-shift", "binding",
11580 "bleed", "bookmark-label", "bookmark-level", "bookmark-state",
11581 "bookmark-target", "border", "border-bottom", "border-bottom-color",
11582 "border-bottom-left-radius", "border-bottom-right-radius",
11583 "border-bottom-style", "border-bottom-width", "border-collapse",
11584 "border-color", "border-image", "border-image-outset",
11585 "border-image-repeat", "border-image-slice", "border-image-source",
11586 "border-image-width", "border-left", "border-left-color",
11587 "border-left-style", "border-left-width", "border-radius", "border-right",
11588 "border-right-color", "border-right-style", "border-right-width",
11589 "border-spacing", "border-style", "border-top", "border-top-color",
11590 "border-top-left-radius", "border-top-right-radius", "border-top-style",
11591 "border-top-width", "border-width", "bottom", "box-decoration-break",
11592 "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
11593 "caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count",
11594 "column-fill", "column-gap", "column-rule", "column-rule-color",
11595 "column-rule-style", "column-rule-width", "column-span", "column-width",
11596 "columns", "content", "counter-increment", "counter-reset", "crop", "cue",
11597 "cue-after", "cue-before", "cursor", "direction", "display",
11598 "dominant-baseline", "drop-initial-after-adjust",
11599 "drop-initial-after-align", "drop-initial-before-adjust",
11600 "drop-initial-before-align", "drop-initial-size", "drop-initial-value",
11601 "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
11602 "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
11603 "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
11604 "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
11605 "font-stretch", "font-style", "font-synthesis", "font-variant",
11606 "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
11607 "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
11608 "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
11609 "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
11610 "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap",
11611 "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns",
11612 "grid-template-rows", "hanging-punctuation", "height", "hyphens",
11613 "icon", "image-orientation", "image-rendering", "image-resolution",
11614 "inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing",
11615 "line-break", "line-height", "line-stacking", "line-stacking-ruby",
11616 "line-stacking-shift", "line-stacking-strategy", "list-style",
11617 "list-style-image", "list-style-position", "list-style-type", "margin",
11618 "margin-bottom", "margin-left", "margin-right", "margin-top",
11619 "marks", "marquee-direction", "marquee-loop",
11620 "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
11621 "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
11622 "nav-left", "nav-right", "nav-up", "object-fit", "object-position",
11623 "opacity", "order", "orphans", "outline",
11624 "outline-color", "outline-offset", "outline-style", "outline-width",
11625 "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
11626 "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
11627 "page", "page-break-after", "page-break-before", "page-break-inside",
11628 "page-policy", "pause", "pause-after", "pause-before", "perspective",
11629 "perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position",
11630 "presentation-level", "punctuation-trim", "quotes", "region-break-after",
11631 "region-break-before", "region-break-inside", "region-fragment",
11632 "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
11633 "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
11634 "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
11635 "shape-outside", "size", "speak", "speak-as", "speak-header",
11636 "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
11637 "tab-size", "table-layout", "target", "target-name", "target-new",
11638 "target-position", "text-align", "text-align-last", "text-decoration",
11639 "text-decoration-color", "text-decoration-line", "text-decoration-skip",
11640 "text-decoration-style", "text-emphasis", "text-emphasis-color",
11641 "text-emphasis-position", "text-emphasis-style", "text-height",
11642 "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
11643 "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
11644 "text-wrap", "top", "transform", "transform-origin", "transform-style",
11645 "transition", "transition-delay", "transition-duration",
11646 "transition-property", "transition-timing-function", "unicode-bidi",
11647 "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration",
11648 "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
11649 "voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break",
11650 "word-spacing", "word-wrap", "z-index",
11651 // SVG-specific
11652 "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
11653 "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
11654 "color-interpolation", "color-interpolation-filters",
11655 "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
11656 "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
11657 "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
11658 "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
11659 "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
11660 "glyph-orientation-vertical", "text-anchor", "writing-mode"
11661 ], propertyKeywords = keySet(propertyKeywords_);
11662
11663 var nonStandardPropertyKeywords_ = [
11664 "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
11665 "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
11666 "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
11667 "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
11668 "searchfield-results-decoration", "zoom"
11669 ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
11670
11671 var fontProperties_ = [
11672 "font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
11673 "font-stretch", "font-weight", "font-style"
11674 ], fontProperties = keySet(fontProperties_);
11675
11676 var counterDescriptors_ = [
11677 "additive-symbols", "fallback", "negative", "pad", "prefix", "range",
11678 "speak-as", "suffix", "symbols", "system"
11679 ], counterDescriptors = keySet(counterDescriptors_);
11680
11681 var colorKeywords_ = [
11682 "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
11683 "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
11684 "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
11685 "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
11686 "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
11687 "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
11688 "darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
11689 "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
11690 "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
11691 "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
11692 "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
11693 "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
11694 "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
11695 "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
11696 "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
11697 "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
11698 "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
11699 "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
11700 "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
11701 "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
11702 "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
11703 "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown",
11704 "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
11705 "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
11706 "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
11707 "whitesmoke", "yellow", "yellowgreen"
11708 ], colorKeywords = keySet(colorKeywords_);
11709
11710 var valueKeywords_ = [
11711 "above", "absolute", "activeborder", "additive", "activecaption", "afar",
11712 "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
11713 "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
11714 "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page",
11715 "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
11716 "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
11717 "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
11718 "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian",
11719 "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
11720 "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
11721 "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
11722 "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
11723 "compact", "condensed", "contain", "content", "contents",
11724 "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
11725 "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
11726 "decimal-leading-zero", "default", "default-button", "dense", "destination-atop",
11727 "destination-in", "destination-out", "destination-over", "devanagari", "difference",
11728 "disc", "discard", "disclosure-closed", "disclosure-open", "document",
11729 "dot-dash", "dot-dot-dash",
11730 "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
11731 "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
11732 "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
11733 "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
11734 "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
11735 "ethiopic-halehame-gez", "ethiopic-halehame-om-et",
11736 "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
11737 "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
11738 "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
11739 "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
11740 "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove",
11741 "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
11742 "help", "hidden", "hide", "higher", "highlight", "highlighttext",
11743 "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore",
11744 "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
11745 "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
11746 "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert",
11747 "italic", "japanese-formal", "japanese-informal", "justify", "kannada",
11748 "katakana", "katakana-iroha", "keep-all", "khmer",
11749 "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal",
11750 "landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten",
11751 "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem",
11752 "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
11753 "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
11754 "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d",
11755 "media-controls-background", "media-current-time-display",
11756 "media-fullscreen-button", "media-mute-button", "media-play-button",
11757 "media-return-to-realtime-button", "media-rewind-button",
11758 "media-seek-back-button", "media-seek-forward-button", "media-slider",
11759 "media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
11760 "media-volume-slider-container", "media-volume-sliderthumb", "medium",
11761 "menu", "menulist", "menulist-button", "menulist-text",
11762 "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
11763 "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
11764 "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
11765 "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
11766 "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote",
11767 "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
11768 "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
11769 "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
11770 "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d",
11771 "progress", "push-button", "radial-gradient", "radio", "read-only",
11772 "read-write", "read-write-plaintext-only", "rectangle", "region",
11773 "relative", "repeat", "repeating-linear-gradient",
11774 "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse",
11775 "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
11776 "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
11777 "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
11778 "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield",
11779 "searchfield-cancel-button", "searchfield-decoration",
11780 "searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end",
11781 "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
11782 "simp-chinese-formal", "simp-chinese-informal", "single",
11783 "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal",
11784 "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
11785 "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
11786 "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square",
11787 "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
11788 "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table",
11789 "table-caption", "table-cell", "table-column", "table-column-group",
11790 "table-footer-group", "table-header-group", "table-row", "table-row-group",
11791 "tamil",
11792 "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
11793 "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
11794 "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
11795 "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
11796 "trad-chinese-formal", "trad-chinese-informal", "transform",
11797 "translate", "translate3d", "translateX", "translateY", "translateZ",
11798 "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up",
11799 "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
11800 "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
11801 "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
11802 "visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
11803 "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor",
11804 "xx-large", "xx-small"
11805 ], valueKeywords = keySet(valueKeywords_);
11806
11807 var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_)
11808 .concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_)
11809 .concat(valueKeywords_);
11810 CodeMirror.registerHelper("hintWords", "css", allWords);
11811
11812 function tokenCComment(stream, state) {
11813 var maybeEnd = false, ch;
11814 while ((ch = stream.next()) != null) {
11815 if (maybeEnd && ch == "/") {
11816 state.tokenize = null;
11817 break;
11818 }
11819 maybeEnd = (ch == "*");
11820 }
11821 return ["comment", "comment"];
11822 }
11823
11824 CodeMirror.defineMIME("text/css", {
11825 documentTypes: documentTypes,
11826 mediaTypes: mediaTypes,
11827 mediaFeatures: mediaFeatures,
11828 mediaValueKeywords: mediaValueKeywords,
11829 propertyKeywords: propertyKeywords,
11830 nonStandardPropertyKeywords: nonStandardPropertyKeywords,
11831 fontProperties: fontProperties,
11832 counterDescriptors: counterDescriptors,
11833 colorKeywords: colorKeywords,
11834 valueKeywords: valueKeywords,
11835 tokenHooks: {
11836 "/": function(stream, state) {
11837 if (!stream.eat("*")) return false;
11838 state.tokenize = tokenCComment;
11839 return tokenCComment(stream, state);
11840 }
11841 },
11842 name: "css"
11843 });
11844
11845 CodeMirror.defineMIME("text/x-scss", {
11846 mediaTypes: mediaTypes,
11847 mediaFeatures: mediaFeatures,
11848 mediaValueKeywords: mediaValueKeywords,
11849 propertyKeywords: propertyKeywords,
11850 nonStandardPropertyKeywords: nonStandardPropertyKeywords,
11851 colorKeywords: colorKeywords,
11852 valueKeywords: valueKeywords,
11853 fontProperties: fontProperties,
11854 allowNested: true,
11855 lineComment: "//",
11856 tokenHooks: {
11857 "/": function(stream, state) {
11858 if (stream.eat("/")) {
11859 stream.skipToEnd();
11860 return ["comment", "comment"];
11861 } else if (stream.eat("*")) {
11862 state.tokenize = tokenCComment;
11863 return tokenCComment(stream, state);
11864 } else {
11865 return ["operator", "operator"];
11866 }
11867 },
11868 ":": function(stream) {
11869 if (stream.match(/\s*\{/, false))
11870 return [null, null]
11871 return false;
11872 },
11873 "$": function(stream) {
11874 stream.match(/^[\w-]+/);
11875 if (stream.match(/^\s*:/, false))
11876 return ["variable-2", "variable-definition"];
11877 return ["variable-2", "variable"];
11878 },
11879 "#": function(stream) {
11880 if (!stream.eat("{")) return false;
11881 return [null, "interpolation"];
11882 }
11883 },
11884 name: "css",
11885 helperType: "scss"
11886 });
11887
11888 CodeMirror.defineMIME("text/x-less", {
11889 mediaTypes: mediaTypes,
11890 mediaFeatures: mediaFeatures,
11891 mediaValueKeywords: mediaValueKeywords,
11892 propertyKeywords: propertyKeywords,
11893 nonStandardPropertyKeywords: nonStandardPropertyKeywords,
11894 colorKeywords: colorKeywords,
11895 valueKeywords: valueKeywords,
11896 fontProperties: fontProperties,
11897 allowNested: true,
11898 lineComment: "//",
11899 tokenHooks: {
11900 "/": function(stream, state) {
11901 if (stream.eat("/")) {
11902 stream.skipToEnd();
11903 return ["comment", "comment"];
11904 } else if (stream.eat("*")) {
11905 state.tokenize = tokenCComment;
11906 return tokenCComment(stream, state);
11907 } else {
11908 return ["operator", "operator"];
11909 }
11910 },
11911 "@": function(stream) {
11912 if (stream.eat("{")) return [null, "interpolation"];
11913 if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false;
11914 stream.eatWhile(/[\w\\\-]/);
11915 if (stream.match(/^\s*:/, false))
11916 return ["variable-2", "variable-definition"];
11917 return ["variable-2", "variable"];
11918 },
11919 "&": function() {
11920 return ["atom", "atom"];
11921 }
11922 },
11923 name: "css",
11924 helperType: "less"
11925 });
11926
11927 CodeMirror.defineMIME("text/x-gss", {
11928 documentTypes: documentTypes,
11929 mediaTypes: mediaTypes,
11930 mediaFeatures: mediaFeatures,
11931 propertyKeywords: propertyKeywords,
11932 nonStandardPropertyKeywords: nonStandardPropertyKeywords,
11933 fontProperties: fontProperties,
11934 counterDescriptors: counterDescriptors,
11935 colorKeywords: colorKeywords,
11936 valueKeywords: valueKeywords,
11937 supportsAtComponent: true,
11938 tokenHooks: {
11939 "/": function(stream, state) {
11940 if (!stream.eat("*")) return false;
11941 state.tokenize = tokenCComment;
11942 return tokenCComment(stream, state);
11943 }
11944 },
11945 name: "css",
11946 helperType: "gss"
11947 });
11948
11949 });
11950
11951 },{"../../lib/codemirror":12}],14:[function(require,module,exports){
11952 // CodeMirror, copyright (c) by Marijn Haverbeke and others
11953 // Distributed under an MIT license: http://codemirror.net/LICENSE
11954
11955 (function(mod) {
11956 if (typeof exports == "object" && typeof module == "object") // CommonJS
11957 mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css"));
11958 else if (typeof define == "function" && define.amd) // AMD
11959 define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod);
11960 else // Plain browser env
11961 mod(CodeMirror);
11962 })(function(CodeMirror) {
11963 "use strict";
11964
11965 var defaultTags = {
11966 script: [
11967 ["lang", /(javascript|babel)/i, "javascript"],
11968 ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i, "javascript"],
11969 ["type", /./, "text/plain"],
11970 [null, null, "javascript"]
11971 ],
11972 style: [
11973 ["lang", /^css$/i, "css"],
11974 ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"],
11975 ["type", /./, "text/plain"],
11976 [null, null, "css"]
11977 ]
11978 };
11979
11980 function maybeBackup(stream, pat, style) {
11981 var cur = stream.current(), close = cur.search(pat);
11982 if (close > -1) {
11983 stream.backUp(cur.length - close);
11984 } else if (cur.match(/<\/?$/)) {
11985 stream.backUp(cur.length);
11986 if (!stream.match(pat, false)) stream.match(cur);
11987 }
11988 return style;
11989 }
11990
11991 var attrRegexpCache = {};
11992 function getAttrRegexp(attr) {
11993 var regexp = attrRegexpCache[attr];
11994 if (regexp) return regexp;
11995 return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*");
11996 }
11997
11998 function getAttrValue(text, attr) {
11999 var match = text.match(getAttrRegexp(attr))
12000 return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : ""
12001 }
12002
12003 function getTagRegexp(tagName, anchored) {
12004 return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i");
12005 }
12006
12007 function addTags(from, to) {
12008 for (var tag in from) {
12009 var dest = to[tag] || (to[tag] = []);
12010 var source = from[tag];
12011 for (var i = source.length - 1; i >= 0; i--)
12012 dest.unshift(source[i])
12013 }
12014 }
12015
12016 function findMatchingMode(tagInfo, tagText) {
12017 for (var i = 0; i < tagInfo.length; i++) {
12018 var spec = tagInfo[i];
12019 if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2];
12020 }
12021 }
12022
12023 CodeMirror.defineMode("htmlmixed", function (config, parserConfig) {
12024 var htmlMode = CodeMirror.getMode(config, {
12025 name: "xml",
12026 htmlMode: true,
12027 multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
12028 multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag
12029 });
12030
12031 var tags = {};
12032 var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes;
12033 addTags(defaultTags, tags);
12034 if (configTags) addTags(configTags, tags);
12035 if (configScript) for (var i = configScript.length - 1; i >= 0; i--)
12036 tags.script.unshift(["type", configScript[i].matches, configScript[i].mode])
12037
12038 function html(stream, state) {
12039 var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName
12040 if (tag && !/[<>\s\/]/.test(stream.current()) &&
12041 (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) &&
12042 tags.hasOwnProperty(tagName)) {
12043 state.inTag = tagName + " "
12044 } else if (state.inTag && tag && />$/.test(stream.current())) {
12045 var inTag = /^([\S]+) (.*)/.exec(state.inTag)
12046 state.inTag = null
12047 var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2])
12048 var mode = CodeMirror.getMode(config, modeSpec)
12049 var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false);
12050 state.token = function (stream, state) {
12051 if (stream.match(endTagA, false)) {
12052 state.token = html;
12053 state.localState = state.localMode = null;
12054 return null;
12055 }
12056 return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState));
12057 };
12058 state.localMode = mode;
12059 state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, ""));
12060 } else if (state.inTag) {
12061 state.inTag += stream.current()
12062 if (stream.eol()) state.inTag += " "
12063 }
12064 return style;
12065 };
12066
12067 return {
12068 startState: function () {
12069 var state = CodeMirror.startState(htmlMode);
12070 return {token: html, inTag: null, localMode: null, localState: null, htmlState: state};
12071 },
12072
12073 copyState: function (state) {
12074 var local;
12075 if (state.localState) {
12076 local = CodeMirror.copyState(state.localMode, state.localState);
12077 }
12078 return {token: state.token, inTag: state.inTag,
12079 localMode: state.localMode, localState: local,
12080 htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
12081 },
12082
12083 token: function (stream, state) {
12084 return state.token(stream, state);
12085 },
12086
12087 indent: function (state, textAfter, line) {
12088 if (!state.localMode || /^\s*<\//.test(textAfter))
12089 return htmlMode.indent(state.htmlState, textAfter);
12090 else if (state.localMode.indent)
12091 return state.localMode.indent(state.localState, textAfter, line);
12092 else
12093 return CodeMirror.Pass;
12094 },
12095
12096 innerMode: function (state) {
12097 return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
12098 }
12099 };
12100 }, "xml", "javascript", "css");
12101
12102 CodeMirror.defineMIME("text/html", "htmlmixed");
12103 });
12104
12105 },{"../../lib/codemirror":12,"../css/css":13,"../javascript/javascript":15,"../xml/xml":16}],15:[function(require,module,exports){
12106 // CodeMirror, copyright (c) by Marijn Haverbeke and others
12107 // Distributed under an MIT license: http://codemirror.net/LICENSE
12108
12109 (function(mod) {
12110 if (typeof exports == "object" && typeof module == "object") // CommonJS
12111 mod(require("../../lib/codemirror"));
12112 else if (typeof define == "function" && define.amd) // AMD
12113 define(["../../lib/codemirror"], mod);
12114 else // Plain browser env
12115 mod(CodeMirror);
12116 })(function(CodeMirror) {
12117 "use strict";
12118
12119 CodeMirror.defineMode("javascript", function(config, parserConfig) {
12120 var indentUnit = config.indentUnit;
12121 var statementIndent = parserConfig.statementIndent;
12122 var jsonldMode = parserConfig.jsonld;
12123 var jsonMode = parserConfig.json || jsonldMode;
12124 var isTS = parserConfig.typescript;
12125 var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
12126
12127 // Tokenizer
12128
12129 var keywords = function(){
12130 function kw(type) {return {type: type, style: "keyword"};}
12131 var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d");
12132 var operator = kw("operator"), atom = {type: "atom", style: "atom"};
12133
12134 return {
12135 "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
12136 "return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C,
12137 "debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"),
12138 "function": kw("function"), "catch": kw("catch"),
12139 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
12140 "in": operator, "typeof": operator, "instanceof": operator,
12141 "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
12142 "this": kw("this"), "class": kw("class"), "super": kw("atom"),
12143 "yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
12144 "await": C
12145 };
12146 }();
12147
12148 var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
12149 var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
12150
12151 function readRegexp(stream) {
12152 var escaped = false, next, inSet = false;
12153 while ((next = stream.next()) != null) {
12154 if (!escaped) {
12155 if (next == "/" && !inSet) return;
12156 if (next == "[") inSet = true;
12157 else if (inSet && next == "]") inSet = false;
12158 }
12159 escaped = !escaped && next == "\\";
12160 }
12161 }
12162
12163 // Used as scratch variables to communicate multiple values without
12164 // consing up tons of objects.
12165 var type, content;
12166 function ret(tp, style, cont) {
12167 type = tp; content = cont;
12168 return style;
12169 }
12170 function tokenBase(stream, state) {
12171 var ch = stream.next();
12172 if (ch == '"' || ch == "'") {
12173 state.tokenize = tokenString(ch);
12174 return state.tokenize(stream, state);
12175 } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
12176 return ret("number", "number");
12177 } else if (ch == "." && stream.match("..")) {
12178 return ret("spread", "meta");
12179 } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
12180 return ret(ch);
12181 } else if (ch == "=" && stream.eat(">")) {
12182 return ret("=>", "operator");
12183 } else if (ch == "0" && stream.eat(/x/i)) {
12184 stream.eatWhile(/[\da-f]/i);
12185 return ret("number", "number");
12186 } else if (ch == "0" && stream.eat(/o/i)) {
12187 stream.eatWhile(/[0-7]/i);
12188 return ret("number", "number");
12189 } else if (ch == "0" && stream.eat(/b/i)) {
12190 stream.eatWhile(/[01]/i);
12191 return ret("number", "number");
12192 } else if (/\d/.test(ch)) {
12193 stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
12194 return ret("number", "number");
12195 } else if (ch == "/") {
12196 if (stream.eat("*")) {
12197 state.tokenize = tokenComment;
12198 return tokenComment(stream, state);
12199 } else if (stream.eat("/")) {
12200 stream.skipToEnd();
12201 return ret("comment", "comment");
12202 } else if (expressionAllowed(stream, state, 1)) {
12203 readRegexp(stream);
12204 stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
12205 return ret("regexp", "string-2");
12206 } else {
12207 stream.eat("=");
12208 return ret("operator", "operator", stream.current());
12209 }
12210 } else if (ch == "`") {
12211 state.tokenize = tokenQuasi;
12212 return tokenQuasi(stream, state);
12213 } else if (ch == "#") {
12214 stream.skipToEnd();
12215 return ret("error", "error");
12216 } else if (isOperatorChar.test(ch)) {
12217 if (ch != ">" || !state.lexical || state.lexical.type != ">") {
12218 if (stream.eat("=")) {
12219 if (ch == "!" || ch == "=") stream.eat("=")
12220 } else if (/[<>*+\-]/.test(ch)) {
12221 stream.eat(ch)
12222 if (ch == ">") stream.eat(ch)
12223 }
12224 }
12225 return ret("operator", "operator", stream.current());
12226 } else if (wordRE.test(ch)) {
12227 stream.eatWhile(wordRE);
12228 var word = stream.current()
12229 if (state.lastType != ".") {
12230 if (keywords.propertyIsEnumerable(word)) {
12231 var kw = keywords[word]
12232 return ret(kw.type, kw.style, word)
12233 }
12234 if (word == "async" && stream.match(/^(\s|\/\*.*?\*\/)*[\(\w]/, false))
12235 return ret("async", "keyword", word)
12236 }
12237 return ret("variable", "variable", word)
12238 }
12239 }
12240
12241 function tokenString(quote) {
12242 return function(stream, state) {
12243 var escaped = false, next;
12244 if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
12245 state.tokenize = tokenBase;
12246 return ret("jsonld-keyword", "meta");
12247 }
12248 while ((next = stream.next()) != null) {
12249 if (next == quote && !escaped) break;
12250 escaped = !escaped && next == "\\";
12251 }
12252 if (!escaped) state.tokenize = tokenBase;
12253 return ret("string", "string");
12254 };
12255 }
12256
12257 function tokenComment(stream, state) {
12258 var maybeEnd = false, ch;
12259 while (ch = stream.next()) {
12260 if (ch == "/" && maybeEnd) {
12261 state.tokenize = tokenBase;
12262 break;
12263 }
12264 maybeEnd = (ch == "*");
12265 }
12266 return ret("comment", "comment");
12267 }
12268
12269 function tokenQuasi(stream, state) {
12270 var escaped = false, next;
12271 while ((next = stream.next()) != null) {
12272 if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
12273 state.tokenize = tokenBase;
12274 break;
12275 }
12276 escaped = !escaped && next == "\\";
12277 }
12278 return ret("quasi", "string-2", stream.current());
12279 }
12280
12281 var brackets = "([{}])";
12282 // This is a crude lookahead trick to try and notice that we're
12283 // parsing the argument patterns for a fat-arrow function before we
12284 // actually hit the arrow token. It only works if the arrow is on
12285 // the same line as the arguments and there's no strange noise
12286 // (comments) in between. Fallback is to only notice when we hit the
12287 // arrow, and not declare the arguments as locals for the arrow
12288 // body.
12289 function findFatArrow(stream, state) {
12290 if (state.fatArrowAt) state.fatArrowAt = null;
12291 var arrow = stream.string.indexOf("=>", stream.start);
12292 if (arrow < 0) return;
12293
12294 if (isTS) { // Try to skip TypeScript return type declarations after the arguments
12295 var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow))
12296 if (m) arrow = m.index
12297 }
12298
12299 var depth = 0, sawSomething = false;
12300 for (var pos = arrow - 1; pos >= 0; --pos) {
12301 var ch = stream.string.charAt(pos);
12302 var bracket = brackets.indexOf(ch);
12303 if (bracket >= 0 && bracket < 3) {
12304 if (!depth) { ++pos; break; }
12305 if (--depth == 0) { if (ch == "(") sawSomething = true; break; }
12306 } else if (bracket >= 3 && bracket < 6) {
12307 ++depth;
12308 } else if (wordRE.test(ch)) {
12309 sawSomething = true;
12310 } else if (/["'\/]/.test(ch)) {
12311 return;
12312 } else if (sawSomething && !depth) {
12313 ++pos;
12314 break;
12315 }
12316 }
12317 if (sawSomething && !depth) state.fatArrowAt = pos;
12318 }
12319
12320 // Parser
12321
12322 var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
12323
12324 function JSLexical(indented, column, type, align, prev, info) {
12325 this.indented = indented;
12326 this.column = column;
12327 this.type = type;
12328 this.prev = prev;
12329 this.info = info;
12330 if (align != null) this.align = align;
12331 }
12332
12333 function inScope(state, varname) {
12334 for (var v = state.localVars; v; v = v.next)
12335 if (v.name == varname) return true;
12336 for (var cx = state.context; cx; cx = cx.prev) {
12337 for (var v = cx.vars; v; v = v.next)
12338 if (v.name == varname) return true;
12339 }
12340 }
12341
12342 function parseJS(state, style, type, content, stream) {
12343 var cc = state.cc;
12344 // Communicate our context to the combinators.
12345 // (Less wasteful than consing up a hundred closures on every call.)
12346 cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
12347
12348 if (!state.lexical.hasOwnProperty("align"))
12349 state.lexical.align = true;
12350
12351 while(true) {
12352 var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
12353 if (combinator(type, content)) {
12354 while(cc.length && cc[cc.length - 1].lex)
12355 cc.pop()();
12356 if (cx.marked) return cx.marked;
12357 if (type == "variable" && inScope(state, content)) return "variable-2";
12358 return style;
12359 }
12360 }
12361 }
12362
12363 // Combinator utils
12364
12365 var cx = {state: null, column: null, marked: null, cc: null};
12366 function pass() {
12367 for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
12368 }
12369 function cont() {
12370 pass.apply(null, arguments);
12371 return true;
12372 }
12373 function register(varname) {
12374 function inList(list) {
12375 for (var v = list; v; v = v.next)
12376 if (v.name == varname) return true;
12377 return false;
12378 }
12379 var state = cx.state;
12380 cx.marked = "def";
12381 if (state.context) {
12382 if (inList(state.localVars)) return;
12383 state.localVars = {name: varname, next: state.localVars};
12384 } else {
12385 if (inList(state.globalVars)) return;
12386 if (parserConfig.globalVars)
12387 state.globalVars = {name: varname, next: state.globalVars};
12388 }
12389 }
12390
12391 function isModifier(name) {
12392 return name == "public" || name == "private" || name == "protected" || name == "abstract" || name == "readonly"
12393 }
12394
12395 // Combinators
12396
12397 var defaultVars = {name: "this", next: {name: "arguments"}};
12398 function pushcontext() {
12399 cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
12400 cx.state.localVars = defaultVars;
12401 }
12402 function popcontext() {
12403 cx.state.localVars = cx.state.context.vars;
12404 cx.state.context = cx.state.context.prev;
12405 }
12406 function pushlex(type, info) {
12407 var result = function() {
12408 var state = cx.state, indent = state.indented;
12409 if (state.lexical.type == "stat") indent = state.lexical.indented;
12410 else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
12411 indent = outer.indented;
12412 state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
12413 };
12414 result.lex = true;
12415 return result;
12416 }
12417 function poplex() {
12418 var state = cx.state;
12419 if (state.lexical.prev) {
12420 if (state.lexical.type == ")")
12421 state.indented = state.lexical.indented;
12422 state.lexical = state.lexical.prev;
12423 }
12424 }
12425 poplex.lex = true;
12426
12427 function expect(wanted) {
12428 function exp(type) {
12429 if (type == wanted) return cont();
12430 else if (wanted == ";") return pass();
12431 else return cont(exp);
12432 };
12433 return exp;
12434 }
12435
12436 function statement(type, value) {
12437 if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
12438 if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
12439 if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
12440 if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex);
12441 if (type == "debugger") return cont(expect(";"));
12442 if (type == "{") return cont(pushlex("}"), block, poplex);
12443 if (type == ";") return cont();
12444 if (type == "if") {
12445 if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
12446 cx.state.cc.pop()();
12447 return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse);
12448 }
12449 if (type == "function") return cont(functiondef);
12450 if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
12451 if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), className, poplex); }
12452 if (type == "variable") {
12453 if (isTS && value == "type") {
12454 cx.marked = "keyword"
12455 return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
12456 } else if (isTS && value == "declare") {
12457 cx.marked = "keyword"
12458 return cont(statement)
12459 } else if (isTS && (value == "module" || value == "enum") && cx.stream.match(/^\s*\w/, false)) {
12460 cx.marked = "keyword"
12461 return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
12462 } else if (isTS && value == "namespace") {
12463 cx.marked = "keyword"
12464 return cont(pushlex("form"), expression, block, poplex)
12465 } else {
12466 return cont(pushlex("stat"), maybelabel);
12467 }
12468 }
12469 if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"),
12470 block, poplex, poplex);
12471 if (type == "case") return cont(expression, expect(":"));
12472 if (type == "default") return cont(expect(":"));
12473 if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
12474 statement, poplex, popcontext);
12475 if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
12476 if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
12477 if (type == "async") return cont(statement)
12478 if (value == "@") return cont(expression, statement)
12479 return pass(pushlex("stat"), expression, expect(";"), poplex);
12480 }
12481 function expression(type, value) {
12482 return expressionInner(type, value, false);
12483 }
12484 function expressionNoComma(type, value) {
12485 return expressionInner(type, value, true);
12486 }
12487 function parenExpr(type) {
12488 if (type != "(") return pass()
12489 return cont(pushlex(")"), expression, expect(")"), poplex)
12490 }
12491 function expressionInner(type, value, noComma) {
12492 if (cx.state.fatArrowAt == cx.stream.start) {
12493 var body = noComma ? arrowBodyNoComma : arrowBody;
12494 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);
12495 else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
12496 }
12497
12498 var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
12499 if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
12500 if (type == "function") return cont(functiondef, maybeop);
12501 if (type == "class" || (isTS && value == "interface")) { cx.marked = "keyword"; return cont(pushlex("form"), classExpression, poplex); }
12502 if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression);
12503 if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
12504 if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
12505 if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
12506 if (type == "{") return contCommasep(objprop, "}", null, maybeop);
12507 if (type == "quasi") return pass(quasi, maybeop);
12508 if (type == "new") return cont(maybeTarget(noComma));
12509 return cont();
12510 }
12511 function maybeexpression(type) {
12512 if (type.match(/[;\}\)\],]/)) return pass();
12513 return pass(expression);
12514 }
12515
12516 function maybeoperatorComma(type, value) {
12517 if (type == ",") return cont(expression);
12518 return maybeoperatorNoComma(type, value, false);
12519 }
12520 function maybeoperatorNoComma(type, value, noComma) {
12521 var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
12522 var expr = noComma == false ? expression : expressionNoComma;
12523 if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
12524 if (type == "operator") {
12525 if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me);
12526 if (isTS && value == "<" && cx.stream.match(/^([^>]|<.*?>)*>\s*\(/, false))
12527 return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, me);
12528 if (value == "?") return cont(expression, expect(":"), expr);
12529 return cont(expr);
12530 }
12531 if (type == "quasi") { return pass(quasi, me); }
12532 if (type == ";") return;
12533 if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
12534 if (type == ".") return cont(property, me);
12535 if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
12536 if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
12537 if (type == "regexp") {
12538 cx.state.lastType = cx.marked = "operator"
12539 cx.stream.backUp(cx.stream.pos - cx.stream.start - 1)
12540 return cont(expr)
12541 }
12542 }
12543 function quasi(type, value) {
12544 if (type != "quasi") return pass();
12545 if (value.slice(value.length - 2) != "${") return cont(quasi);
12546 return cont(expression, continueQuasi);
12547 }
12548 function continueQuasi(type) {
12549 if (type == "}") {
12550 cx.marked = "string-2";
12551 cx.state.tokenize = tokenQuasi;
12552 return cont(quasi);
12553 }
12554 }
12555 function arrowBody(type) {
12556 findFatArrow(cx.stream, cx.state);
12557 return pass(type == "{" ? statement : expression);
12558 }
12559 function arrowBodyNoComma(type) {
12560 findFatArrow(cx.stream, cx.state);
12561 return pass(type == "{" ? statement : expressionNoComma);
12562 }
12563 function maybeTarget(noComma) {
12564 return function(type) {
12565 if (type == ".") return cont(noComma ? targetNoComma : target);
12566 else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma)
12567 else return pass(noComma ? expressionNoComma : expression);
12568 };
12569 }
12570 function target(_, value) {
12571 if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
12572 }
12573 function targetNoComma(_, value) {
12574 if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
12575 }
12576 function maybelabel(type) {
12577 if (type == ":") return cont(poplex, statement);
12578 return pass(maybeoperatorComma, expect(";"), poplex);
12579 }
12580 function property(type) {
12581 if (type == "variable") {cx.marked = "property"; return cont();}
12582 }
12583 function objprop(type, value) {
12584 if (type == "async") {
12585 cx.marked = "property";
12586 return cont(objprop);
12587 } else if (type == "variable" || cx.style == "keyword") {
12588 cx.marked = "property";
12589 if (value == "get" || value == "set") return cont(getterSetter);
12590 var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params
12591 if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false)))
12592 cx.state.fatArrowAt = cx.stream.pos + m[0].length
12593 return cont(afterprop);
12594 } else if (type == "number" || type == "string") {
12595 cx.marked = jsonldMode ? "property" : (cx.style + " property");
12596 return cont(afterprop);
12597 } else if (type == "jsonld-keyword") {
12598 return cont(afterprop);
12599 } else if (isTS && isModifier(value)) {
12600 cx.marked = "keyword"
12601 return cont(objprop)
12602 } else if (type == "[") {
12603 return cont(expression, maybetype, expect("]"), afterprop);
12604 } else if (type == "spread") {
12605 return cont(expressionNoComma, afterprop);
12606 } else if (value == "*") {
12607 cx.marked = "keyword";
12608 return cont(objprop);
12609 } else if (type == ":") {
12610 return pass(afterprop)
12611 }
12612 }
12613 function getterSetter(type) {
12614 if (type != "variable") return pass(afterprop);
12615 cx.marked = "property";
12616 return cont(functiondef);
12617 }
12618 function afterprop(type) {
12619 if (type == ":") return cont(expressionNoComma);
12620 if (type == "(") return pass(functiondef);
12621 }
12622 function commasep(what, end, sep) {
12623 function proceed(type, value) {
12624 if (sep ? sep.indexOf(type) > -1 : type == ",") {
12625 var lex = cx.state.lexical;
12626 if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
12627 return cont(function(type, value) {
12628 if (type == end || value == end) return pass()
12629 return pass(what)
12630 }, proceed);
12631 }
12632 if (type == end || value == end) return cont();
12633 return cont(expect(end));
12634 }
12635 return function(type, value) {
12636 if (type == end || value == end) return cont();
12637 return pass(what, proceed);
12638 };
12639 }
12640 function contCommasep(what, end, info) {
12641 for (var i = 3; i < arguments.length; i++)
12642 cx.cc.push(arguments[i]);
12643 return cont(pushlex(end, info), commasep(what, end), poplex);
12644 }
12645 function block(type) {
12646 if (type == "}") return cont();
12647 return pass(statement, block);
12648 }
12649 function maybetype(type, value) {
12650 if (isTS) {
12651 if (type == ":") return cont(typeexpr);
12652 if (value == "?") return cont(maybetype);
12653 }
12654 }
12655 function mayberettype(type) {
12656 if (isTS && type == ":") {
12657 if (cx.stream.match(/^\s*\w+\s+is\b/, false)) return cont(expression, isKW, typeexpr)
12658 else return cont(typeexpr)
12659 }
12660 }
12661 function isKW(_, value) {
12662 if (value == "is") {
12663 cx.marked = "keyword"
12664 return cont()
12665 }
12666 }
12667 function typeexpr(type, value) {
12668 if (type == "variable" || value == "void") {
12669 if (value == "keyof") {
12670 cx.marked = "keyword"
12671 return cont(typeexpr)
12672 } else {
12673 cx.marked = "type"
12674 return cont(afterType)
12675 }
12676 }
12677 if (type == "string" || type == "number" || type == "atom") return cont(afterType);
12678 if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)
12679 if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType)
12680 if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
12681 }
12682 function maybeReturnType(type) {
12683 if (type == "=>") return cont(typeexpr)
12684 }
12685 function typeprop(type, value) {
12686 if (type == "variable" || cx.style == "keyword") {
12687 cx.marked = "property"
12688 return cont(typeprop)
12689 } else if (value == "?") {
12690 return cont(typeprop)
12691 } else if (type == ":") {
12692 return cont(typeexpr)
12693 } else if (type == "[") {
12694 return cont(expression, maybetype, expect("]"), typeprop)
12695 }
12696 }
12697 function typearg(type) {
12698 if (type == "variable") return cont(typearg)
12699 else if (type == ":") return cont(typeexpr)
12700 }
12701 function afterType(type, value) {
12702 if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
12703 if (value == "|" || type == ".") return cont(typeexpr)
12704 if (type == "[") return cont(expect("]"), afterType)
12705 if (value == "extends" || value == "implements") { cx.marked = "keyword"; return cont(typeexpr) }
12706 }
12707 function maybeTypeArgs(_, value) {
12708 if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
12709 }
12710 function typeparam() {
12711 return pass(typeexpr, maybeTypeDefault)
12712 }
12713 function maybeTypeDefault(_, value) {
12714 if (value == "=") return cont(typeexpr)
12715 }
12716 function vardef() {
12717 return pass(pattern, maybetype, maybeAssign, vardefCont);
12718 }
12719 function pattern(type, value) {
12720 if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(pattern) }
12721 if (type == "variable") { register(value); return cont(); }
12722 if (type == "spread") return cont(pattern);
12723 if (type == "[") return contCommasep(pattern, "]");
12724 if (type == "{") return contCommasep(proppattern, "}");
12725 }
12726 function proppattern(type, value) {
12727 if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
12728 register(value);
12729 return cont(maybeAssign);
12730 }
12731 if (type == "variable") cx.marked = "property";
12732 if (type == "spread") return cont(pattern);
12733 if (type == "}") return pass();
12734 return cont(expect(":"), pattern, maybeAssign);
12735 }
12736 function maybeAssign(_type, value) {
12737 if (value == "=") return cont(expressionNoComma);
12738 }
12739 function vardefCont(type) {
12740 if (type == ",") return cont(vardef);
12741 }
12742 function maybeelse(type, value) {
12743 if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
12744 }
12745 function forspec(type) {
12746 if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
12747 }
12748 function forspec1(type) {
12749 if (type == "var") return cont(vardef, expect(";"), forspec2);
12750 if (type == ";") return cont(forspec2);
12751 if (type == "variable") return cont(formaybeinof);
12752 return pass(expression, expect(";"), forspec2);
12753 }
12754 function formaybeinof(_type, value) {
12755 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
12756 return cont(maybeoperatorComma, forspec2);
12757 }
12758 function forspec2(type, value) {
12759 if (type == ";") return cont(forspec3);
12760 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
12761 return pass(expression, expect(";"), forspec3);
12762 }
12763 function forspec3(type) {
12764 if (type != ")") cont(expression);
12765 }
12766 function functiondef(type, value) {
12767 if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
12768 if (type == "variable") {register(value); return cont(functiondef);}
12769 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, mayberettype, statement, popcontext);
12770 if (isTS && value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, functiondef)
12771 }
12772 function funarg(type, value) {
12773 if (value == "@") cont(expression, funarg)
12774 if (type == "spread") return cont(funarg);
12775 if (isTS && isModifier(value)) { cx.marked = "keyword"; return cont(funarg); }
12776 return pass(pattern, maybetype, maybeAssign);
12777 }
12778 function classExpression(type, value) {
12779 // Class expressions may have an optional name.
12780 if (type == "variable") return className(type, value);
12781 return classNameAfter(type, value);
12782 }
12783 function className(type, value) {
12784 if (type == "variable") {register(value); return cont(classNameAfter);}
12785 }
12786 function classNameAfter(type, value) {
12787 if (value == "<") return cont(pushlex(">"), commasep(typeparam, ">"), poplex, classNameAfter)
12788 if (value == "extends" || value == "implements" || (isTS && type == ","))
12789 return cont(isTS ? typeexpr : expression, classNameAfter);
12790 if (type == "{") return cont(pushlex("}"), classBody, poplex);
12791 }
12792 function classBody(type, value) {
12793 if (type == "async" ||
12794 (type == "variable" &&
12795 (value == "static" || value == "get" || value == "set" || (isTS && isModifier(value))) &&
12796 cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) {
12797 cx.marked = "keyword";
12798 return cont(classBody);
12799 }
12800 if (type == "variable" || cx.style == "keyword") {
12801 cx.marked = "property";
12802 return cont(isTS ? classfield : functiondef, classBody);
12803 }
12804 if (type == "[")
12805 return cont(expression, maybetype, expect("]"), isTS ? classfield : functiondef, classBody)
12806 if (value == "*") {
12807 cx.marked = "keyword";
12808 return cont(classBody);
12809 }
12810 if (type == ";") return cont(classBody);
12811 if (type == "}") return cont();
12812 if (value == "@") return cont(expression, classBody)
12813 }
12814 function classfield(type, value) {
12815 if (value == "?") return cont(classfield)
12816 if (type == ":") return cont(typeexpr, maybeAssign)
12817 if (value == "=") return cont(expressionNoComma)
12818 return pass(functiondef)
12819 }
12820 function afterExport(type, value) {
12821 if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
12822 if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
12823 if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";"));
12824 return pass(statement);
12825 }
12826 function exportField(type, value) {
12827 if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
12828 if (type == "variable") return pass(expressionNoComma, exportField);
12829 }
12830 function afterImport(type) {
12831 if (type == "string") return cont();
12832 return pass(importSpec, maybeMoreImports, maybeFrom);
12833 }
12834 function importSpec(type, value) {
12835 if (type == "{") return contCommasep(importSpec, "}");
12836 if (type == "variable") register(value);
12837 if (value == "*") cx.marked = "keyword";
12838 return cont(maybeAs);
12839 }
12840 function maybeMoreImports(type) {
12841 if (type == ",") return cont(importSpec, maybeMoreImports)
12842 }
12843 function maybeAs(_type, value) {
12844 if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
12845 }
12846 function maybeFrom(_type, value) {
12847 if (value == "from") { cx.marked = "keyword"; return cont(expression); }
12848 }
12849 function arrayLiteral(type) {
12850 if (type == "]") return cont();
12851 return pass(commasep(expressionNoComma, "]"));
12852 }
12853
12854 function isContinuedStatement(state, textAfter) {
12855 return state.lastType == "operator" || state.lastType == "," ||
12856 isOperatorChar.test(textAfter.charAt(0)) ||
12857 /[,.]/.test(textAfter.charAt(0));
12858 }
12859
12860 function expressionAllowed(stream, state, backUp) {
12861 return state.tokenize == tokenBase &&
12862 /^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
12863 (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
12864 }
12865
12866 // Interface
12867
12868 return {
12869 startState: function(basecolumn) {
12870 var state = {
12871 tokenize: tokenBase,
12872 lastType: "sof",
12873 cc: [],
12874 lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
12875 localVars: parserConfig.localVars,
12876 context: parserConfig.localVars && {vars: parserConfig.localVars},
12877 indented: basecolumn || 0
12878 };
12879 if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
12880 state.globalVars = parserConfig.globalVars;
12881 return state;
12882 },
12883
12884 token: function(stream, state) {
12885 if (stream.sol()) {
12886 if (!state.lexical.hasOwnProperty("align"))
12887 state.lexical.align = false;
12888 state.indented = stream.indentation();
12889 findFatArrow(stream, state);
12890 }
12891 if (state.tokenize != tokenComment && stream.eatSpace()) return null;
12892 var style = state.tokenize(stream, state);
12893 if (type == "comment") return style;
12894 state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
12895 return parseJS(state, style, type, content, stream);
12896 },
12897
12898 indent: function(state, textAfter) {
12899 if (state.tokenize == tokenComment) return CodeMirror.Pass;
12900 if (state.tokenize != tokenBase) return 0;
12901 var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top
12902 // Kludge to prevent 'maybelse' from blocking lexical scope pops
12903 if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
12904 var c = state.cc[i];
12905 if (c == poplex) lexical = lexical.prev;
12906 else if (c != maybeelse) break;
12907 }
12908 while ((lexical.type == "stat" || lexical.type == "form") &&
12909 (firstChar == "}" || ((top = state.cc[state.cc.length - 1]) &&
12910 (top == maybeoperatorComma || top == maybeoperatorNoComma) &&
12911 !/^[,\.=+\-*:?[\(]/.test(textAfter))))
12912 lexical = lexical.prev;
12913 if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
12914 lexical = lexical.prev;
12915 var type = lexical.type, closing = firstChar == type;
12916
12917 if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
12918 else if (type == "form" && firstChar == "{") return lexical.indented;
12919 else if (type == "form") return lexical.indented + indentUnit;
12920 else if (type == "stat")
12921 return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
12922 else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
12923 return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
12924 else if (lexical.align) return lexical.column + (closing ? 0 : 1);
12925 else return lexical.indented + (closing ? 0 : indentUnit);
12926 },
12927
12928 electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
12929 blockCommentStart: jsonMode ? null : "/*",
12930 blockCommentEnd: jsonMode ? null : "*/",
12931 blockCommentContinue: jsonMode ? null : " * ",
12932 lineComment: jsonMode ? null : "//",
12933 fold: "brace",
12934 closeBrackets: "()[]{}''\"\"``",
12935
12936 helperType: jsonMode ? "json" : "javascript",
12937 jsonldMode: jsonldMode,
12938 jsonMode: jsonMode,
12939
12940 expressionAllowed: expressionAllowed,
12941
12942 skipExpression: function(state) {
12943 var top = state.cc[state.cc.length - 1]
12944 if (top == expression || top == expressionNoComma) state.cc.pop()
12945 }
12946 };
12947 });
12948
12949 CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
12950
12951 CodeMirror.defineMIME("text/javascript", "javascript");
12952 CodeMirror.defineMIME("text/ecmascript", "javascript");
12953 CodeMirror.defineMIME("application/javascript", "javascript");
12954 CodeMirror.defineMIME("application/x-javascript", "javascript");
12955 CodeMirror.defineMIME("application/ecmascript", "javascript");
12956 CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
12957 CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
12958 CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
12959 CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
12960 CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
12961
12962 });
12963
12964 },{"../../lib/codemirror":12}],16:[function(require,module,exports){
12965 // CodeMirror, copyright (c) by Marijn Haverbeke and others
12966 // Distributed under an MIT license: http://codemirror.net/LICENSE
12967
12968 (function(mod) {
12969 if (typeof exports == "object" && typeof module == "object") // CommonJS
12970 mod(require("../../lib/codemirror"));
12971 else if (typeof define == "function" && define.amd) // AMD
12972 define(["../../lib/codemirror"], mod);
12973 else // Plain browser env
12974 mod(CodeMirror);
12975 })(function(CodeMirror) {
12976 "use strict";
12977
12978 var htmlConfig = {
12979 autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
12980 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
12981 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
12982 'track': true, 'wbr': true, 'menuitem': true},
12983 implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
12984 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
12985 'th': true, 'tr': true},
12986 contextGrabbers: {
12987 'dd': {'dd': true, 'dt': true},
12988 'dt': {'dd': true, 'dt': true},
12989 'li': {'li': true},
12990 'option': {'option': true, 'optgroup': true},
12991 'optgroup': {'optgroup': true},
12992 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
12993 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
12994 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
12995 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
12996 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
12997 'rp': {'rp': true, 'rt': true},
12998 'rt': {'rp': true, 'rt': true},
12999 'tbody': {'tbody': true, 'tfoot': true},
13000 'td': {'td': true, 'th': true},
13001 'tfoot': {'tbody': true},
13002 'th': {'td': true, 'th': true},
13003 'thead': {'tbody': true, 'tfoot': true},
13004 'tr': {'tr': true}
13005 },
13006 doNotIndent: {"pre": true},
13007 allowUnquoted: true,
13008 allowMissing: true,
13009 caseFold: true
13010 }
13011
13012 var xmlConfig = {
13013 autoSelfClosers: {},
13014 implicitlyClosed: {},
13015 contextGrabbers: {},
13016 doNotIndent: {},
13017 allowUnquoted: false,
13018 allowMissing: false,
13019 allowMissingTagName: false,
13020 caseFold: false
13021 }
13022
13023 CodeMirror.defineMode("xml", function(editorConf, config_) {
13024 var indentUnit = editorConf.indentUnit
13025 var config = {}
13026 var defaults = config_.htmlMode ? htmlConfig : xmlConfig
13027 for (var prop in defaults) config[prop] = defaults[prop]
13028 for (var prop in config_) config[prop] = config_[prop]
13029
13030 // Return variables for tokenizers
13031 var type, setStyle;
13032
13033 function inText(stream, state) {
13034 function chain(parser) {
13035 state.tokenize = parser;
13036 return parser(stream, state);
13037 }
13038
13039 var ch = stream.next();
13040 if (ch == "<") {
13041 if (stream.eat("!")) {
13042 if (stream.eat("[")) {
13043 if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
13044 else return null;
13045 } else if (stream.match("--")) {
13046 return chain(inBlock("comment", "-->"));
13047 } else if (stream.match("DOCTYPE", true, true)) {
13048 stream.eatWhile(/[\w\._\-]/);
13049 return chain(doctype(1));
13050 } else {
13051 return null;
13052 }
13053 } else if (stream.eat("?")) {
13054 stream.eatWhile(/[\w\._\-]/);
13055 state.tokenize = inBlock("meta", "?>");
13056 return "meta";
13057 } else {
13058 type = stream.eat("/") ? "closeTag" : "openTag";
13059 state.tokenize = inTag;
13060 return "tag bracket";
13061 }
13062 } else if (ch == "&") {
13063 var ok;
13064 if (stream.eat("#")) {
13065 if (stream.eat("x")) {
13066 ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
13067 } else {
13068 ok = stream.eatWhile(/[\d]/) && stream.eat(";");
13069 }
13070 } else {
13071 ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
13072 }
13073 return ok ? "atom" : "error";
13074 } else {
13075 stream.eatWhile(/[^&<]/);
13076 return null;
13077 }
13078 }
13079 inText.isInText = true;
13080
13081 function inTag(stream, state) {
13082 var ch = stream.next();
13083 if (ch == ">" || (ch == "/" && stream.eat(">"))) {
13084 state.tokenize = inText;
13085 type = ch == ">" ? "endTag" : "selfcloseTag";
13086 return "tag bracket";
13087 } else if (ch == "=") {
13088 type = "equals";
13089 return null;
13090 } else if (ch == "<") {
13091 state.tokenize = inText;
13092 state.state = baseState;
13093 state.tagName = state.tagStart = null;
13094 var next = state.tokenize(stream, state);
13095 return next ? next + " tag error" : "tag error";
13096 } else if (/[\'\"]/.test(ch)) {
13097 state.tokenize = inAttribute(ch);
13098 state.stringStartCol = stream.column();
13099 return state.tokenize(stream, state);
13100 } else {
13101 stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
13102 return "word";
13103 }
13104 }
13105
13106 function inAttribute(quote) {
13107 var closure = function(stream, state) {
13108 while (!stream.eol()) {
13109 if (stream.next() == quote) {
13110 state.tokenize = inTag;
13111 break;
13112 }
13113 }
13114 return "string";
13115 };
13116 closure.isInAttribute = true;
13117 return closure;
13118 }
13119
13120 function inBlock(style, terminator) {
13121 return function(stream, state) {
13122 while (!stream.eol()) {
13123 if (stream.match(terminator)) {
13124 state.tokenize = inText;
13125 break;
13126 }
13127 stream.next();
13128 }
13129 return style;
13130 };
13131 }
13132 function doctype(depth) {
13133 return function(stream, state) {
13134 var ch;
13135 while ((ch = stream.next()) != null) {
13136 if (ch == "<") {
13137 state.tokenize = doctype(depth + 1);
13138 return state.tokenize(stream, state);
13139 } else if (ch == ">") {
13140 if (depth == 1) {
13141 state.tokenize = inText;
13142 break;
13143 } else {
13144 state.tokenize = doctype(depth - 1);
13145 return state.tokenize(stream, state);
13146 }
13147 }
13148 }
13149 return "meta";
13150 };
13151 }
13152
13153 function Context(state, tagName, startOfLine) {
13154 this.prev = state.context;
13155 this.tagName = tagName;
13156 this.indent = state.indented;
13157 this.startOfLine = startOfLine;
13158 if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
13159 this.noIndent = true;
13160 }
13161 function popContext(state) {
13162 if (state.context) state.context = state.context.prev;
13163 }
13164 function maybePopContext(state, nextTagName) {
13165 var parentTagName;
13166 while (true) {
13167 if (!state.context) {
13168 return;
13169 }
13170 parentTagName = state.context.tagName;
13171 if (!config.contextGrabbers.hasOwnProperty(parentTagName) ||
13172 !config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
13173 return;
13174 }
13175 popContext(state);
13176 }
13177 }
13178
13179 function baseState(type, stream, state) {
13180 if (type == "openTag") {
13181 state.tagStart = stream.column();
13182 return tagNameState;
13183 } else if (type == "closeTag") {
13184 return closeTagNameState;
13185 } else {
13186 return baseState;
13187 }
13188 }
13189 function tagNameState(type, stream, state) {
13190 if (type == "word") {
13191 state.tagName = stream.current();
13192 setStyle = "tag";
13193 return attrState;
13194 } else if (config.allowMissingTagName && type == "endTag") {
13195 setStyle = "tag bracket";
13196 return attrState(type, stream, state);
13197 } else {
13198 setStyle = "error";
13199 return tagNameState;
13200 }
13201 }
13202 function closeTagNameState(type, stream, state) {
13203 if (type == "word") {
13204 var tagName = stream.current();
13205 if (state.context && state.context.tagName != tagName &&
13206 config.implicitlyClosed.hasOwnProperty(state.context.tagName))
13207 popContext(state);
13208 if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {
13209 setStyle = "tag";
13210 return closeState;
13211 } else {
13212 setStyle = "tag error";
13213 return closeStateErr;
13214 }
13215 } else if (config.allowMissingTagName && type == "endTag") {
13216 setStyle = "tag bracket";
13217 return closeState(type, stream, state);
13218 } else {
13219 setStyle = "error";
13220 return closeStateErr;
13221 }
13222 }
13223
13224 function closeState(type, _stream, state) {
13225 if (type != "endTag") {
13226 setStyle = "error";
13227 return closeState;
13228 }
13229 popContext(state);
13230 return baseState;
13231 }
13232 function closeStateErr(type, stream, state) {
13233 setStyle = "error";
13234 return closeState(type, stream, state);
13235 }
13236
13237 function attrState(type, _stream, state) {
13238 if (type == "word") {
13239 setStyle = "attribute";
13240 return attrEqState;
13241 } else if (type == "endTag" || type == "selfcloseTag") {
13242 var tagName = state.tagName, tagStart = state.tagStart;
13243 state.tagName = state.tagStart = null;
13244 if (type == "selfcloseTag" ||
13245 config.autoSelfClosers.hasOwnProperty(tagName)) {
13246 maybePopContext(state, tagName);
13247 } else {
13248 maybePopContext(state, tagName);
13249 state.context = new Context(state, tagName, tagStart == state.indented);
13250 }
13251 return baseState;
13252 }
13253 setStyle = "error";
13254 return attrState;
13255 }
13256 function attrEqState(type, stream, state) {
13257 if (type == "equals") return attrValueState;
13258 if (!config.allowMissing) setStyle = "error";
13259 return attrState(type, stream, state);
13260 }
13261 function attrValueState(type, stream, state) {
13262 if (type == "string") return attrContinuedState;
13263 if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;}
13264 setStyle = "error";
13265 return attrState(type, stream, state);
13266 }
13267 function attrContinuedState(type, stream, state) {
13268 if (type == "string") return attrContinuedState;
13269 return attrState(type, stream, state);
13270 }
13271
13272 return {
13273 startState: function(baseIndent) {
13274 var state = {tokenize: inText,
13275 state: baseState,
13276 indented: baseIndent || 0,
13277 tagName: null, tagStart: null,
13278 context: null}
13279 if (baseIndent != null) state.baseIndent = baseIndent
13280 return state
13281 },
13282
13283 token: function(stream, state) {
13284 if (!state.tagName && stream.sol())
13285 state.indented = stream.indentation();
13286
13287 if (stream.eatSpace()) return null;
13288 type = null;
13289 var style = state.tokenize(stream, state);
13290 if ((style || type) && style != "comment") {
13291 setStyle = null;
13292 state.state = state.state(type || style, stream, state);
13293 if (setStyle)
13294 style = setStyle == "error" ? style + " error" : setStyle;
13295 }
13296 return style;
13297 },
13298
13299 indent: function(state, textAfter, fullLine) {
13300 var context = state.context;
13301 // Indent multi-line strings (e.g. css).
13302 if (state.tokenize.isInAttribute) {
13303 if (state.tagStart == state.indented)
13304 return state.stringStartCol + 1;
13305 else
13306 return state.indented + indentUnit;
13307 }
13308 if (context && context.noIndent) return CodeMirror.Pass;
13309 if (state.tokenize != inTag && state.tokenize != inText)
13310 return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
13311 // Indent the starts of attribute names.
13312 if (state.tagName) {
13313 if (config.multilineTagIndentPastTag !== false)
13314 return state.tagStart + state.tagName.length + 2;
13315 else
13316 return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1);
13317 }
13318 if (config.alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
13319 var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
13320 if (tagAfter && tagAfter[1]) { // Closing tag spotted
13321 while (context) {
13322 if (context.tagName == tagAfter[2]) {
13323 context = context.prev;
13324 break;
13325 } else if (config.implicitlyClosed.hasOwnProperty(context.tagName)) {
13326 context = context.prev;
13327 } else {
13328 break;
13329 }
13330 }
13331 } else if (tagAfter) { // Opening tag spotted
13332 while (context) {
13333 var grabbers = config.contextGrabbers[context.tagName];
13334 if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
13335 context = context.prev;
13336 else
13337 break;
13338 }
13339 }
13340 while (context && context.prev && !context.startOfLine)
13341 context = context.prev;
13342 if (context) return context.indent + indentUnit;
13343 else return state.baseIndent || 0;
13344 },
13345
13346 electricInput: /<\/[\s\w:]+>$/,
13347 blockCommentStart: "<!--",
13348 blockCommentEnd: "-->",
13349
13350 configuration: config.htmlMode ? "html" : "xml",
13351 helperType: config.htmlMode ? "html" : "xml",
13352
13353 skipAttribute: function(state) {
13354 if (state.state == attrValueState)
13355 state.state = attrState
13356 }
13357 };
13358 });
13359
13360 CodeMirror.defineMIME("text/xml", "xml");
13361 CodeMirror.defineMIME("application/xml", "xml");
13362 if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
13363 CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
13364
13365 });
13366
13367 },{"../../lib/codemirror":12}],17:[function(require,module,exports){
13368 (function(global,factory){if(typeof define === 'function' && define.amd){define(['exports'],factory);}else if(typeof exports !== 'undefined'){factory(exports);}else {var mod={exports:{}};factory(mod.exports);global.decko = mod.exports;}})(this,function(exports){'use strict';exports.__esModule = true;var EMPTY={};var HOP=Object.prototype.hasOwnProperty;var fns={memoize:function memoize(fn){var opt=arguments.length <= 1 || arguments[1] === undefined?EMPTY:arguments[1];var cache=opt.cache || {};return function(){for(var _len=arguments.length,a=Array(_len),_key=0;_key < _len;_key++) {a[_key] = arguments[_key];}var k=String(a[0]);if(opt.caseSensitive === false)k = k.toLowerCase();return HOP.call(cache,k)?cache[k]:cache[k] = fn.apply(this,a);};},debounce:function debounce(fn,opts){if(typeof opts === 'function'){var p=fn;fn = opts;opts = p;}var delay=opts && opts.delay || opts || 0,args=undefined,context=undefined,timer=undefined;return function(){for(var _len2=arguments.length,a=Array(_len2),_key2=0;_key2 < _len2;_key2++) {a[_key2] = arguments[_key2];}args = a;context = this;if(!timer)timer = setTimeout(function(){fn.apply(context,args);args = context = timer = null;},delay);};},bind:function bind(target,key,_ref){var fn=_ref.value;return {configurable:true,get:function get(){var value=fn.bind(this);Object.defineProperty(this,key,{value:value,configurable:true,writable:true});return value;}};}};var memoize=multiMethod(fns.memoize),debounce=multiMethod(fns.debounce),bind=multiMethod(function(f,c){return f.bind(c);},function(){return fns.bind;});exports.memoize = memoize;exports.debounce = debounce;exports.bind = bind;exports['default'] = {memoize:memoize,debounce:debounce,bind:bind};function multiMethod(inner,deco){deco = deco || inner.decorate || decorator(inner);var d=deco();return function(){for(var _len3=arguments.length,args=Array(_len3),_key3=0;_key3 < _len3;_key3++) {args[_key3] = arguments[_key3];}var l=args.length;return (l < 2?deco:l > 2?d:inner).apply(undefined,args);};}function decorator(fn){return function(opt){return typeof opt === 'function'?fn(opt):function(target,key,desc){desc.value = fn(desc.value,opt,target,key,desc);};};}});
13369
13370
13371 },{}],18:[function(require,module,exports){
13372 /*
13373
13374 Style HTML
13375 ---------------
13376
13377 Written by Nochum Sossonko, (nsossonko@hotmail.com)
13378
13379 Based on code initially developed by: Einar Lielmanis, <elfz@laacz.lv>
13380 http://jsbeautifier.org/
13381
13382
13383 You are free to use this in any way you want, in case you find this useful or working for you.
13384
13385 Usage:
13386 style_html(html_source);
13387
13388 style_html(html_source, options);
13389
13390 The options are:
13391 indent_size (default 4) — indentation size,
13392 indent_char (default space) — character to indent with,
13393 max_char (default 70) - maximum amount of characters per line,
13394 brace_style (default "collapse") - "collapse" | "expand" | "end-expand"
13395 put braces on the same line as control statements (default), or put braces on own line (Allman / ANSI style), or just put end braces on own line.
13396 unformatted (defaults to inline tags) - list of tags, that shouldn't be reformatted
13397 indent_scripts (default normal) - "keep"|"separate"|"normal"
13398
13399 e.g.
13400
13401 style_html(html_source, {
13402 'indent_size': 2,
13403 'indent_char': ' ',
13404 'max_char': 78,
13405 'brace_style': 'expand',
13406 'unformatted': ['a', 'sub', 'sup', 'b', 'i', 'u']
13407 });
13408 */
13409
13410 function style_html(html_source, options) {
13411 //Wrapper function to invoke all the necessary constructors and deal with the output.
13412
13413 var multi_parser,
13414 indent_size,
13415 indent_character,
13416 max_char,
13417 brace_style,
13418 unformatted;
13419
13420 options = options || {};
13421 indent_size = options.indent_size || 4;
13422 indent_character = options.indent_char || ' ';
13423 brace_style = options.brace_style || 'collapse';
13424 max_char = options.max_char == 0 ? Infinity : options.max_char || 70;
13425 unformatted = options.unformatted || ['a', 'span', 'bdo', 'em', 'strong', 'dfn', 'code', 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'q', 'sub', 'sup', 'tt', 'i', 'b', 'big', 'small', 'u', 's', 'strike', 'font', 'ins', 'del', 'pre', 'address', 'dt', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
13426
13427 function Parser() {
13428
13429 this.pos = 0; //Parser position
13430 this.token = '';
13431 this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT
13432 this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values
13433 parent: 'parent1',
13434 parentcount: 1,
13435 parent1: ''
13436 };
13437 this.tag_type = '';
13438 this.token_text = this.last_token = this.last_text = this.token_type = '';
13439
13440 this.Utils = { //Uilities made available to the various functions
13441 whitespace: "\n\r\t ".split(''),
13442 single_token: 'br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed,?php,?,?='.split(','), //all the single tags for HTML
13443 extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them
13444 in_array: function (what, arr) {
13445 for (var i=0; i<arr.length; i++) {
13446 if (what === arr[i]) {
13447 return true;
13448 }
13449 }
13450 return false;
13451 }
13452 }
13453
13454 this.get_content = function () { //function to capture regular content between tags
13455
13456 var input_char = '',
13457 content = [],
13458 space = false; //if a space is needed
13459
13460 while (this.input.charAt(this.pos) !== '<') {
13461 if (this.pos >= this.input.length) {
13462 return content.length?content.join(''):['', 'TK_EOF'];
13463 }
13464
13465 input_char = this.input.charAt(this.pos);
13466 this.pos++;
13467 this.line_char_count++;
13468
13469 if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
13470 if (content.length) {
13471 space = true;
13472 }
13473 this.line_char_count--;
13474 continue; //don't want to insert unnecessary space
13475 }
13476 else if (space) {
13477 if (this.line_char_count >= this.max_char) { //insert a line when the max_char is reached
13478 content.push('\n');
13479 for (var i=0; i<this.indent_level; i++) {
13480 content.push(this.indent_string);
13481 }
13482 this.line_char_count = 0;
13483 }
13484 else{
13485 content.push(' ');
13486 this.line_char_count++;
13487 }
13488 space = false;
13489 }
13490 content.push(input_char); //letter at-a-time (or string) inserted to an array
13491 }
13492 return content.length?content.join(''):'';
13493 }
13494
13495 this.get_contents_to = function (name) { //get the full content of a script or style to pass to js_beautify
13496 if (this.pos == this.input.length) {
13497 return ['', 'TK_EOF'];
13498 }
13499 var input_char = '';
13500 var content = '';
13501 var reg_match = new RegExp('\<\/' + name + '\\s*\>', 'igm');
13502 reg_match.lastIndex = this.pos;
13503 var reg_array = reg_match.exec(this.input);
13504 var end_script = reg_array?reg_array.index:this.input.length; //absolute end of script
13505 if(this.pos < end_script) { //get everything in between the script tags
13506 content = this.input.substring(this.pos, end_script);
13507 this.pos = end_script;
13508 }
13509 return content;
13510 }
13511
13512 this.record_tag = function (tag){ //function to record a tag and its parent in this.tags Object
13513 if (this.tags[tag + 'count']) { //check for the existence of this tag type
13514 this.tags[tag + 'count']++;
13515 this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
13516 }
13517 else { //otherwise initialize this tag type
13518 this.tags[tag + 'count'] = 1;
13519 this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
13520 }
13521 this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent; //set the parent (i.e. in the case of a div this.tags.div1parent)
13522 this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1')
13523 }
13524
13525 this.retrieve_tag = function (tag) { //function to retrieve the opening tag to the corresponding closer
13526 if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it
13527 var temp_parent = this.tags.parent; //check to see if it's a closable tag.
13528 while (temp_parent) { //till we reach '' (the initial value);
13529 if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it
13530 break;
13531 }
13532 temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree
13533 }
13534 if (temp_parent) { //if we caught something
13535 this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly
13536 this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent
13537 }
13538 delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference...
13539 delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself
13540 if (this.tags[tag + 'count'] == 1) {
13541 delete this.tags[tag + 'count'];
13542 }
13543 else {
13544 this.tags[tag + 'count']--;
13545 }
13546 }
13547 }
13548
13549 this.get_tag = function () { //function to get a full tag and parse its type
13550 var input_char = '',
13551 content = [],
13552 space = false,
13553 tag_start, tag_end;
13554
13555 do {
13556 if (this.pos >= this.input.length) {
13557 return content.length?content.join(''):['', 'TK_EOF'];
13558 }
13559
13560 input_char = this.input.charAt(this.pos);
13561 this.pos++;
13562 this.line_char_count++;
13563
13564 if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space
13565 space = true;
13566 this.line_char_count--;
13567 continue;
13568 }
13569
13570 if (input_char === "'" || input_char === '"') {
13571 if (!content[1] || content[1] !== '!') { //if we're in a comment strings don't get treated specially
13572 input_char += this.get_unformatted(input_char);
13573 space = true;
13574 }
13575 }
13576
13577 if (input_char === '=') { //no space before =
13578 space = false;
13579 }
13580
13581 if (content.length && content[content.length-1] !== '=' && input_char !== '>'
13582 && space) { //no space after = or before >
13583 if (this.line_char_count >= this.max_char) {
13584 this.print_newline(false, content);
13585 this.line_char_count = 0;
13586 }
13587 else {
13588 content.push(' ');
13589 this.line_char_count++;
13590 }
13591 space = false;
13592 }
13593 if (input_char === '<') {
13594 tag_start = this.pos - 1;
13595 }
13596 content.push(input_char); //inserts character at-a-time (or string)
13597 } while (input_char !== '>');
13598
13599 var tag_complete = content.join('');
13600 var tag_index;
13601 if (tag_complete.indexOf(' ') != -1) { //if there's whitespace, thats where the tag name ends
13602 tag_index = tag_complete.indexOf(' ');
13603 }
13604 else { //otherwise go with the tag ending
13605 tag_index = tag_complete.indexOf('>');
13606 }
13607 var tag_check = tag_complete.substring(1, tag_index).toLowerCase();
13608 if (tag_complete.charAt(tag_complete.length-2) === '/' ||
13609 this.Utils.in_array(tag_check, this.Utils.single_token)) { //if this tag name is a single tag type (either in the list or has a closing /)
13610 this.tag_type = 'SINGLE';
13611 }
13612 else if (tag_check === 'script') { //for later script handling
13613 this.record_tag(tag_check);
13614 this.tag_type = 'SCRIPT';
13615 }
13616 else if (tag_check === 'style') { //for future style handling (for now it justs uses get_content)
13617 this.record_tag(tag_check);
13618 this.tag_type = 'STYLE';
13619 }
13620 else if (this.Utils.in_array(tag_check, unformatted)) { // do not reformat the "unformatted" tags
13621 var comment = this.get_unformatted('</'+tag_check+'>', tag_complete); //...delegate to get_unformatted function
13622 content.push(comment);
13623 // Preserve collapsed whitespace either before or after this tag.
13624 if (tag_start > 0 && this.Utils.in_array(this.input.charAt(tag_start - 1), this.Utils.whitespace)){
13625 content.splice(0, 0, this.input.charAt(tag_start - 1));
13626 }
13627 tag_end = this.pos - 1;
13628 if (this.Utils.in_array(this.input.charAt(tag_end + 1), this.Utils.whitespace)){
13629 content.push(this.input.charAt(tag_end + 1));
13630 }
13631 this.tag_type = 'SINGLE';
13632 }
13633 else if (tag_check.charAt(0) === '!') { //peek for <!-- comment
13634 if (tag_check.indexOf('[if') != -1) { //peek for <!--[if conditional comment
13635 if (tag_complete.indexOf('!IE') != -1) { //this type needs a closing --> so...
13636 var comment = this.get_unformatted('-->', tag_complete); //...delegate to get_unformatted
13637 content.push(comment);
13638 }
13639 this.tag_type = 'START';
13640 }
13641 else if (tag_check.indexOf('[endif') != -1) {//peek for <!--[endif end conditional comment
13642 this.tag_type = 'END';
13643 this.unindent();
13644 }
13645 else if (tag_check.indexOf('[cdata[') != -1) { //if it's a <[cdata[ comment...
13646 var comment = this.get_unformatted(']]>', tag_complete); //...delegate to get_unformatted function
13647 content.push(comment);
13648 this.tag_type = 'SINGLE'; //<![CDATA[ comments are treated like single tags
13649 }
13650 else {
13651 var comment = this.get_unformatted('-->', tag_complete);
13652 content.push(comment);
13653 this.tag_type = 'SINGLE';
13654 }
13655 }
13656 else {
13657 if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending
13658 this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors
13659 this.tag_type = 'END';
13660 }
13661 else { //otherwise it's a start-tag
13662 this.record_tag(tag_check); //push it on the tag stack
13663 this.tag_type = 'START';
13664 }
13665 if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line
13666 this.print_newline(true, this.output);
13667 }
13668 }
13669 return content.join(''); //returns fully formatted tag
13670 }
13671
13672 this.get_unformatted = function (delimiter, orig_tag) { //function to return unformatted content in its entirety
13673
13674 if (orig_tag && orig_tag.toLowerCase().indexOf(delimiter) != -1) {
13675 return '';
13676 }
13677 var input_char = '';
13678 var content = '';
13679 var space = true;
13680 do {
13681
13682 if (this.pos >= this.input.length) {
13683 return content;
13684 }
13685
13686 input_char = this.input.charAt(this.pos);
13687 this.pos++
13688
13689 if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
13690 if (!space) {
13691 this.line_char_count--;
13692 continue;
13693 }
13694 if (input_char === '\n' || input_char === '\r') {
13695 content += '\n';
13696 /* Don't change tab indention for unformatted blocks. If using code for html editing, this will greatly affect <pre> tags if they are specified in the 'unformatted array'
13697 for (var i=0; i<this.indent_level; i++) {
13698 content += this.indent_string;
13699 }
13700 space = false; //...and make sure other indentation is erased
13701 */
13702 this.line_char_count = 0;
13703 continue;
13704 }
13705 }
13706 content += input_char;
13707 this.line_char_count++;
13708 space = true;
13709
13710
13711 } while (content.toLowerCase().indexOf(delimiter) == -1);
13712 return content;
13713 }
13714
13715 this.get_token = function () { //initial handler for token-retrieval
13716 var token;
13717
13718 if (this.last_token === 'TK_TAG_SCRIPT' || this.last_token === 'TK_TAG_STYLE') { //check if we need to format javascript
13719 var type = this.last_token.substr(7)
13720 token = this.get_contents_to(type);
13721 if (typeof token !== 'string') {
13722 return token;
13723 }
13724 return [token, 'TK_' + type];
13725 }
13726 if (this.current_mode === 'CONTENT') {
13727 token = this.get_content();
13728 if (typeof token !== 'string') {
13729 return token;
13730 }
13731 else {
13732 return [token, 'TK_CONTENT'];
13733 }
13734 }
13735
13736 if (this.current_mode === 'TAG') {
13737 token = this.get_tag();
13738 if (typeof token !== 'string') {
13739 return token;
13740 }
13741 else {
13742 var tag_name_type = 'TK_TAG_' + this.tag_type;
13743 return [token, tag_name_type];
13744 }
13745 }
13746 }
13747
13748 this.get_full_indent = function (level) {
13749 level = this.indent_level + level || 0;
13750 if (level < 1)
13751 return '';
13752
13753 return Array(level + 1).join(this.indent_string);
13754 }
13755
13756
13757 this.printer = function (js_source, indent_character, indent_size, max_char, brace_style) { //handles input/output and some other printing functions
13758
13759 this.input = js_source || ''; //gets the input for the Parser
13760 this.output = [];
13761 this.indent_character = indent_character;
13762 this.indent_string = '';
13763 this.indent_size = indent_size;
13764 this.brace_style = brace_style;
13765 this.indent_level = 0;
13766 this.max_char = max_char;
13767 this.line_char_count = 0; //count to see if max_char was exceeded
13768
13769 for (var i=0; i<this.indent_size; i++) {
13770 this.indent_string += this.indent_character;
13771 }
13772
13773 this.print_newline = function (ignore, arr) {
13774 this.line_char_count = 0;
13775 if (!arr || !arr.length) {
13776 return;
13777 }
13778 if (!ignore) { //we might want the extra line
13779 while (this.Utils.in_array(arr[arr.length-1], this.Utils.whitespace)) {
13780 arr.pop();
13781 }
13782 }
13783 arr.push('\n');
13784 for (var i=0; i<this.indent_level; i++) {
13785 arr.push(this.indent_string);
13786 }
13787 }
13788
13789 this.print_token = function (text) {
13790 this.output.push(text);
13791 }
13792
13793 this.indent = function () {
13794 this.indent_level++;
13795 }
13796
13797 this.unindent = function () {
13798 if (this.indent_level > 0) {
13799 this.indent_level--;
13800 }
13801 }
13802 }
13803 return this;
13804 }
13805
13806 /*_____________________--------------------_____________________*/
13807
13808 multi_parser = new Parser(); //wrapping functions Parser
13809 multi_parser.printer(html_source, indent_character, indent_size, max_char, brace_style); //initialize starting values
13810
13811 while (true) {
13812 var t = multi_parser.get_token();
13813 multi_parser.token_text = t[0];
13814 multi_parser.token_type = t[1];
13815
13816 if (multi_parser.token_type === 'TK_EOF') {
13817 break;
13818 }
13819
13820 switch (multi_parser.token_type) {
13821 case 'TK_TAG_START':
13822 multi_parser.print_newline(false, multi_parser.output);
13823 multi_parser.print_token(multi_parser.token_text);
13824 multi_parser.indent();
13825 multi_parser.current_mode = 'CONTENT';
13826 break;
13827 case 'TK_TAG_STYLE':
13828 case 'TK_TAG_SCRIPT':
13829 multi_parser.print_newline(false, multi_parser.output);
13830 multi_parser.print_token(multi_parser.token_text);
13831 multi_parser.current_mode = 'CONTENT';
13832 break;
13833 case 'TK_TAG_END':
13834 //Print new line only if the tag has no content and has child
13835 if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') {
13836 var tag_name = multi_parser.token_text.match(/\w+/)[0];
13837 var tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length -1].match(/<\s*(\w+)/);
13838 if (tag_extracted_from_last_output === null || tag_extracted_from_last_output[1] !== tag_name)
13839 multi_parser.print_newline(true, multi_parser.output);
13840 }
13841 multi_parser.print_token(multi_parser.token_text);
13842 multi_parser.current_mode = 'CONTENT';
13843 break;
13844 case 'TK_TAG_SINGLE':
13845 // Don't add a newline before elements that should remain unformatted.
13846 var tag_check = multi_parser.token_text.match(/^\s*<([a-z]+)/i);
13847 if (!tag_check || !multi_parser.Utils.in_array(tag_check[1], unformatted)){
13848 multi_parser.print_newline(false, multi_parser.output);
13849 }
13850 multi_parser.print_token(multi_parser.token_text);
13851 multi_parser.current_mode = 'CONTENT';
13852 break;
13853 case 'TK_CONTENT':
13854 if (multi_parser.token_text !== '') {
13855 multi_parser.print_token(multi_parser.token_text);
13856 }
13857 multi_parser.current_mode = 'TAG';
13858 break;
13859 case 'TK_STYLE':
13860 case 'TK_SCRIPT':
13861 if (multi_parser.token_text !== '') {
13862 multi_parser.output.push('\n');
13863 var text = multi_parser.token_text;
13864 if (multi_parser.token_type == 'TK_SCRIPT') {
13865 var _beautifier = typeof js_beautify == 'function' && js_beautify;
13866 } else if (multi_parser.token_type == 'TK_STYLE') {
13867 var _beautifier = typeof css_beautify == 'function' && css_beautify;
13868 }
13869
13870 if (options.indent_scripts == "keep") {
13871 var script_indent_level = 0;
13872 } else if (options.indent_scripts == "separate") {
13873 var script_indent_level = -multi_parser.indent_level;
13874 } else {
13875 var script_indent_level = 1;
13876 }
13877
13878 var indentation = multi_parser.get_full_indent(script_indent_level);
13879 if (_beautifier) {
13880 // call the Beautifier if avaliable
13881 text = _beautifier(text.replace(/^\s*/, indentation), options);
13882 } else {
13883 // simply indent the string otherwise
13884 var white = text.match(/^\s*/)[0];
13885 var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1;
13886 var reindent = multi_parser.get_full_indent(script_indent_level -_level);
13887 text = text.replace(/^\s*/, indentation)
13888 .replace(/\r\n|\r|\n/g, '\n' + reindent)
13889 .replace(/\s*$/, '');
13890 }
13891 if (text) {
13892 multi_parser.print_token(text);
13893 multi_parser.print_newline(true, multi_parser.output);
13894 }
13895 }
13896 multi_parser.current_mode = 'TAG';
13897 break;
13898 }
13899 multi_parser.last_token = multi_parser.token_type;
13900 multi_parser.last_text = multi_parser.token_text;
13901 }
13902 return multi_parser.output.join('');
13903 }
13904
13905 module.exports = {
13906 prettyPrint: style_html
13907 };
13908 },{}],19:[function(require,module,exports){
13909 function dlv(t,e,n,l){for(l=0,e=e.split?e.split("."):e;t&&l<e.length;)t=t[e[l++]];return void 0===t?n:t}function linkState(t,e,n){var l=e.split("."),r=t.__lsc||(t.__lsc={});return r[e+n]||(r[e+n]=function(e){for(var r=e&&e.target||this,a={},i=a,o="string"==typeof n?dlv(e,n):r.nodeName?r.type.match(/^che|rad/)?r.checked:r.value:e,s=0;s<l.length-1;s++)i=i[l[s]]||(i[l[s]]=!s&&t.state[l[s]]||{});i[l[s]]=o,t.setState(a)})}module.exports=linkState;
13910
13911
13912 },{}],20:[function(require,module,exports){
13913 (function (global, factory) {
13914 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
13915 typeof define === 'function' && define.amd ? define(factory) :
13916 (global.preactRenderToString = factory());
13917 }(this, (function () {
13918
13919 var NON_DIMENSION_PROPS = {
13920 boxFlex: 1, boxFlexGroup: 1, columnCount: 1, fillOpacity: 1, flex: 1, flexGrow: 1,
13921 flexPositive: 1, flexShrink: 1, flexNegative: 1, fontWeight: 1, lineClamp: 1, lineHeight: 1,
13922 opacity: 1, order: 1, orphans: 1, strokeOpacity: 1, widows: 1, zIndex: 1, zoom: 1
13923 };
13924
13925 var ESC = {
13926 '<': '&lt;',
13927 '>': '&gt;',
13928 '"': '&quot;',
13929 '&': '&amp;'
13930 };
13931
13932 var objectKeys = Object.keys || function (obj) {
13933 var keys = [];
13934 for (var i in obj) {
13935 if (obj.hasOwnProperty(i)) keys.push(i);
13936 }return keys;
13937 };
13938
13939 var encodeEntities = function encodeEntities(s) {
13940 return String(s).replace(/[<>"&]/g, escapeChar);
13941 };
13942
13943 var escapeChar = function escapeChar(a) {
13944 return ESC[a] || a;
13945 };
13946
13947 var falsey = function falsey(v) {
13948 return v == null || v === false;
13949 };
13950
13951 var memoize = function memoize(fn) {
13952 var mem = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
13953 return function (v) {
13954 return mem[v] || (mem[v] = fn(v));
13955 };
13956 };
13957
13958 var indent = function indent(s, char) {
13959 return String(s).replace(/(\n+)/g, '$1' + (char || '\t'));
13960 };
13961
13962 var isLargeString = function isLargeString(s, length, ignoreLines) {
13963 return String(s).length > (length || 40) || !ignoreLines && String(s).indexOf('\n') !== -1 || String(s).indexOf('<') !== -1;
13964 };
13965
13966 function styleObjToCss(s) {
13967 var str = '';
13968 for (var prop in s) {
13969 var val = s[prop];
13970 if (val != null) {
13971 if (str) str += ' ';
13972 str += jsToCss(prop);
13973 str += ': ';
13974 str += val;
13975 if (typeof val === 'number' && !NON_DIMENSION_PROPS[prop]) {
13976 str += 'px';
13977 }
13978 str += ';';
13979 }
13980 }
13981 return str || undefined;
13982 }
13983
13984 function hashToClassName(c) {
13985 var str = '';
13986 for (var prop in c) {
13987 if (c[prop]) {
13988 if (str) str += ' ';
13989 str += prop;
13990 }
13991 }
13992 return str;
13993 }
13994
13995 var jsToCss = memoize(function (s) {
13996 return s.replace(/([A-Z])/g, '-$1').toLowerCase();
13997 });
13998
13999 function assign(obj, props) {
14000 for (var i in props) {
14001 obj[i] = props[i];
14002 }return obj;
14003 }
14004
14005 function getNodeProps(vnode) {
14006 var defaultProps = vnode.nodeName.defaultProps,
14007 props = assign({}, defaultProps || vnode.attributes);
14008 if (defaultProps) assign(props, vnode.attributes);
14009 if (vnode.children) props.children = vnode.children;
14010 return props;
14011 }
14012
14013 var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
14014
14015 var SHALLOW = { shallow: true };
14016
14017 var UNNAMED = [];
14018
14019 var EMPTY = {};
14020
14021 var VOID_ELEMENTS = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
14022
14023 renderToString.render = renderToString;
14024
14025 var shallowRender = function shallowRender(vnode, context) {
14026 return renderToString(vnode, context, SHALLOW);
14027 };
14028
14029 function renderToString(vnode, context, opts, inner, isSvgMode) {
14030 var _ref = vnode || EMPTY,
14031 nodeName = _ref.nodeName,
14032 attributes = _ref.attributes,
14033 children = _ref.children,
14034 isComponent = false;
14035
14036 context = context || {};
14037 opts = opts || {};
14038
14039 var pretty = opts.pretty,
14040 indentChar = typeof pretty === 'string' ? pretty : '\t';
14041
14042 if (vnode == null || typeof vnode === 'boolean') {
14043 return '';
14044 }
14045
14046 if ((typeof vnode === 'undefined' ? 'undefined' : _typeof(vnode)) !== 'object' && !nodeName) {
14047 return encodeEntities(vnode);
14048 }
14049
14050 if (typeof nodeName === 'function') {
14051 isComponent = true;
14052 if (opts.shallow && (inner || opts.renderRootComponent === false)) {
14053 nodeName = getComponentName(nodeName);
14054 } else {
14055 var props = getNodeProps(vnode),
14056 rendered = void 0;
14057
14058 if (!nodeName.prototype || typeof nodeName.prototype.render !== 'function') {
14059 rendered = nodeName(props, context);
14060 } else {
14061 var c = new nodeName(props, context);
14062
14063 c._disable = c.__x = true;
14064 c.props = props;
14065 c.context = context;
14066 if (c.componentWillMount) c.componentWillMount();
14067 rendered = c.render(c.props, c.state, c.context);
14068
14069 if (c.getChildContext) {
14070 context = assign(assign({}, context), c.getChildContext());
14071 }
14072 }
14073
14074 return renderToString(rendered, context, opts, opts.shallowHighOrder !== false);
14075 }
14076 }
14077
14078 var s = '',
14079 html = void 0;
14080
14081 if (attributes) {
14082 var attrs = objectKeys(attributes);
14083
14084 if (opts && opts.sortAttributes === true) attrs.sort();
14085
14086 for (var i = 0; i < attrs.length; i++) {
14087 var name = attrs[i],
14088 v = attributes[name];
14089 if (name === 'children') continue;
14090 if (!(opts && opts.allAttributes) && (name === 'key' || name === 'ref')) continue;
14091
14092 if (name === 'className') {
14093 if (attributes['class']) continue;
14094 name = 'class';
14095 } else if (isSvgMode && name.match(/^xlink\:?(.+)/)) {
14096 name = name.toLowerCase().replace(/^xlink\:?(.+)/, 'xlink:$1');
14097 }
14098
14099 if (name === 'class' && v && (typeof v === 'undefined' ? 'undefined' : _typeof(v)) === 'object') {
14100 v = hashToClassName(v);
14101 } else if (name === 'style' && v && (typeof v === 'undefined' ? 'undefined' : _typeof(v)) === 'object') {
14102 v = styleObjToCss(v);
14103 }
14104
14105 var hooked = opts.attributeHook && opts.attributeHook(name, v, context, opts, isComponent);
14106 if (hooked || hooked === '') {
14107 s += hooked;
14108 continue;
14109 }
14110
14111 if (name === 'dangerouslySetInnerHTML') {
14112 html = v && v.__html;
14113 } else if ((v || v === 0 || v === '') && typeof v !== 'function') {
14114 if (v === true || v === '') {
14115 v = name;
14116
14117 if (!opts || !opts.xml) {
14118 s += ' ' + name;
14119 continue;
14120 }
14121 }
14122 s += ' ' + name + '="' + encodeEntities(v) + '"';
14123 }
14124 }
14125 }
14126
14127 var sub = s.replace(/^\n\s*/, ' ');
14128 if (sub !== s && !~sub.indexOf('\n')) s = sub;else if (pretty && ~s.indexOf('\n')) s += '\n';
14129
14130 s = '<' + nodeName + s + '>';
14131
14132 if (VOID_ELEMENTS.indexOf(nodeName) > -1) {
14133 s = s.replace(/>$/, ' />');
14134 }
14135
14136 if (html) {
14137 if (pretty && isLargeString(html)) {
14138 html = '\n' + indentChar + indent(html, indentChar);
14139 }
14140 s += html;
14141 } else {
14142 var len = children && children.length,
14143 pieces = [],
14144 hasLarge = ~s.indexOf('\n');
14145 for (var _i = 0; _i < len; _i++) {
14146 var child = children[_i];
14147 if (!falsey(child)) {
14148 var childSvgMode = nodeName === 'svg' ? true : nodeName === 'foreignObject' ? false : isSvgMode,
14149 ret = renderToString(child, context, opts, true, childSvgMode);
14150 if (!hasLarge && pretty && isLargeString(ret)) hasLarge = true;
14151 if (ret) pieces.push(ret);
14152 }
14153 }
14154 if (pretty && hasLarge) {
14155 for (var _i2 = pieces.length; _i2--;) {
14156 pieces[_i2] = '\n' + indentChar + indent(pieces[_i2], indentChar);
14157 }
14158 }
14159 if (pieces.length) {
14160 s += pieces.join('');
14161 } else if (opts && opts.xml) {
14162 return s.substring(0, s.length - 1) + ' />';
14163 }
14164 }
14165
14166 if (VOID_ELEMENTS.indexOf(nodeName) === -1) {
14167 if (pretty && ~s.indexOf('\n')) s += '\n';
14168 s += '</' + nodeName + '>';
14169 }
14170
14171 return s;
14172 }
14173
14174 function getComponentName(component) {
14175 return component.displayName || component !== Function && component.name || getFallbackComponentName(component);
14176 }
14177
14178 function getFallbackComponentName(component) {
14179 var str = Function.prototype.toString.call(component),
14180 name = (str.match(/^\s*function\s+([^\( ]+)/) || EMPTY)[1];
14181 if (!name) {
14182 var index = -1;
14183 for (var i = UNNAMED.length; i--;) {
14184 if (UNNAMED[i] === component) {
14185 index = i;
14186 break;
14187 }
14188 }
14189
14190 if (index < 0) {
14191 index = UNNAMED.push(component) - 1;
14192 }
14193 name = 'UnnamedComponent' + index;
14194 }
14195 return name;
14196 }
14197 renderToString.shallowRender = shallowRender;
14198
14199 return renderToString;
14200
14201 })));
14202
14203
14204 },{}],21:[function(require,module,exports){
14205 !function() {
14206 'use strict';
14207 function VNode() {}
14208 function h(nodeName, attributes) {
14209 var lastSimple, child, simple, i, children = EMPTY_CHILDREN;
14210 for (i = arguments.length; i-- > 2; ) stack.push(arguments[i]);
14211 if (attributes && null != attributes.children) {
14212 if (!stack.length) stack.push(attributes.children);
14213 delete attributes.children;
14214 }
14215 while (stack.length) if ((child = stack.pop()) && void 0 !== child.pop) for (i = child.length; i--; ) stack.push(child[i]); else {
14216 if ('boolean' == typeof child) child = null;
14217 if (simple = 'function' != typeof nodeName) if (null == child) child = ''; else if ('number' == typeof child) child = String(child); else if ('string' != typeof child) simple = !1;
14218 if (simple && lastSimple) children[children.length - 1] += child; else if (children === EMPTY_CHILDREN) children = [ child ]; else children.push(child);
14219 lastSimple = simple;
14220 }
14221 var p = new VNode();
14222 p.nodeName = nodeName;
14223 p.children = children;
14224 p.attributes = null == attributes ? void 0 : attributes;
14225 p.key = null == attributes ? void 0 : attributes.key;
14226 if (void 0 !== options.vnode) options.vnode(p);
14227 return p;
14228 }
14229 function extend(obj, props) {
14230 for (var i in props) obj[i] = props[i];
14231 return obj;
14232 }
14233 function cloneElement(vnode, props) {
14234 return h(vnode.nodeName, extend(extend({}, vnode.attributes), props), arguments.length > 2 ? [].slice.call(arguments, 2) : vnode.children);
14235 }
14236 function enqueueRender(component) {
14237 if (!component.__d && (component.__d = !0) && 1 == items.push(component)) (options.debounceRendering || defer)(rerender);
14238 }
14239 function rerender() {
14240 var p, list = items;
14241 items = [];
14242 while (p = list.pop()) if (p.__d) renderComponent(p);
14243 }
14244 function isSameNodeType(node, vnode, hydrating) {
14245 if ('string' == typeof vnode || 'number' == typeof vnode) return void 0 !== node.splitText;
14246 if ('string' == typeof vnode.nodeName) return !node._componentConstructor && isNamedNode(node, vnode.nodeName); else return hydrating || node._componentConstructor === vnode.nodeName;
14247 }
14248 function isNamedNode(node, nodeName) {
14249 return node.__n === nodeName || node.nodeName.toLowerCase() === nodeName.toLowerCase();
14250 }
14251 function getNodeProps(vnode) {
14252 var props = extend({}, vnode.attributes);
14253 props.children = vnode.children;
14254 var defaultProps = vnode.nodeName.defaultProps;
14255 if (void 0 !== defaultProps) for (var i in defaultProps) if (void 0 === props[i]) props[i] = defaultProps[i];
14256 return props;
14257 }
14258 function createNode(nodeName, isSvg) {
14259 var node = isSvg ? document.createElementNS('http://www.w3.org/2000/svg', nodeName) : document.createElement(nodeName);
14260 node.__n = nodeName;
14261 return node;
14262 }
14263 function removeNode(node) {
14264 var parentNode = node.parentNode;
14265 if (parentNode) parentNode.removeChild(node);
14266 }
14267 function setAccessor(node, name, old, value, isSvg) {
14268 if ('className' === name) name = 'class';
14269 if ('key' === name) ; else if ('ref' === name) {
14270 if (old) old(null);
14271 if (value) value(node);
14272 } else if ('class' === name && !isSvg) node.className = value || ''; else if ('style' === name) {
14273 if (!value || 'string' == typeof value || 'string' == typeof old) node.style.cssText = value || '';
14274 if (value && 'object' == typeof value) {
14275 if ('string' != typeof old) for (var i in old) if (!(i in value)) node.style[i] = '';
14276 for (var i in value) node.style[i] = 'number' == typeof value[i] && !1 === IS_NON_DIMENSIONAL.test(i) ? value[i] + 'px' : value[i];
14277 }
14278 } else if ('dangerouslySetInnerHTML' === name) {
14279 if (value) node.innerHTML = value.__html || '';
14280 } else if ('o' == name[0] && 'n' == name[1]) {
14281 var useCapture = name !== (name = name.replace(/Capture$/, ''));
14282 name = name.toLowerCase().substring(2);
14283 if (value) {
14284 if (!old) node.addEventListener(name, eventProxy, useCapture);
14285 } else node.removeEventListener(name, eventProxy, useCapture);
14286 (node.__l || (node.__l = {}))[name] = value;
14287 } else if ('list' !== name && 'type' !== name && !isSvg && name in node) {
14288 setProperty(node, name, null == value ? '' : value);
14289 if (null == value || !1 === value) node.removeAttribute(name);
14290 } else {
14291 var ns = isSvg && name !== (name = name.replace(/^xlink\:?/, ''));
14292 if (null == value || !1 === value) if (ns) node.removeAttributeNS('http://www.w3.org/1999/xlink', name.toLowerCase()); else node.removeAttribute(name); else if ('function' != typeof value) if (ns) node.setAttributeNS('http://www.w3.org/1999/xlink', name.toLowerCase(), value); else node.setAttribute(name, value);
14293 }
14294 }
14295 function setProperty(node, name, value) {
14296 try {
14297 node[name] = value;
14298 } catch (e) {}
14299 }
14300 function eventProxy(e) {
14301 return this.__l[e.type](options.event && options.event(e) || e);
14302 }
14303 function flushMounts() {
14304 var c;
14305 while (c = mounts.pop()) {
14306 if (options.afterMount) options.afterMount(c);
14307 if (c.componentDidMount) c.componentDidMount();
14308 }
14309 }
14310 function diff(dom, vnode, context, mountAll, parent, componentRoot) {
14311 if (!diffLevel++) {
14312 isSvgMode = null != parent && void 0 !== parent.ownerSVGElement;
14313 hydrating = null != dom && !('__preactattr_' in dom);
14314 }
14315 var ret = idiff(dom, vnode, context, mountAll, componentRoot);
14316 if (parent && ret.parentNode !== parent) parent.appendChild(ret);
14317 if (!--diffLevel) {
14318 hydrating = !1;
14319 if (!componentRoot) flushMounts();
14320 }
14321 return ret;
14322 }
14323 function idiff(dom, vnode, context, mountAll, componentRoot) {
14324 var out = dom, prevSvgMode = isSvgMode;
14325 if (null == vnode || 'boolean' == typeof vnode) vnode = '';
14326 if ('string' == typeof vnode || 'number' == typeof vnode) {
14327 if (dom && void 0 !== dom.splitText && dom.parentNode && (!dom._component || componentRoot)) {
14328 if (dom.nodeValue != vnode) dom.nodeValue = vnode;
14329 } else {
14330 out = document.createTextNode(vnode);
14331 if (dom) {
14332 if (dom.parentNode) dom.parentNode.replaceChild(out, dom);
14333 recollectNodeTree(dom, !0);
14334 }
14335 }
14336 out.__preactattr_ = !0;
14337 return out;
14338 }
14339 var vnodeName = vnode.nodeName;
14340 if ('function' == typeof vnodeName) return buildComponentFromVNode(dom, vnode, context, mountAll);
14341 isSvgMode = 'svg' === vnodeName ? !0 : 'foreignObject' === vnodeName ? !1 : isSvgMode;
14342 vnodeName = String(vnodeName);
14343 if (!dom || !isNamedNode(dom, vnodeName)) {
14344 out = createNode(vnodeName, isSvgMode);
14345 if (dom) {
14346 while (dom.firstChild) out.appendChild(dom.firstChild);
14347 if (dom.parentNode) dom.parentNode.replaceChild(out, dom);
14348 recollectNodeTree(dom, !0);
14349 }
14350 }
14351 var fc = out.firstChild, props = out.__preactattr_, vchildren = vnode.children;
14352 if (null == props) {
14353 props = out.__preactattr_ = {};
14354 for (var a = out.attributes, i = a.length; i--; ) props[a[i].name] = a[i].value;
14355 }
14356 if (!hydrating && vchildren && 1 === vchildren.length && 'string' == typeof vchildren[0] && null != fc && void 0 !== fc.splitText && null == fc.nextSibling) {
14357 if (fc.nodeValue != vchildren[0]) fc.nodeValue = vchildren[0];
14358 } else if (vchildren && vchildren.length || null != fc) innerDiffNode(out, vchildren, context, mountAll, hydrating || null != props.dangerouslySetInnerHTML);
14359 diffAttributes(out, vnode.attributes, props);
14360 isSvgMode = prevSvgMode;
14361 return out;
14362 }
14363 function innerDiffNode(dom, vchildren, context, mountAll, isHydrating) {
14364 var j, c, f, vchild, child, originalChildren = dom.childNodes, children = [], keyed = {}, keyedLen = 0, min = 0, len = originalChildren.length, childrenLen = 0, vlen = vchildren ? vchildren.length : 0;
14365 if (0 !== len) for (var i = 0; i < len; i++) {
14366 var _child = originalChildren[i], props = _child.__preactattr_, key = vlen && props ? _child._component ? _child._component.__k : props.key : null;
14367 if (null != key) {
14368 keyedLen++;
14369 keyed[key] = _child;
14370 } else if (props || (void 0 !== _child.splitText ? isHydrating ? _child.nodeValue.trim() : !0 : isHydrating)) children[childrenLen++] = _child;
14371 }
14372 if (0 !== vlen) for (var i = 0; i < vlen; i++) {
14373 vchild = vchildren[i];
14374 child = null;
14375 var key = vchild.key;
14376 if (null != key) {
14377 if (keyedLen && void 0 !== keyed[key]) {
14378 child = keyed[key];
14379 keyed[key] = void 0;
14380 keyedLen--;
14381 }
14382 } else if (!child && min < childrenLen) for (j = min; j < childrenLen; j++) if (void 0 !== children[j] && isSameNodeType(c = children[j], vchild, isHydrating)) {
14383 child = c;
14384 children[j] = void 0;
14385 if (j === childrenLen - 1) childrenLen--;
14386 if (j === min) min++;
14387 break;
14388 }
14389 child = idiff(child, vchild, context, mountAll);
14390 f = originalChildren[i];
14391 if (child && child !== dom && child !== f) if (null == f) dom.appendChild(child); else if (child === f.nextSibling) removeNode(f); else dom.insertBefore(child, f);
14392 }
14393 if (keyedLen) for (var i in keyed) if (void 0 !== keyed[i]) recollectNodeTree(keyed[i], !1);
14394 while (min <= childrenLen) if (void 0 !== (child = children[childrenLen--])) recollectNodeTree(child, !1);
14395 }
14396 function recollectNodeTree(node, unmountOnly) {
14397 var component = node._component;
14398 if (component) unmountComponent(component); else {
14399 if (null != node.__preactattr_ && node.__preactattr_.ref) node.__preactattr_.ref(null);
14400 if (!1 === unmountOnly || null == node.__preactattr_) removeNode(node);
14401 removeChildren(node);
14402 }
14403 }
14404 function removeChildren(node) {
14405 node = node.lastChild;
14406 while (node) {
14407 var next = node.previousSibling;
14408 recollectNodeTree(node, !0);
14409 node = next;
14410 }
14411 }
14412 function diffAttributes(dom, attrs, old) {
14413 var name;
14414 for (name in old) if ((!attrs || null == attrs[name]) && null != old[name]) setAccessor(dom, name, old[name], old[name] = void 0, isSvgMode);
14415 for (name in attrs) if (!('children' === name || 'innerHTML' === name || name in old && attrs[name] === ('value' === name || 'checked' === name ? dom[name] : old[name]))) setAccessor(dom, name, old[name], old[name] = attrs[name], isSvgMode);
14416 }
14417 function collectComponent(component) {
14418 var name = component.constructor.name;
14419 (components[name] || (components[name] = [])).push(component);
14420 }
14421 function createComponent(Ctor, props, context) {
14422 var inst, list = components[Ctor.name];
14423 if (Ctor.prototype && Ctor.prototype.render) {
14424 inst = new Ctor(props, context);
14425 Component.call(inst, props, context);
14426 } else {
14427 inst = new Component(props, context);
14428 inst.constructor = Ctor;
14429 inst.render = doRender;
14430 }
14431 if (list) for (var i = list.length; i--; ) if (list[i].constructor === Ctor) {
14432 inst.__b = list[i].__b;
14433 list.splice(i, 1);
14434 break;
14435 }
14436 return inst;
14437 }
14438 function doRender(props, state, context) {
14439 return this.constructor(props, context);
14440 }
14441 function setComponentProps(component, props, opts, context, mountAll) {
14442 if (!component.__x) {
14443 component.__x = !0;
14444 if (component.__r = props.ref) delete props.ref;
14445 if (component.__k = props.key) delete props.key;
14446 if (!component.base || mountAll) {
14447 if (component.componentWillMount) component.componentWillMount();
14448 } else if (component.componentWillReceiveProps) component.componentWillReceiveProps(props, context);
14449 if (context && context !== component.context) {
14450 if (!component.__c) component.__c = component.context;
14451 component.context = context;
14452 }
14453 if (!component.__p) component.__p = component.props;
14454 component.props = props;
14455 component.__x = !1;
14456 if (0 !== opts) if (1 === opts || !1 !== options.syncComponentUpdates || !component.base) renderComponent(component, 1, mountAll); else enqueueRender(component);
14457 if (component.__r) component.__r(component);
14458 }
14459 }
14460 function renderComponent(component, opts, mountAll, isChild) {
14461 if (!component.__x) {
14462 var rendered, inst, cbase, props = component.props, state = component.state, context = component.context, previousProps = component.__p || props, previousState = component.__s || state, previousContext = component.__c || context, isUpdate = component.base, nextBase = component.__b, initialBase = isUpdate || nextBase, initialChildComponent = component._component, skip = !1;
14463 if (isUpdate) {
14464 component.props = previousProps;
14465 component.state = previousState;
14466 component.context = previousContext;
14467 if (2 !== opts && component.shouldComponentUpdate && !1 === component.shouldComponentUpdate(props, state, context)) skip = !0; else if (component.componentWillUpdate) component.componentWillUpdate(props, state, context);
14468 component.props = props;
14469 component.state = state;
14470 component.context = context;
14471 }
14472 component.__p = component.__s = component.__c = component.__b = null;
14473 component.__d = !1;
14474 if (!skip) {
14475 rendered = component.render(props, state, context);
14476 if (component.getChildContext) context = extend(extend({}, context), component.getChildContext());
14477 var toUnmount, base, childComponent = rendered && rendered.nodeName;
14478 if ('function' == typeof childComponent) {
14479 var childProps = getNodeProps(rendered);
14480 inst = initialChildComponent;
14481 if (inst && inst.constructor === childComponent && childProps.key == inst.__k) setComponentProps(inst, childProps, 1, context, !1); else {
14482 toUnmount = inst;
14483 component._component = inst = createComponent(childComponent, childProps, context);
14484 inst.__b = inst.__b || nextBase;
14485 inst.__u = component;
14486 setComponentProps(inst, childProps, 0, context, !1);
14487 renderComponent(inst, 1, mountAll, !0);
14488 }
14489 base = inst.base;
14490 } else {
14491 cbase = initialBase;
14492 toUnmount = initialChildComponent;
14493 if (toUnmount) cbase = component._component = null;
14494 if (initialBase || 1 === opts) {
14495 if (cbase) cbase._component = null;
14496 base = diff(cbase, rendered, context, mountAll || !isUpdate, initialBase && initialBase.parentNode, !0);
14497 }
14498 }
14499 if (initialBase && base !== initialBase && inst !== initialChildComponent) {
14500 var baseParent = initialBase.parentNode;
14501 if (baseParent && base !== baseParent) {
14502 baseParent.replaceChild(base, initialBase);
14503 if (!toUnmount) {
14504 initialBase._component = null;
14505 recollectNodeTree(initialBase, !1);
14506 }
14507 }
14508 }
14509 if (toUnmount) unmountComponent(toUnmount);
14510 component.base = base;
14511 if (base && !isChild) {
14512 var componentRef = component, t = component;
14513 while (t = t.__u) (componentRef = t).base = base;
14514 base._component = componentRef;
14515 base._componentConstructor = componentRef.constructor;
14516 }
14517 }
14518 if (!isUpdate || mountAll) mounts.unshift(component); else if (!skip) {
14519 if (component.componentDidUpdate) component.componentDidUpdate(previousProps, previousState, previousContext);
14520 if (options.afterUpdate) options.afterUpdate(component);
14521 }
14522 if (null != component.__h) while (component.__h.length) component.__h.pop().call(component);
14523 if (!diffLevel && !isChild) flushMounts();
14524 }
14525 }
14526 function buildComponentFromVNode(dom, vnode, context, mountAll) {
14527 var c = dom && dom._component, originalComponent = c, oldDom = dom, isDirectOwner = c && dom._componentConstructor === vnode.nodeName, isOwner = isDirectOwner, props = getNodeProps(vnode);
14528 while (c && !isOwner && (c = c.__u)) isOwner = c.constructor === vnode.nodeName;
14529 if (c && isOwner && (!mountAll || c._component)) {
14530 setComponentProps(c, props, 3, context, mountAll);
14531 dom = c.base;
14532 } else {
14533 if (originalComponent && !isDirectOwner) {
14534 unmountComponent(originalComponent);
14535 dom = oldDom = null;
14536 }
14537 c = createComponent(vnode.nodeName, props, context);
14538 if (dom && !c.__b) {
14539 c.__b = dom;
14540 oldDom = null;
14541 }
14542 setComponentProps(c, props, 1, context, mountAll);
14543 dom = c.base;
14544 if (oldDom && dom !== oldDom) {
14545 oldDom._component = null;
14546 recollectNodeTree(oldDom, !1);
14547 }
14548 }
14549 return dom;
14550 }
14551 function unmountComponent(component) {
14552 if (options.beforeUnmount) options.beforeUnmount(component);
14553 var base = component.base;
14554 component.__x = !0;
14555 if (component.componentWillUnmount) component.componentWillUnmount();
14556 component.base = null;
14557 var inner = component._component;
14558 if (inner) unmountComponent(inner); else if (base) {
14559 if (base.__preactattr_ && base.__preactattr_.ref) base.__preactattr_.ref(null);
14560 component.__b = base;
14561 removeNode(base);
14562 collectComponent(component);
14563 removeChildren(base);
14564 }
14565 if (component.__r) component.__r(null);
14566 }
14567 function Component(props, context) {
14568 this.__d = !0;
14569 this.context = context;
14570 this.props = props;
14571 this.state = this.state || {};
14572 }
14573 function render(vnode, parent, merge) {
14574 return diff(merge, vnode, {}, !1, parent, !1);
14575 }
14576 var options = {};
14577 var stack = [];
14578 var EMPTY_CHILDREN = [];
14579 var defer = 'function' == typeof Promise ? Promise.resolve().then.bind(Promise.resolve()) : setTimeout;
14580 var IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i;
14581 var items = [];
14582 var mounts = [];
14583 var diffLevel = 0;
14584 var isSvgMode = !1;
14585 var hydrating = !1;
14586 var components = {};
14587 extend(Component.prototype, {
14588 setState: function(state, callback) {
14589 var s = this.state;
14590 if (!this.__s) this.__s = extend({}, s);
14591 extend(s, 'function' == typeof state ? state(s, this.props) : state);
14592 if (callback) (this.__h = this.__h || []).push(callback);
14593 enqueueRender(this);
14594 },
14595 forceUpdate: function(callback) {
14596 if (callback) (this.__h = this.__h || []).push(callback);
14597 renderComponent(this, 2);
14598 },
14599 render: function() {}
14600 });
14601 var preact = {
14602 h: h,
14603 createElement: h,
14604 cloneElement: cloneElement,
14605 Component: Component,
14606 render: render,
14607 rerender: rerender,
14608 options: options
14609 };
14610 if ('undefined' != typeof module) module.exports = preact; else self.preact = preact;
14611 }();
14612
14613 },{}],22:[function(require,module,exports){
14614 function tlite(getTooltipOpts) {
14615 document.addEventListener('mouseover', function (e) {
14616 var el = e.target;
14617 var opts = getTooltipOpts(el);
14618
14619 if (!opts) {
14620 el = el.parentElement;
14621 opts = el && getTooltipOpts(el);
14622 }
14623
14624 opts && tlite.show(el, opts, true);
14625 });
14626 }
14627
14628 tlite.show = function (el, opts, isAuto) {
14629 var fallbackAttrib = 'data-tlite';
14630 opts = opts || {};
14631
14632 (el.tooltip || Tooltip(el, opts)).show();
14633
14634 function Tooltip(el, opts) {
14635 var tooltipEl;
14636 var showTimer;
14637 var text;
14638
14639 el.addEventListener('mousedown', autoHide);
14640 el.addEventListener('mouseleave', autoHide);
14641
14642 function show() {
14643 text = el.title || el.getAttribute(fallbackAttrib) || text;
14644 el.title = '';
14645 el.setAttribute(fallbackAttrib, '');
14646 text && !showTimer && (showTimer = setTimeout(fadeIn, isAuto ? 150 : 1))
14647 }
14648
14649 function autoHide() {
14650 tlite.hide(el, true);
14651 }
14652
14653 function hide(isAutoHiding) {
14654 if (isAuto === isAutoHiding) {
14655 showTimer = clearTimeout(showTimer);
14656 var parent = tooltipEl && tooltipEl.parentNode;
14657 parent && parent.removeChild(tooltipEl);
14658 tooltipEl = undefined;
14659 }
14660 }
14661
14662 function fadeIn() {
14663 if (!tooltipEl) {
14664 tooltipEl = createTooltip(el, text, opts);
14665 }
14666 }
14667
14668 return el.tooltip = {
14669 show: show,
14670 hide: hide
14671 };
14672 }
14673
14674 function createTooltip(el, text, opts) {
14675 var tooltipEl = document.createElement('span');
14676 var grav = opts.grav || el.getAttribute('data-tlite') || 'n';
14677
14678 tooltipEl.innerHTML = text;
14679
14680 el.appendChild(tooltipEl);
14681
14682 var vertGrav = grav[0] || '';
14683 var horzGrav = grav[1] || '';
14684
14685 function positionTooltip() {
14686 tooltipEl.className = 'tlite ' + 'tlite-' + vertGrav + horzGrav;
14687
14688 var arrowSize = 10;
14689 var top = el.offsetTop;
14690 var left = el.offsetLeft;
14691
14692 if (tooltipEl.offsetParent === el) {
14693 top = left = 0;
14694 }
14695
14696 var width = el.offsetWidth;
14697 var height = el.offsetHeight;
14698 var tooltipHeight = tooltipEl.offsetHeight;
14699 var tooltipWidth = tooltipEl.offsetWidth;
14700 var centerEl = left + (width / 2);
14701
14702 tooltipEl.style.top = (
14703 vertGrav === 's' ? (top - tooltipHeight - arrowSize) :
14704 vertGrav === 'n' ? (top + height + arrowSize) :
14705 (top + (height / 2) - (tooltipHeight / 2))
14706 ) + 'px';
14707
14708 tooltipEl.style.left = (
14709 horzGrav === 'w' ? left :
14710 horzGrav === 'e' ? left + width - tooltipWidth :
14711 vertGrav === 'w' ? (left + width + arrowSize) :
14712 vertGrav === 'e' ? (left - tooltipWidth - arrowSize) :
14713 (centerEl - tooltipWidth / 2)
14714 ) + 'px';
14715 }
14716
14717 positionTooltip();
14718
14719 var rect = tooltipEl.getBoundingClientRect();
14720
14721 if (vertGrav === 's' && rect.top < 0) {
14722 vertGrav = 'n';
14723 positionTooltip();
14724 } else if (vertGrav === 'n' && rect.bottom > window.innerHeight) {
14725 vertGrav = 's';
14726 positionTooltip();
14727 } else if (vertGrav === 'e' && rect.left < 0) {
14728 vertGrav = 'w';
14729 positionTooltip();
14730 } else if (vertGrav === 'w' && rect.right > window.innerWidth) {
14731 vertGrav = 'e';
14732 positionTooltip();
14733 }
14734
14735 tooltipEl.className += ' tlite-visible';
14736
14737 return tooltipEl;
14738 }
14739 };
14740
14741 tlite.hide = function (el, isAuto) {
14742 el.tooltip && el.tooltip.hide(isAuto);
14743 };
14744
14745 if (typeof module !== 'undefined' && module.exports) {
14746 module.exports = tlite;
14747 }
14748
14749 },{}]},{},[2]);
14750 ; })();