PluginProbe
HTML Forms – Simple WordPress Forms Plugin / 1.0
HTML Forms – Simple WordPress Forms Plugin v1.0
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.0, at assets/js/admin.js

14,358 lines 543.9 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 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
53
54 _tabs2.default.init();
55 _actionConfirmations2.default.init();
56
57 if (document.getElementById('hf-form-editor')) {
58 _formEditor2.default.init();
59 _formActions2.default.init();
60
61 _fieldBuilder2.default.init(_formEditor2.default);
62 }
63
64 },{"./action-confirmations.js":1,"./field-builder.js":3,"./form-actions.js":6,"./form-editor.js":7,"./tabs.js":8}],3:[function(require,module,exports){
65 'use strict';
66
67 Object.defineProperty(exports, "__esModule", {
68 value: true
69 });
70
71 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; }; }();
72
73 var _desc, _value, _class, _desc2, _value2, _class2;
74
75 var _preact = require('preact');
76
77 var _linkstate = require('linkstate');
78
79 var _linkstate2 = _interopRequireDefault(_linkstate);
80
81 var _configFields = require('./field-builder/config-fields.js');
82
83 var _html = require('./field-builder/html.js');
84
85 var _decko = require('decko');
86
87 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
88
89 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
90
91 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; }
92
93 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; }
94
95 function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
96 var desc = {};
97 Object['ke' + 'ys'](descriptor).forEach(function (key) {
98 desc[key] = descriptor[key];
99 });
100 desc.enumerable = !!desc.enumerable;
101 desc.configurable = !!desc.configurable;
102
103 if ('value' in desc || desc.initializer) {
104 desc.writable = true;
105 }
106
107 desc = decorators.slice().reverse().reduce(function (desc, decorator) {
108 return decorator(target, property, desc) || desc;
109 }, desc);
110
111 if (context && desc.initializer !== void 0) {
112 desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
113 desc.initializer = undefined;
114 }
115
116 if (desc.initializer === void 0) {
117 Object['define' + 'Property'](target, property, desc);
118 desc = null;
119 }
120
121 return desc;
122 }
123
124 var Editor = void 0;
125
126
127 var fields = {
128 "text": "Text",
129 "email": "Email",
130 "url": "URL",
131 "number": "Number",
132 "date": "Date",
133 "textarea": "Textarea",
134 "dropdown": "Dropdown",
135 "checkboxes": "Checkboxes",
136 "radio-buttons": "Radio buttons",
137 "submit": "Submit button"
138 };
139
140 var FieldBuilder = (_class = function (_Component) {
141 _inherits(FieldBuilder, _Component);
142
143 function FieldBuilder() {
144 _classCallCheck(this, FieldBuilder);
145
146 var _this = _possibleConstructorReturn(this, (FieldBuilder.__proto__ || Object.getPrototypeOf(FieldBuilder)).call(this));
147
148 _this.state = {
149 fieldType: ""
150 };
151 return _this;
152 }
153
154 _createClass(FieldBuilder, [{
155 key: 'handleCancel',
156 value: function handleCancel() {
157 this.setState({
158 fieldType: ""
159 });
160 }
161 }, {
162 key: 'openFieldConfig',
163 value: function openFieldConfig(e) {
164 var newFieldType = e.target.value;
165
166 if (this.state.fieldType === newFieldType) {
167 this.setState({ fieldType: "" });
168 } else {
169 this.setState({ fieldType: newFieldType });
170 }
171 }
172 }, {
173 key: 'render',
174 value: function render(props, state) {
175 var _this2 = this;
176
177 var fieldButtons = Object.keys(fields).map(function (key) {
178 var label = fields[key];
179 return (0, _preact.h)(
180 'button',
181 { type: 'button', value: key, className: "button " + (state.fieldType === key ? "active" : ""), onClick: _this2.openFieldConfig },
182 label
183 );
184 });
185
186 return (0, _preact.h)(
187 'div',
188 { 'class': 'hf-field-builder' },
189 (0, _preact.h)(
190 'h4',
191 null,
192 'Add field'
193 ),
194 (0, _preact.h)(
195 'div',
196 { 'class': 'available-fields' },
197 fieldButtons
198 ),
199 (0, _preact.h)(
200 'div',
201 { style: 'max-width: 480px;' },
202 (0, _preact.h)(FieldConfigurator, { fieldType: state.fieldType, onCancel: this.handleCancel })
203 ),
204 state.fieldType === "" ? (0, _preact.h)(
205 'p',
206 { 'class': 'help', style: 'margin-bottom: 0;' },
207 'Use the buttons above to generate your field HTML, or manually modify your form below.'
208 ) : ""
209 );
210 }
211 }]);
212
213 return FieldBuilder;
214 }(_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);
215 var FieldConfigurator = (_class2 = function (_Component2) {
216 _inherits(FieldConfigurator, _Component2);
217
218 function FieldConfigurator(props) {
219 _classCallCheck(this, FieldConfigurator);
220
221 var _this3 = _possibleConstructorReturn(this, (FieldConfigurator.__proto__ || Object.getPrototypeOf(FieldConfigurator)).call(this, props));
222
223 _this3.state = _this3.getInitialState();
224 _this3.choiceHandlers = {
225 "add": _this3.addChoice,
226 "delete": _this3.deleteChoice,
227 "changeLabel": _this3.changeChoiceLabel,
228 "toggleChecked": _this3.toggleChoiceChecked
229 };
230 return _this3;
231 }
232
233 _createClass(FieldConfigurator, [{
234 key: 'getInitialState',
235 value: function getInitialState() {
236 return {
237 fieldType: this.props.fieldType,
238 fieldLabel: "",
239 placeholder: "",
240 value: "",
241 wrap: true,
242 required: false,
243 choices: [{
244 checked: false,
245 label: "One"
246 }, {
247 checked: false,
248 label: "Two"
249 }]
250 };
251 }
252 }, {
253 key: 'componentWillReceiveProps',
254 value: function componentWillReceiveProps(props) {
255 this.setState({
256 fieldType: props.fieldType
257 });
258 }
259 }, {
260 key: 'addToForm',
261 value: function addToForm() {
262 var html = (0, _html.htmlgenerate)(this.state);
263 Editor.replaceSelection(html);
264 }
265 }, {
266 key: 'addChoice',
267 value: function addChoice() {
268 var arr = this.state.choices;
269 arr.push({ checked: false, label: "..." });
270 this.setState({ choices: arr });
271 }
272 }, {
273 key: 'deleteChoice',
274 value: function deleteChoice(e) {
275 var arr = this.state.choices;
276 var index = e.target.parentElement.getAttribute('data-key');
277 arr.splice(index, 1);
278 this.setState({ choices: arr });
279 }
280 }, {
281 key: 'changeChoiceLabel',
282 value: function changeChoiceLabel(e) {
283 var arr = this.state.choices;
284 var index = e.target.parentElement.getAttribute('data-key');
285 arr[index].label = e.target.value;
286 this.setState({ choices: arr });
287 }
288 }, {
289 key: 'toggleChoiceChecked',
290 value: function toggleChoiceChecked(e) {
291 var arr = this.state.choices;
292 var index = e.target.parentElement.getAttribute('data-key');
293 arr[index].checked = !arr[index].checked;
294 this.setState({ choices: arr });
295 }
296 }, {
297 key: 'handleCancel',
298 value: function handleCancel() {
299 // revert back to initial state
300 this.setState(this.getInitialState());
301 this.props.onCancel();
302 }
303 }, {
304 key: 'render',
305 value: function render(props, state) {
306 if (state.fieldType === "") {
307 return "";
308 }
309
310 var formFields = void 0;
311
312 switch (state.fieldType) {
313 case "text":
314 case "email":
315 case "url":
316 case "number":
317 case "textarea":
318 formFields = (0, _preact.h)(
319 'div',
320 null,
321 (0, _preact.h)(_configFields.Label, { value: state.fieldLabel, onChange: (0, _linkstate2.default)(this, 'fieldLabel') }),
322 (0, _preact.h)(_configFields.Placeholder, { value: state.placeholder, onChange: (0, _linkstate2.default)(this, 'placeholder') }),
323 (0, _preact.h)(_configFields.DefaultValue, { value: state.value, onChange: (0, _linkstate2.default)(this, 'value') }),
324 (0, _preact.h)(_configFields.Required, { checked: state.required, onChange: (0, _linkstate2.default)(this, 'required') }),
325 (0, _preact.h)(_configFields.Wrap, { checked: state.wrap, onChange: (0, _linkstate2.default)(this, 'wrap') }),
326 (0, _preact.h)(_configFields.AddToForm, { onSubmit: this.addToForm, onCancel: this.handleCancel })
327 );
328 break;
329 case "submit":
330 formFields = (0, _preact.h)(
331 'div',
332 null,
333 (0, _preact.h)(_configFields.ButtonText, { value: state.value, onChange: (0, _linkstate2.default)(this, 'value') }),
334 (0, _preact.h)(_configFields.Wrap, { checked: state.wrap, onChange: (0, _linkstate2.default)(this, 'wrap') }),
335 (0, _preact.h)(_configFields.AddToForm, { onSubmit: this.addToForm, onCancel: this.handleCancel })
336 );
337 break;
338
339 case "date":
340 formFields = (0, _preact.h)(
341 'div',
342 null,
343 (0, _preact.h)(_configFields.Label, { value: state.fieldLabel, onChange: (0, _linkstate2.default)(this, 'fieldLabel') }),
344 (0, _preact.h)(_configFields.DefaultValue, { value: state.value, onChange: (0, _linkstate2.default)(this, 'value') }),
345 (0, _preact.h)(_configFields.Required, { checked: state.required, onChange: (0, _linkstate2.default)(this, 'required') }),
346 (0, _preact.h)(_configFields.Wrap, { checked: state.wrap, onChange: (0, _linkstate2.default)(this, 'wrap') }),
347 (0, _preact.h)(_configFields.AddToForm, { onSubmit: this.addToForm, onCancel: this.handleCancel })
348 );
349 break;
350 case "dropdown":
351 formFields = (0, _preact.h)(
352 'div',
353 null,
354 (0, _preact.h)(_configFields.Label, { value: state.fieldLabel, onChange: (0, _linkstate2.default)(this, 'fieldLabel') }),
355 (0, _preact.h)(_configFields.Choices, { multiple: false, choices: state.choices, handlers: this.choiceHandlers }),
356 (0, _preact.h)(_configFields.Required, { checked: state.required, onChange: (0, _linkstate2.default)(this, 'required') }),
357 (0, _preact.h)(_configFields.Wrap, { checked: state.wrap, onChange: (0, _linkstate2.default)(this, 'wrap') }),
358 (0, _preact.h)(_configFields.AddToForm, { onSubmit: this.addToForm, onCancel: this.handleCancel })
359 );
360 break;
361
362 case "radio-buttons":
363 case "checkboxes":
364 formFields = (0, _preact.h)(
365 'div',
366 null,
367 (0, _preact.h)(_configFields.Label, { value: state.fieldLabel, onChange: (0, _linkstate2.default)(this, 'fieldLabel') }),
368 (0, _preact.h)(_configFields.Choices, { multiple: state.fieldType === "checkboxes", choices: state.choices, handlers: this.choiceHandlers }),
369 (0, _preact.h)(_configFields.Wrap, { checked: state.wrap, onChange: (0, _linkstate2.default)(this, 'wrap') }),
370 (0, _preact.h)(_configFields.AddToForm, { onSubmit: this.addToForm, onCancel: this.handleCancel })
371 );
372 break;
373 }
374
375 return (0, _preact.h)(
376 'div',
377 { 'class': 'field-config', onKeyPress: FieldConfigurator.handleKeyPress },
378 formFields
379 );
380 }
381 }], [{
382 key: 'handleKeyPress',
383 value: function handleKeyPress(e) {
384 // stop RETURN from submitting the parent form.
385 if (e.keyCode === 13) {
386 e.preventDefault();
387 }
388 }
389 }]);
390
391 return FieldConfigurator;
392 }(_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);
393 exports.default = {
394 init: function init(editor) {
395 Editor = editor;
396
397 (0, _preact.render)((0, _preact.h)(FieldBuilder, null), document.getElementById('hf-field-builder'));
398 }
399 };
400
401 },{"./field-builder/config-fields.js":4,"./field-builder/html.js":5,"decko":17,"linkstate":19,"preact":21}],4:[function(require,module,exports){
402 "use strict";
403
404 Object.defineProperty(exports, "__esModule", {
405 value: true
406 });
407 exports.ButtonText = exports.Choices = exports.Required = exports.Wrap = exports.DefaultValue = exports.Placeholder = exports.Label = exports.AddToForm = undefined;
408
409 var _preact = require("preact");
410
411 function AddToForm(props) {
412 return (0, _preact.h)(
413 "div",
414 { "class": "hf-small-margin" },
415 (0, _preact.h)(
416 "button",
417 { "class": "button", type: "button", onClick: props.onSubmit },
418 "Add field to form"
419 ),
420 " \xA0 ",
421 (0, _preact.h)(
422 "a",
423 { href: "javascript:void(0);", "class": "hf-small", style: "vertical-align: middle;", onClick: props.onCancel },
424 "or close field helper"
425 )
426 );
427 }
428
429 function Label(props) {
430 return (0, _preact.h)(
431 "div",
432 { "class": "hf-small-margin" },
433 (0, _preact.h)(
434 "label",
435 { "for": "hf-fg-field-label" },
436 "Field label ",
437 (0, _preact.h)(
438 "span",
439 { "class": "hf-required" },
440 "*"
441 )
442 ),
443 (0, _preact.h)("input", { id: "hf-fg-field-label", type: "text", value: props.value, onChange: props.onChange })
444 );
445 }
446
447 function Placeholder(props) {
448 return (0, _preact.h)(
449 "div",
450 { "class": "hf-small-margin" },
451 (0, _preact.h)(
452 "label",
453 { "for": "hf-fg-placeholder" },
454 "Placeholder ",
455 (0, _preact.h)(
456 "span",
457 { "class": "hf-italic hf-pull-right" },
458 "Optional"
459 )
460 ),
461 (0, _preact.h)("input", { id: "hf-fg-placeholder", type: "text", value: props.value, onChange: props.onChange }),
462 (0, _preact.h)(
463 "p",
464 { "class": "help" },
465 "Text to show when field has no value."
466 )
467 );
468 }
469
470 function ButtonText(props) {
471 return (0, _preact.h)(
472 "div",
473 { "class": "hf-small-margin" },
474 (0, _preact.h)(
475 "label",
476 { "for": "hf-fg-default-value" },
477 "Button text ",
478 (0, _preact.h)(
479 "span",
480 { "class": "hf-required" },
481 "*"
482 )
483 ),
484 (0, _preact.h)("input", { id: "hf-fg-default-value", type: "text", value: props.value, onChange: props.onChange }),
485 (0, _preact.h)(
486 "p",
487 { "class": "help" },
488 "Text to show on the button."
489 )
490 );
491 }
492
493 function DefaultValue(props) {
494 return (0, _preact.h)(
495 "div",
496 { "class": "hf-small-margin" },
497 (0, _preact.h)(
498 "label",
499 { "for": "hf-fg-default-value" },
500 "Default value ",
501 (0, _preact.h)(
502 "span",
503 { "class": "hf-italic hf-pull-right" },
504 "Optional"
505 )
506 ),
507 (0, _preact.h)("input", { id: "hf-fg-default-value", type: "text", value: props.value, onChange: props.onChange }),
508 (0, _preact.h)(
509 "p",
510 { "class": "help" },
511 "Text to pre-fill this field with."
512 )
513 );
514 }
515
516 function Wrap(props) {
517 return (0, _preact.h)(
518 "div",
519 { "class": "hf-small-margin" },
520 (0, _preact.h)(
521 "label",
522 { "class": "inline" },
523 (0, _preact.h)("input", { type: "checkbox", value: "1", defaultChecked: props.checked, onChange: props.onChange }),
524 "Wrap this field in paragraph tags."
525 )
526 );
527 }
528
529 function Required(props) {
530 return (0, _preact.h)(
531 "div",
532 { "class": "hf-small-margin" },
533 (0, _preact.h)(
534 "label",
535 { "class": "inline" },
536 (0, _preact.h)("input", { type: "checkbox", value: "1", defaultChecked: props.checked, onChange: props.onChange }),
537 "This field is required."
538 )
539 );
540 }
541
542 function Choices(props) {
543 var choiceFields = props.choices.map(function (choice, k) {
544 return (0, _preact.h)(
545 "div",
546 { "data-key": k },
547 (0, _preact.h)("input", { type: props.multiple ? "checkbox" : "radio", name: "selected", defaultChecked: choice.checked, onChange: props.handlers.toggleChecked, title: "Pre-select this choice?" }),
548 (0, _preact.h)("input", { type: "text", value: choice.label, placeholder: "Choice label", style: "width: 80%;", onChange: props.handlers.changeLabel }),
549 (0, _preact.h)(
550 "a",
551 { href: "javascript:void(0);", onClick: props.handlers.delete, style: "text-decoration: none;", title: "Delete choice" },
552 "\u2715"
553 )
554 );
555 });
556
557 return (0, _preact.h)(
558 "div",
559 { "class": "hf-small-margin" },
560 (0, _preact.h)(
561 "label",
562 null,
563 "Choices"
564 ),
565 choiceFields,
566 (0, _preact.h)("input", { type: props.multiple ? "checkbox" : "radio", style: "visibility: hidden;" }),
567 (0, _preact.h)(
568 "a",
569 { href: "javascript:void(0);", onClick: props.handlers.add },
570 "Add choice"
571 )
572 );
573 }
574
575 exports.AddToForm = AddToForm;
576 exports.Label = Label;
577 exports.Placeholder = Placeholder;
578 exports.DefaultValue = DefaultValue;
579 exports.Wrap = Wrap;
580 exports.Required = Required;
581 exports.Choices = Choices;
582 exports.ButtonText = ButtonText;
583
584 },{"preact":21}],5:[function(require,module,exports){
585 'use strict';
586
587 Object.defineProperty(exports, "__esModule", {
588 value: true
589 });
590 exports.htmlgenerate = undefined;
591
592 var _html = require('html');
593
594 var _html2 = _interopRequireDefault(_html);
595
596 var _preactRenderToString = require('preact-render-to-string');
597
598 var _preactRenderToString2 = _interopRequireDefault(_preactRenderToString);
599
600 var _preact = require('preact');
601
602 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
603
604 function htmlgenerate(conf) {
605 var label = conf.fieldLabel.length ? (0, _preact.h)("label", {}, conf.fieldLabel) : "";
606 var fieldAttr = void 0,
607 field = void 0;
608
609 switch (conf.fieldType) {
610 case "text":
611 default:
612 fieldAttr = {
613 type: conf.fieldType,
614 name: namify(conf.fieldLabel),
615 value: conf.value,
616 placeholder: conf.placeholder,
617 required: conf.required
618 };
619 field = html("input", fieldAttr);
620 break;
621 case "textarea":
622 fieldAttr = {
623 name: namify(conf.fieldLabel),
624 placeholder: conf.placeholder,
625 required: conf.required
626 };
627 field = html("textarea", fieldAttr, conf.value);
628 break;
629
630 case "dropdown":
631 fieldAttr = {
632 name: namify(conf.fieldLabel),
633 required: conf.required
634 };
635 var opts = conf.choices.map(function (choice) {
636 return html("option", { defaultChecked: choice.checked }, choice.label);
637 });
638 field = html("select", fieldAttr, opts);
639 break;
640
641 case "radio-buttons":
642 field = conf.choices.map(function (choice) {
643 return html("label", {}, [html("input", {
644 type: "radio",
645 name: namify(conf.fieldLabel),
646 value: choice.label,
647 selected: choice.checked
648 }), " ", html("span", {}, choice.label)]);
649 });
650 break;
651
652 case "checkboxes":
653 field = conf.choices.map(function (choice) {
654 return html("label", {}, [html("input", {
655 type: "checkbox",
656 name: namify(conf.fieldLabel) + "[]",
657 value: choice.label,
658 checked: choice.checked
659 }), " ", html("span", {}, choice.label)]);
660 });
661 break;
662
663 case "submit":
664 fieldAttr = {
665 type: "submit",
666 value: conf.value
667 };
668 field = html("input", fieldAttr);
669 break;
670
671 }
672
673 var str = "";
674 if (conf.wrap) {
675 var tmpl = (0, _preact.h)("p", {}, [label, field]);
676 str = (0, _preactRenderToString2.default)(tmpl);
677 } else {
678 str += (0, _preactRenderToString2.default)(label);
679 str += (0, _preactRenderToString2.default)(field);
680 }
681
682 str = _html2.default.prettyPrint(str);
683
684 return str;
685 }
686
687 function html(tag, attr, children) {
688 return (0, _preact.h)(tag, filterEmptyObjectValues(attr), children);
689 }
690
691 function namify(str) {
692 return str.replace(/ /g, '_').replace(/[^\w\[\]_]*/g, "").toUpperCase();
693 }
694
695 function filterEmptyObjectValues(obj) {
696 var newObj = {};
697 for (var propName in obj) {
698 if (obj[propName] !== false && obj[propName] !== "") {
699 newObj[propName] = obj[propName];
700 }
701 }
702 return newObj;
703 }
704
705 exports.htmlgenerate = htmlgenerate;
706
707 },{"html":18,"preact":21,"preact-render-to-string":20}],6:[function(require,module,exports){
708 'use strict';
709
710 Object.defineProperty(exports, "__esModule", {
711 value: true
712 });
713 var availableActions = void 0,
714 actionTemplates = void 0,
715 actions = void 0;
716
717 function init() {
718 actions = document.getElementById('hf-form-actions');
719 availableActions = document.getElementById('hf-available-form-actions');
720 actionTemplates = document.getElementById('hf-form-action-templates');
721
722 // turn settings into accordions
723 [].forEach.call(actions.querySelectorAll('.hf-action-settings'), function (el) {
724 el.parentNode.removeChild(el);
725
726 var heading = el.getAttribute('data-title');
727 var summary = el.querySelector('.hf-action-summary');
728 if (summary) {
729 heading += ' &mdash; <span class="hf-muted">' + summary.innerHTML + '</span>';
730 }
731 var wrap = createAccordion(heading, el.innerHTML);
732 actions.appendChild(wrap);
733
734 actions.querySelector('#hf-form-actions-empty').style.display = 'none';
735 });
736
737 availableActions.addEventListener('click', addAction, true);
738 }
739
740 function createAccordion(headingHTML, contentHTML) {
741 var wrap = document.createElement('div');
742 wrap.className = "hf-accordion expanded ";
743
744 var heading = document.createElement('h4');
745 heading.className = "hf-accordion-heading";
746 heading.innerHTML = headingHTML;
747 wrap.appendChild(heading);
748
749 var content = document.createElement('div');
750 content.className = "hf-accordion-content";
751 content.innerHTML = contentHTML;
752 wrap.appendChild(content);
753
754 var deleteWrap = document.createElement('p');
755 deleteWrap.style.textAlign = 'right';
756 var deleteLink = document.createElement('a');
757 deleteLink.href = 'javascript:void(0);';
758 deleteLink.className = "danger";
759 deleteLink.innerText = 'Delete this action';
760 deleteWrap.appendChild(deleteLink);
761 content.appendChild(deleteWrap);
762
763 // bind handlers
764 heading.addEventListener('click', createToggleActionHandler(wrap, content));
765 deleteLink.addEventListener('click', createDeleteActionHandler(wrap));
766 return wrap;
767 }
768
769 function addAction(e) {
770 var el = e.target || e.srcElement;
771 if (el.tagName !== 'INPUT') {
772 return;
773 }
774
775 var actionType = el.getAttribute('data-action-type');
776 var actionTemplate = actionTemplates.querySelector('#hf-action-type-' + actionType + '-template');
777
778 // append HTML to actions wrapper
779 var wrap = createAccordion(el.value, actionTemplate.innerHTML);
780 actions.appendChild(wrap);
781
782 // hide "no form actions" message
783 actions.querySelector('#hf-form-actions-empty').style.display = 'none';
784 }
785
786 function createDeleteActionHandler(wrap) {
787 return function () {
788 actions.removeChild(wrap);
789
790 if (actions.childElementCount === 1) {
791 actions.querySelector('#hf-form-actions-empty').style.display = '';
792 }
793 };
794 }
795
796 function createToggleActionHandler(wrap, content) {
797 return function () {
798 var show = content.offsetParent === null;
799 wrap.className = wrap.className.replace('expanded', '');
800 if (show) {
801 wrap.className = wrap.className + " expanded";
802 }
803 content.style.display = show ? 'block' : 'none';
804 };
805 }
806
807 exports.default = {
808 'init': init
809 };
810
811 },{}],7:[function(require,module,exports){
812 'use strict';
813
814 // load CodeMirror & plugins
815
816 Object.defineProperty(exports, "__esModule", {
817 value: true
818 });
819 var CodeMirror = require('codemirror');
820 require('codemirror/mode/xml/xml');
821 require('codemirror/mode/javascript/javascript');
822 require('codemirror/mode/css/css');
823 require('codemirror/mode/htmlmixed/htmlmixed');
824 require('codemirror/addon/fold/xml-fold');
825 require('codemirror/addon/edit/matchtags');
826 require('codemirror/addon/edit/closetag.js');
827
828 var editor = void 0,
829 element = void 0,
830 dom = void 0,
831 requiredFieldsInput = void 0,
832 emailFieldsInput = void 0;
833
834 function init() {
835 element = document.getElementById('hf-form-editor');
836 dom = document.createElement('form');
837 requiredFieldsInput = document.getElementById('hf-required-fields');
838 emailFieldsInput = document.getElementById('hf-email-fields');
839
840 dom.innerHTML = element.value;
841
842 editor = CodeMirror.fromTextArea(element, {
843 selectionPointer: true,
844 matchTags: { bothTags: true },
845 mode: "htmlmixed",
846 htmlMode: true,
847 autoCloseTags: true,
848 autoRefresh: true,
849 styleActiveLine: true,
850 matchBrackets: true
851 });
852
853 editor.on('changes', debounce(updateShadowDOM, 100));
854 editor.on('blur', updateShadowDOM);
855 editor.on('blur', updateFieldVariables);
856 editor.on('blur', updateRequiredFields);
857 editor.on('blur', updateEmailFields);
858
859 document.getElementById('wpbody').addEventListener('click', updateFieldVariables);
860 }
861
862 function getFieldVariableName(f) {
863 return f.name.replace('[]', '').replace(/\[(\w+)\]/g, '.$1');
864 }
865
866 function updateFieldVariables() {
867 var fields = dom.querySelectorAll('input[name], select[name], textarea[name], button[name]');
868 var fieldVariables = [].map.call(fields, function (f) {
869 return '[' + getFieldVariableName(f) + ']';
870 });
871
872 [].forEach.call(document.querySelectorAll('.hf-field-names'), function (el) {
873 while (el.firstChild) {
874 el.removeChild(el.firstChild);
875 }
876
877 var variableElements = fieldVariables.map(function (n) {
878 var el = document.createElement('code');
879 el.innerText = n;
880 return el;
881 });
882
883 variableElements.forEach(function (vel, i, arr) {
884 el.appendChild(vel);
885
886 if (i < arr.length - 1) {
887 el.appendChild(document.createTextNode(', '));
888 }
889 });
890 });
891 }
892
893 function updateShadowDOM() {
894 dom.innerHTML = editor.getValue();
895 }
896
897 function updateRequiredFields() {
898 var fields = dom.querySelectorAll('[required]');
899 var fieldNames = [].map.call(fields, getFieldVariableName);
900 requiredFieldsInput.value = fieldNames.join(',');
901 }
902
903 function updateEmailFields() {
904 var fields = dom.querySelectorAll('input[type="email"]');
905 var fieldNames = [].map.call(fields, getFieldVariableName);
906 emailFieldsInput.value = fieldNames.join(',');
907 }
908
909 function replaceSelection(str) {
910 editor.replaceSelection(str);
911 editor.focus();
912 }
913
914 function debounce(func, wait, immediate) {
915 var timeout;
916 return function () {
917 var context = this,
918 args = arguments;
919 var later = function later() {
920 timeout = null;
921 if (!immediate) func.apply(context, args);
922 };
923 var callNow = immediate && !timeout;
924 clearTimeout(timeout);
925 timeout = setTimeout(later, wait);
926 if (callNow) func.apply(context, args);
927 };
928 };
929
930 exports.default = {
931 'init': init,
932 'replaceSelection': replaceSelection
933 };
934
935 },{"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){
936 'use strict';
937
938 Object.defineProperty(exports, "__esModule", {
939 value: true
940 });
941 var tabs = void 0,
942 tabNavs = void 0;
943 var Tabs = {};
944
945 Tabs.init = function () {
946 tabs = document.querySelectorAll('.hf-tab');
947 tabNavs = document.querySelectorAll('#hf-tabs-nav a');
948 for (var i = 0; i < tabNavs.length; i++) {
949 tabNavs[i].addEventListener('click', Tabs.open);
950 }
951 };
952
953 Tabs.open = function (e) {
954 var tabTarget = this.getAttribute('data-tab-target');
955 for (var i = 0; i < tabNavs.length; i++) {
956 tabNavs[i].classList.toggle('nav-tab-active', tabNavs[i] === this);
957 }
958 this.blur();
959
960 for (var _i = 0; _i < tabs.length; _i++) {
961 var tab = tabs[_i];
962 tab.classList.toggle('hf-tab-active', tab.getAttribute('data-tab') === tabTarget);
963 }
964
965 document.title = document.title.replace(document.title.split(' - ').shift(), this.innerText + " ");
966
967 e.preventDefault();
968 };
969
970 exports.default = Tabs;
971
972 },{}],9:[function(require,module,exports){
973 // CodeMirror, copyright (c) by Marijn Haverbeke and others
974 // Distributed under an MIT license: http://codemirror.net/LICENSE
975
976 /**
977 * Tag-closer extension for CodeMirror.
978 *
979 * This extension adds an "autoCloseTags" option that can be set to
980 * either true to get the default behavior, or an object to further
981 * configure its behavior.
982 *
983 * These are supported options:
984 *
985 * `whenClosing` (default true)
986 * Whether to autoclose when the '/' of a closing tag is typed.
987 * `whenOpening` (default true)
988 * Whether to autoclose the tag when the final '>' of an opening
989 * tag is typed.
990 * `dontCloseTags` (default is empty tags for HTML, none for XML)
991 * An array of tag names that should not be autoclosed.
992 * `indentTags` (default is block tags for HTML, none for XML)
993 * An array of tag names that should, when opened, cause a
994 * blank line to be added inside the tag, and the blank line and
995 * closing line to be indented.
996 *
997 * See demos/closetag.html for a usage example.
998 */
999
1000 (function(mod) {
1001 if (typeof exports == "object" && typeof module == "object") // CommonJS
1002 mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
1003 else if (typeof define == "function" && define.amd) // AMD
1004 define(["../../lib/codemirror", "../fold/xml-fold"], mod);
1005 else // Plain browser env
1006 mod(CodeMirror);
1007 })(function(CodeMirror) {
1008 CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
1009 if (old != CodeMirror.Init && old)
1010 cm.removeKeyMap("autoCloseTags");
1011 if (!val) return;
1012 var map = {name: "autoCloseTags"};
1013 if (typeof val != "object" || val.whenClosing)
1014 map["'/'"] = function(cm) { return autoCloseSlash(cm); };
1015 if (typeof val != "object" || val.whenOpening)
1016 map["'>'"] = function(cm) { return autoCloseGT(cm); };
1017 cm.addKeyMap(map);
1018 });
1019
1020 var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
1021 "source", "track", "wbr"];
1022 var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4",
1023 "h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"];
1024
1025 function autoCloseGT(cm) {
1026 if (cm.getOption("disableInput")) return CodeMirror.Pass;
1027 var ranges = cm.listSelections(), replacements = [];
1028 for (var i = 0; i < ranges.length; i++) {
1029 if (!ranges[i].empty()) return CodeMirror.Pass;
1030 var pos = ranges[i].head, tok = cm.getTokenAt(pos);
1031 var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
1032 if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;
1033
1034 var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html";
1035 var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
1036 var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
1037
1038 var tagName = state.tagName;
1039 if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
1040 var lowerTagName = tagName.toLowerCase();
1041 // Don't process the '>' at the end of an end-tag or self-closing tag
1042 if (!tagName ||
1043 tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
1044 tok.type == "tag" && state.type == "closeTag" ||
1045 tok.string.indexOf("/") == (tok.string.length - 1) || // match something like <someTagName />
1046 dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
1047 closingTagExists(cm, tagName, pos, state, true))
1048 return CodeMirror.Pass;
1049
1050 var indent = indentTags && indexOf(indentTags, lowerTagName) > -1;
1051 replacements[i] = {indent: indent,
1052 text: ">" + (indent ? "\n\n" : "") + "</" + tagName + ">",
1053 newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)};
1054 }
1055
1056 for (var i = ranges.length - 1; i >= 0; i--) {
1057 var info = replacements[i];
1058 cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert");
1059 var sel = cm.listSelections().slice(0);
1060 sel[i] = {head: info.newPos, anchor: info.newPos};
1061 cm.setSelections(sel);
1062 if (info.indent) {
1063 cm.indentLine(info.newPos.line, null, true);
1064 cm.indentLine(info.newPos.line + 1, null, true);
1065 }
1066 }
1067 }
1068
1069 function autoCloseCurrent(cm, typingSlash) {
1070 var ranges = cm.listSelections(), replacements = [];
1071 var head = typingSlash ? "/" : "</";
1072 for (var i = 0; i < ranges.length; i++) {
1073 if (!ranges[i].empty()) return CodeMirror.Pass;
1074 var pos = ranges[i].head, tok = cm.getTokenAt(pos);
1075 var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
1076 if (typingSlash && (tok.type == "string" || tok.string.charAt(0) != "<" ||
1077 tok.start != pos.ch - 1))
1078 return CodeMirror.Pass;
1079 // Kludge to get around the fact that we are not in XML mode
1080 // when completing in JS/CSS snippet in htmlmixed mode. Does not
1081 // work for other XML embedded languages (there is no general
1082 // way to go from a mixed mode to its current XML state).
1083 var replacement;
1084 if (inner.mode.name != "xml") {
1085 if (cm.getMode().name == "htmlmixed" && inner.mode.name == "javascript")
1086 replacement = head + "script";
1087 else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css")
1088 replacement = head + "style";
1089 else
1090 return CodeMirror.Pass;
1091 } else {
1092 if (!state.context || !state.context.tagName ||
1093 closingTagExists(cm, state.context.tagName, pos, state))
1094 return CodeMirror.Pass;
1095 replacement = head + state.context.tagName;
1096 }
1097 if (cm.getLine(pos.line).charAt(tok.end) != ">") replacement += ">";
1098 replacements[i] = replacement;
1099 }
1100 cm.replaceSelections(replacements);
1101 ranges = cm.listSelections();
1102 for (var i = 0; i < ranges.length; i++)
1103 if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line)
1104 cm.indentLine(ranges[i].head.line);
1105 }
1106
1107 function autoCloseSlash(cm) {
1108 if (cm.getOption("disableInput")) return CodeMirror.Pass;
1109 return autoCloseCurrent(cm, true);
1110 }
1111
1112 CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); };
1113
1114 function indexOf(collection, elt) {
1115 if (collection.indexOf) return collection.indexOf(elt);
1116 for (var i = 0, e = collection.length; i < e; ++i)
1117 if (collection[i] == elt) return i;
1118 return -1;
1119 }
1120
1121 // If xml-fold is loaded, we use its functionality to try and verify
1122 // whether a given tag is actually unclosed.
1123 function closingTagExists(cm, tagName, pos, state, newTag) {
1124 if (!CodeMirror.scanForClosingTag) return false;
1125 var end = Math.min(cm.lastLine() + 1, pos.line + 500);
1126 var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end);
1127 if (!nextClose || nextClose.tag != tagName) return false;
1128 var cx = state.context;
1129 // If the immediate wrapping context contains onCx instances of
1130 // the same tag, a closing tag only exists if there are at least
1131 // that many closing tags of that type following.
1132 for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx;
1133 pos = nextClose.to;
1134 for (var i = 1; i < onCx; i++) {
1135 var next = CodeMirror.scanForClosingTag(cm, pos, null, end);
1136 if (!next || next.tag != tagName) return false;
1137 pos = next.to;
1138 }
1139 return true;
1140 }
1141 });
1142
1143 },{"../../lib/codemirror":12,"../fold/xml-fold":11}],10:[function(require,module,exports){
1144 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1145 // Distributed under an MIT license: http://codemirror.net/LICENSE
1146
1147 (function(mod) {
1148 if (typeof exports == "object" && typeof module == "object") // CommonJS
1149 mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
1150 else if (typeof define == "function" && define.amd) // AMD
1151 define(["../../lib/codemirror", "../fold/xml-fold"], mod);
1152 else // Plain browser env
1153 mod(CodeMirror);
1154 })(function(CodeMirror) {
1155 "use strict";
1156
1157 CodeMirror.defineOption("matchTags", false, function(cm, val, old) {
1158 if (old && old != CodeMirror.Init) {
1159 cm.off("cursorActivity", doMatchTags);
1160 cm.off("viewportChange", maybeUpdateMatch);
1161 clear(cm);
1162 }
1163 if (val) {
1164 cm.state.matchBothTags = typeof val == "object" && val.bothTags;
1165 cm.on("cursorActivity", doMatchTags);
1166 cm.on("viewportChange", maybeUpdateMatch);
1167 doMatchTags(cm);
1168 }
1169 });
1170
1171 function clear(cm) {
1172 if (cm.state.tagHit) cm.state.tagHit.clear();
1173 if (cm.state.tagOther) cm.state.tagOther.clear();
1174 cm.state.tagHit = cm.state.tagOther = null;
1175 }
1176
1177 function doMatchTags(cm) {
1178 cm.state.failedTagMatch = false;
1179 cm.operation(function() {
1180 clear(cm);
1181 if (cm.somethingSelected()) return;
1182 var cur = cm.getCursor(), range = cm.getViewport();
1183 range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to);
1184 var match = CodeMirror.findMatchingTag(cm, cur, range);
1185 if (!match) return;
1186 if (cm.state.matchBothTags) {
1187 var hit = match.at == "open" ? match.open : match.close;
1188 if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"});
1189 }
1190 var other = match.at == "close" ? match.open : match.close;
1191 if (other)
1192 cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"});
1193 else
1194 cm.state.failedTagMatch = true;
1195 });
1196 }
1197
1198 function maybeUpdateMatch(cm) {
1199 if (cm.state.failedTagMatch) doMatchTags(cm);
1200 }
1201
1202 CodeMirror.commands.toMatchingTag = function(cm) {
1203 var found = CodeMirror.findMatchingTag(cm, cm.getCursor());
1204 if (found) {
1205 var other = found.at == "close" ? found.open : found.close;
1206 if (other) cm.extendSelection(other.to, other.from);
1207 }
1208 };
1209 });
1210
1211 },{"../../lib/codemirror":12,"../fold/xml-fold":11}],11:[function(require,module,exports){
1212 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1213 // Distributed under an MIT license: http://codemirror.net/LICENSE
1214
1215 (function(mod) {
1216 if (typeof exports == "object" && typeof module == "object") // CommonJS
1217 mod(require("../../lib/codemirror"));
1218 else if (typeof define == "function" && define.amd) // AMD
1219 define(["../../lib/codemirror"], mod);
1220 else // Plain browser env
1221 mod(CodeMirror);
1222 })(function(CodeMirror) {
1223 "use strict";
1224
1225 var Pos = CodeMirror.Pos;
1226 function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
1227
1228 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";
1229 var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
1230 var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
1231
1232 function Iter(cm, line, ch, range) {
1233 this.line = line; this.ch = ch;
1234 this.cm = cm; this.text = cm.getLine(line);
1235 this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine();
1236 this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine();
1237 }
1238
1239 function tagAt(iter, ch) {
1240 var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
1241 return type && /\btag\b/.test(type);
1242 }
1243
1244 function nextLine(iter) {
1245 if (iter.line >= iter.max) return;
1246 iter.ch = 0;
1247 iter.text = iter.cm.getLine(++iter.line);
1248 return true;
1249 }
1250 function prevLine(iter) {
1251 if (iter.line <= iter.min) return;
1252 iter.text = iter.cm.getLine(--iter.line);
1253 iter.ch = iter.text.length;
1254 return true;
1255 }
1256
1257 function toTagEnd(iter) {
1258 for (;;) {
1259 var gt = iter.text.indexOf(">", iter.ch);
1260 if (gt == -1) { if (nextLine(iter)) continue; else return; }
1261 if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
1262 var lastSlash = iter.text.lastIndexOf("/", gt);
1263 var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
1264 iter.ch = gt + 1;
1265 return selfClose ? "selfClose" : "regular";
1266 }
1267 }
1268 function toTagStart(iter) {
1269 for (;;) {
1270 var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;
1271 if (lt == -1) { if (prevLine(iter)) continue; else return; }
1272 if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
1273 xmlTagStart.lastIndex = lt;
1274 iter.ch = lt;
1275 var match = xmlTagStart.exec(iter.text);
1276 if (match && match.index == lt) return match;
1277 }
1278 }
1279
1280 function toNextTag(iter) {
1281 for (;;) {
1282 xmlTagStart.lastIndex = iter.ch;
1283 var found = xmlTagStart.exec(iter.text);
1284 if (!found) { if (nextLine(iter)) continue; else return; }
1285 if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
1286 iter.ch = found.index + found[0].length;
1287 return found;
1288 }
1289 }
1290 function toPrevTag(iter) {
1291 for (;;) {
1292 var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;
1293 if (gt == -1) { if (prevLine(iter)) continue; else return; }
1294 if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
1295 var lastSlash = iter.text.lastIndexOf("/", gt);
1296 var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
1297 iter.ch = gt + 1;
1298 return selfClose ? "selfClose" : "regular";
1299 }
1300 }
1301
1302 function findMatchingClose(iter, tag) {
1303 var stack = [];
1304 for (;;) {
1305 var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
1306 if (!next || !(end = toTagEnd(iter))) return;
1307 if (end == "selfClose") continue;
1308 if (next[1]) { // closing tag
1309 for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
1310 stack.length = i;
1311 break;
1312 }
1313 if (i < 0 && (!tag || tag == next[2])) return {
1314 tag: next[2],
1315 from: Pos(startLine, startCh),
1316 to: Pos(iter.line, iter.ch)
1317 };
1318 } else { // opening tag
1319 stack.push(next[2]);
1320 }
1321 }
1322 }
1323 function findMatchingOpen(iter, tag) {
1324 var stack = [];
1325 for (;;) {
1326 var prev = toPrevTag(iter);
1327 if (!prev) return;
1328 if (prev == "selfClose") { toTagStart(iter); continue; }
1329 var endLine = iter.line, endCh = iter.ch;
1330 var start = toTagStart(iter);
1331 if (!start) return;
1332 if (start[1]) { // closing tag
1333 stack.push(start[2]);
1334 } else { // opening tag
1335 for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
1336 stack.length = i;
1337 break;
1338 }
1339 if (i < 0 && (!tag || tag == start[2])) return {
1340 tag: start[2],
1341 from: Pos(iter.line, iter.ch),
1342 to: Pos(endLine, endCh)
1343 };
1344 }
1345 }
1346 }
1347
1348 CodeMirror.registerHelper("fold", "xml", function(cm, start) {
1349 var iter = new Iter(cm, start.line, 0);
1350 for (;;) {
1351 var openTag = toNextTag(iter), end;
1352 if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
1353 if (!openTag[1] && end != "selfClose") {
1354 var startPos = Pos(iter.line, iter.ch);
1355 var endPos = findMatchingClose(iter, openTag[2]);
1356 return endPos && {from: startPos, to: endPos.from};
1357 }
1358 }
1359 });
1360 CodeMirror.findMatchingTag = function(cm, pos, range) {
1361 var iter = new Iter(cm, pos.line, pos.ch, range);
1362 if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
1363 var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
1364 var start = end && toTagStart(iter);
1365 if (!end || !start || cmp(iter, pos) > 0) return;
1366 var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
1367 if (end == "selfClose") return {open: here, close: null, at: "open"};
1368
1369 if (start[1]) { // closing tag
1370 return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
1371 } else { // opening tag
1372 iter = new Iter(cm, to.line, to.ch, range);
1373 return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};
1374 }
1375 };
1376
1377 CodeMirror.findEnclosingTag = function(cm, pos, range, tag) {
1378 var iter = new Iter(cm, pos.line, pos.ch, range);
1379 for (;;) {
1380 var open = findMatchingOpen(iter, tag);
1381 if (!open) break;
1382 var forward = new Iter(cm, pos.line, pos.ch, range);
1383 var close = findMatchingClose(forward, open.tag);
1384 if (close) return {open: open, close: close};
1385 }
1386 };
1387
1388 // Used by addon/edit/closetag.js
1389 CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
1390 var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
1391 return findMatchingClose(iter, name);
1392 };
1393 });
1394
1395 },{"../../lib/codemirror":12}],12:[function(require,module,exports){
1396 // CodeMirror, copyright (c) by Marijn Haverbeke and others
1397 // Distributed under an MIT license: http://codemirror.net/LICENSE
1398
1399 // This is CodeMirror (http://codemirror.net), a code editor
1400 // implemented in JavaScript on top of the browser's DOM.
1401 //
1402 // You can find some technical background for some of the code below
1403 // at http://marijnhaverbeke.nl/blog/#cm-internals .
1404
1405 (function (global, factory) {
1406 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
1407 typeof define === 'function' && define.amd ? define(factory) :
1408 (global.CodeMirror = factory());
1409 }(this, (function () { 'use strict';
1410
1411 // Kludges for bugs and behavior differences that can't be feature
1412 // detected are enabled based on userAgent etc sniffing.
1413 var userAgent = navigator.userAgent;
1414 var platform = navigator.platform;
1415
1416 var gecko = /gecko\/\d/i.test(userAgent);
1417 var ie_upto10 = /MSIE \d/.test(userAgent);
1418 var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
1419 var edge = /Edge\/(\d+)/.exec(userAgent);
1420 var ie = ie_upto10 || ie_11up || edge;
1421 var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]);
1422 var webkit = !edge && /WebKit\//.test(userAgent);
1423 var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
1424 var chrome = !edge && /Chrome\//.test(userAgent);
1425 var presto = /Opera\//.test(userAgent);
1426 var safari = /Apple Computer/.test(navigator.vendor);
1427 var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
1428 var phantom = /PhantomJS/.test(userAgent);
1429
1430 var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
1431 var android = /Android/.test(userAgent);
1432 // This is woefully incomplete. Suggestions for alternative methods welcome.
1433 var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
1434 var mac = ios || /Mac/.test(platform);
1435 var chromeOS = /\bCrOS\b/.test(userAgent);
1436 var windows = /win/i.test(platform);
1437
1438 var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
1439 if (presto_version) { presto_version = Number(presto_version[1]); }
1440 if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
1441 // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
1442 var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
1443 var captureRightClick = gecko || (ie && ie_version >= 9);
1444
1445 function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
1446
1447 var rmClass = function(node, cls) {
1448 var current = node.className;
1449 var match = classTest(cls).exec(current);
1450 if (match) {
1451 var after = current.slice(match.index + match[0].length);
1452 node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
1453 }
1454 };
1455
1456 function removeChildren(e) {
1457 for (var count = e.childNodes.length; count > 0; --count)
1458 { e.removeChild(e.firstChild); }
1459 return e
1460 }
1461
1462 function removeChildrenAndAdd(parent, e) {
1463 return removeChildren(parent).appendChild(e)
1464 }
1465
1466 function elt(tag, content, className, style) {
1467 var e = document.createElement(tag);
1468 if (className) { e.className = className; }
1469 if (style) { e.style.cssText = style; }
1470 if (typeof content == "string") { e.appendChild(document.createTextNode(content)); }
1471 else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } }
1472 return e
1473 }
1474 // wrapper for elt, which removes the elt from the accessibility tree
1475 function eltP(tag, content, className, style) {
1476 var e = elt(tag, content, className, style);
1477 e.setAttribute("role", "presentation");
1478 return e
1479 }
1480
1481 var range;
1482 if (document.createRange) { range = function(node, start, end, endNode) {
1483 var r = document.createRange();
1484 r.setEnd(endNode || node, end);
1485 r.setStart(node, start);
1486 return r
1487 }; }
1488 else { range = function(node, start, end) {
1489 var r = document.body.createTextRange();
1490 try { r.moveToElementText(node.parentNode); }
1491 catch(e) { return r }
1492 r.collapse(true);
1493 r.moveEnd("character", end);
1494 r.moveStart("character", start);
1495 return r
1496 }; }
1497
1498 function contains(parent, child) {
1499 if (child.nodeType == 3) // Android browser always returns false when child is a textnode
1500 { child = child.parentNode; }
1501 if (parent.contains)
1502 { return parent.contains(child) }
1503 do {
1504 if (child.nodeType == 11) { child = child.host; }
1505 if (child == parent) { return true }
1506 } while (child = child.parentNode)
1507 }
1508
1509 function activeElt() {
1510 // IE and Edge may throw an "Unspecified Error" when accessing document.activeElement.
1511 // IE < 10 will throw when accessed while the page is loading or in an iframe.
1512 // IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.
1513 var activeElement;
1514 try {
1515 activeElement = document.activeElement;
1516 } catch(e) {
1517 activeElement = document.body || null;
1518 }
1519 while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
1520 { activeElement = activeElement.shadowRoot.activeElement; }
1521 return activeElement
1522 }
1523
1524 function addClass(node, cls) {
1525 var current = node.className;
1526 if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls; }
1527 }
1528 function joinClasses(a, b) {
1529 var as = a.split(" ");
1530 for (var i = 0; i < as.length; i++)
1531 { if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i]; } }
1532 return b
1533 }
1534
1535 var selectInput = function(node) { node.select(); };
1536 if (ios) // Mobile Safari apparently has a bug where select() is broken.
1537 { selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; }
1538 else if (ie) // Suppress mysterious IE10 errors
1539 { selectInput = function(node) { try { node.select(); } catch(_e) {} }; }
1540
1541 function bind(f) {
1542 var args = Array.prototype.slice.call(arguments, 1);
1543 return function(){return f.apply(null, args)}
1544 }
1545
1546 function copyObj(obj, target, overwrite) {
1547 if (!target) { target = {}; }
1548 for (var prop in obj)
1549 { if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
1550 { target[prop] = obj[prop]; } }
1551 return target
1552 }
1553
1554 // Counts the column offset in a string, taking tabs into account.
1555 // Used mostly to find indentation.
1556 function countColumn(string, end, tabSize, startIndex, startValue) {
1557 if (end == null) {
1558 end = string.search(/[^\s\u00a0]/);
1559 if (end == -1) { end = string.length; }
1560 }
1561 for (var i = startIndex || 0, n = startValue || 0;;) {
1562 var nextTab = string.indexOf("\t", i);
1563 if (nextTab < 0 || nextTab >= end)
1564 { return n + (end - i) }
1565 n += nextTab - i;
1566 n += tabSize - (n % tabSize);
1567 i = nextTab + 1;
1568 }
1569 }
1570
1571 var Delayed = function() {this.id = null;};
1572 Delayed.prototype.set = function (ms, f) {
1573 clearTimeout(this.id);
1574 this.id = setTimeout(f, ms);
1575 };
1576
1577 function indexOf(array, elt) {
1578 for (var i = 0; i < array.length; ++i)
1579 { if (array[i] == elt) { return i } }
1580 return -1
1581 }
1582
1583 // Number of pixels added to scroller and sizer to hide scrollbar
1584 var scrollerGap = 30;
1585
1586 // Returned or thrown by various protocols to signal 'I'm not
1587 // handling this'.
1588 var Pass = {toString: function(){return "CodeMirror.Pass"}};
1589
1590 // Reused option objects for setSelection & friends
1591 var sel_dontScroll = {scroll: false};
1592 var sel_mouse = {origin: "*mouse"};
1593 var sel_move = {origin: "+move"};
1594
1595 // The inverse of countColumn -- find the offset that corresponds to
1596 // a particular column.
1597 function findColumn(string, goal, tabSize) {
1598 for (var pos = 0, col = 0;;) {
1599 var nextTab = string.indexOf("\t", pos);
1600 if (nextTab == -1) { nextTab = string.length; }
1601 var skipped = nextTab - pos;
1602 if (nextTab == string.length || col + skipped >= goal)
1603 { return pos + Math.min(skipped, goal - col) }
1604 col += nextTab - pos;
1605 col += tabSize - (col % tabSize);
1606 pos = nextTab + 1;
1607 if (col >= goal) { return pos }
1608 }
1609 }
1610
1611 var spaceStrs = [""];
1612 function spaceStr(n) {
1613 while (spaceStrs.length <= n)
1614 { spaceStrs.push(lst(spaceStrs) + " "); }
1615 return spaceStrs[n]
1616 }
1617
1618 function lst(arr) { return arr[arr.length-1] }
1619
1620 function map(array, f) {
1621 var out = [];
1622 for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i); }
1623 return out
1624 }
1625
1626 function insertSorted(array, value, score) {
1627 var pos = 0, priority = score(value);
1628 while (pos < array.length && score(array[pos]) <= priority) { pos++; }
1629 array.splice(pos, 0, value);
1630 }
1631
1632 function nothing() {}
1633
1634 function createObj(base, props) {
1635 var inst;
1636 if (Object.create) {
1637 inst = Object.create(base);
1638 } else {
1639 nothing.prototype = base;
1640 inst = new nothing();
1641 }
1642 if (props) { copyObj(props, inst); }
1643 return inst
1644 }
1645
1646 var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
1647 function isWordCharBasic(ch) {
1648 return /\w/.test(ch) || ch > "\x80" &&
1649 (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))
1650 }
1651 function isWordChar(ch, helper) {
1652 if (!helper) { return isWordCharBasic(ch) }
1653 if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true }
1654 return helper.test(ch)
1655 }
1656
1657 function isEmpty(obj) {
1658 for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }
1659 return true
1660 }
1661
1662 // Extending unicode characters. A series of a non-extending char +
1663 // any number of extending chars is treated as a single unit as far
1664 // as editing and measuring is concerned. This is not fully correct,
1665 // since some scripts/fonts/browsers also treat other configurations
1666 // of code points as a group.
1667 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]/;
1668 function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }
1669
1670 // Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.
1671 function skipExtendingChars(str, pos, dir) {
1672 while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; }
1673 return pos
1674 }
1675
1676 // Returns the value from the range [`from`; `to`] that satisfies
1677 // `pred` and is closest to `from`. Assumes that at least `to` satisfies `pred`.
1678 function findFirst(pred, from, to) {
1679 for (;;) {
1680 if (Math.abs(from - to) <= 1) { return pred(from) ? from : to }
1681 var mid = Math.floor((from + to) / 2);
1682 if (pred(mid)) { to = mid; }
1683 else { from = mid; }
1684 }
1685 }
1686
1687 // The display handles the DOM integration, both for input reading
1688 // and content drawing. It holds references to DOM nodes and
1689 // display-related state.
1690
1691 function Display(place, doc, input) {
1692 var d = this;
1693 this.input = input;
1694
1695 // Covers bottom-right square when both scrollbars are present.
1696 d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
1697 d.scrollbarFiller.setAttribute("cm-not-content", "true");
1698 // Covers bottom of gutter when coverGutterNextToScrollbar is on
1699 // and h scrollbar is present.
1700 d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
1701 d.gutterFiller.setAttribute("cm-not-content", "true");
1702 // Will contain the actual code, positioned to cover the viewport.
1703 d.lineDiv = eltP("div", null, "CodeMirror-code");
1704 // Elements are added to these to represent selection and cursors.
1705 d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
1706 d.cursorDiv = elt("div", null, "CodeMirror-cursors");
1707 // A visibility: hidden element used to find the size of things.
1708 d.measure = elt("div", null, "CodeMirror-measure");
1709 // When lines outside of the viewport are measured, they are drawn in this.
1710 d.lineMeasure = elt("div", null, "CodeMirror-measure");
1711 // Wraps everything that needs to exist inside the vertically-padded coordinate system
1712 d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
1713 null, "position: relative; outline: none");
1714 var lines = eltP("div", [d.lineSpace], "CodeMirror-lines");
1715 // Moved around its parent to cover visible view.
1716 d.mover = elt("div", [lines], null, "position: relative");
1717 // Set to the height of the document, allowing scrolling.
1718 d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
1719 d.sizerWidth = null;
1720 // Behavior of elts with overflow: auto and padding is
1721 // inconsistent across browsers. This is used to ensure the
1722 // scrollable area is big enough.
1723 d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
1724 // Will contain the gutters, if any.
1725 d.gutters = elt("div", null, "CodeMirror-gutters");
1726 d.lineGutter = null;
1727 // Actual scrollable element.
1728 d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
1729 d.scroller.setAttribute("tabIndex", "-1");
1730 // The element in which the editor lives.
1731 d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
1732
1733 // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
1734 if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
1735 if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; }
1736
1737 if (place) {
1738 if (place.appendChild) { place.appendChild(d.wrapper); }
1739 else { place(d.wrapper); }
1740 }
1741
1742 // Current rendered range (may be bigger than the view window).
1743 d.viewFrom = d.viewTo = doc.first;
1744 d.reportedViewFrom = d.reportedViewTo = doc.first;
1745 // Information about the rendered lines.
1746 d.view = [];
1747 d.renderedView = null;
1748 // Holds info about a single rendered line when it was rendered
1749 // for measurement, while not in view.
1750 d.externalMeasured = null;
1751 // Empty space (in pixels) above the view
1752 d.viewOffset = 0;
1753 d.lastWrapHeight = d.lastWrapWidth = 0;
1754 d.updateLineNumbers = null;
1755
1756 d.nativeBarWidth = d.barHeight = d.barWidth = 0;
1757 d.scrollbarsClipped = false;
1758
1759 // Used to only resize the line number gutter when necessary (when
1760 // the amount of lines crosses a boundary that makes its width change)
1761 d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
1762 // Set to true when a non-horizontal-scrolling line widget is
1763 // added. As an optimization, line widget aligning is skipped when
1764 // this is false.
1765 d.alignWidgets = false;
1766
1767 d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
1768
1769 // Tracks the maximum line length so that the horizontal scrollbar
1770 // can be kept static when scrolling.
1771 d.maxLine = null;
1772 d.maxLineLength = 0;
1773 d.maxLineChanged = false;
1774
1775 // Used for measuring wheel scrolling granularity
1776 d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
1777
1778 // True when shift is held down.
1779 d.shift = false;
1780
1781 // Used to track whether anything happened since the context menu
1782 // was opened.
1783 d.selForContextMenu = null;
1784
1785 d.activeTouch = null;
1786
1787 input.init(d);
1788 }
1789
1790 // Find the line object corresponding to the given line number.
1791 function getLine(doc, n) {
1792 n -= doc.first;
1793 if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
1794 var chunk = doc;
1795 while (!chunk.lines) {
1796 for (var i = 0;; ++i) {
1797 var child = chunk.children[i], sz = child.chunkSize();
1798 if (n < sz) { chunk = child; break }
1799 n -= sz;
1800 }
1801 }
1802 return chunk.lines[n]
1803 }
1804
1805 // Get the part of a document between two positions, as an array of
1806 // strings.
1807 function getBetween(doc, start, end) {
1808 var out = [], n = start.line;
1809 doc.iter(start.line, end.line + 1, function (line) {
1810 var text = line.text;
1811 if (n == end.line) { text = text.slice(0, end.ch); }
1812 if (n == start.line) { text = text.slice(start.ch); }
1813 out.push(text);
1814 ++n;
1815 });
1816 return out
1817 }
1818 // Get the lines between from and to, as array of strings.
1819 function getLines(doc, from, to) {
1820 var out = [];
1821 doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value
1822 return out
1823 }
1824
1825 // Update the height of a line, propagating the height change
1826 // upwards to parent nodes.
1827 function updateLineHeight(line, height) {
1828 var diff = height - line.height;
1829 if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } }
1830 }
1831
1832 // Given a line object, find its line number by walking up through
1833 // its parent links.
1834 function lineNo(line) {
1835 if (line.parent == null) { return null }
1836 var cur = line.parent, no = indexOf(cur.lines, line);
1837 for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
1838 for (var i = 0;; ++i) {
1839 if (chunk.children[i] == cur) { break }
1840 no += chunk.children[i].chunkSize();
1841 }
1842 }
1843 return no + cur.first
1844 }
1845
1846 // Find the line at the given vertical position, using the height
1847 // information in the document tree.
1848 function lineAtHeight(chunk, h) {
1849 var n = chunk.first;
1850 outer: do {
1851 for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
1852 var child = chunk.children[i$1], ch = child.height;
1853 if (h < ch) { chunk = child; continue outer }
1854 h -= ch;
1855 n += child.chunkSize();
1856 }
1857 return n
1858 } while (!chunk.lines)
1859 var i = 0;
1860 for (; i < chunk.lines.length; ++i) {
1861 var line = chunk.lines[i], lh = line.height;
1862 if (h < lh) { break }
1863 h -= lh;
1864 }
1865 return n + i
1866 }
1867
1868 function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
1869
1870 function lineNumberFor(options, i) {
1871 return String(options.lineNumberFormatter(i + options.firstLineNumber))
1872 }
1873
1874 // A Pos instance represents a position within the text.
1875 function Pos(line, ch, sticky) {
1876 if ( sticky === void 0 ) sticky = null;
1877
1878 if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }
1879 this.line = line;
1880 this.ch = ch;
1881 this.sticky = sticky;
1882 }
1883
1884 // Compare two positions, return 0 if they are the same, a negative
1885 // number when a is less, and a positive number otherwise.
1886 function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
1887
1888 function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }
1889
1890 function copyPos(x) {return Pos(x.line, x.ch)}
1891 function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
1892 function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
1893
1894 // Most of the external API clips given positions to make sure they
1895 // actually exist within the document.
1896 function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
1897 function clipPos(doc, pos) {
1898 if (pos.line < doc.first) { return Pos(doc.first, 0) }
1899 var last = doc.first + doc.size - 1;
1900 if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
1901 return clipToLen(pos, getLine(doc, pos.line).text.length)
1902 }
1903 function clipToLen(pos, linelen) {
1904 var ch = pos.ch;
1905 if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
1906 else if (ch < 0) { return Pos(pos.line, 0) }
1907 else { return pos }
1908 }
1909 function clipPosArray(doc, array) {
1910 var out = [];
1911 for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); }
1912 return out
1913 }
1914
1915 // Optimize some code when these features are not used.
1916 var sawReadOnlySpans = false;
1917 var sawCollapsedSpans = false;
1918
1919 function seeReadOnlySpans() {
1920 sawReadOnlySpans = true;
1921 }
1922
1923 function seeCollapsedSpans() {
1924 sawCollapsedSpans = true;
1925 }
1926
1927 // TEXTMARKER SPANS
1928
1929 function MarkedSpan(marker, from, to) {
1930 this.marker = marker;
1931 this.from = from; this.to = to;
1932 }
1933
1934 // Search an array of spans for a span matching the given marker.
1935 function getMarkedSpanFor(spans, marker) {
1936 if (spans) { for (var i = 0; i < spans.length; ++i) {
1937 var span = spans[i];
1938 if (span.marker == marker) { return span }
1939 } }
1940 }
1941 // Remove a span from an array, returning undefined if no spans are
1942 // left (we don't store arrays for lines without spans).
1943 function removeMarkedSpan(spans, span) {
1944 var r;
1945 for (var i = 0; i < spans.length; ++i)
1946 { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } }
1947 return r
1948 }
1949 // Add a span to a line.
1950 function addMarkedSpan(line, span) {
1951 line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
1952 span.marker.attachLine(line);
1953 }
1954
1955 // Used for the algorithm that adjusts markers for a change in the
1956 // document. These functions cut an array of spans at a given
1957 // character position, returning an array of remaining chunks (or
1958 // undefined if nothing remains).
1959 function markedSpansBefore(old, startCh, isInsert) {
1960 var nw;
1961 if (old) { for (var i = 0; i < old.length; ++i) {
1962 var span = old[i], marker = span.marker;
1963 var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
1964 if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
1965 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));
1966 }
1967 } }
1968 return nw
1969 }
1970 function markedSpansAfter(old, endCh, isInsert) {
1971 var nw;
1972 if (old) { for (var i = 0; i < old.length; ++i) {
1973 var span = old[i], marker = span.marker;
1974 var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
1975 if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
1976 var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
1977 span.to == null ? null : span.to - endCh));
1978 }
1979 } }
1980 return nw
1981 }
1982
1983 // Given a change object, compute the new set of marker spans that
1984 // cover the line in which the change took place. Removes spans
1985 // entirely within the change, reconnects spans belonging to the
1986 // same marker that appear on both sides of the change, and cuts off
1987 // spans partially within the change. Returns an array of span
1988 // arrays with one element for each line in (after) the change.
1989 function stretchSpansOverChange(doc, change) {
1990 if (change.full) { return null }
1991 var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
1992 var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
1993 if (!oldFirst && !oldLast) { return null }
1994
1995 var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
1996 // Get the spans that 'stick out' on both sides
1997 var first = markedSpansBefore(oldFirst, startCh, isInsert);
1998 var last = markedSpansAfter(oldLast, endCh, isInsert);
1999
2000 // Next, merge those two ends
2001 var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
2002 if (first) {
2003 // Fix up .to properties of first
2004 for (var i = 0; i < first.length; ++i) {
2005 var span = first[i];
2006 if (span.to == null) {
2007 var found = getMarkedSpanFor(last, span.marker);
2008 if (!found) { span.to = startCh; }
2009 else if (sameLine) { span.to = found.to == null ? null : found.to + offset; }
2010 }
2011 }
2012 }
2013 if (last) {
2014 // Fix up .from in last (or move them into first in case of sameLine)
2015 for (var i$1 = 0; i$1 < last.length; ++i$1) {
2016 var span$1 = last[i$1];
2017 if (span$1.to != null) { span$1.to += offset; }
2018 if (span$1.from == null) {
2019 var found$1 = getMarkedSpanFor(first, span$1.marker);
2020 if (!found$1) {
2021 span$1.from = offset;
2022 if (sameLine) { (first || (first = [])).push(span$1); }
2023 }
2024 } else {
2025 span$1.from += offset;
2026 if (sameLine) { (first || (first = [])).push(span$1); }
2027 }
2028 }
2029 }
2030 // Make sure we didn't create any zero-length spans
2031 if (first) { first = clearEmptySpans(first); }
2032 if (last && last != first) { last = clearEmptySpans(last); }
2033
2034 var newMarkers = [first];
2035 if (!sameLine) {
2036 // Fill gap with whole-line-spans
2037 var gap = change.text.length - 2, gapMarkers;
2038 if (gap > 0 && first)
2039 { for (var i$2 = 0; i$2 < first.length; ++i$2)
2040 { if (first[i$2].to == null)
2041 { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } }
2042 for (var i$3 = 0; i$3 < gap; ++i$3)
2043 { newMarkers.push(gapMarkers); }
2044 newMarkers.push(last);
2045 }
2046 return newMarkers
2047 }
2048
2049 // Remove spans that are empty and don't have a clearWhenEmpty
2050 // option of false.
2051 function clearEmptySpans(spans) {
2052 for (var i = 0; i < spans.length; ++i) {
2053 var span = spans[i];
2054 if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
2055 { spans.splice(i--, 1); }
2056 }
2057 if (!spans.length) { return null }
2058 return spans
2059 }
2060
2061 // Used to 'clip' out readOnly ranges when making a change.
2062 function removeReadOnlyRanges(doc, from, to) {
2063 var markers = null;
2064 doc.iter(from.line, to.line + 1, function (line) {
2065 if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
2066 var mark = line.markedSpans[i].marker;
2067 if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
2068 { (markers || (markers = [])).push(mark); }
2069 } }
2070 });
2071 if (!markers) { return null }
2072 var parts = [{from: from, to: to}];
2073 for (var i = 0; i < markers.length; ++i) {
2074 var mk = markers[i], m = mk.find(0);
2075 for (var j = 0; j < parts.length; ++j) {
2076 var p = parts[j];
2077 if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
2078 var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
2079 if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
2080 { newParts.push({from: p.from, to: m.from}); }
2081 if (dto > 0 || !mk.inclusiveRight && !dto)
2082 { newParts.push({from: m.to, to: p.to}); }
2083 parts.splice.apply(parts, newParts);
2084 j += newParts.length - 3;
2085 }
2086 }
2087 return parts
2088 }
2089
2090 // Connect or disconnect spans from a line.
2091 function detachMarkedSpans(line) {
2092 var spans = line.markedSpans;
2093 if (!spans) { return }
2094 for (var i = 0; i < spans.length; ++i)
2095 { spans[i].marker.detachLine(line); }
2096 line.markedSpans = null;
2097 }
2098 function attachMarkedSpans(line, spans) {
2099 if (!spans) { return }
2100 for (var i = 0; i < spans.length; ++i)
2101 { spans[i].marker.attachLine(line); }
2102 line.markedSpans = spans;
2103 }
2104
2105 // Helpers used when computing which overlapping collapsed span
2106 // counts as the larger one.
2107 function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
2108 function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
2109
2110 // Returns a number indicating which of two overlapping collapsed
2111 // spans is larger (and thus includes the other). Falls back to
2112 // comparing ids when the spans cover exactly the same range.
2113 function compareCollapsedMarkers(a, b) {
2114 var lenDiff = a.lines.length - b.lines.length;
2115 if (lenDiff != 0) { return lenDiff }
2116 var aPos = a.find(), bPos = b.find();
2117 var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
2118 if (fromCmp) { return -fromCmp }
2119 var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
2120 if (toCmp) { return toCmp }
2121 return b.id - a.id
2122 }
2123
2124 // Find out whether a line ends or starts in a collapsed span. If
2125 // so, return the marker for that span.
2126 function collapsedSpanAtSide(line, start) {
2127 var sps = sawCollapsedSpans && line.markedSpans, found;
2128 if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
2129 sp = sps[i];
2130 if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
2131 (!found || compareCollapsedMarkers(found, sp.marker) < 0))
2132 { found = sp.marker; }
2133 } }
2134 return found
2135 }
2136 function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
2137 function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
2138
2139 // Test whether there exists a collapsed span that partially
2140 // overlaps (covers the start or end, but not both) of a new span.
2141 // Such overlap is not allowed.
2142 function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) {
2143 var line = getLine(doc, lineNo$$1);
2144 var sps = sawCollapsedSpans && line.markedSpans;
2145 if (sps) { for (var i = 0; i < sps.length; ++i) {
2146 var sp = sps[i];
2147 if (!sp.marker.collapsed) { continue }
2148 var found = sp.marker.find(0);
2149 var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
2150 var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
2151 if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
2152 if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
2153 fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
2154 { return true }
2155 } }
2156 }
2157
2158 // A visual line is a line as drawn on the screen. Folding, for
2159 // example, can cause multiple logical lines to appear on the same
2160 // visual line. This finds the start of the visual line that the
2161 // given line is part of (usually that is the line itself).
2162 function visualLine(line) {
2163 var merged;
2164 while (merged = collapsedSpanAtStart(line))
2165 { line = merged.find(-1, true).line; }
2166 return line
2167 }
2168
2169 function visualLineEnd(line) {
2170 var merged;
2171 while (merged = collapsedSpanAtEnd(line))
2172 { line = merged.find(1, true).line; }
2173 return line
2174 }
2175
2176 // Returns an array of logical lines that continue the visual line
2177 // started by the argument, or undefined if there are no such lines.
2178 function visualLineContinued(line) {
2179 var merged, lines;
2180 while (merged = collapsedSpanAtEnd(line)) {
2181 line = merged.find(1, true).line
2182 ;(lines || (lines = [])).push(line);
2183 }
2184 return lines
2185 }
2186
2187 // Get the line number of the start of the visual line that the
2188 // given line number is part of.
2189 function visualLineNo(doc, lineN) {
2190 var line = getLine(doc, lineN), vis = visualLine(line);
2191 if (line == vis) { return lineN }
2192 return lineNo(vis)
2193 }
2194
2195 // Get the line number of the start of the next visual line after
2196 // the given line.
2197 function visualLineEndNo(doc, lineN) {
2198 if (lineN > doc.lastLine()) { return lineN }
2199 var line = getLine(doc, lineN), merged;
2200 if (!lineIsHidden(doc, line)) { return lineN }
2201 while (merged = collapsedSpanAtEnd(line))
2202 { line = merged.find(1, true).line; }
2203 return lineNo(line) + 1
2204 }
2205
2206 // Compute whether a line is hidden. Lines count as hidden when they
2207 // are part of a visual line that starts with another line, or when
2208 // they are entirely covered by collapsed, non-widget span.
2209 function lineIsHidden(doc, line) {
2210 var sps = sawCollapsedSpans && line.markedSpans;
2211 if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
2212 sp = sps[i];
2213 if (!sp.marker.collapsed) { continue }
2214 if (sp.from == null) { return true }
2215 if (sp.marker.widgetNode) { continue }
2216 if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
2217 { return true }
2218 } }
2219 }
2220 function lineIsHiddenInner(doc, line, span) {
2221 if (span.to == null) {
2222 var end = span.marker.find(1, true);
2223 return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
2224 }
2225 if (span.marker.inclusiveRight && span.to == line.text.length)
2226 { return true }
2227 for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {
2228 sp = line.markedSpans[i];
2229 if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
2230 (sp.to == null || sp.to != span.from) &&
2231 (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
2232 lineIsHiddenInner(doc, line, sp)) { return true }
2233 }
2234 }
2235
2236 // Find the height above the given line.
2237 function heightAtLine(lineObj) {
2238 lineObj = visualLine(lineObj);
2239
2240 var h = 0, chunk = lineObj.parent;
2241 for (var i = 0; i < chunk.lines.length; ++i) {
2242 var line = chunk.lines[i];
2243 if (line == lineObj) { break }
2244 else { h += line.height; }
2245 }
2246 for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
2247 for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
2248 var cur = p.children[i$1];
2249 if (cur == chunk) { break }
2250 else { h += cur.height; }
2251 }
2252 }
2253 return h
2254 }
2255
2256 // Compute the character length of a line, taking into account
2257 // collapsed ranges (see markText) that might hide parts, and join
2258 // other lines onto it.
2259 function lineLength(line) {
2260 if (line.height == 0) { return 0 }
2261 var len = line.text.length, merged, cur = line;
2262 while (merged = collapsedSpanAtStart(cur)) {
2263 var found = merged.find(0, true);
2264 cur = found.from.line;
2265 len += found.from.ch - found.to.ch;
2266 }
2267 cur = line;
2268 while (merged = collapsedSpanAtEnd(cur)) {
2269 var found$1 = merged.find(0, true);
2270 len -= cur.text.length - found$1.from.ch;
2271 cur = found$1.to.line;
2272 len += cur.text.length - found$1.to.ch;
2273 }
2274 return len
2275 }
2276
2277 // Find the longest line in the document.
2278 function findMaxLine(cm) {
2279 var d = cm.display, doc = cm.doc;
2280 d.maxLine = getLine(doc, doc.first);
2281 d.maxLineLength = lineLength(d.maxLine);
2282 d.maxLineChanged = true;
2283 doc.iter(function (line) {
2284 var len = lineLength(line);
2285 if (len > d.maxLineLength) {
2286 d.maxLineLength = len;
2287 d.maxLine = line;
2288 }
2289 });
2290 }
2291
2292 // BIDI HELPERS
2293
2294 function iterateBidiSections(order, from, to, f) {
2295 if (!order) { return f(from, to, "ltr") }
2296 var found = false;
2297 for (var i = 0; i < order.length; ++i) {
2298 var part = order[i];
2299 if (part.from < to && part.to > from || from == to && part.to == from) {
2300 f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
2301 found = true;
2302 }
2303 }
2304 if (!found) { f(from, to, "ltr"); }
2305 }
2306
2307 var bidiOther = null;
2308 function getBidiPartAt(order, ch, sticky) {
2309 var found;
2310 bidiOther = null;
2311 for (var i = 0; i < order.length; ++i) {
2312 var cur = order[i];
2313 if (cur.from < ch && cur.to > ch) { return i }
2314 if (cur.to == ch) {
2315 if (cur.from != cur.to && sticky == "before") { found = i; }
2316 else { bidiOther = i; }
2317 }
2318 if (cur.from == ch) {
2319 if (cur.from != cur.to && sticky != "before") { found = i; }
2320 else { bidiOther = i; }
2321 }
2322 }
2323 return found != null ? found : bidiOther
2324 }
2325
2326 // Bidirectional ordering algorithm
2327 // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
2328 // that this (partially) implements.
2329
2330 // One-char codes used for character types:
2331 // L (L): Left-to-Right
2332 // R (R): Right-to-Left
2333 // r (AL): Right-to-Left Arabic
2334 // 1 (EN): European Number
2335 // + (ES): European Number Separator
2336 // % (ET): European Number Terminator
2337 // n (AN): Arabic Number
2338 // , (CS): Common Number Separator
2339 // m (NSM): Non-Spacing Mark
2340 // b (BN): Boundary Neutral
2341 // s (B): Paragraph Separator
2342 // t (S): Segment Separator
2343 // w (WS): Whitespace
2344 // N (ON): Other Neutrals
2345
2346 // Returns null if characters are ordered as they appear
2347 // (left-to-right), or an array of sections ({from, to, level}
2348 // objects) in the order in which they occur visually.
2349 var bidiOrdering = (function() {
2350 // Character types for codepoints 0 to 0xff
2351 var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
2352 // Character types for codepoints 0x600 to 0x6f9
2353 var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";
2354 function charType(code) {
2355 if (code <= 0xf7) { return lowTypes.charAt(code) }
2356 else if (0x590 <= code && code <= 0x5f4) { return "R" }
2357 else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
2358 else if (0x6ee <= code && code <= 0x8ac) { return "r" }
2359 else if (0x2000 <= code && code <= 0x200b) { return "w" }
2360 else if (code == 0x200c) { return "b" }
2361 else { return "L" }
2362 }
2363
2364 var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
2365 var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
2366
2367 function BidiSpan(level, from, to) {
2368 this.level = level;
2369 this.from = from; this.to = to;
2370 }
2371
2372 return function(str, direction) {
2373 var outerType = direction == "ltr" ? "L" : "R";
2374
2375 if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false }
2376 var len = str.length, types = [];
2377 for (var i = 0; i < len; ++i)
2378 { types.push(charType(str.charCodeAt(i))); }
2379
2380 // W1. Examine each non-spacing mark (NSM) in the level run, and
2381 // change the type of the NSM to the type of the previous
2382 // character. If the NSM is at the start of the level run, it will
2383 // get the type of sor.
2384 for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
2385 var type = types[i$1];
2386 if (type == "m") { types[i$1] = prev; }
2387 else { prev = type; }
2388 }
2389
2390 // W2. Search backwards from each instance of a European number
2391 // until the first strong type (R, L, AL, or sor) is found. If an
2392 // AL is found, change the type of the European number to Arabic
2393 // number.
2394 // W3. Change all ALs to R.
2395 for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
2396 var type$1 = types[i$2];
2397 if (type$1 == "1" && cur == "r") { types[i$2] = "n"; }
2398 else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R"; } }
2399 }
2400
2401 // W4. A single European separator between two European numbers
2402 // changes to a European number. A single common separator between
2403 // two numbers of the same type changes to that type.
2404 for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
2405 var type$2 = types[i$3];
2406 if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1"; }
2407 else if (type$2 == "," && prev$1 == types[i$3+1] &&
2408 (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1; }
2409 prev$1 = type$2;
2410 }
2411
2412 // W5. A sequence of European terminators adjacent to European
2413 // numbers changes to all European numbers.
2414 // W6. Otherwise, separators and terminators change to Other
2415 // Neutral.
2416 for (var i$4 = 0; i$4 < len; ++i$4) {
2417 var type$3 = types[i$4];
2418 if (type$3 == ",") { types[i$4] = "N"; }
2419 else if (type$3 == "%") {
2420 var end = (void 0);
2421 for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
2422 var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
2423 for (var j = i$4; j < end; ++j) { types[j] = replace; }
2424 i$4 = end - 1;
2425 }
2426 }
2427
2428 // W7. Search backwards from each instance of a European number
2429 // until the first strong type (R, L, or sor) is found. If an L is
2430 // found, then change the type of the European number to L.
2431 for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
2432 var type$4 = types[i$5];
2433 if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L"; }
2434 else if (isStrong.test(type$4)) { cur$1 = type$4; }
2435 }
2436
2437 // N1. A sequence of neutrals takes the direction of the
2438 // surrounding strong text if the text on both sides has the same
2439 // direction. European and Arabic numbers act as if they were R in
2440 // terms of their influence on neutrals. Start-of-level-run (sor)
2441 // and end-of-level-run (eor) are used at level run boundaries.
2442 // N2. Any remaining neutrals take the embedding direction.
2443 for (var i$6 = 0; i$6 < len; ++i$6) {
2444 if (isNeutral.test(types[i$6])) {
2445 var end$1 = (void 0);
2446 for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
2447 var before = (i$6 ? types[i$6-1] : outerType) == "L";
2448 var after = (end$1 < len ? types[end$1] : outerType) == "L";
2449 var replace$1 = before == after ? (before ? "L" : "R") : outerType;
2450 for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }
2451 i$6 = end$1 - 1;
2452 }
2453 }
2454
2455 // Here we depart from the documented algorithm, in order to avoid
2456 // building up an actual levels array. Since there are only three
2457 // levels (0, 1, 2) in an implementation that doesn't take
2458 // explicit embedding into account, we can build up the order on
2459 // the fly, without following the level-based algorithm.
2460 var order = [], m;
2461 for (var i$7 = 0; i$7 < len;) {
2462 if (countsAsLeft.test(types[i$7])) {
2463 var start = i$7;
2464 for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
2465 order.push(new BidiSpan(0, start, i$7));
2466 } else {
2467 var pos = i$7, at = order.length;
2468 for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
2469 for (var j$2 = pos; j$2 < i$7;) {
2470 if (countsAsNum.test(types[j$2])) {
2471 if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); }
2472 var nstart = j$2;
2473 for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
2474 order.splice(at, 0, new BidiSpan(2, nstart, j$2));
2475 pos = j$2;
2476 } else { ++j$2; }
2477 }
2478 if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }
2479 }
2480 }
2481 if (order[0].level == 1 && (m = str.match(/^\s+/))) {
2482 order[0].from = m[0].length;
2483 order.unshift(new BidiSpan(0, 0, m[0].length));
2484 }
2485 if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
2486 lst(order).to -= m[0].length;
2487 order.push(new BidiSpan(0, len - m[0].length, len));
2488 }
2489
2490 return direction == "rtl" ? order.reverse() : order
2491 }
2492 })();
2493
2494 // Get the bidi ordering for the given line (and cache it). Returns
2495 // false for lines that are fully left-to-right, and an array of
2496 // BidiSpan objects otherwise.
2497 function getOrder(line, direction) {
2498 var order = line.order;
2499 if (order == null) { order = line.order = bidiOrdering(line.text, direction); }
2500 return order
2501 }
2502
2503 function moveCharLogically(line, ch, dir) {
2504 var target = skipExtendingChars(line.text, ch + dir, dir);
2505 return target < 0 || target > line.text.length ? null : target
2506 }
2507
2508 function moveLogically(line, start, dir) {
2509 var ch = moveCharLogically(line, start.ch, dir);
2510 return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
2511 }
2512
2513 function endOfLine(visually, cm, lineObj, lineNo, dir) {
2514 if (visually) {
2515 var order = getOrder(lineObj, cm.doc.direction);
2516 if (order) {
2517 var part = dir < 0 ? lst(order) : order[0];
2518 var moveInStorageOrder = (dir < 0) == (part.level == 1);
2519 var sticky = moveInStorageOrder ? "after" : "before";
2520 var ch;
2521 // With a wrapped rtl chunk (possibly spanning multiple bidi parts),
2522 // it could be that the last bidi part is not on the last visual line,
2523 // since visual lines contain content order-consecutive chunks.
2524 // Thus, in rtl, we are looking for the first (content-order) character
2525 // in the rtl chunk that is on the last line (that is, the same line
2526 // as the last (content-order) character).
2527 if (part.level > 0) {
2528 var prep = prepareMeasureForLine(cm, lineObj);
2529 ch = dir < 0 ? lineObj.text.length - 1 : 0;
2530 var targetTop = measureCharPrepared(cm, prep, ch).top;
2531 ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch);
2532 if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1); }
2533 } else { ch = dir < 0 ? part.to : part.from; }
2534 return new Pos(lineNo, ch, sticky)
2535 }
2536 }
2537 return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
2538 }
2539
2540 function moveVisually(cm, line, start, dir) {
2541 var bidi = getOrder(line, cm.doc.direction);
2542 if (!bidi) { return moveLogically(line, start, dir) }
2543 if (start.ch >= line.text.length) {
2544 start.ch = line.text.length;
2545 start.sticky = "before";
2546 } else if (start.ch <= 0) {
2547 start.ch = 0;
2548 start.sticky = "after";
2549 }
2550 var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos];
2551 if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
2552 // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
2553 // nothing interesting happens.
2554 return moveLogically(line, start, dir)
2555 }
2556
2557 var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); };
2558 var prep;
2559 var getWrappedLineExtent = function (ch) {
2560 if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
2561 prep = prep || prepareMeasureForLine(cm, line);
2562 return wrappedLineExtentChar(cm, line, prep, ch)
2563 };
2564 var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch);
2565
2566 if (cm.doc.direction == "rtl" || part.level == 1) {
2567 var moveInStorageOrder = (part.level == 1) == (dir < 0);
2568 var ch = mv(start, moveInStorageOrder ? 1 : -1);
2569 if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
2570 // Case 2: We move within an rtl part or in an rtl editor on the same visual line
2571 var sticky = moveInStorageOrder ? "before" : "after";
2572 return new Pos(start.line, ch, sticky)
2573 }
2574 }
2575
2576 // Case 3: Could not move within this bidi part in this visual line, so leave
2577 // the current bidi part
2578
2579 var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
2580 var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
2581 ? new Pos(start.line, mv(ch, 1), "before")
2582 : new Pos(start.line, ch, "after"); };
2583
2584 for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
2585 var part = bidi[partPos];
2586 var moveInStorageOrder = (dir > 0) == (part.level != 1);
2587 var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1);
2588 if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
2589 ch = moveInStorageOrder ? part.from : mv(part.to, -1);
2590 if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
2591 }
2592 };
2593
2594 // Case 3a: Look for other bidi parts on the same visual line
2595 var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent);
2596 if (res) { return res }
2597
2598 // Case 3b: Look for other bidi parts on the next visual line
2599 var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1);
2600 if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
2601 res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh));
2602 if (res) { return res }
2603 }
2604
2605 // Case 4: Nowhere to move
2606 return null
2607 }
2608
2609 // EVENT HANDLING
2610
2611 // Lightweight event framework. on/off also work on DOM nodes,
2612 // registering native DOM handlers.
2613
2614 var noHandlers = [];
2615
2616 var on = function(emitter, type, f) {
2617 if (emitter.addEventListener) {
2618 emitter.addEventListener(type, f, false);
2619 } else if (emitter.attachEvent) {
2620 emitter.attachEvent("on" + type, f);
2621 } else {
2622 var map$$1 = emitter._handlers || (emitter._handlers = {});
2623 map$$1[type] = (map$$1[type] || noHandlers).concat(f);
2624 }
2625 };
2626
2627 function getHandlers(emitter, type) {
2628 return emitter._handlers && emitter._handlers[type] || noHandlers
2629 }
2630
2631 function off(emitter, type, f) {
2632 if (emitter.removeEventListener) {
2633 emitter.removeEventListener(type, f, false);
2634 } else if (emitter.detachEvent) {
2635 emitter.detachEvent("on" + type, f);
2636 } else {
2637 var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type];
2638 if (arr) {
2639 var index = indexOf(arr, f);
2640 if (index > -1)
2641 { map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }
2642 }
2643 }
2644 }
2645
2646 function signal(emitter, type /*, values...*/) {
2647 var handlers = getHandlers(emitter, type);
2648 if (!handlers.length) { return }
2649 var args = Array.prototype.slice.call(arguments, 2);
2650 for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }
2651 }
2652
2653 // The DOM events that CodeMirror handles can be overridden by
2654 // registering a (non-DOM) handler on the editor for the event name,
2655 // and preventDefault-ing the event in that handler.
2656 function signalDOMEvent(cm, e, override) {
2657 if (typeof e == "string")
2658 { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }
2659 signal(cm, override || e.type, cm, e);
2660 return e_defaultPrevented(e) || e.codemirrorIgnore
2661 }
2662
2663 function signalCursorActivity(cm) {
2664 var arr = cm._handlers && cm._handlers.cursorActivity;
2665 if (!arr) { return }
2666 var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
2667 for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
2668 { set.push(arr[i]); } }
2669 }
2670
2671 function hasHandler(emitter, type) {
2672 return getHandlers(emitter, type).length > 0
2673 }
2674
2675 // Add on and off methods to a constructor's prototype, to make
2676 // registering events on such objects more convenient.
2677 function eventMixin(ctor) {
2678 ctor.prototype.on = function(type, f) {on(this, type, f);};
2679 ctor.prototype.off = function(type, f) {off(this, type, f);};
2680 }
2681
2682 // Due to the fact that we still support jurassic IE versions, some
2683 // compatibility wrappers are needed.
2684
2685 function e_preventDefault(e) {
2686 if (e.preventDefault) { e.preventDefault(); }
2687 else { e.returnValue = false; }
2688 }
2689 function e_stopPropagation(e) {
2690 if (e.stopPropagation) { e.stopPropagation(); }
2691 else { e.cancelBubble = true; }
2692 }
2693 function e_defaultPrevented(e) {
2694 return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
2695 }
2696 function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
2697
2698 function e_target(e) {return e.target || e.srcElement}
2699 function e_button(e) {
2700 var b = e.which;
2701 if (b == null) {
2702 if (e.button & 1) { b = 1; }
2703 else if (e.button & 2) { b = 3; }
2704 else if (e.button & 4) { b = 2; }
2705 }
2706 if (mac && e.ctrlKey && b == 1) { b = 3; }
2707 return b
2708 }
2709
2710 // Detect drag-and-drop
2711 var dragAndDrop = function() {
2712 // There is *some* kind of drag-and-drop support in IE6-8, but I
2713 // couldn't get it to work yet.
2714 if (ie && ie_version < 9) { return false }
2715 var div = elt('div');
2716 return "draggable" in div || "dragDrop" in div
2717 }();
2718
2719 var zwspSupported;
2720 function zeroWidthElement(measure) {
2721 if (zwspSupported == null) {
2722 var test = elt("span", "\u200b");
2723 removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
2724 if (measure.firstChild.offsetHeight != 0)
2725 { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }
2726 }
2727 var node = zwspSupported ? elt("span", "\u200b") :
2728 elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
2729 node.setAttribute("cm-text", "");
2730 return node
2731 }
2732
2733 // Feature-detect IE's crummy client rect reporting for bidi text
2734 var badBidiRects;
2735 function hasBadBidiRects(measure) {
2736 if (badBidiRects != null) { return badBidiRects }
2737 var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
2738 var r0 = range(txt, 0, 1).getBoundingClientRect();
2739 var r1 = range(txt, 1, 2).getBoundingClientRect();
2740 removeChildren(measure);
2741 if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)
2742 return badBidiRects = (r1.right - r0.right < 3)
2743 }
2744
2745 // See if "".split is the broken IE version, if so, provide an
2746 // alternative way to split lines.
2747 var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) {
2748 var pos = 0, result = [], l = string.length;
2749 while (pos <= l) {
2750 var nl = string.indexOf("\n", pos);
2751 if (nl == -1) { nl = string.length; }
2752 var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
2753 var rt = line.indexOf("\r");
2754 if (rt != -1) {
2755 result.push(line.slice(0, rt));
2756 pos += rt + 1;
2757 } else {
2758 result.push(line);
2759 pos = nl + 1;
2760 }
2761 }
2762 return result
2763 } : function (string) { return string.split(/\r\n?|\n/); };
2764
2765 var hasSelection = window.getSelection ? function (te) {
2766 try { return te.selectionStart != te.selectionEnd }
2767 catch(e) { return false }
2768 } : function (te) {
2769 var range$$1;
2770 try {range$$1 = te.ownerDocument.selection.createRange();}
2771 catch(e) {}
2772 if (!range$$1 || range$$1.parentElement() != te) { return false }
2773 return range$$1.compareEndPoints("StartToEnd", range$$1) != 0
2774 };
2775
2776 var hasCopyEvent = (function () {
2777 var e = elt("div");
2778 if ("oncopy" in e) { return true }
2779 e.setAttribute("oncopy", "return;");
2780 return typeof e.oncopy == "function"
2781 })();
2782
2783 var badZoomedRects = null;
2784 function hasBadZoomedRects(measure) {
2785 if (badZoomedRects != null) { return badZoomedRects }
2786 var node = removeChildrenAndAdd(measure, elt("span", "x"));
2787 var normal = node.getBoundingClientRect();
2788 var fromRange = range(node, 0, 1).getBoundingClientRect();
2789 return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
2790 }
2791
2792 // Known modes, by name and by MIME
2793 var modes = {};
2794 var mimeModes = {};
2795
2796 // Extra arguments are stored as the mode's dependencies, which is
2797 // used by (legacy) mechanisms like loadmode.js to automatically
2798 // load a mode. (Preferred mechanism is the require/define calls.)
2799 function defineMode(name, mode) {
2800 if (arguments.length > 2)
2801 { mode.dependencies = Array.prototype.slice.call(arguments, 2); }
2802 modes[name] = mode;
2803 }
2804
2805 function defineMIME(mime, spec) {
2806 mimeModes[mime] = spec;
2807 }
2808
2809 // Given a MIME type, a {name, ...options} config object, or a name
2810 // string, return a mode config object.
2811 function resolveMode(spec) {
2812 if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
2813 spec = mimeModes[spec];
2814 } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
2815 var found = mimeModes[spec.name];
2816 if (typeof found == "string") { found = {name: found}; }
2817 spec = createObj(found, spec);
2818 spec.name = found.name;
2819 } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
2820 return resolveMode("application/xml")
2821 } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
2822 return resolveMode("application/json")
2823 }
2824 if (typeof spec == "string") { return {name: spec} }
2825 else { return spec || {name: "null"} }
2826 }
2827
2828 // Given a mode spec (anything that resolveMode accepts), find and
2829 // initialize an actual mode object.
2830 function getMode(options, spec) {
2831 spec = resolveMode(spec);
2832 var mfactory = modes[spec.name];
2833 if (!mfactory) { return getMode(options, "text/plain") }
2834 var modeObj = mfactory(options, spec);
2835 if (modeExtensions.hasOwnProperty(spec.name)) {
2836 var exts = modeExtensions[spec.name];
2837 for (var prop in exts) {
2838 if (!exts.hasOwnProperty(prop)) { continue }
2839 if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; }
2840 modeObj[prop] = exts[prop];
2841 }
2842 }
2843 modeObj.name = spec.name;
2844 if (spec.helperType) { modeObj.helperType = spec.helperType; }
2845 if (spec.modeProps) { for (var prop$1 in spec.modeProps)
2846 { modeObj[prop$1] = spec.modeProps[prop$1]; } }
2847
2848 return modeObj
2849 }
2850
2851 // This can be used to attach properties to mode objects from
2852 // outside the actual mode definition.
2853 var modeExtensions = {};
2854 function extendMode(mode, properties) {
2855 var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
2856 copyObj(properties, exts);
2857 }
2858
2859 function copyState(mode, state) {
2860 if (state === true) { return state }
2861 if (mode.copyState) { return mode.copyState(state) }
2862 var nstate = {};
2863 for (var n in state) {
2864 var val = state[n];
2865 if (val instanceof Array) { val = val.concat([]); }
2866 nstate[n] = val;
2867 }
2868 return nstate
2869 }
2870
2871 // Given a mode and a state (for that mode), find the inner mode and
2872 // state at the position that the state refers to.
2873 function innerMode(mode, state) {
2874 var info;
2875 while (mode.innerMode) {
2876 info = mode.innerMode(state);
2877 if (!info || info.mode == mode) { break }
2878 state = info.state;
2879 mode = info.mode;
2880 }
2881 return info || {mode: mode, state: state}
2882 }
2883
2884 function startState(mode, a1, a2) {
2885 return mode.startState ? mode.startState(a1, a2) : true
2886 }
2887
2888 // STRING STREAM
2889
2890 // Fed to the mode parsers, provides helper functions to make
2891 // parsers more succinct.
2892
2893 var StringStream = function(string, tabSize, lineOracle) {
2894 this.pos = this.start = 0;
2895 this.string = string;
2896 this.tabSize = tabSize || 8;
2897 this.lastColumnPos = this.lastColumnValue = 0;
2898 this.lineStart = 0;
2899 this.lineOracle = lineOracle;
2900 };
2901
2902 StringStream.prototype.eol = function () {return this.pos >= this.string.length};
2903 StringStream.prototype.sol = function () {return this.pos == this.lineStart};
2904 StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
2905 StringStream.prototype.next = function () {
2906 if (this.pos < this.string.length)
2907 { return this.string.charAt(this.pos++) }
2908 };
2909 StringStream.prototype.eat = function (match) {
2910 var ch = this.string.charAt(this.pos);
2911 var ok;
2912 if (typeof match == "string") { ok = ch == match; }
2913 else { ok = ch && (match.test ? match.test(ch) : match(ch)); }
2914 if (ok) {++this.pos; return ch}
2915 };
2916 StringStream.prototype.eatWhile = function (match) {
2917 var start = this.pos;
2918 while (this.eat(match)){}
2919 return this.pos > start
2920 };
2921 StringStream.prototype.eatSpace = function () {
2922 var this$1 = this;
2923
2924 var start = this.pos;
2925 while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos; }
2926 return this.pos > start
2927 };
2928 StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};
2929 StringStream.prototype.skipTo = function (ch) {
2930 var found = this.string.indexOf(ch, this.pos);
2931 if (found > -1) {this.pos = found; return true}
2932 };
2933 StringStream.prototype.backUp = function (n) {this.pos -= n;};
2934 StringStream.prototype.column = function () {
2935 if (this.lastColumnPos < this.start) {
2936 this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
2937 this.lastColumnPos = this.start;
2938 }
2939 return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
2940 };
2941 StringStream.prototype.indentation = function () {
2942 return countColumn(this.string, null, this.tabSize) -
2943 (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
2944 };
2945 StringStream.prototype.match = function (pattern, consume, caseInsensitive) {
2946 if (typeof pattern == "string") {
2947 var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };
2948 var substr = this.string.substr(this.pos, pattern.length);
2949 if (cased(substr) == cased(pattern)) {
2950 if (consume !== false) { this.pos += pattern.length; }
2951 return true
2952 }
2953 } else {
2954 var match = this.string.slice(this.pos).match(pattern);
2955 if (match && match.index > 0) { return null }
2956 if (match && consume !== false) { this.pos += match[0].length; }
2957 return match
2958 }
2959 };
2960 StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};
2961 StringStream.prototype.hideFirstChars = function (n, inner) {
2962 this.lineStart += n;
2963 try { return inner() }
2964 finally { this.lineStart -= n; }
2965 };
2966 StringStream.prototype.lookAhead = function (n) {
2967 var oracle = this.lineOracle;
2968 return oracle && oracle.lookAhead(n)
2969 };
2970
2971 var SavedContext = function(state, lookAhead) {
2972 this.state = state;
2973 this.lookAhead = lookAhead;
2974 };
2975
2976 var Context = function(doc, state, line, lookAhead) {
2977 this.state = state;
2978 this.doc = doc;
2979 this.line = line;
2980 this.maxLookAhead = lookAhead || 0;
2981 };
2982
2983 Context.prototype.lookAhead = function (n) {
2984 var line = this.doc.getLine(this.line + n);
2985 if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; }
2986 return line
2987 };
2988
2989 Context.prototype.nextLine = function () {
2990 this.line++;
2991 if (this.maxLookAhead > 0) { this.maxLookAhead--; }
2992 };
2993
2994 Context.fromSaved = function (doc, saved, line) {
2995 if (saved instanceof SavedContext)
2996 { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) }
2997 else
2998 { return new Context(doc, copyState(doc.mode, saved), line) }
2999 };
3000
3001 Context.prototype.save = function (copy) {
3002 var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state;
3003 return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state
3004 };
3005
3006
3007 // Compute a style array (an array starting with a mode generation
3008 // -- for invalidation -- followed by pairs of end positions and
3009 // style strings), which is used to highlight the tokens on the
3010 // line.
3011 function highlightLine(cm, line, context, forceToEnd) {
3012 // A styles array always starts with a number identifying the
3013 // mode/overlays that it is based on (for easy invalidation).
3014 var st = [cm.state.modeGen], lineClasses = {};
3015 // Compute the base array of styles
3016 runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); },
3017 lineClasses, forceToEnd);
3018 var state = context.state;
3019
3020 // Run overlays, adjust style array.
3021 var loop = function ( o ) {
3022 var overlay = cm.state.overlays[o], i = 1, at = 0;
3023 context.state = true;
3024 runMode(cm, line.text, overlay.mode, context, function (end, style) {
3025 var start = i;
3026 // Ensure there's a token end at the current position, and that i points at it
3027 while (at < end) {
3028 var i_end = st[i];
3029 if (i_end > end)
3030 { st.splice(i, 1, end, st[i+1], i_end); }
3031 i += 2;
3032 at = Math.min(end, i_end);
3033 }
3034 if (!style) { return }
3035 if (overlay.opaque) {
3036 st.splice(start, i - start, end, "overlay " + style);
3037 i = start + 2;
3038 } else {
3039 for (; start < i; start += 2) {
3040 var cur = st[start+1];
3041 st[start+1] = (cur ? cur + " " : "") + "overlay " + style;
3042 }
3043 }
3044 }, lineClasses);
3045 };
3046
3047 for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );
3048 context.state = state;
3049
3050 return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
3051 }
3052
3053 function getLineStyles(cm, line, updateFrontier) {
3054 if (!line.styles || line.styles[0] != cm.state.modeGen) {
3055 var context = getContextBefore(cm, lineNo(line));
3056 var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state);
3057 var result = highlightLine(cm, line, context);
3058 if (resetState) { context.state = resetState; }
3059 line.stateAfter = context.save(!resetState);
3060 line.styles = result.styles;
3061 if (result.classes) { line.styleClasses = result.classes; }
3062 else if (line.styleClasses) { line.styleClasses = null; }
3063 if (updateFrontier === cm.doc.highlightFrontier)
3064 { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }
3065 }
3066 return line.styles
3067 }
3068
3069 function getContextBefore(cm, n, precise) {
3070 var doc = cm.doc, display = cm.display;
3071 if (!doc.mode.startState) { return new Context(doc, true, n) }
3072 var start = findStartLine(cm, n, precise);
3073 var saved = start > doc.first && getLine(doc, start - 1).stateAfter;
3074 var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start);
3075
3076 doc.iter(start, n, function (line) {
3077 processLine(cm, line.text, context);
3078 var pos = context.line;
3079 line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null;
3080 context.nextLine();
3081 });
3082 if (precise) { doc.modeFrontier = context.line; }
3083 return context
3084 }
3085
3086 // Lightweight form of highlight -- proceed over this line and
3087 // update state, but don't save a style array. Used for lines that
3088 // aren't currently visible.
3089 function processLine(cm, text, context, startAt) {
3090 var mode = cm.doc.mode;
3091 var stream = new StringStream(text, cm.options.tabSize, context);
3092 stream.start = stream.pos = startAt || 0;
3093 if (text == "") { callBlankLine(mode, context.state); }
3094 while (!stream.eol()) {
3095 readToken(mode, stream, context.state);
3096 stream.start = stream.pos;
3097 }
3098 }
3099
3100 function callBlankLine(mode, state) {
3101 if (mode.blankLine) { return mode.blankLine(state) }
3102 if (!mode.innerMode) { return }
3103 var inner = innerMode(mode, state);
3104 if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
3105 }
3106
3107 function readToken(mode, stream, state, inner) {
3108 for (var i = 0; i < 10; i++) {
3109 if (inner) { inner[0] = innerMode(mode, state).mode; }
3110 var style = mode.token(stream, state);
3111 if (stream.pos > stream.start) { return style }
3112 }
3113 throw new Error("Mode " + mode.name + " failed to advance stream.")
3114 }
3115
3116 var Token = function(stream, type, state) {
3117 this.start = stream.start; this.end = stream.pos;
3118 this.string = stream.current();
3119 this.type = type || null;
3120 this.state = state;
3121 };
3122
3123 // Utility for getTokenAt and getLineTokens
3124 function takeToken(cm, pos, precise, asArray) {
3125 var doc = cm.doc, mode = doc.mode, style;
3126 pos = clipPos(doc, pos);
3127 var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise);
3128 var stream = new StringStream(line.text, cm.options.tabSize, context), tokens;
3129 if (asArray) { tokens = []; }
3130 while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
3131 stream.start = stream.pos;
3132 style = readToken(mode, stream, context.state);
3133 if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); }
3134 }
3135 return asArray ? tokens : new Token(stream, style, context.state)
3136 }
3137
3138 function extractLineClasses(type, output) {
3139 if (type) { for (;;) {
3140 var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
3141 if (!lineClass) { break }
3142 type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
3143 var prop = lineClass[1] ? "bgClass" : "textClass";
3144 if (output[prop] == null)
3145 { output[prop] = lineClass[2]; }
3146 else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
3147 { output[prop] += " " + lineClass[2]; }
3148 } }
3149 return type
3150 }
3151
3152 // Run the given mode's parser over a line, calling f for each token.
3153 function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {
3154 var flattenSpans = mode.flattenSpans;
3155 if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; }
3156 var curStart = 0, curStyle = null;
3157 var stream = new StringStream(text, cm.options.tabSize, context), style;
3158 var inner = cm.options.addModeClass && [null];
3159 if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); }
3160 while (!stream.eol()) {
3161 if (stream.pos > cm.options.maxHighlightLength) {
3162 flattenSpans = false;
3163 if (forceToEnd) { processLine(cm, text, context, stream.pos); }
3164 stream.pos = text.length;
3165 style = null;
3166 } else {
3167 style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses);
3168 }
3169 if (inner) {
3170 var mName = inner[0].name;
3171 if (mName) { style = "m-" + (style ? mName + " " + style : mName); }
3172 }
3173 if (!flattenSpans || curStyle != style) {
3174 while (curStart < stream.start) {
3175 curStart = Math.min(stream.start, curStart + 5000);
3176 f(curStart, curStyle);
3177 }
3178 curStyle = style;
3179 }
3180 stream.start = stream.pos;
3181 }
3182 while (curStart < stream.pos) {
3183 // Webkit seems to refuse to render text nodes longer than 57444
3184 // characters, and returns inaccurate measurements in nodes
3185 // starting around 5000 chars.
3186 var pos = Math.min(stream.pos, curStart + 5000);
3187 f(pos, curStyle);
3188 curStart = pos;
3189 }
3190 }
3191
3192 // Finds the line to start with when starting a parse. Tries to
3193 // find a line with a stateAfter, so that it can start with a
3194 // valid state. If that fails, it returns the line with the
3195 // smallest indentation, which tends to need the least context to
3196 // parse correctly.
3197 function findStartLine(cm, n, precise) {
3198 var minindent, minline, doc = cm.doc;
3199 var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
3200 for (var search = n; search > lim; --search) {
3201 if (search <= doc.first) { return doc.first }
3202 var line = getLine(doc, search - 1), after = line.stateAfter;
3203 if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))
3204 { return search }
3205 var indented = countColumn(line.text, null, cm.options.tabSize);
3206 if (minline == null || minindent > indented) {
3207 minline = search - 1;
3208 minindent = indented;
3209 }
3210 }
3211 return minline
3212 }
3213
3214 function retreatFrontier(doc, n) {
3215 doc.modeFrontier = Math.min(doc.modeFrontier, n);
3216 if (doc.highlightFrontier < n - 10) { return }
3217 var start = doc.first;
3218 for (var line = n - 1; line > start; line--) {
3219 var saved = getLine(doc, line).stateAfter;
3220 // change is on 3
3221 // state on line 1 looked ahead 2 -- so saw 3
3222 // test 1 + 2 < 3 should cover this
3223 if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {
3224 start = line + 1;
3225 break
3226 }
3227 }
3228 doc.highlightFrontier = Math.min(doc.highlightFrontier, start);
3229 }
3230
3231 // LINE DATA STRUCTURE
3232
3233 // Line objects. These hold state related to a line, including
3234 // highlighting info (the styles array).
3235 var Line = function(text, markedSpans, estimateHeight) {
3236 this.text = text;
3237 attachMarkedSpans(this, markedSpans);
3238 this.height = estimateHeight ? estimateHeight(this) : 1;
3239 };
3240
3241 Line.prototype.lineNo = function () { return lineNo(this) };
3242 eventMixin(Line);
3243
3244 // Change the content (text, markers) of a line. Automatically
3245 // invalidates cached information and tries to re-estimate the
3246 // line's height.
3247 function updateLine(line, text, markedSpans, estimateHeight) {
3248 line.text = text;
3249 if (line.stateAfter) { line.stateAfter = null; }
3250 if (line.styles) { line.styles = null; }
3251 if (line.order != null) { line.order = null; }
3252 detachMarkedSpans(line);
3253 attachMarkedSpans(line, markedSpans);
3254 var estHeight = estimateHeight ? estimateHeight(line) : 1;
3255 if (estHeight != line.height) { updateLineHeight(line, estHeight); }
3256 }
3257
3258 // Detach a line from the document tree and its markers.
3259 function cleanUpLine(line) {
3260 line.parent = null;
3261 detachMarkedSpans(line);
3262 }
3263
3264 // Convert a style as returned by a mode (either null, or a string
3265 // containing one or more styles) to a CSS style. This is cached,
3266 // and also looks for line-wide styles.
3267 var styleToClassCache = {};
3268 var styleToClassCacheWithMode = {};
3269 function interpretTokenStyle(style, options) {
3270 if (!style || /^\s*$/.test(style)) { return null }
3271 var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
3272 return cache[style] ||
3273 (cache[style] = style.replace(/\S+/g, "cm-$&"))
3274 }
3275
3276 // Render the DOM representation of the text of a line. Also builds
3277 // up a 'line map', which points at the DOM nodes that represent
3278 // specific stretches of text, and is used by the measuring code.
3279 // The returned object contains the DOM node, this map, and
3280 // information about line-wide styles that were set by the mode.
3281 function buildLineContent(cm, lineView) {
3282 // The padding-right forces the element to have a 'border', which
3283 // is needed on Webkit to be able to get line-level bounding
3284 // rectangles for it (in measureChar).
3285 var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null);
3286 var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content,
3287 col: 0, pos: 0, cm: cm,
3288 trailingSpace: false,
3289 splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")};
3290 lineView.measure = {};
3291
3292 // Iterate over the logical lines that make up this visual line.
3293 for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
3294 var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0);
3295 builder.pos = 0;
3296 builder.addToken = buildToken;
3297 // Optionally wire in some hacks into the token-rendering
3298 // algorithm, to deal with browser quirks.
3299 if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction)))
3300 { builder.addToken = buildTokenBadBidi(builder.addToken, order); }
3301 builder.map = [];
3302 var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
3303 insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
3304 if (line.styleClasses) {
3305 if (line.styleClasses.bgClass)
3306 { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); }
3307 if (line.styleClasses.textClass)
3308 { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); }
3309 }
3310
3311 // Ensure at least a single node is present, for measuring.
3312 if (builder.map.length == 0)
3313 { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); }
3314
3315 // Store the map and a cache object for the current logical line
3316 if (i == 0) {
3317 lineView.measure.map = builder.map;
3318 lineView.measure.cache = {};
3319 } else {
3320 (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)
3321 ;(lineView.measure.caches || (lineView.measure.caches = [])).push({});
3322 }
3323 }
3324
3325 // See issue #2901
3326 if (webkit) {
3327 var last = builder.content.lastChild;
3328 if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
3329 { builder.content.className = "cm-tab-wrap-hack"; }
3330 }
3331
3332 signal(cm, "renderLine", cm, lineView.line, builder.pre);
3333 if (builder.pre.className)
3334 { builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); }
3335
3336 return builder
3337 }
3338
3339 function defaultSpecialCharPlaceholder(ch) {
3340 var token = elt("span", "\u2022", "cm-invalidchar");
3341 token.title = "\\u" + ch.charCodeAt(0).toString(16);
3342 token.setAttribute("aria-label", token.title);
3343 return token
3344 }
3345
3346 // Build up the DOM representation for a single token, and add it to
3347 // the line map. Takes care to render special characters separately.
3348 function buildToken(builder, text, style, startStyle, endStyle, title, css) {
3349 if (!text) { return }
3350 var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;
3351 var special = builder.cm.state.specialChars, mustWrap = false;
3352 var content;
3353 if (!special.test(text)) {
3354 builder.col += text.length;
3355 content = document.createTextNode(displayText);
3356 builder.map.push(builder.pos, builder.pos + text.length, content);
3357 if (ie && ie_version < 9) { mustWrap = true; }
3358 builder.pos += text.length;
3359 } else {
3360 content = document.createDocumentFragment();
3361 var pos = 0;
3362 while (true) {
3363 special.lastIndex = pos;
3364 var m = special.exec(text);
3365 var skipped = m ? m.index - pos : text.length - pos;
3366 if (skipped) {
3367 var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
3368 if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])); }
3369 else { content.appendChild(txt); }
3370 builder.map.push(builder.pos, builder.pos + skipped, txt);
3371 builder.col += skipped;
3372 builder.pos += skipped;
3373 }
3374 if (!m) { break }
3375 pos += skipped + 1;
3376 var txt$1 = (void 0);
3377 if (m[0] == "\t") {
3378 var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
3379 txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
3380 txt$1.setAttribute("role", "presentation");
3381 txt$1.setAttribute("cm-text", "\t");
3382 builder.col += tabWidth;
3383 } else if (m[0] == "\r" || m[0] == "\n") {
3384 txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
3385 txt$1.setAttribute("cm-text", m[0]);
3386 builder.col += 1;
3387 } else {
3388 txt$1 = builder.cm.options.specialCharPlaceholder(m[0]);
3389 txt$1.setAttribute("cm-text", m[0]);
3390 if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])); }
3391 else { content.appendChild(txt$1); }
3392 builder.col += 1;
3393 }
3394 builder.map.push(builder.pos, builder.pos + 1, txt$1);
3395 builder.pos++;
3396 }
3397 }
3398 builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32;
3399 if (style || startStyle || endStyle || mustWrap || css) {
3400 var fullStyle = style || "";
3401 if (startStyle) { fullStyle += startStyle; }
3402 if (endStyle) { fullStyle += endStyle; }
3403 var token = elt("span", [content], fullStyle, css);
3404 if (title) { token.title = title; }
3405 return builder.content.appendChild(token)
3406 }
3407 builder.content.appendChild(content);
3408 }
3409
3410 function splitSpaces(text, trailingBefore) {
3411 if (text.length > 1 && !/ /.test(text)) { return text }
3412 var spaceBefore = trailingBefore, result = "";
3413 for (var i = 0; i < text.length; i++) {
3414 var ch = text.charAt(i);
3415 if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))
3416 { ch = "\u00a0"; }
3417 result += ch;
3418 spaceBefore = ch == " ";
3419 }
3420 return result
3421 }
3422
3423 // Work around nonsense dimensions being reported for stretches of
3424 // right-to-left text.
3425 function buildTokenBadBidi(inner, order) {
3426 return function (builder, text, style, startStyle, endStyle, title, css) {
3427 style = style ? style + " cm-force-border" : "cm-force-border";
3428 var start = builder.pos, end = start + text.length;
3429 for (;;) {
3430 // Find the part that overlaps with the start of this text
3431 var part = (void 0);
3432 for (var i = 0; i < order.length; i++) {
3433 part = order[i];
3434 if (part.to > start && part.from <= start) { break }
3435 }
3436 if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) }
3437 inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);
3438 startStyle = null;
3439 text = text.slice(part.to - start);
3440 start = part.to;
3441 }
3442 }
3443 }
3444
3445 function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
3446 var widget = !ignoreWidget && marker.widgetNode;
3447 if (widget) { builder.map.push(builder.pos, builder.pos + size, widget); }
3448 if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
3449 if (!widget)
3450 { widget = builder.content.appendChild(document.createElement("span")); }
3451 widget.setAttribute("cm-marker", marker.id);
3452 }
3453 if (widget) {
3454 builder.cm.display.input.setUneditable(widget);
3455 builder.content.appendChild(widget);
3456 }
3457 builder.pos += size;
3458 builder.trailingSpace = false;
3459 }
3460
3461 // Outputs a number of spans to make up a line, taking highlighting
3462 // and marked text into account.
3463 function insertLineContent(line, builder, styles) {
3464 var spans = line.markedSpans, allText = line.text, at = 0;
3465 if (!spans) {
3466 for (var i$1 = 1; i$1 < styles.length; i$1+=2)
3467 { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); }
3468 return
3469 }
3470
3471 var len = allText.length, pos = 0, i = 1, text = "", style, css;
3472 var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
3473 for (;;) {
3474 if (nextChange == pos) { // Update current marker set
3475 spanStyle = spanEndStyle = spanStartStyle = title = css = "";
3476 collapsed = null; nextChange = Infinity;
3477 var foundBookmarks = [], endStyles = (void 0);
3478 for (var j = 0; j < spans.length; ++j) {
3479 var sp = spans[j], m = sp.marker;
3480 if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
3481 foundBookmarks.push(m);
3482 } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
3483 if (sp.to != null && sp.to != pos && nextChange > sp.to) {
3484 nextChange = sp.to;
3485 spanEndStyle = "";
3486 }
3487 if (m.className) { spanStyle += " " + m.className; }
3488 if (m.css) { css = (css ? css + ";" : "") + m.css; }
3489 if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle; }
3490 if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); }
3491 if (m.title && !title) { title = m.title; }
3492 if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
3493 { collapsed = sp; }
3494 } else if (sp.from > pos && nextChange > sp.from) {
3495 nextChange = sp.from;
3496 }
3497 }
3498 if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)
3499 { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1]; } } }
3500
3501 if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)
3502 { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]); } }
3503 if (collapsed && (collapsed.from || 0) == pos) {
3504 buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
3505 collapsed.marker, collapsed.from == null);
3506 if (collapsed.to == null) { return }
3507 if (collapsed.to == pos) { collapsed = false; }
3508 }
3509 }
3510 if (pos >= len) { break }
3511
3512 var upto = Math.min(len, nextChange);
3513 while (true) {
3514 if (text) {
3515 var end = pos + text.length;
3516 if (!collapsed) {
3517 var tokenText = end > upto ? text.slice(0, upto - pos) : text;
3518 builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
3519 spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
3520 }
3521 if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
3522 pos = end;
3523 spanStartStyle = "";
3524 }
3525 text = allText.slice(at, at = styles[i++]);
3526 style = interpretTokenStyle(styles[i++], builder.cm.options);
3527 }
3528 }
3529 }
3530
3531
3532 // These objects are used to represent the visible (currently drawn)
3533 // part of the document. A LineView may correspond to multiple
3534 // logical lines, if those are connected by collapsed ranges.
3535 function LineView(doc, line, lineN) {
3536 // The starting line
3537 this.line = line;
3538 // Continuing lines, if any
3539 this.rest = visualLineContinued(line);
3540 // Number of logical lines in this visual line
3541 this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
3542 this.node = this.text = null;
3543 this.hidden = lineIsHidden(doc, line);
3544 }
3545
3546 // Create a range of LineView objects for the given lines.
3547 function buildViewArray(cm, from, to) {
3548 var array = [], nextPos;
3549 for (var pos = from; pos < to; pos = nextPos) {
3550 var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
3551 nextPos = pos + view.size;
3552 array.push(view);
3553 }
3554 return array
3555 }
3556
3557 var operationGroup = null;
3558
3559 function pushOperation(op) {
3560 if (operationGroup) {
3561 operationGroup.ops.push(op);
3562 } else {
3563 op.ownsGroup = operationGroup = {
3564 ops: [op],
3565 delayedCallbacks: []
3566 };
3567 }
3568 }
3569
3570 function fireCallbacksForOps(group) {
3571 // Calls delayed callbacks and cursorActivity handlers until no
3572 // new ones appear
3573 var callbacks = group.delayedCallbacks, i = 0;
3574 do {
3575 for (; i < callbacks.length; i++)
3576 { callbacks[i].call(null); }
3577 for (var j = 0; j < group.ops.length; j++) {
3578 var op = group.ops[j];
3579 if (op.cursorActivityHandlers)
3580 { while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
3581 { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } }
3582 }
3583 } while (i < callbacks.length)
3584 }
3585
3586 function finishOperation(op, endCb) {
3587 var group = op.ownsGroup;
3588 if (!group) { return }
3589
3590 try { fireCallbacksForOps(group); }
3591 finally {
3592 operationGroup = null;
3593 endCb(group);
3594 }
3595 }
3596
3597 var orphanDelayedCallbacks = null;
3598
3599 // Often, we want to signal events at a point where we are in the
3600 // middle of some work, but don't want the handler to start calling
3601 // other methods on the editor, which might be in an inconsistent
3602 // state or simply not expect any other events to happen.
3603 // signalLater looks whether there are any handlers, and schedules
3604 // them to be executed when the last operation ends, or, if no
3605 // operation is active, when a timeout fires.
3606 function signalLater(emitter, type /*, values...*/) {
3607 var arr = getHandlers(emitter, type);
3608 if (!arr.length) { return }
3609 var args = Array.prototype.slice.call(arguments, 2), list;
3610 if (operationGroup) {
3611 list = operationGroup.delayedCallbacks;
3612 } else if (orphanDelayedCallbacks) {
3613 list = orphanDelayedCallbacks;
3614 } else {
3615 list = orphanDelayedCallbacks = [];
3616 setTimeout(fireOrphanDelayed, 0);
3617 }
3618 var loop = function ( i ) {
3619 list.push(function () { return arr[i].apply(null, args); });
3620 };
3621
3622 for (var i = 0; i < arr.length; ++i)
3623 loop( i );
3624 }
3625
3626 function fireOrphanDelayed() {
3627 var delayed = orphanDelayedCallbacks;
3628 orphanDelayedCallbacks = null;
3629 for (var i = 0; i < delayed.length; ++i) { delayed[i](); }
3630 }
3631
3632 // When an aspect of a line changes, a string is added to
3633 // lineView.changes. This updates the relevant part of the line's
3634 // DOM structure.
3635 function updateLineForChanges(cm, lineView, lineN, dims) {
3636 for (var j = 0; j < lineView.changes.length; j++) {
3637 var type = lineView.changes[j];
3638 if (type == "text") { updateLineText(cm, lineView); }
3639 else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims); }
3640 else if (type == "class") { updateLineClasses(cm, lineView); }
3641 else if (type == "widget") { updateLineWidgets(cm, lineView, dims); }
3642 }
3643 lineView.changes = null;
3644 }
3645
3646 // Lines with gutter elements, widgets or a background class need to
3647 // be wrapped, and have the extra elements added to the wrapper div
3648 function ensureLineWrapped(lineView) {
3649 if (lineView.node == lineView.text) {
3650 lineView.node = elt("div", null, null, "position: relative");
3651 if (lineView.text.parentNode)
3652 { lineView.text.parentNode.replaceChild(lineView.node, lineView.text); }
3653 lineView.node.appendChild(lineView.text);
3654 if (ie && ie_version < 8) { lineView.node.style.zIndex = 2; }
3655 }
3656 return lineView.node
3657 }
3658
3659 function updateLineBackground(cm, lineView) {
3660 var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
3661 if (cls) { cls += " CodeMirror-linebackground"; }
3662 if (lineView.background) {
3663 if (cls) { lineView.background.className = cls; }
3664 else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
3665 } else if (cls) {
3666 var wrap = ensureLineWrapped(lineView);
3667 lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
3668 cm.display.input.setUneditable(lineView.background);
3669 }
3670 }
3671
3672 // Wrapper around buildLineContent which will reuse the structure
3673 // in display.externalMeasured when possible.
3674 function getLineContent(cm, lineView) {
3675 var ext = cm.display.externalMeasured;
3676 if (ext && ext.line == lineView.line) {
3677 cm.display.externalMeasured = null;
3678 lineView.measure = ext.measure;
3679 return ext.built
3680 }
3681 return buildLineContent(cm, lineView)
3682 }
3683
3684 // Redraw the line's text. Interacts with the background and text
3685 // classes because the mode may output tokens that influence these
3686 // classes.
3687 function updateLineText(cm, lineView) {
3688 var cls = lineView.text.className;
3689 var built = getLineContent(cm, lineView);
3690 if (lineView.text == lineView.node) { lineView.node = built.pre; }
3691 lineView.text.parentNode.replaceChild(built.pre, lineView.text);
3692 lineView.text = built.pre;
3693 if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
3694 lineView.bgClass = built.bgClass;
3695 lineView.textClass = built.textClass;
3696 updateLineClasses(cm, lineView);
3697 } else if (cls) {
3698 lineView.text.className = cls;
3699 }
3700 }
3701
3702 function updateLineClasses(cm, lineView) {
3703 updateLineBackground(cm, lineView);
3704 if (lineView.line.wrapClass)
3705 { ensureLineWrapped(lineView).className = lineView.line.wrapClass; }
3706 else if (lineView.node != lineView.text)
3707 { lineView.node.className = ""; }
3708 var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
3709 lineView.text.className = textClass || "";
3710 }
3711
3712 function updateLineGutter(cm, lineView, lineN, dims) {
3713 if (lineView.gutter) {
3714 lineView.node.removeChild(lineView.gutter);
3715 lineView.gutter = null;
3716 }
3717 if (lineView.gutterBackground) {
3718 lineView.node.removeChild(lineView.gutterBackground);
3719 lineView.gutterBackground = null;
3720 }
3721 if (lineView.line.gutterClass) {
3722 var wrap = ensureLineWrapped(lineView);
3723 lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
3724 ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px"));
3725 cm.display.input.setUneditable(lineView.gutterBackground);
3726 wrap.insertBefore(lineView.gutterBackground, lineView.text);
3727 }
3728 var markers = lineView.line.gutterMarkers;
3729 if (cm.options.lineNumbers || markers) {
3730 var wrap$1 = ensureLineWrapped(lineView);
3731 var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"));
3732 cm.display.input.setUneditable(gutterWrap);
3733 wrap$1.insertBefore(gutterWrap, lineView.text);
3734 if (lineView.line.gutterClass)
3735 { gutterWrap.className += " " + lineView.line.gutterClass; }
3736 if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
3737 { lineView.lineNumber = gutterWrap.appendChild(
3738 elt("div", lineNumberFor(cm.options, lineN),
3739 "CodeMirror-linenumber CodeMirror-gutter-elt",
3740 ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))); }
3741 if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) {
3742 var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
3743 if (found)
3744 { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
3745 ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))); }
3746 } }
3747 }
3748 }
3749
3750 function updateLineWidgets(cm, lineView, dims) {
3751 if (lineView.alignable) { lineView.alignable = null; }
3752 for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {
3753 next = node.nextSibling;
3754 if (node.className == "CodeMirror-linewidget")
3755 { lineView.node.removeChild(node); }
3756 }
3757 insertLineWidgets(cm, lineView, dims);
3758 }
3759
3760 // Build a line's DOM representation from scratch
3761 function buildLineElement(cm, lineView, lineN, dims) {
3762 var built = getLineContent(cm, lineView);
3763 lineView.text = lineView.node = built.pre;
3764 if (built.bgClass) { lineView.bgClass = built.bgClass; }
3765 if (built.textClass) { lineView.textClass = built.textClass; }
3766
3767 updateLineClasses(cm, lineView);
3768 updateLineGutter(cm, lineView, lineN, dims);
3769 insertLineWidgets(cm, lineView, dims);
3770 return lineView.node
3771 }
3772
3773 // A lineView may contain multiple logical lines (when merged by
3774 // collapsed spans). The widgets for all of them need to be drawn.
3775 function insertLineWidgets(cm, lineView, dims) {
3776 insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
3777 if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
3778 { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } }
3779 }
3780
3781 function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
3782 if (!line.widgets) { return }
3783 var wrap = ensureLineWrapped(lineView);
3784 for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
3785 var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
3786 if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); }
3787 positionLineWidget(widget, node, lineView, dims);
3788 cm.display.input.setUneditable(node);
3789 if (allowAbove && widget.above)
3790 { wrap.insertBefore(node, lineView.gutter || lineView.text); }
3791 else
3792 { wrap.appendChild(node); }
3793 signalLater(widget, "redraw");
3794 }
3795 }
3796
3797 function positionLineWidget(widget, node, lineView, dims) {
3798 if (widget.noHScroll) {
3799 (lineView.alignable || (lineView.alignable = [])).push(node);
3800 var width = dims.wrapperWidth;
3801 node.style.left = dims.fixedPos + "px";
3802 if (!widget.coverGutter) {
3803 width -= dims.gutterTotalWidth;
3804 node.style.paddingLeft = dims.gutterTotalWidth + "px";
3805 }
3806 node.style.width = width + "px";
3807 }
3808 if (widget.coverGutter) {
3809 node.style.zIndex = 5;
3810 node.style.position = "relative";
3811 if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px"; }
3812 }
3813 }
3814
3815 function widgetHeight(widget) {
3816 if (widget.height != null) { return widget.height }
3817 var cm = widget.doc.cm;
3818 if (!cm) { return 0 }
3819 if (!contains(document.body, widget.node)) {
3820 var parentStyle = "position: relative;";
3821 if (widget.coverGutter)
3822 { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; }
3823 if (widget.noHScroll)
3824 { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; }
3825 removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
3826 }
3827 return widget.height = widget.node.parentNode.offsetHeight
3828 }
3829
3830 // Return true when the given mouse event happened in a widget
3831 function eventInWidget(display, e) {
3832 for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
3833 if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
3834 (n.parentNode == display.sizer && n != display.mover))
3835 { return true }
3836 }
3837 }
3838
3839 // POSITION MEASUREMENT
3840
3841 function paddingTop(display) {return display.lineSpace.offsetTop}
3842 function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}
3843 function paddingH(display) {
3844 if (display.cachedPaddingH) { return display.cachedPaddingH }
3845 var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
3846 var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
3847 var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
3848 if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; }
3849 return data
3850 }
3851
3852 function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
3853 function displayWidth(cm) {
3854 return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth
3855 }
3856 function displayHeight(cm) {
3857 return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight
3858 }
3859
3860 // Ensure the lineView.wrapping.heights array is populated. This is
3861 // an array of bottom offsets for the lines that make up a drawn
3862 // line. When lineWrapping is on, there might be more than one
3863 // height.
3864 function ensureLineHeights(cm, lineView, rect) {
3865 var wrapping = cm.options.lineWrapping;
3866 var curWidth = wrapping && displayWidth(cm);
3867 if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
3868 var heights = lineView.measure.heights = [];
3869 if (wrapping) {
3870 lineView.measure.width = curWidth;
3871 var rects = lineView.text.firstChild.getClientRects();
3872 for (var i = 0; i < rects.length - 1; i++) {
3873 var cur = rects[i], next = rects[i + 1];
3874 if (Math.abs(cur.bottom - next.bottom) > 2)
3875 { heights.push((cur.bottom + next.top) / 2 - rect.top); }
3876 }
3877 }
3878 heights.push(rect.bottom - rect.top);
3879 }
3880 }
3881
3882 // Find a line map (mapping character offsets to text nodes) and a
3883 // measurement cache for the given line number. (A line view might
3884 // contain multiple lines when collapsed ranges are present.)
3885 function mapFromLineView(lineView, line, lineN) {
3886 if (lineView.line == line)
3887 { return {map: lineView.measure.map, cache: lineView.measure.cache} }
3888 for (var i = 0; i < lineView.rest.length; i++)
3889 { if (lineView.rest[i] == line)
3890 { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
3891 for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
3892 { if (lineNo(lineView.rest[i$1]) > lineN)
3893 { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
3894 }
3895
3896 // Render a line into the hidden node display.externalMeasured. Used
3897 // when measurement is needed for a line that's not in the viewport.
3898 function updateExternalMeasurement(cm, line) {
3899 line = visualLine(line);
3900 var lineN = lineNo(line);
3901 var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
3902 view.lineN = lineN;
3903 var built = view.built = buildLineContent(cm, view);
3904 view.text = built.pre;
3905 removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
3906 return view
3907 }
3908
3909 // Get a {top, bottom, left, right} box (in line-local coordinates)
3910 // for a given character.
3911 function measureChar(cm, line, ch, bias) {
3912 return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)
3913 }
3914
3915 // Find a line view that corresponds to the given line number.
3916 function findViewForLine(cm, lineN) {
3917 if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
3918 { return cm.display.view[findViewIndex(cm, lineN)] }
3919 var ext = cm.display.externalMeasured;
3920 if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
3921 { return ext }
3922 }
3923
3924 // Measurement can be split in two steps, the set-up work that
3925 // applies to the whole line, and the measurement of the actual
3926 // character. Functions like coordsChar, that need to do a lot of
3927 // measurements in a row, can thus ensure that the set-up work is
3928 // only done once.
3929 function prepareMeasureForLine(cm, line) {
3930 var lineN = lineNo(line);
3931 var view = findViewForLine(cm, lineN);
3932 if (view && !view.text) {
3933 view = null;
3934 } else if (view && view.changes) {
3935 updateLineForChanges(cm, view, lineN, getDimensions(cm));
3936 cm.curOp.forceUpdate = true;
3937 }
3938 if (!view)
3939 { view = updateExternalMeasurement(cm, line); }
3940
3941 var info = mapFromLineView(view, line, lineN);
3942 return {
3943 line: line, view: view, rect: null,
3944 map: info.map, cache: info.cache, before: info.before,
3945 hasHeights: false
3946 }
3947 }
3948
3949 // Given a prepared measurement object, measures the position of an
3950 // actual character (or fetches it from the cache).
3951 function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
3952 if (prepared.before) { ch = -1; }
3953 var key = ch + (bias || ""), found;
3954 if (prepared.cache.hasOwnProperty(key)) {
3955 found = prepared.cache[key];
3956 } else {
3957 if (!prepared.rect)
3958 { prepared.rect = prepared.view.text.getBoundingClientRect(); }
3959 if (!prepared.hasHeights) {
3960 ensureLineHeights(cm, prepared.view, prepared.rect);
3961 prepared.hasHeights = true;
3962 }
3963 found = measureCharInner(cm, prepared, ch, bias);
3964 if (!found.bogus) { prepared.cache[key] = found; }
3965 }
3966 return {left: found.left, right: found.right,
3967 top: varHeight ? found.rtop : found.top,
3968 bottom: varHeight ? found.rbottom : found.bottom}
3969 }
3970
3971 var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
3972
3973 function nodeAndOffsetInLineMap(map$$1, ch, bias) {
3974 var node, start, end, collapse, mStart, mEnd;
3975 // First, search the line map for the text node corresponding to,
3976 // or closest to, the target character.
3977 for (var i = 0; i < map$$1.length; i += 3) {
3978 mStart = map$$1[i];
3979 mEnd = map$$1[i + 1];
3980 if (ch < mStart) {
3981 start = 0; end = 1;
3982 collapse = "left";
3983 } else if (ch < mEnd) {
3984 start = ch - mStart;
3985 end = start + 1;
3986 } else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) {
3987 end = mEnd - mStart;
3988 start = end - 1;
3989 if (ch >= mEnd) { collapse = "right"; }
3990 }
3991 if (start != null) {
3992 node = map$$1[i + 2];
3993 if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
3994 { collapse = bias; }
3995 if (bias == "left" && start == 0)
3996 { while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) {
3997 node = map$$1[(i -= 3) + 2];
3998 collapse = "left";
3999 } }
4000 if (bias == "right" && start == mEnd - mStart)
4001 { while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) {
4002 node = map$$1[(i += 3) + 2];
4003 collapse = "right";
4004 } }
4005 break
4006 }
4007 }
4008 return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}
4009 }
4010
4011 function getUsefulRect(rects, bias) {
4012 var rect = nullRect;
4013 if (bias == "left") { for (var i = 0; i < rects.length; i++) {
4014 if ((rect = rects[i]).left != rect.right) { break }
4015 } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {
4016 if ((rect = rects[i$1]).left != rect.right) { break }
4017 } }
4018 return rect
4019 }
4020
4021 function measureCharInner(cm, prepared, ch, bias) {
4022 var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
4023 var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
4024
4025 var rect;
4026 if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
4027 for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned
4028 while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start; }
4029 while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end; }
4030 if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)
4031 { rect = node.parentNode.getBoundingClientRect(); }
4032 else
4033 { rect = getUsefulRect(range(node, start, end).getClientRects(), bias); }
4034 if (rect.left || rect.right || start == 0) { break }
4035 end = start;
4036 start = start - 1;
4037 collapse = "right";
4038 }
4039 if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect); }
4040 } else { // If it is a widget, simply get the box for the whole widget.
4041 if (start > 0) { collapse = bias = "right"; }
4042 var rects;
4043 if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
4044 { rect = rects[bias == "right" ? rects.length - 1 : 0]; }
4045 else
4046 { rect = node.getBoundingClientRect(); }
4047 }
4048 if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
4049 var rSpan = node.parentNode.getClientRects()[0];
4050 if (rSpan)
4051 { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; }
4052 else
4053 { rect = nullRect; }
4054 }
4055
4056 var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
4057 var mid = (rtop + rbot) / 2;
4058 var heights = prepared.view.measure.heights;
4059 var i = 0;
4060 for (; i < heights.length - 1; i++)
4061 { if (mid < heights[i]) { break } }
4062 var top = i ? heights[i - 1] : 0, bot = heights[i];
4063 var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
4064 right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
4065 top: top, bottom: bot};
4066 if (!rect.left && !rect.right) { result.bogus = true; }
4067 if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
4068
4069 return result
4070 }
4071
4072 // Work around problem with bounding client rects on ranges being
4073 // returned incorrectly when zoomed on IE10 and below.
4074 function maybeUpdateRectForZooming(measure, rect) {
4075 if (!window.screen || screen.logicalXDPI == null ||
4076 screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
4077 { return rect }
4078 var scaleX = screen.logicalXDPI / screen.deviceXDPI;
4079 var scaleY = screen.logicalYDPI / screen.deviceYDPI;
4080 return {left: rect.left * scaleX, right: rect.right * scaleX,
4081 top: rect.top * scaleY, bottom: rect.bottom * scaleY}
4082 }
4083
4084 function clearLineMeasurementCacheFor(lineView) {
4085 if (lineView.measure) {
4086 lineView.measure.cache = {};
4087 lineView.measure.heights = null;
4088 if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
4089 { lineView.measure.caches[i] = {}; } }
4090 }
4091 }
4092
4093 function clearLineMeasurementCache(cm) {
4094 cm.display.externalMeasure = null;
4095 removeChildren(cm.display.lineMeasure);
4096 for (var i = 0; i < cm.display.view.length; i++)
4097 { clearLineMeasurementCacheFor(cm.display.view[i]); }
4098 }
4099
4100 function clearCaches(cm) {
4101 clearLineMeasurementCache(cm);
4102 cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
4103 if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true; }
4104 cm.display.lineNumChars = null;
4105 }
4106
4107 function pageScrollX() {
4108 // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206
4109 // which causes page_Offset and bounding client rects to use
4110 // different reference viewports and invalidate our calculations.
4111 if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }
4112 return window.pageXOffset || (document.documentElement || document.body).scrollLeft
4113 }
4114 function pageScrollY() {
4115 if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }
4116 return window.pageYOffset || (document.documentElement || document.body).scrollTop
4117 }
4118
4119 // Converts a {top, bottom, left, right} box from line-local
4120 // coordinates into another coordinate system. Context may be one of
4121 // "line", "div" (display.lineDiv), "local"./null (editor), "window",
4122 // or "page".
4123 function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
4124 if (!includeWidgets && lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above) {
4125 var size = widgetHeight(lineObj.widgets[i]);
4126 rect.top += size; rect.bottom += size;
4127 } } }
4128 if (context == "line") { return rect }
4129 if (!context) { context = "local"; }
4130 var yOff = heightAtLine(lineObj);
4131 if (context == "local") { yOff += paddingTop(cm.display); }
4132 else { yOff -= cm.display.viewOffset; }
4133 if (context == "page" || context == "window") {
4134 var lOff = cm.display.lineSpace.getBoundingClientRect();
4135 yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
4136 var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
4137 rect.left += xOff; rect.right += xOff;
4138 }
4139 rect.top += yOff; rect.bottom += yOff;
4140 return rect
4141 }
4142
4143 // Coverts a box from "div" coords to another coordinate system.
4144 // Context may be "window", "page", "div", or "local"./null.
4145 function fromCoordSystem(cm, coords, context) {
4146 if (context == "div") { return coords }
4147 var left = coords.left, top = coords.top;
4148 // First move into "page" coordinate system
4149 if (context == "page") {
4150 left -= pageScrollX();
4151 top -= pageScrollY();
4152 } else if (context == "local" || !context) {
4153 var localBox = cm.display.sizer.getBoundingClientRect();
4154 left += localBox.left;
4155 top += localBox.top;
4156 }
4157
4158 var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
4159 return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}
4160 }
4161
4162 function charCoords(cm, pos, context, lineObj, bias) {
4163 if (!lineObj) { lineObj = getLine(cm.doc, pos.line); }
4164 return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)
4165 }
4166
4167 // Returns a box for a given cursor position, which may have an
4168 // 'other' property containing the position of the secondary cursor
4169 // on a bidi boundary.
4170 // A cursor Pos(line, char, "before") is on the same visual line as `char - 1`
4171 // and after `char - 1` in writing order of `char - 1`
4172 // A cursor Pos(line, char, "after") is on the same visual line as `char`
4173 // and before `char` in writing order of `char`
4174 // Examples (upper-case letters are RTL, lower-case are LTR):
4175 // Pos(0, 1, ...)
4176 // before after
4177 // ab a|b a|b
4178 // aB a|B aB|
4179 // Ab |Ab A|b
4180 // AB B|A B|A
4181 // Every position after the last character on a line is considered to stick
4182 // to the last character on the line.
4183 function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
4184 lineObj = lineObj || getLine(cm.doc, pos.line);
4185 if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
4186 function get(ch, right) {
4187 var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
4188 if (right) { m.left = m.right; } else { m.right = m.left; }
4189 return intoCoordSystem(cm, lineObj, m, context)
4190 }
4191 var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky;
4192 if (ch >= lineObj.text.length) {
4193 ch = lineObj.text.length;
4194 sticky = "before";
4195 } else if (ch <= 0) {
4196 ch = 0;
4197 sticky = "after";
4198 }
4199 if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") }
4200
4201 function getBidi(ch, partPos, invert) {
4202 var part = order[partPos], right = (part.level % 2) != 0;
4203 return get(invert ? ch - 1 : ch, right != invert)
4204 }
4205 var partPos = getBidiPartAt(order, ch, sticky);
4206 var other = bidiOther;
4207 var val = getBidi(ch, partPos, sticky == "before");
4208 if (other != null) { val.other = getBidi(ch, other, sticky != "before"); }
4209 return val
4210 }
4211
4212 // Used to cheaply estimate the coordinates for a position. Used for
4213 // intermediate scroll updates.
4214 function estimateCoords(cm, pos) {
4215 var left = 0;
4216 pos = clipPos(cm.doc, pos);
4217 if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch; }
4218 var lineObj = getLine(cm.doc, pos.line);
4219 var top = heightAtLine(lineObj) + paddingTop(cm.display);
4220 return {left: left, right: left, top: top, bottom: top + lineObj.height}
4221 }
4222
4223 // Positions returned by coordsChar contain some extra information.
4224 // xRel is the relative x position of the input coordinates compared
4225 // to the found position (so xRel > 0 means the coordinates are to
4226 // the right of the character position, for example). When outside
4227 // is true, that means the coordinates lie outside the line's
4228 // vertical range.
4229 function PosWithInfo(line, ch, sticky, outside, xRel) {
4230 var pos = Pos(line, ch, sticky);
4231 pos.xRel = xRel;
4232 if (outside) { pos.outside = true; }
4233 return pos
4234 }
4235
4236 // Compute the character position closest to the given coordinates.
4237 // Input must be lineSpace-local ("div" coordinate system).
4238 function coordsChar(cm, x, y) {
4239 var doc = cm.doc;
4240 y += cm.display.viewOffset;
4241 if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) }
4242 var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
4243 if (lineN > last)
4244 { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) }
4245 if (x < 0) { x = 0; }
4246
4247 var lineObj = getLine(doc, lineN);
4248 for (;;) {
4249 var found = coordsCharInner(cm, lineObj, lineN, x, y);
4250 var merged = collapsedSpanAtEnd(lineObj);
4251 var mergedPos = merged && merged.find(0, true);
4252 if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
4253 { lineN = lineNo(lineObj = mergedPos.to.line); }
4254 else
4255 { return found }
4256 }
4257 }
4258
4259 function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
4260 var measure = function (ch) { return intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), "line"); };
4261 var end = lineObj.text.length;
4262 var begin = findFirst(function (ch) { return measure(ch - 1).bottom <= y; }, end, 0);
4263 end = findFirst(function (ch) { return measure(ch).top > y; }, begin, end);
4264 return {begin: begin, end: end}
4265 }
4266
4267 function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
4268 var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top;
4269 return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)
4270 }
4271
4272 function coordsCharInner(cm, lineObj, lineNo$$1, x, y) {
4273 y -= heightAtLine(lineObj);
4274 var begin = 0, end = lineObj.text.length;
4275 var preparedMeasure = prepareMeasureForLine(cm, lineObj);
4276 var pos;
4277 var order = getOrder(lineObj, cm.doc.direction);
4278 if (order) {
4279 if (cm.options.lineWrapping) {
4280 var assign;
4281 ((assign = wrappedLineExtent(cm, lineObj, preparedMeasure, y), begin = assign.begin, end = assign.end, assign));
4282 }
4283 pos = new Pos(lineNo$$1, Math.floor(begin + (end - begin) / 2));
4284 var beginLeft = cursorCoords(cm, pos, "line", lineObj, preparedMeasure).left;
4285 var dir = beginLeft < x ? 1 : -1;
4286 var prevDiff, diff = beginLeft - x, prevPos;
4287 var steps = Math.ceil((end - begin) / 4);
4288 outer: do {
4289 prevDiff = diff;
4290 prevPos = pos;
4291 var i = 0;
4292 for (; i < steps; ++i) {
4293 var prevPos$1 = pos;
4294 pos = moveVisually(cm, lineObj, pos, dir);
4295 if (pos == null || pos.ch < begin || end <= (pos.sticky == "before" ? pos.ch - 1 : pos.ch)) {
4296 pos = prevPos$1;
4297 break outer
4298 }
4299 }
4300 diff = cursorCoords(cm, pos, "line", lineObj, preparedMeasure).left - x;
4301 if (steps > 1) {
4302 var diff_change_per_step = Math.abs(diff - prevDiff) / steps;
4303 steps = Math.min(steps, Math.ceil(Math.abs(diff) / diff_change_per_step));
4304 dir = diff < 0 ? 1 : -1;
4305 }
4306 } while (diff != 0 && (steps > 1 || ((dir < 0) != (diff < 0) && (Math.abs(diff) <= Math.abs(prevDiff)))))
4307 if (Math.abs(diff) > Math.abs(prevDiff)) {
4308 if ((diff < 0) == (prevDiff < 0)) { throw new Error("Broke out of infinite loop in coordsCharInner") }
4309 pos = prevPos;
4310 }
4311 } else {
4312 var ch = findFirst(function (ch) {
4313 var box = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, ch), "line");
4314 if (box.top > y) {
4315 // For the cursor stickiness
4316 end = Math.min(ch, end);
4317 return true
4318 }
4319 else if (box.bottom <= y) { return false }
4320 else if (box.left > x) { return true }
4321 else if (box.right < x) { return false }
4322 else { return (x - box.left < box.right - x) }
4323 }, begin, end);
4324 ch = skipExtendingChars(lineObj.text, ch, 1);
4325 pos = new Pos(lineNo$$1, ch, ch == end ? "before" : "after");
4326 }
4327 var coords = cursorCoords(cm, pos, "line", lineObj, preparedMeasure);
4328 if (y < coords.top || coords.bottom < y) { pos.outside = true; }
4329 pos.xRel = x < coords.left ? -1 : (x > coords.right ? 1 : 0);
4330 return pos
4331 }
4332
4333 var measureText;
4334 // Compute the default text height.
4335 function textHeight(display) {
4336 if (display.cachedTextHeight != null) { return display.cachedTextHeight }
4337 if (measureText == null) {
4338 measureText = elt("pre");
4339 // Measure a bunch of lines, for browsers that compute
4340 // fractional heights.
4341 for (var i = 0; i < 49; ++i) {
4342 measureText.appendChild(document.createTextNode("x"));
4343 measureText.appendChild(elt("br"));
4344 }
4345 measureText.appendChild(document.createTextNode("x"));
4346 }
4347 removeChildrenAndAdd(display.measure, measureText);
4348 var height = measureText.offsetHeight / 50;
4349 if (height > 3) { display.cachedTextHeight = height; }
4350 removeChildren(display.measure);
4351 return height || 1
4352 }
4353
4354 // Compute the default character width.
4355 function charWidth(display) {
4356 if (display.cachedCharWidth != null) { return display.cachedCharWidth }
4357 var anchor = elt("span", "xxxxxxxxxx");
4358 var pre = elt("pre", [anchor]);
4359 removeChildrenAndAdd(display.measure, pre);
4360 var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
4361 if (width > 2) { display.cachedCharWidth = width; }
4362 return width || 10
4363 }
4364
4365 // Do a bulk-read of the DOM positions and sizes needed to draw the
4366 // view, so that we don't interleave reading and writing to the DOM.
4367 function getDimensions(cm) {
4368 var d = cm.display, left = {}, width = {};
4369 var gutterLeft = d.gutters.clientLeft;
4370 for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
4371 left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
4372 width[cm.options.gutters[i]] = n.clientWidth;
4373 }
4374 return {fixedPos: compensateForHScroll(d),
4375 gutterTotalWidth: d.gutters.offsetWidth,
4376 gutterLeft: left,
4377 gutterWidth: width,
4378 wrapperWidth: d.wrapper.clientWidth}
4379 }
4380
4381 // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
4382 // but using getBoundingClientRect to get a sub-pixel-accurate
4383 // result.
4384 function compensateForHScroll(display) {
4385 return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left
4386 }
4387
4388 // Returns a function that estimates the height of a line, to use as
4389 // first approximation until the line becomes visible (and is thus
4390 // properly measurable).
4391 function estimateHeight(cm) {
4392 var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
4393 var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
4394 return function (line) {
4395 if (lineIsHidden(cm.doc, line)) { return 0 }
4396
4397 var widgetsHeight = 0;
4398 if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {
4399 if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height; }
4400 } }
4401
4402 if (wrapping)
4403 { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }
4404 else
4405 { return widgetsHeight + th }
4406 }
4407 }
4408
4409 function estimateLineHeights(cm) {
4410 var doc = cm.doc, est = estimateHeight(cm);
4411 doc.iter(function (line) {
4412 var estHeight = est(line);
4413 if (estHeight != line.height) { updateLineHeight(line, estHeight); }
4414 });
4415 }
4416
4417 // Given a mouse event, find the corresponding position. If liberal
4418 // is false, it checks whether a gutter or scrollbar was clicked,
4419 // and returns null if it was. forRect is used by rectangular
4420 // selections, and tries to estimate a character position even for
4421 // coordinates beyond the right of the text.
4422 function posFromMouse(cm, e, liberal, forRect) {
4423 var display = cm.display;
4424 if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null }
4425
4426 var x, y, space = display.lineSpace.getBoundingClientRect();
4427 // Fails unpredictably on IE[67] when mouse is dragged around quickly.
4428 try { x = e.clientX - space.left; y = e.clientY - space.top; }
4429 catch (e) { return null }
4430 var coords = coordsChar(cm, x, y), line;
4431 if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
4432 var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
4433 coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
4434 }
4435 return coords
4436 }
4437
4438 // Find the view element corresponding to a given line. Return null
4439 // when the line isn't visible.
4440 function findViewIndex(cm, n) {
4441 if (n >= cm.display.viewTo) { return null }
4442 n -= cm.display.viewFrom;
4443 if (n < 0) { return null }
4444 var view = cm.display.view;
4445 for (var i = 0; i < view.length; i++) {
4446 n -= view[i].size;
4447 if (n < 0) { return i }
4448 }
4449 }
4450
4451 function updateSelection(cm) {
4452 cm.display.input.showSelection(cm.display.input.prepareSelection());
4453 }
4454
4455 function prepareSelection(cm, primary) {
4456 var doc = cm.doc, result = {};
4457 var curFragment = result.cursors = document.createDocumentFragment();
4458 var selFragment = result.selection = document.createDocumentFragment();
4459
4460 for (var i = 0; i < doc.sel.ranges.length; i++) {
4461 if (primary === false && i == doc.sel.primIndex) { continue }
4462 var range$$1 = doc.sel.ranges[i];
4463 if (range$$1.from().line >= cm.display.viewTo || range$$1.to().line < cm.display.viewFrom) { continue }
4464 var collapsed = range$$1.empty();
4465 if (collapsed || cm.options.showCursorWhenSelecting)
4466 { drawSelectionCursor(cm, range$$1.head, curFragment); }
4467 if (!collapsed)
4468 { drawSelectionRange(cm, range$$1, selFragment); }
4469 }
4470 return result
4471 }
4472
4473 // Draws a cursor for the given range
4474 function drawSelectionCursor(cm, head, output) {
4475 var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine);
4476
4477 var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
4478 cursor.style.left = pos.left + "px";
4479 cursor.style.top = pos.top + "px";
4480 cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
4481
4482 if (pos.other) {
4483 // Secondary cursor, shown when on a 'jump' in bi-directional text
4484 var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
4485 otherCursor.style.display = "";
4486 otherCursor.style.left = pos.other.left + "px";
4487 otherCursor.style.top = pos.other.top + "px";
4488 otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
4489 }
4490 }
4491
4492 // Draws the given range as a highlighted selection
4493 function drawSelectionRange(cm, range$$1, output) {
4494 var display = cm.display, doc = cm.doc;
4495 var fragment = document.createDocumentFragment();
4496 var padding = paddingH(cm.display), leftSide = padding.left;
4497 var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
4498
4499 function add(left, top, width, bottom) {
4500 if (top < 0) { top = 0; }
4501 top = Math.round(top);
4502 bottom = Math.round(bottom);
4503 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")));
4504 }
4505
4506 function drawForLine(line, fromArg, toArg) {
4507 var lineObj = getLine(doc, line);
4508 var lineLen = lineObj.text.length;
4509 var start, end;
4510 function coords(ch, bias) {
4511 return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
4512 }
4513
4514 iterateBidiSections(getOrder(lineObj, doc.direction), fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir) {
4515 var leftPos = coords(from, "left"), rightPos, left, right;
4516 if (from == to) {
4517 rightPos = leftPos;
4518 left = right = leftPos.left;
4519 } else {
4520 rightPos = coords(to - 1, "right");
4521 if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }
4522 left = leftPos.left;
4523 right = rightPos.right;
4524 }
4525 if (fromArg == null && from == 0) { left = leftSide; }
4526 if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
4527 add(left, leftPos.top, null, leftPos.bottom);
4528 left = leftSide;
4529 if (leftPos.bottom < rightPos.top) { add(left, leftPos.bottom, null, rightPos.top); }
4530 }
4531 if (toArg == null && to == lineLen) { right = rightSide; }
4532 if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
4533 { start = leftPos; }
4534 if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
4535 { end = rightPos; }
4536 if (left < leftSide + 1) { left = leftSide; }
4537 add(left, rightPos.top, right - left, rightPos.bottom);
4538 });
4539 return {start: start, end: end}
4540 }
4541
4542 var sFrom = range$$1.from(), sTo = range$$1.to();
4543 if (sFrom.line == sTo.line) {
4544 drawForLine(sFrom.line, sFrom.ch, sTo.ch);
4545 } else {
4546 var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
4547 var singleVLine = visualLine(fromLine) == visualLine(toLine);
4548 var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
4549 var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
4550 if (singleVLine) {
4551 if (leftEnd.top < rightStart.top - 2) {
4552 add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
4553 add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
4554 } else {
4555 add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
4556 }
4557 }
4558 if (leftEnd.bottom < rightStart.top)
4559 { add(leftSide, leftEnd.bottom, null, rightStart.top); }
4560 }
4561
4562 output.appendChild(fragment);
4563 }
4564
4565 // Cursor-blinking
4566 function restartBlink(cm) {
4567 if (!cm.state.focused) { return }
4568 var display = cm.display;
4569 clearInterval(display.blinker);
4570 var on = true;
4571 display.cursorDiv.style.visibility = "";
4572 if (cm.options.cursorBlinkRate > 0)
4573 { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; },
4574 cm.options.cursorBlinkRate); }
4575 else if (cm.options.cursorBlinkRate < 0)
4576 { display.cursorDiv.style.visibility = "hidden"; }
4577 }
4578
4579 function ensureFocus(cm) {
4580 if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
4581 }
4582
4583 function delayBlurEvent(cm) {
4584 cm.state.delayingBlurEvent = true;
4585 setTimeout(function () { if (cm.state.delayingBlurEvent) {
4586 cm.state.delayingBlurEvent = false;
4587 onBlur(cm);
4588 } }, 100);
4589 }
4590
4591 function onFocus(cm, e) {
4592 if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; }
4593
4594 if (cm.options.readOnly == "nocursor") { return }
4595 if (!cm.state.focused) {
4596 signal(cm, "focus", cm, e);
4597 cm.state.focused = true;
4598 addClass(cm.display.wrapper, "CodeMirror-focused");
4599 // This test prevents this from firing when a context
4600 // menu is closed (since the input reset would kill the
4601 // select-all detection hack)
4602 if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
4603 cm.display.input.reset();
4604 if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730
4605 }
4606 cm.display.input.receivedFocus();
4607 }
4608 restartBlink(cm);
4609 }
4610 function onBlur(cm, e) {
4611 if (cm.state.delayingBlurEvent) { return }
4612
4613 if (cm.state.focused) {
4614 signal(cm, "blur", cm, e);
4615 cm.state.focused = false;
4616 rmClass(cm.display.wrapper, "CodeMirror-focused");
4617 }
4618 clearInterval(cm.display.blinker);
4619 setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false; } }, 150);
4620 }
4621
4622 // Read the actual heights of the rendered lines, and update their
4623 // stored heights to match.
4624 function updateHeightsInViewport(cm) {
4625 var display = cm.display;
4626 var prevBottom = display.lineDiv.offsetTop;
4627 for (var i = 0; i < display.view.length; i++) {
4628 var cur = display.view[i], height = (void 0);
4629 if (cur.hidden) { continue }
4630 if (ie && ie_version < 8) {
4631 var bot = cur.node.offsetTop + cur.node.offsetHeight;
4632 height = bot - prevBottom;
4633 prevBottom = bot;
4634 } else {
4635 var box = cur.node.getBoundingClientRect();
4636 height = box.bottom - box.top;
4637 }
4638 var diff = cur.line.height - height;
4639 if (height < 2) { height = textHeight(display); }
4640 if (diff > .005 || diff < -.005) {
4641 updateLineHeight(cur.line, height);
4642 updateWidgetHeight(cur.line);
4643 if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
4644 { updateWidgetHeight(cur.rest[j]); } }
4645 }
4646 }
4647 }
4648
4649 // Read and store the height of line widgets associated with the
4650 // given line.
4651 function updateWidgetHeight(line) {
4652 if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i)
4653 { line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight; } }
4654 }
4655
4656 // Compute the lines that are visible in a given viewport (defaults
4657 // the the current scroll position). viewport may contain top,
4658 // height, and ensure (see op.scrollToPos) properties.
4659 function visibleLines(display, doc, viewport) {
4660 var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
4661 top = Math.floor(top - paddingTop(display));
4662 var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
4663
4664 var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
4665 // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
4666 // forces those lines into the viewport (if possible).
4667 if (viewport && viewport.ensure) {
4668 var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
4669 if (ensureFrom < from) {
4670 from = ensureFrom;
4671 to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
4672 } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
4673 from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
4674 to = ensureTo;
4675 }
4676 }
4677 return {from: from, to: Math.max(to, from + 1)}
4678 }
4679
4680 // Re-align line numbers and gutter marks to compensate for
4681 // horizontal scrolling.
4682 function alignHorizontally(cm) {
4683 var display = cm.display, view = display.view;
4684 if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
4685 var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
4686 var gutterW = display.gutters.offsetWidth, left = comp + "px";
4687 for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {
4688 if (cm.options.fixedGutter) {
4689 if (view[i].gutter)
4690 { view[i].gutter.style.left = left; }
4691 if (view[i].gutterBackground)
4692 { view[i].gutterBackground.style.left = left; }
4693 }
4694 var align = view[i].alignable;
4695 if (align) { for (var j = 0; j < align.length; j++)
4696 { align[j].style.left = left; } }
4697 } }
4698 if (cm.options.fixedGutter)
4699 { display.gutters.style.left = (comp + gutterW) + "px"; }
4700 }
4701
4702 // Used to ensure that the line number gutter is still the right
4703 // size for the current document size. Returns true when an update
4704 // is needed.
4705 function maybeUpdateLineNumberWidth(cm) {
4706 if (!cm.options.lineNumbers) { return false }
4707 var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
4708 if (last.length != display.lineNumChars) {
4709 var test = display.measure.appendChild(elt("div", [elt("div", last)],
4710 "CodeMirror-linenumber CodeMirror-gutter-elt"));
4711 var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
4712 display.lineGutter.style.width = "";
4713 display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
4714 display.lineNumWidth = display.lineNumInnerWidth + padding;
4715 display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
4716 display.lineGutter.style.width = display.lineNumWidth + "px";
4717 updateGutterSpace(cm);
4718 return true
4719 }
4720 return false
4721 }
4722
4723 // SCROLLING THINGS INTO VIEW
4724
4725 // If an editor sits on the top or bottom of the window, partially
4726 // scrolled out of view, this ensures that the cursor is visible.
4727 function maybeScrollWindow(cm, rect) {
4728 if (signalDOMEvent(cm, "scrollCursorIntoView")) { return }
4729
4730 var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
4731 if (rect.top + box.top < 0) { doScroll = true; }
4732 else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; }
4733 if (doScroll != null && !phantom) {
4734 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;"));
4735 cm.display.lineSpace.appendChild(scrollNode);
4736 scrollNode.scrollIntoView(doScroll);
4737 cm.display.lineSpace.removeChild(scrollNode);
4738 }
4739 }
4740
4741 // Scroll a given position into view (immediately), verifying that
4742 // it actually became visible (as line heights are accurately
4743 // measured, the position of something may 'drift' during drawing).
4744 function scrollPosIntoView(cm, pos, end, margin) {
4745 if (margin == null) { margin = 0; }
4746 var rect;
4747 if (!cm.options.lineWrapping && pos == end) {
4748 // Set pos and end to the cursor positions around the character pos sticks to
4749 // If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch
4750 // If pos == Pos(_, 0, "before"), pos and end are unchanged
4751 pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos;
4752 end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos;
4753 }
4754 for (var limit = 0; limit < 5; limit++) {
4755 var changed = false;
4756 var coords = cursorCoords(cm, pos);
4757 var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
4758 rect = {left: Math.min(coords.left, endCoords.left),
4759 top: Math.min(coords.top, endCoords.top) - margin,
4760 right: Math.max(coords.left, endCoords.left),
4761 bottom: Math.max(coords.bottom, endCoords.bottom) + margin};
4762 var scrollPos = calculateScrollPos(cm, rect);
4763 var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
4764 if (scrollPos.scrollTop != null) {
4765 updateScrollTop(cm, scrollPos.scrollTop);
4766 if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true; }
4767 }
4768 if (scrollPos.scrollLeft != null) {
4769 setScrollLeft(cm, scrollPos.scrollLeft);
4770 if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true; }
4771 }
4772 if (!changed) { break }
4773 }
4774 return rect
4775 }
4776
4777 // Scroll a given set of coordinates into view (immediately).
4778 function scrollIntoView(cm, rect) {
4779 var scrollPos = calculateScrollPos(cm, rect);
4780 if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop); }
4781 if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); }
4782 }
4783
4784 // Calculate a new scroll position needed to scroll the given
4785 // rectangle into view. Returns an object with scrollTop and
4786 // scrollLeft properties. When these are undefined, the
4787 // vertical/horizontal position does not need to be adjusted.
4788 function calculateScrollPos(cm, rect) {
4789 var display = cm.display, snapMargin = textHeight(cm.display);
4790 if (rect.top < 0) { rect.top = 0; }
4791 var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
4792 var screen = displayHeight(cm), result = {};
4793 if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen; }
4794 var docBottom = cm.doc.height + paddingVert(display);
4795 var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin;
4796 if (rect.top < screentop) {
4797 result.scrollTop = atTop ? 0 : rect.top;
4798 } else if (rect.bottom > screentop + screen) {
4799 var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen);
4800 if (newTop != screentop) { result.scrollTop = newTop; }
4801 }
4802
4803 var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
4804 var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
4805 var tooWide = rect.right - rect.left > screenw;
4806 if (tooWide) { rect.right = rect.left + screenw; }
4807 if (rect.left < 10)
4808 { result.scrollLeft = 0; }
4809 else if (rect.left < screenleft)
4810 { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); }
4811 else if (rect.right > screenw + screenleft - 3)
4812 { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }
4813 return result
4814 }
4815
4816 // Store a relative adjustment to the scroll position in the current
4817 // operation (to be applied when the operation finishes).
4818 function addToScrollTop(cm, top) {
4819 if (top == null) { return }
4820 resolveScrollToPos(cm);
4821 cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
4822 }
4823
4824 // Make sure that at the end of the operation the current cursor is
4825 // shown.
4826 function ensureCursorVisible(cm) {
4827 resolveScrollToPos(cm);
4828 var cur = cm.getCursor();
4829 cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin};
4830 }
4831
4832 function scrollToCoords(cm, x, y) {
4833 if (x != null || y != null) { resolveScrollToPos(cm); }
4834 if (x != null) { cm.curOp.scrollLeft = x; }
4835 if (y != null) { cm.curOp.scrollTop = y; }
4836 }
4837
4838 function scrollToRange(cm, range$$1) {
4839 resolveScrollToPos(cm);
4840 cm.curOp.scrollToPos = range$$1;
4841 }
4842
4843 // When an operation has its scrollToPos property set, and another
4844 // scroll action is applied before the end of the operation, this
4845 // 'simulates' scrolling that position into view in a cheap way, so
4846 // that the effect of intermediate scroll commands is not ignored.
4847 function resolveScrollToPos(cm) {
4848 var range$$1 = cm.curOp.scrollToPos;
4849 if (range$$1) {
4850 cm.curOp.scrollToPos = null;
4851 var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to);
4852 scrollToCoordsRange(cm, from, to, range$$1.margin);
4853 }
4854 }
4855
4856 function scrollToCoordsRange(cm, from, to, margin) {
4857 var sPos = calculateScrollPos(cm, {
4858 left: Math.min(from.left, to.left),
4859 top: Math.min(from.top, to.top) - margin,
4860 right: Math.max(from.right, to.right),
4861 bottom: Math.max(from.bottom, to.bottom) + margin
4862 });
4863 scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop);
4864 }
4865
4866 // Sync the scrollable area and scrollbars, ensure the viewport
4867 // covers the visible area.
4868 function updateScrollTop(cm, val) {
4869 if (Math.abs(cm.doc.scrollTop - val) < 2) { return }
4870 if (!gecko) { updateDisplaySimple(cm, {top: val}); }
4871 setScrollTop(cm, val, true);
4872 if (gecko) { updateDisplaySimple(cm); }
4873 startWorker(cm, 100);
4874 }
4875
4876 function setScrollTop(cm, val, forceScroll) {
4877 val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val);
4878 if (cm.display.scroller.scrollTop == val && !forceScroll) { return }
4879 cm.doc.scrollTop = val;
4880 cm.display.scrollbars.setScrollTop(val);
4881 if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val; }
4882 }
4883
4884 // Sync scroller and scrollbar, ensure the gutter elements are
4885 // aligned.
4886 function setScrollLeft(cm, val, isScroller, forceScroll) {
4887 val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
4888 if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }
4889 cm.doc.scrollLeft = val;
4890 alignHorizontally(cm);
4891 if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val; }
4892 cm.display.scrollbars.setScrollLeft(val);
4893 }
4894
4895 // SCROLLBARS
4896
4897 // Prepare DOM reads needed to update the scrollbars. Done in one
4898 // shot to minimize update/measure roundtrips.
4899 function measureForScrollbars(cm) {
4900 var d = cm.display, gutterW = d.gutters.offsetWidth;
4901 var docH = Math.round(cm.doc.height + paddingVert(cm.display));
4902 return {
4903 clientHeight: d.scroller.clientHeight,
4904 viewHeight: d.wrapper.clientHeight,
4905 scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
4906 viewWidth: d.wrapper.clientWidth,
4907 barLeft: cm.options.fixedGutter ? gutterW : 0,
4908 docHeight: docH,
4909 scrollHeight: docH + scrollGap(cm) + d.barHeight,
4910 nativeBarWidth: d.nativeBarWidth,
4911 gutterWidth: gutterW
4912 }
4913 }
4914
4915 var NativeScrollbars = function(place, scroll, cm) {
4916 this.cm = cm;
4917 var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
4918 var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
4919 place(vert); place(horiz);
4920
4921 on(vert, "scroll", function () {
4922 if (vert.clientHeight) { scroll(vert.scrollTop, "vertical"); }
4923 });
4924 on(horiz, "scroll", function () {
4925 if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal"); }
4926 });
4927
4928 this.checkedZeroWidth = false;
4929 // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
4930 if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; }
4931 };
4932
4933 NativeScrollbars.prototype.update = function (measure) {
4934 var needsH = measure.scrollWidth > measure.clientWidth + 1;
4935 var needsV = measure.scrollHeight > measure.clientHeight + 1;
4936 var sWidth = measure.nativeBarWidth;
4937
4938 if (needsV) {
4939 this.vert.style.display = "block";
4940 this.vert.style.bottom = needsH ? sWidth + "px" : "0";
4941 var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
4942 // A bug in IE8 can cause this value to be negative, so guard it.
4943 this.vert.firstChild.style.height =
4944 Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
4945 } else {
4946 this.vert.style.display = "";
4947 this.vert.firstChild.style.height = "0";
4948 }
4949
4950 if (needsH) {
4951 this.horiz.style.display = "block";
4952 this.horiz.style.right = needsV ? sWidth + "px" : "0";
4953 this.horiz.style.left = measure.barLeft + "px";
4954 var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
4955 this.horiz.firstChild.style.width =
4956 Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
4957 } else {
4958 this.horiz.style.display = "";
4959 this.horiz.firstChild.style.width = "0";
4960 }
4961
4962 if (!this.checkedZeroWidth && measure.clientHeight > 0) {
4963 if (sWidth == 0) { this.zeroWidthHack(); }
4964 this.checkedZeroWidth = true;
4965 }
4966
4967 return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
4968 };
4969
4970 NativeScrollbars.prototype.setScrollLeft = function (pos) {
4971 if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos; }
4972 if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz"); }
4973 };
4974
4975 NativeScrollbars.prototype.setScrollTop = function (pos) {
4976 if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos; }
4977 if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, "vert"); }
4978 };
4979
4980 NativeScrollbars.prototype.zeroWidthHack = function () {
4981 var w = mac && !mac_geMountainLion ? "12px" : "18px";
4982 this.horiz.style.height = this.vert.style.width = w;
4983 this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
4984 this.disableHoriz = new Delayed;
4985 this.disableVert = new Delayed;
4986 };
4987
4988 NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) {
4989 bar.style.pointerEvents = "auto";
4990 function maybeDisable() {
4991 // To find out whether the scrollbar is still visible, we
4992 // check whether the element under the pixel in the bottom
4993 // right corner of the scrollbar box is the scrollbar box
4994 // itself (when the bar is still visible) or its filler child
4995 // (when the bar is hidden). If it is still visible, we keep
4996 // it enabled, if it's hidden, we disable pointer events.
4997 var box = bar.getBoundingClientRect();
4998 var elt$$1 = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)
4999 : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1);
5000 if (elt$$1 != bar) { bar.style.pointerEvents = "none"; }
5001 else { delay.set(1000, maybeDisable); }
5002 }
5003 delay.set(1000, maybeDisable);
5004 };
5005
5006 NativeScrollbars.prototype.clear = function () {
5007 var parent = this.horiz.parentNode;
5008 parent.removeChild(this.horiz);
5009 parent.removeChild(this.vert);
5010 };
5011
5012 var NullScrollbars = function () {};
5013
5014 NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} };
5015 NullScrollbars.prototype.setScrollLeft = function () {};
5016 NullScrollbars.prototype.setScrollTop = function () {};
5017 NullScrollbars.prototype.clear = function () {};
5018
5019 function updateScrollbars(cm, measure) {
5020 if (!measure) { measure = measureForScrollbars(cm); }
5021 var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
5022 updateScrollbarsInner(cm, measure);
5023 for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
5024 if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
5025 { updateHeightsInViewport(cm); }
5026 updateScrollbarsInner(cm, measureForScrollbars(cm));
5027 startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
5028 }
5029 }
5030
5031 // Re-synchronize the fake scrollbars with the actual size of the
5032 // content.
5033 function updateScrollbarsInner(cm, measure) {
5034 var d = cm.display;
5035 var sizes = d.scrollbars.update(measure);
5036
5037 d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
5038 d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
5039 d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent";
5040
5041 if (sizes.right && sizes.bottom) {
5042 d.scrollbarFiller.style.display = "block";
5043 d.scrollbarFiller.style.height = sizes.bottom + "px";
5044 d.scrollbarFiller.style.width = sizes.right + "px";
5045 } else { d.scrollbarFiller.style.display = ""; }
5046 if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
5047 d.gutterFiller.style.display = "block";
5048 d.gutterFiller.style.height = sizes.bottom + "px";
5049 d.gutterFiller.style.width = measure.gutterWidth + "px";
5050 } else { d.gutterFiller.style.display = ""; }
5051 }
5052
5053 var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
5054
5055 function initScrollbars(cm) {
5056 if (cm.display.scrollbars) {
5057 cm.display.scrollbars.clear();
5058 if (cm.display.scrollbars.addClass)
5059 { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
5060 }
5061
5062 cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {
5063 cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
5064 // Prevent clicks in the scrollbars from killing focus
5065 on(node, "mousedown", function () {
5066 if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); }
5067 });
5068 node.setAttribute("cm-not-content", "true");
5069 }, function (pos, axis) {
5070 if (axis == "horizontal") { setScrollLeft(cm, pos); }
5071 else { updateScrollTop(cm, pos); }
5072 }, cm);
5073 if (cm.display.scrollbars.addClass)
5074 { addClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
5075 }
5076
5077 // Operations are used to wrap a series of changes to the editor
5078 // state in such a way that each change won't have to update the
5079 // cursor and display (which would be awkward, slow, and
5080 // error-prone). Instead, display updates are batched and then all
5081 // combined and executed at once.
5082
5083 var nextOpId = 0;
5084 // Start a new operation.
5085 function startOperation(cm) {
5086 cm.curOp = {
5087 cm: cm,
5088 viewChanged: false, // Flag that indicates that lines might need to be redrawn
5089 startHeight: cm.doc.height, // Used to detect need to update scrollbar
5090 forceUpdate: false, // Used to force a redraw
5091 updateInput: null, // Whether to reset the input textarea
5092 typing: false, // Whether this reset should be careful to leave existing text (for compositing)
5093 changeObjs: null, // Accumulated changes, for firing change events
5094 cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
5095 cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
5096 selectionChanged: false, // Whether the selection needs to be redrawn
5097 updateMaxLine: false, // Set when the widest line needs to be determined anew
5098 scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
5099 scrollToPos: null, // Used to scroll to a specific position
5100 focus: false,
5101 id: ++nextOpId // Unique ID
5102 };
5103 pushOperation(cm.curOp);
5104 }
5105
5106 // Finish an operation, updating the display and signalling delayed events
5107 function endOperation(cm) {
5108 var op = cm.curOp;
5109 finishOperation(op, function (group) {
5110 for (var i = 0; i < group.ops.length; i++)
5111 { group.ops[i].cm.curOp = null; }
5112 endOperations(group);
5113 });
5114 }
5115
5116 // The DOM updates done when an operation finishes are batched so
5117 // that the minimum number of relayouts are required.
5118 function endOperations(group) {
5119 var ops = group.ops;
5120 for (var i = 0; i < ops.length; i++) // Read DOM
5121 { endOperation_R1(ops[i]); }
5122 for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)
5123 { endOperation_W1(ops[i$1]); }
5124 for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM
5125 { endOperation_R2(ops[i$2]); }
5126 for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)
5127 { endOperation_W2(ops[i$3]); }
5128 for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM
5129 { endOperation_finish(ops[i$4]); }
5130 }
5131
5132 function endOperation_R1(op) {
5133 var cm = op.cm, display = cm.display;
5134 maybeClipScrollbars(cm);
5135 if (op.updateMaxLine) { findMaxLine(cm); }
5136
5137 op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
5138 op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
5139 op.scrollToPos.to.line >= display.viewTo) ||
5140 display.maxLineChanged && cm.options.lineWrapping;
5141 op.update = op.mustUpdate &&
5142 new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
5143 }
5144
5145 function endOperation_W1(op) {
5146 op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
5147 }
5148
5149 function endOperation_R2(op) {
5150 var cm = op.cm, display = cm.display;
5151 if (op.updatedDisplay) { updateHeightsInViewport(cm); }
5152
5153 op.barMeasure = measureForScrollbars(cm);
5154
5155 // If the max line changed since it was last measured, measure it,
5156 // and ensure the document's width matches it.
5157 // updateDisplay_W2 will use these properties to do the actual resizing
5158 if (display.maxLineChanged && !cm.options.lineWrapping) {
5159 op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
5160 cm.display.sizerWidth = op.adjustWidthTo;
5161 op.barMeasure.scrollWidth =
5162 Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
5163 op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
5164 }
5165
5166 if (op.updatedDisplay || op.selectionChanged)
5167 { op.preparedSelection = display.input.prepareSelection(op.focus); }
5168 }
5169
5170 function endOperation_W2(op) {
5171 var cm = op.cm;
5172
5173 if (op.adjustWidthTo != null) {
5174 cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
5175 if (op.maxScrollLeft < cm.doc.scrollLeft)
5176 { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); }
5177 cm.display.maxLineChanged = false;
5178 }
5179
5180 var takeFocus = op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus());
5181 if (op.preparedSelection)
5182 { cm.display.input.showSelection(op.preparedSelection, takeFocus); }
5183 if (op.updatedDisplay || op.startHeight != cm.doc.height)
5184 { updateScrollbars(cm, op.barMeasure); }
5185 if (op.updatedDisplay)
5186 { setDocumentHeight(cm, op.barMeasure); }
5187
5188 if (op.selectionChanged) { restartBlink(cm); }
5189
5190 if (cm.state.focused && op.updateInput)
5191 { cm.display.input.reset(op.typing); }
5192 if (takeFocus) { ensureFocus(op.cm); }
5193 }
5194
5195 function endOperation_finish(op) {
5196 var cm = op.cm, display = cm.display, doc = cm.doc;
5197
5198 if (op.updatedDisplay) { postUpdateDisplay(cm, op.update); }
5199
5200 // Abort mouse wheel delta measurement, when scrolling explicitly
5201 if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
5202 { display.wheelStartX = display.wheelStartY = null; }
5203
5204 // Propagate the scroll position to the actual DOM scroller
5205 if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll); }
5206
5207 if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true); }
5208 // If we need to scroll a specific position into view, do so.
5209 if (op.scrollToPos) {
5210 var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
5211 clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
5212 maybeScrollWindow(cm, rect);
5213 }
5214
5215 // Fire events for markers that are hidden/unidden by editing or
5216 // undoing
5217 var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
5218 if (hidden) { for (var i = 0; i < hidden.length; ++i)
5219 { if (!hidden[i].lines.length) { signal(hidden[i], "hide"); } } }
5220 if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1)
5221 { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide"); } } }
5222
5223 if (display.wrapper.offsetHeight)
5224 { doc.scrollTop = cm.display.scroller.scrollTop; }
5225
5226 // Fire change events, and delayed event handlers
5227 if (op.changeObjs)
5228 { signal(cm, "changes", cm, op.changeObjs); }
5229 if (op.update)
5230 { op.update.finish(); }
5231 }
5232
5233 // Run the given function in an operation
5234 function runInOp(cm, f) {
5235 if (cm.curOp) { return f() }
5236 startOperation(cm);
5237 try { return f() }
5238 finally { endOperation(cm); }
5239 }
5240 // Wraps a function in an operation. Returns the wrapped function.
5241 function operation(cm, f) {
5242 return function() {
5243 if (cm.curOp) { return f.apply(cm, arguments) }
5244 startOperation(cm);
5245 try { return f.apply(cm, arguments) }
5246 finally { endOperation(cm); }
5247 }
5248 }
5249 // Used to add methods to editor and doc instances, wrapping them in
5250 // operations.
5251 function methodOp(f) {
5252 return function() {
5253 if (this.curOp) { return f.apply(this, arguments) }
5254 startOperation(this);
5255 try { return f.apply(this, arguments) }
5256 finally { endOperation(this); }
5257 }
5258 }
5259 function docMethodOp(f) {
5260 return function() {
5261 var cm = this.cm;
5262 if (!cm || cm.curOp) { return f.apply(this, arguments) }
5263 startOperation(cm);
5264 try { return f.apply(this, arguments) }
5265 finally { endOperation(cm); }
5266 }
5267 }
5268
5269 // Updates the display.view data structure for a given change to the
5270 // document. From and to are in pre-change coordinates. Lendiff is
5271 // the amount of lines added or subtracted by the change. This is
5272 // used for changes that span multiple lines, or change the way
5273 // lines are divided into visual lines. regLineChange (below)
5274 // registers single-line changes.
5275 function regChange(cm, from, to, lendiff) {
5276 if (from == null) { from = cm.doc.first; }
5277 if (to == null) { to = cm.doc.first + cm.doc.size; }
5278 if (!lendiff) { lendiff = 0; }
5279
5280 var display = cm.display;
5281 if (lendiff && to < display.viewTo &&
5282 (display.updateLineNumbers == null || display.updateLineNumbers > from))
5283 { display.updateLineNumbers = from; }
5284
5285 cm.curOp.viewChanged = true;
5286
5287 if (from >= display.viewTo) { // Change after
5288 if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
5289 { resetView(cm); }
5290 } else if (to <= display.viewFrom) { // Change before
5291 if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
5292 resetView(cm);
5293 } else {
5294 display.viewFrom += lendiff;
5295 display.viewTo += lendiff;
5296 }
5297 } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
5298 resetView(cm);
5299 } else if (from <= display.viewFrom) { // Top overlap
5300 var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
5301 if (cut) {
5302 display.view = display.view.slice(cut.index);
5303 display.viewFrom = cut.lineN;
5304 display.viewTo += lendiff;
5305 } else {
5306 resetView(cm);
5307 }
5308 } else if (to >= display.viewTo) { // Bottom overlap
5309 var cut$1 = viewCuttingPoint(cm, from, from, -1);
5310 if (cut$1) {
5311 display.view = display.view.slice(0, cut$1.index);
5312 display.viewTo = cut$1.lineN;
5313 } else {
5314 resetView(cm);
5315 }
5316 } else { // Gap in the middle
5317 var cutTop = viewCuttingPoint(cm, from, from, -1);
5318 var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
5319 if (cutTop && cutBot) {
5320 display.view = display.view.slice(0, cutTop.index)
5321 .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
5322 .concat(display.view.slice(cutBot.index));
5323 display.viewTo += lendiff;
5324 } else {
5325 resetView(cm);
5326 }
5327 }
5328
5329 var ext = display.externalMeasured;
5330 if (ext) {
5331 if (to < ext.lineN)
5332 { ext.lineN += lendiff; }
5333 else if (from < ext.lineN + ext.size)
5334 { display.externalMeasured = null; }
5335 }
5336 }
5337
5338 // Register a change to a single line. Type must be one of "text",
5339 // "gutter", "class", "widget"
5340 function regLineChange(cm, line, type) {
5341 cm.curOp.viewChanged = true;
5342 var display = cm.display, ext = cm.display.externalMeasured;
5343 if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
5344 { display.externalMeasured = null; }
5345
5346 if (line < display.viewFrom || line >= display.viewTo) { return }
5347 var lineView = display.view[findViewIndex(cm, line)];
5348 if (lineView.node == null) { return }
5349 var arr = lineView.changes || (lineView.changes = []);
5350 if (indexOf(arr, type) == -1) { arr.push(type); }
5351 }
5352
5353 // Clear the view.
5354 function resetView(cm) {
5355 cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
5356 cm.display.view = [];
5357 cm.display.viewOffset = 0;
5358 }
5359
5360 function viewCuttingPoint(cm, oldN, newN, dir) {
5361 var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
5362 if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
5363 { return {index: index, lineN: newN} }
5364 var n = cm.display.viewFrom;
5365 for (var i = 0; i < index; i++)
5366 { n += view[i].size; }
5367 if (n != oldN) {
5368 if (dir > 0) {
5369 if (index == view.length - 1) { return null }
5370 diff = (n + view[index].size) - oldN;
5371 index++;
5372 } else {
5373 diff = n - oldN;
5374 }
5375 oldN += diff; newN += diff;
5376 }
5377 while (visualLineNo(cm.doc, newN) != newN) {
5378 if (index == (dir < 0 ? 0 : view.length - 1)) { return null }
5379 newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
5380 index += dir;
5381 }
5382 return {index: index, lineN: newN}
5383 }
5384
5385 // Force the view to cover a given range, adding empty view element
5386 // or clipping off existing ones as needed.
5387 function adjustView(cm, from, to) {
5388 var display = cm.display, view = display.view;
5389 if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
5390 display.view = buildViewArray(cm, from, to);
5391 display.viewFrom = from;
5392 } else {
5393 if (display.viewFrom > from)
5394 { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); }
5395 else if (display.viewFrom < from)
5396 { display.view = display.view.slice(findViewIndex(cm, from)); }
5397 display.viewFrom = from;
5398 if (display.viewTo < to)
5399 { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); }
5400 else if (display.viewTo > to)
5401 { display.view = display.view.slice(0, findViewIndex(cm, to)); }
5402 }
5403 display.viewTo = to;
5404 }
5405
5406 // Count the number of lines in the view whose DOM representation is
5407 // out of date (or nonexistent).
5408 function countDirtyView(cm) {
5409 var view = cm.display.view, dirty = 0;
5410 for (var i = 0; i < view.length; i++) {
5411 var lineView = view[i];
5412 if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }
5413 }
5414 return dirty
5415 }
5416
5417 // HIGHLIGHT WORKER
5418
5419 function startWorker(cm, time) {
5420 if (cm.doc.highlightFrontier < cm.display.viewTo)
5421 { cm.state.highlight.set(time, bind(highlightWorker, cm)); }
5422 }
5423
5424 function highlightWorker(cm) {
5425 var doc = cm.doc;
5426 if (doc.highlightFrontier >= cm.display.viewTo) { return }
5427 var end = +new Date + cm.options.workTime;
5428 var context = getContextBefore(cm, doc.highlightFrontier);
5429 var changedLines = [];
5430
5431 doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {
5432 if (context.line >= cm.display.viewFrom) { // Visible
5433 var oldStyles = line.styles;
5434 var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null;
5435 var highlighted = highlightLine(cm, line, context, true);
5436 if (resetState) { context.state = resetState; }
5437 line.styles = highlighted.styles;
5438 var oldCls = line.styleClasses, newCls = highlighted.classes;
5439 if (newCls) { line.styleClasses = newCls; }
5440 else if (oldCls) { line.styleClasses = null; }
5441 var ischange = !oldStyles || oldStyles.length != line.styles.length ||
5442 oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
5443 for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i]; }
5444 if (ischange) { changedLines.push(context.line); }
5445 line.stateAfter = context.save();
5446 context.nextLine();
5447 } else {
5448 if (line.text.length <= cm.options.maxHighlightLength)
5449 { processLine(cm, line.text, context); }
5450 line.stateAfter = context.line % 5 == 0 ? context.save() : null;
5451 context.nextLine();
5452 }
5453 if (+new Date > end) {
5454 startWorker(cm, cm.options.workDelay);
5455 return true
5456 }
5457 });
5458 doc.highlightFrontier = context.line;
5459 doc.modeFrontier = Math.max(doc.modeFrontier, context.line);
5460 if (changedLines.length) { runInOp(cm, function () {
5461 for (var i = 0; i < changedLines.length; i++)
5462 { regLineChange(cm, changedLines[i], "text"); }
5463 }); }
5464 }
5465
5466 // DISPLAY DRAWING
5467
5468 var DisplayUpdate = function(cm, viewport, force) {
5469 var display = cm.display;
5470
5471 this.viewport = viewport;
5472 // Store some values that we'll need later (but don't want to force a relayout for)
5473 this.visible = visibleLines(display, cm.doc, viewport);
5474 this.editorIsHidden = !display.wrapper.offsetWidth;
5475 this.wrapperHeight = display.wrapper.clientHeight;
5476 this.wrapperWidth = display.wrapper.clientWidth;
5477 this.oldDisplayWidth = displayWidth(cm);
5478 this.force = force;
5479 this.dims = getDimensions(cm);
5480 this.events = [];
5481 };
5482
5483 DisplayUpdate.prototype.signal = function (emitter, type) {
5484 if (hasHandler(emitter, type))
5485 { this.events.push(arguments); }
5486 };
5487 DisplayUpdate.prototype.finish = function () {
5488 var this$1 = this;
5489
5490 for (var i = 0; i < this.events.length; i++)
5491 { signal.apply(null, this$1.events[i]); }
5492 };
5493
5494 function maybeClipScrollbars(cm) {
5495 var display = cm.display;
5496 if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
5497 display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
5498 display.heightForcer.style.height = scrollGap(cm) + "px";
5499 display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
5500 display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
5501 display.scrollbarsClipped = true;
5502 }
5503 }
5504
5505 function selectionSnapshot(cm) {
5506 if (cm.hasFocus()) { return null }
5507 var active = activeElt();
5508 if (!active || !contains(cm.display.lineDiv, active)) { return null }
5509 var result = {activeElt: active};
5510 if (window.getSelection) {
5511 var sel = window.getSelection();
5512 if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) {
5513 result.anchorNode = sel.anchorNode;
5514 result.anchorOffset = sel.anchorOffset;
5515 result.focusNode = sel.focusNode;
5516 result.focusOffset = sel.focusOffset;
5517 }
5518 }
5519 return result
5520 }
5521
5522 function restoreSelection(snapshot) {
5523 if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }
5524 snapshot.activeElt.focus();
5525 if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {
5526 var sel = window.getSelection(), range$$1 = document.createRange();
5527 range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset);
5528 range$$1.collapse(false);
5529 sel.removeAllRanges();
5530 sel.addRange(range$$1);
5531 sel.extend(snapshot.focusNode, snapshot.focusOffset);
5532 }
5533 }
5534
5535 // Does the actual updating of the line display. Bails out
5536 // (returning false) when there is nothing to be done and forced is
5537 // false.
5538 function updateDisplayIfNeeded(cm, update) {
5539 var display = cm.display, doc = cm.doc;
5540
5541 if (update.editorIsHidden) {
5542 resetView(cm);
5543 return false
5544 }
5545
5546 // Bail out if the visible area is already rendered and nothing changed.
5547 if (!update.force &&
5548 update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
5549 (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
5550 display.renderedView == display.view && countDirtyView(cm) == 0)
5551 { return false }
5552
5553 if (maybeUpdateLineNumberWidth(cm)) {
5554 resetView(cm);
5555 update.dims = getDimensions(cm);
5556 }
5557
5558 // Compute a suitable new viewport (from & to)
5559 var end = doc.first + doc.size;
5560 var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
5561 var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
5562 if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom); }
5563 if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo); }
5564 if (sawCollapsedSpans) {
5565 from = visualLineNo(cm.doc, from);
5566 to = visualLineEndNo(cm.doc, to);
5567 }
5568
5569 var different = from != display.viewFrom || to != display.viewTo ||
5570 display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
5571 adjustView(cm, from, to);
5572
5573 display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
5574 // Position the mover div to align with the current scroll position
5575 cm.display.mover.style.top = display.viewOffset + "px";
5576
5577 var toUpdate = countDirtyView(cm);
5578 if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
5579 (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
5580 { return false }
5581
5582 // For big changes, we hide the enclosing element during the
5583 // update, since that speeds up the operations on most browsers.
5584 var selSnapshot = selectionSnapshot(cm);
5585 if (toUpdate > 4) { display.lineDiv.style.display = "none"; }
5586 patchDisplay(cm, display.updateLineNumbers, update.dims);
5587 if (toUpdate > 4) { display.lineDiv.style.display = ""; }
5588 display.renderedView = display.view;
5589 // There might have been a widget with a focused element that got
5590 // hidden or updated, if so re-focus it.
5591 restoreSelection(selSnapshot);
5592
5593 // Prevent selection and cursors from interfering with the scroll
5594 // width and height.
5595 removeChildren(display.cursorDiv);
5596 removeChildren(display.selectionDiv);
5597 display.gutters.style.height = display.sizer.style.minHeight = 0;
5598
5599 if (different) {
5600 display.lastWrapHeight = update.wrapperHeight;
5601 display.lastWrapWidth = update.wrapperWidth;
5602 startWorker(cm, 400);
5603 }
5604
5605 display.updateLineNumbers = null;
5606
5607 return true
5608 }
5609
5610 function postUpdateDisplay(cm, update) {
5611 var viewport = update.viewport;
5612
5613 for (var first = true;; first = false) {
5614 if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
5615 // Clip forced viewport to actual scrollable area.
5616 if (viewport && viewport.top != null)
5617 { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; }
5618 // Updated line heights might result in the drawn area not
5619 // actually covering the viewport. Keep looping until it does.
5620 update.visible = visibleLines(cm.display, cm.doc, viewport);
5621 if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
5622 { break }
5623 }
5624 if (!updateDisplayIfNeeded(cm, update)) { break }
5625 updateHeightsInViewport(cm);
5626 var barMeasure = measureForScrollbars(cm);
5627 updateSelection(cm);
5628 updateScrollbars(cm, barMeasure);
5629 setDocumentHeight(cm, barMeasure);
5630 update.force = false;
5631 }
5632
5633 update.signal(cm, "update", cm);
5634 if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
5635 update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
5636 cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
5637 }
5638 }
5639
5640 function updateDisplaySimple(cm, viewport) {
5641 var update = new DisplayUpdate(cm, viewport);
5642 if (updateDisplayIfNeeded(cm, update)) {
5643 updateHeightsInViewport(cm);
5644 postUpdateDisplay(cm, update);
5645 var barMeasure = measureForScrollbars(cm);
5646 updateSelection(cm);
5647 updateScrollbars(cm, barMeasure);
5648 setDocumentHeight(cm, barMeasure);
5649 update.finish();
5650 }
5651 }
5652
5653 // Sync the actual display DOM structure with display.view, removing
5654 // nodes for lines that are no longer in view, and creating the ones
5655 // that are not there yet, and updating the ones that are out of
5656 // date.
5657 function patchDisplay(cm, updateNumbersFrom, dims) {
5658 var display = cm.display, lineNumbers = cm.options.lineNumbers;
5659 var container = display.lineDiv, cur = container.firstChild;
5660
5661 function rm(node) {
5662 var next = node.nextSibling;
5663 // Works around a throw-scroll bug in OS X Webkit
5664 if (webkit && mac && cm.display.currentWheelTarget == node)
5665 { node.style.display = "none"; }
5666 else
5667 { node.parentNode.removeChild(node); }
5668 return next
5669 }
5670
5671 var view = display.view, lineN = display.viewFrom;
5672 // Loop over the elements in the view, syncing cur (the DOM nodes
5673 // in display.lineDiv) with the view as we go.
5674 for (var i = 0; i < view.length; i++) {
5675 var lineView = view[i];
5676 if (lineView.hidden) {
5677 } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
5678 var node = buildLineElement(cm, lineView, lineN, dims);
5679 container.insertBefore(node, cur);
5680 } else { // Already drawn
5681 while (cur != lineView.node) { cur = rm(cur); }
5682 var updateNumber = lineNumbers && updateNumbersFrom != null &&
5683 updateNumbersFrom <= lineN && lineView.lineNumber;
5684 if (lineView.changes) {
5685 if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false; }
5686 updateLineForChanges(cm, lineView, lineN, dims);
5687 }
5688 if (updateNumber) {
5689 removeChildren(lineView.lineNumber);
5690 lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
5691 }
5692 cur = lineView.node.nextSibling;
5693 }
5694 lineN += lineView.size;
5695 }
5696 while (cur) { cur = rm(cur); }
5697 }
5698
5699 function updateGutterSpace(cm) {
5700 var width = cm.display.gutters.offsetWidth;
5701 cm.display.sizer.style.marginLeft = width + "px";
5702 }
5703
5704 function setDocumentHeight(cm, measure) {
5705 cm.display.sizer.style.minHeight = measure.docHeight + "px";
5706 cm.display.heightForcer.style.top = measure.docHeight + "px";
5707 cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
5708 }
5709
5710 // Rebuild the gutter elements, ensure the margin to the left of the
5711 // code matches their width.
5712 function updateGutters(cm) {
5713 var gutters = cm.display.gutters, specs = cm.options.gutters;
5714 removeChildren(gutters);
5715 var i = 0;
5716 for (; i < specs.length; ++i) {
5717 var gutterClass = specs[i];
5718 var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
5719 if (gutterClass == "CodeMirror-linenumbers") {
5720 cm.display.lineGutter = gElt;
5721 gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
5722 }
5723 }
5724 gutters.style.display = i ? "" : "none";
5725 updateGutterSpace(cm);
5726 }
5727
5728 // Make sure the gutters options contains the element
5729 // "CodeMirror-linenumbers" when the lineNumbers option is true.
5730 function setGuttersForLineNumbers(options) {
5731 var found = indexOf(options.gutters, "CodeMirror-linenumbers");
5732 if (found == -1 && options.lineNumbers) {
5733 options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
5734 } else if (found > -1 && !options.lineNumbers) {
5735 options.gutters = options.gutters.slice(0);
5736 options.gutters.splice(found, 1);
5737 }
5738 }
5739
5740 // Since the delta values reported on mouse wheel events are
5741 // unstandardized between browsers and even browser versions, and
5742 // generally horribly unpredictable, this code starts by measuring
5743 // the scroll effect that the first few mouse wheel events have,
5744 // and, from that, detects the way it can convert deltas to pixel
5745 // offsets afterwards.
5746 //
5747 // The reason we want to know the amount a wheel event will scroll
5748 // is that it gives us a chance to update the display before the
5749 // actual scrolling happens, reducing flickering.
5750
5751 var wheelSamples = 0;
5752 var wheelPixelsPerUnit = null;
5753 // Fill in a browser-detected starting value on browsers where we
5754 // know one. These don't have to be accurate -- the result of them
5755 // being wrong would just be a slight flicker on the first wheel
5756 // scroll (if it is large enough).
5757 if (ie) { wheelPixelsPerUnit = -.53; }
5758 else if (gecko) { wheelPixelsPerUnit = 15; }
5759 else if (chrome) { wheelPixelsPerUnit = -.7; }
5760 else if (safari) { wheelPixelsPerUnit = -1/3; }
5761
5762 function wheelEventDelta(e) {
5763 var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
5764 if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail; }
5765 if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail; }
5766 else if (dy == null) { dy = e.wheelDelta; }
5767 return {x: dx, y: dy}
5768 }
5769 function wheelEventPixels(e) {
5770 var delta = wheelEventDelta(e);
5771 delta.x *= wheelPixelsPerUnit;
5772 delta.y *= wheelPixelsPerUnit;
5773 return delta
5774 }
5775
5776 function onScrollWheel(cm, e) {
5777 var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
5778
5779 var display = cm.display, scroll = display.scroller;
5780 // Quit if there's nothing to scroll here
5781 var canScrollX = scroll.scrollWidth > scroll.clientWidth;
5782 var canScrollY = scroll.scrollHeight > scroll.clientHeight;
5783 if (!(dx && canScrollX || dy && canScrollY)) { return }
5784
5785 // Webkit browsers on OS X abort momentum scrolls when the target
5786 // of the scroll event is removed from the scrollable element.
5787 // This hack (see related code in patchDisplay) makes sure the
5788 // element is kept around.
5789 if (dy && mac && webkit) {
5790 outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
5791 for (var i = 0; i < view.length; i++) {
5792 if (view[i].node == cur) {
5793 cm.display.currentWheelTarget = cur;
5794 break outer
5795 }
5796 }
5797 }
5798 }
5799
5800 // On some browsers, horizontal scrolling will cause redraws to
5801 // happen before the gutter has been realigned, causing it to
5802 // wriggle around in a most unseemly way. When we have an
5803 // estimated pixels/delta value, we just handle horizontal
5804 // scrolling entirely here. It'll be slightly off from native, but
5805 // better than glitching out.
5806 if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
5807 if (dy && canScrollY)
5808 { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); }
5809 setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit));
5810 // Only prevent default scrolling if vertical scrolling is
5811 // actually possible. Otherwise, it causes vertical scroll
5812 // jitter on OSX trackpads when deltaX is small and deltaY
5813 // is large (issue #3579)
5814 if (!dy || (dy && canScrollY))
5815 { e_preventDefault(e); }
5816 display.wheelStartX = null; // Abort measurement, if in progress
5817 return
5818 }
5819
5820 // 'Project' the visible viewport to cover the area that is being
5821 // scrolled into view (if we know enough to estimate it).
5822 if (dy && wheelPixelsPerUnit != null) {
5823 var pixels = dy * wheelPixelsPerUnit;
5824 var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
5825 if (pixels < 0) { top = Math.max(0, top + pixels - 50); }
5826 else { bot = Math.min(cm.doc.height, bot + pixels + 50); }
5827 updateDisplaySimple(cm, {top: top, bottom: bot});
5828 }
5829
5830 if (wheelSamples < 20) {
5831 if (display.wheelStartX == null) {
5832 display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
5833 display.wheelDX = dx; display.wheelDY = dy;
5834 setTimeout(function () {
5835 if (display.wheelStartX == null) { return }
5836 var movedX = scroll.scrollLeft - display.wheelStartX;
5837 var movedY = scroll.scrollTop - display.wheelStartY;
5838 var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
5839 (movedX && display.wheelDX && movedX / display.wheelDX);
5840 display.wheelStartX = display.wheelStartY = null;
5841 if (!sample) { return }
5842 wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
5843 ++wheelSamples;
5844 }, 200);
5845 } else {
5846 display.wheelDX += dx; display.wheelDY += dy;
5847 }
5848 }
5849 }
5850
5851 // Selection objects are immutable. A new one is created every time
5852 // the selection changes. A selection is one or more non-overlapping
5853 // (and non-touching) ranges, sorted, and an integer that indicates
5854 // which one is the primary selection (the one that's scrolled into
5855 // view, that getCursor returns, etc).
5856 var Selection = function(ranges, primIndex) {
5857 this.ranges = ranges;
5858 this.primIndex = primIndex;
5859 };
5860
5861 Selection.prototype.primary = function () { return this.ranges[this.primIndex] };
5862
5863 Selection.prototype.equals = function (other) {
5864 var this$1 = this;
5865
5866 if (other == this) { return true }
5867 if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }
5868 for (var i = 0; i < this.ranges.length; i++) {
5869 var here = this$1.ranges[i], there = other.ranges[i];
5870 if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false }
5871 }
5872 return true
5873 };
5874
5875 Selection.prototype.deepCopy = function () {
5876 var this$1 = this;
5877
5878 var out = [];
5879 for (var i = 0; i < this.ranges.length; i++)
5880 { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)); }
5881 return new Selection(out, this.primIndex)
5882 };
5883
5884 Selection.prototype.somethingSelected = function () {
5885 var this$1 = this;
5886
5887 for (var i = 0; i < this.ranges.length; i++)
5888 { if (!this$1.ranges[i].empty()) { return true } }
5889 return false
5890 };
5891
5892 Selection.prototype.contains = function (pos, end) {
5893 var this$1 = this;
5894
5895 if (!end) { end = pos; }
5896 for (var i = 0; i < this.ranges.length; i++) {
5897 var range = this$1.ranges[i];
5898 if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
5899 { return i }
5900 }
5901 return -1
5902 };
5903
5904 var Range = function(anchor, head) {
5905 this.anchor = anchor; this.head = head;
5906 };
5907
5908 Range.prototype.from = function () { return minPos(this.anchor, this.head) };
5909 Range.prototype.to = function () { return maxPos(this.anchor, this.head) };
5910 Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch };
5911
5912 // Take an unsorted, potentially overlapping set of ranges, and
5913 // build a selection out of it. 'Consumes' ranges array (modifying
5914 // it).
5915 function normalizeSelection(ranges, primIndex) {
5916 var prim = ranges[primIndex];
5917 ranges.sort(function (a, b) { return cmp(a.from(), b.from()); });
5918 primIndex = indexOf(ranges, prim);
5919 for (var i = 1; i < ranges.length; i++) {
5920 var cur = ranges[i], prev = ranges[i - 1];
5921 if (cmp(prev.to(), cur.from()) >= 0) {
5922 var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
5923 var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
5924 if (i <= primIndex) { --primIndex; }
5925 ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
5926 }
5927 }
5928 return new Selection(ranges, primIndex)
5929 }
5930
5931 function simpleSelection(anchor, head) {
5932 return new Selection([new Range(anchor, head || anchor)], 0)
5933 }
5934
5935 // Compute the position of the end of a change (its 'to' property
5936 // refers to the pre-change end).
5937 function changeEnd(change) {
5938 if (!change.text) { return change.to }
5939 return Pos(change.from.line + change.text.length - 1,
5940 lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0))
5941 }
5942
5943 // Adjust a position to refer to the post-change position of the
5944 // same text, or the end of the change if the change covers it.
5945 function adjustForChange(pos, change) {
5946 if (cmp(pos, change.from) < 0) { return pos }
5947 if (cmp(pos, change.to) <= 0) { return changeEnd(change) }
5948
5949 var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
5950 if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch; }
5951 return Pos(line, ch)
5952 }
5953
5954 function computeSelAfterChange(doc, change) {
5955 var out = [];
5956 for (var i = 0; i < doc.sel.ranges.length; i++) {
5957 var range = doc.sel.ranges[i];
5958 out.push(new Range(adjustForChange(range.anchor, change),
5959 adjustForChange(range.head, change)));
5960 }
5961 return normalizeSelection(out, doc.sel.primIndex)
5962 }
5963
5964 function offsetPos(pos, old, nw) {
5965 if (pos.line == old.line)
5966 { return Pos(nw.line, pos.ch - old.ch + nw.ch) }
5967 else
5968 { return Pos(nw.line + (pos.line - old.line), pos.ch) }
5969 }
5970
5971 // Used by replaceSelections to allow moving the selection to the
5972 // start or around the replaced test. Hint may be "start" or "around".
5973 function computeReplacedSel(doc, changes, hint) {
5974 var out = [];
5975 var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
5976 for (var i = 0; i < changes.length; i++) {
5977 var change = changes[i];
5978 var from = offsetPos(change.from, oldPrev, newPrev);
5979 var to = offsetPos(changeEnd(change), oldPrev, newPrev);
5980 oldPrev = change.to;
5981 newPrev = to;
5982 if (hint == "around") {
5983 var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
5984 out[i] = new Range(inv ? to : from, inv ? from : to);
5985 } else {
5986 out[i] = new Range(from, from);
5987 }
5988 }
5989 return new Selection(out, doc.sel.primIndex)
5990 }
5991
5992 // Used to get the editor into a consistent state again when options change.
5993
5994 function loadMode(cm) {
5995 cm.doc.mode = getMode(cm.options, cm.doc.modeOption);
5996 resetModeState(cm);
5997 }
5998
5999 function resetModeState(cm) {
6000 cm.doc.iter(function (line) {
6001 if (line.stateAfter) { line.stateAfter = null; }
6002 if (line.styles) { line.styles = null; }
6003 });
6004 cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first;
6005 startWorker(cm, 100);
6006 cm.state.modeGen++;
6007 if (cm.curOp) { regChange(cm); }
6008 }
6009
6010 // DOCUMENT DATA STRUCTURE
6011
6012 // By default, updates that start and end at the beginning of a line
6013 // are treated specially, in order to make the association of line
6014 // widgets and marker elements with the text behave more intuitive.
6015 function isWholeLineUpdate(doc, change) {
6016 return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
6017 (!doc.cm || doc.cm.options.wholeLineUpdateBefore)
6018 }
6019
6020 // Perform a change on the document data structure.
6021 function updateDoc(doc, change, markedSpans, estimateHeight$$1) {
6022 function spansFor(n) {return markedSpans ? markedSpans[n] : null}
6023 function update(line, text, spans) {
6024 updateLine(line, text, spans, estimateHeight$$1);
6025 signalLater(line, "change", line, change);
6026 }
6027 function linesFor(start, end) {
6028 var result = [];
6029 for (var i = start; i < end; ++i)
6030 { result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); }
6031 return result
6032 }
6033
6034 var from = change.from, to = change.to, text = change.text;
6035 var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
6036 var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
6037
6038 // Adjust the line structure
6039 if (change.full) {
6040 doc.insert(0, linesFor(0, text.length));
6041 doc.remove(text.length, doc.size - text.length);
6042 } else if (isWholeLineUpdate(doc, change)) {
6043 // This is a whole-line replace. Treated specially to make
6044 // sure line objects move the way they are supposed to.
6045 var added = linesFor(0, text.length - 1);
6046 update(lastLine, lastLine.text, lastSpans);
6047 if (nlines) { doc.remove(from.line, nlines); }
6048 if (added.length) { doc.insert(from.line, added); }
6049 } else if (firstLine == lastLine) {
6050 if (text.length == 1) {
6051 update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
6052 } else {
6053 var added$1 = linesFor(1, text.length - 1);
6054 added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1));
6055 update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
6056 doc.insert(from.line + 1, added$1);
6057 }
6058 } else if (text.length == 1) {
6059 update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
6060 doc.remove(from.line + 1, nlines);
6061 } else {
6062 update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
6063 update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
6064 var added$2 = linesFor(1, text.length - 1);
6065 if (nlines > 1) { doc.remove(from.line + 1, nlines - 1); }
6066 doc.insert(from.line + 1, added$2);
6067 }
6068
6069 signalLater(doc, "change", doc, change);
6070 }
6071
6072 // Call f for all linked documents.
6073 function linkedDocs(doc, f, sharedHistOnly) {
6074 function propagate(doc, skip, sharedHist) {
6075 if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) {
6076 var rel = doc.linked[i];
6077 if (rel.doc == skip) { continue }
6078 var shared = sharedHist && rel.sharedHist;
6079 if (sharedHistOnly && !shared) { continue }
6080 f(rel.doc, shared);
6081 propagate(rel.doc, doc, shared);
6082 } }
6083 }
6084 propagate(doc, null, true);
6085 }
6086
6087 // Attach a document to an editor.
6088 function attachDoc(cm, doc) {
6089 if (doc.cm) { throw new Error("This document is already in use.") }
6090 cm.doc = doc;
6091 doc.cm = cm;
6092 estimateLineHeights(cm);
6093 loadMode(cm);
6094 setDirectionClass(cm);
6095 if (!cm.options.lineWrapping) { findMaxLine(cm); }
6096 cm.options.mode = doc.modeOption;
6097 regChange(cm);
6098 }
6099
6100 function setDirectionClass(cm) {
6101 (cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl");
6102 }
6103
6104 function directionChanged(cm) {
6105 runInOp(cm, function () {
6106 setDirectionClass(cm);
6107 regChange(cm);
6108 });
6109 }
6110
6111 function History(startGen) {
6112 // Arrays of change events and selections. Doing something adds an
6113 // event to done and clears undo. Undoing moves events from done
6114 // to undone, redoing moves them in the other direction.
6115 this.done = []; this.undone = [];
6116 this.undoDepth = Infinity;
6117 // Used to track when changes can be merged into a single undo
6118 // event
6119 this.lastModTime = this.lastSelTime = 0;
6120 this.lastOp = this.lastSelOp = null;
6121 this.lastOrigin = this.lastSelOrigin = null;
6122 // Used by the isClean() method
6123 this.generation = this.maxGeneration = startGen || 1;
6124 }
6125
6126 // Create a history change event from an updateDoc-style change
6127 // object.
6128 function historyChangeFromChange(doc, change) {
6129 var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
6130 attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
6131 linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true);
6132 return histChange
6133 }
6134
6135 // Pop all selection events off the end of a history array. Stop at
6136 // a change event.
6137 function clearSelectionEvents(array) {
6138 while (array.length) {
6139 var last = lst(array);
6140 if (last.ranges) { array.pop(); }
6141 else { break }
6142 }
6143 }
6144
6145 // Find the top change event in the history. Pop off selection
6146 // events that are in the way.
6147 function lastChangeEvent(hist, force) {
6148 if (force) {
6149 clearSelectionEvents(hist.done);
6150 return lst(hist.done)
6151 } else if (hist.done.length && !lst(hist.done).ranges) {
6152 return lst(hist.done)
6153 } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
6154 hist.done.pop();
6155 return lst(hist.done)
6156 }
6157 }
6158
6159 // Register a change in the history. Merges changes that are within
6160 // a single operation, or are close together with an origin that
6161 // allows merging (starting with "+") into a single event.
6162 function addChangeToHistory(doc, change, selAfter, opId) {
6163 var hist = doc.history;
6164 hist.undone.length = 0;
6165 var time = +new Date, cur;
6166 var last;
6167
6168 if ((hist.lastOp == opId ||
6169 hist.lastOrigin == change.origin && change.origin &&
6170 ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
6171 change.origin.charAt(0) == "*")) &&
6172 (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
6173 // Merge this change into the last event
6174 last = lst(cur.changes);
6175 if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
6176 // Optimized case for simple insertion -- don't want to add
6177 // new changesets for every character typed
6178 last.to = changeEnd(change);
6179 } else {
6180 // Add new sub-event
6181 cur.changes.push(historyChangeFromChange(doc, change));
6182 }
6183 } else {
6184 // Can not be merged, start a new event.
6185 var before = lst(hist.done);
6186 if (!before || !before.ranges)
6187 { pushSelectionToHistory(doc.sel, hist.done); }
6188 cur = {changes: [historyChangeFromChange(doc, change)],
6189 generation: hist.generation};
6190 hist.done.push(cur);
6191 while (hist.done.length > hist.undoDepth) {
6192 hist.done.shift();
6193 if (!hist.done[0].ranges) { hist.done.shift(); }
6194 }
6195 }
6196 hist.done.push(selAfter);
6197 hist.generation = ++hist.maxGeneration;
6198 hist.lastModTime = hist.lastSelTime = time;
6199 hist.lastOp = hist.lastSelOp = opId;
6200 hist.lastOrigin = hist.lastSelOrigin = change.origin;
6201
6202 if (!last) { signal(doc, "historyAdded"); }
6203 }
6204
6205 function selectionEventCanBeMerged(doc, origin, prev, sel) {
6206 var ch = origin.charAt(0);
6207 return ch == "*" ||
6208 ch == "+" &&
6209 prev.ranges.length == sel.ranges.length &&
6210 prev.somethingSelected() == sel.somethingSelected() &&
6211 new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500)
6212 }
6213
6214 // Called whenever the selection changes, sets the new selection as
6215 // the pending selection in the history, and pushes the old pending
6216 // selection into the 'done' array when it was significantly
6217 // different (in number of selected ranges, emptiness, or time).
6218 function addSelectionToHistory(doc, sel, opId, options) {
6219 var hist = doc.history, origin = options && options.origin;
6220
6221 // A new event is started when the previous origin does not match
6222 // the current, or the origins don't allow matching. Origins
6223 // starting with * are always merged, those starting with + are
6224 // merged when similar and close together in time.
6225 if (opId == hist.lastSelOp ||
6226 (origin && hist.lastSelOrigin == origin &&
6227 (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
6228 selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
6229 { hist.done[hist.done.length - 1] = sel; }
6230 else
6231 { pushSelectionToHistory(sel, hist.done); }
6232
6233 hist.lastSelTime = +new Date;
6234 hist.lastSelOrigin = origin;
6235 hist.lastSelOp = opId;
6236 if (options && options.clearRedo !== false)
6237 { clearSelectionEvents(hist.undone); }
6238 }
6239
6240 function pushSelectionToHistory(sel, dest) {
6241 var top = lst(dest);
6242 if (!(top && top.ranges && top.equals(sel)))
6243 { dest.push(sel); }
6244 }
6245
6246 // Used to store marked span information in the history.
6247 function attachLocalSpans(doc, change, from, to) {
6248 var existing = change["spans_" + doc.id], n = 0;
6249 doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) {
6250 if (line.markedSpans)
6251 { (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; }
6252 ++n;
6253 });
6254 }
6255
6256 // When un/re-doing restores text containing marked spans, those
6257 // that have been explicitly cleared should not be restored.
6258 function removeClearedSpans(spans) {
6259 if (!spans) { return null }
6260 var out;
6261 for (var i = 0; i < spans.length; ++i) {
6262 if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i); } }
6263 else if (out) { out.push(spans[i]); }
6264 }
6265 return !out ? spans : out.length ? out : null
6266 }
6267
6268 // Retrieve and filter the old marked spans stored in a change event.
6269 function getOldSpans(doc, change) {
6270 var found = change["spans_" + doc.id];
6271 if (!found) { return null }
6272 var nw = [];
6273 for (var i = 0; i < change.text.length; ++i)
6274 { nw.push(removeClearedSpans(found[i])); }
6275 return nw
6276 }
6277
6278 // Used for un/re-doing changes from the history. Combines the
6279 // result of computing the existing spans with the set of spans that
6280 // existed in the history (so that deleting around a span and then
6281 // undoing brings back the span).
6282 function mergeOldSpans(doc, change) {
6283 var old = getOldSpans(doc, change);
6284 var stretched = stretchSpansOverChange(doc, change);
6285 if (!old) { return stretched }
6286 if (!stretched) { return old }
6287
6288 for (var i = 0; i < old.length; ++i) {
6289 var oldCur = old[i], stretchCur = stretched[i];
6290 if (oldCur && stretchCur) {
6291 spans: for (var j = 0; j < stretchCur.length; ++j) {
6292 var span = stretchCur[j];
6293 for (var k = 0; k < oldCur.length; ++k)
6294 { if (oldCur[k].marker == span.marker) { continue spans } }
6295 oldCur.push(span);
6296 }
6297 } else if (stretchCur) {
6298 old[i] = stretchCur;
6299 }
6300 }
6301 return old
6302 }
6303
6304 // Used both to provide a JSON-safe object in .getHistory, and, when
6305 // detaching a document, to split the history in two
6306 function copyHistoryArray(events, newGroup, instantiateSel) {
6307 var copy = [];
6308 for (var i = 0; i < events.length; ++i) {
6309 var event = events[i];
6310 if (event.ranges) {
6311 copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
6312 continue
6313 }
6314 var changes = event.changes, newChanges = [];
6315 copy.push({changes: newChanges});
6316 for (var j = 0; j < changes.length; ++j) {
6317 var change = changes[j], m = (void 0);
6318 newChanges.push({from: change.from, to: change.to, text: change.text});
6319 if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) {
6320 if (indexOf(newGroup, Number(m[1])) > -1) {
6321 lst(newChanges)[prop] = change[prop];
6322 delete change[prop];
6323 }
6324 } } }
6325 }
6326 }
6327 return copy
6328 }
6329
6330 // The 'scroll' parameter given to many of these indicated whether
6331 // the new cursor position should be scrolled into view after
6332 // modifying the selection.
6333
6334 // If shift is held or the extend flag is set, extends a range to
6335 // include a given position (and optionally a second position).
6336 // Otherwise, simply returns the range between the given positions.
6337 // Used for cursor motion and such.
6338 function extendRange(range, head, other, extend) {
6339 if (extend) {
6340 var anchor = range.anchor;
6341 if (other) {
6342 var posBefore = cmp(head, anchor) < 0;
6343 if (posBefore != (cmp(other, anchor) < 0)) {
6344 anchor = head;
6345 head = other;
6346 } else if (posBefore != (cmp(head, other) < 0)) {
6347 head = other;
6348 }
6349 }
6350 return new Range(anchor, head)
6351 } else {
6352 return new Range(other || head, head)
6353 }
6354 }
6355
6356 // Extend the primary selection range, discard the rest.
6357 function extendSelection(doc, head, other, options, extend) {
6358 if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend); }
6359 setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options);
6360 }
6361
6362 // Extend all selections (pos is an array of selections with length
6363 // equal the number of selections)
6364 function extendSelections(doc, heads, options) {
6365 var out = [];
6366 var extend = doc.cm && (doc.cm.display.shift || doc.extend);
6367 for (var i = 0; i < doc.sel.ranges.length; i++)
6368 { out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend); }
6369 var newSel = normalizeSelection(out, doc.sel.primIndex);
6370 setSelection(doc, newSel, options);
6371 }
6372
6373 // Updates a single range in the selection.
6374 function replaceOneSelection(doc, i, range, options) {
6375 var ranges = doc.sel.ranges.slice(0);
6376 ranges[i] = range;
6377 setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
6378 }
6379
6380 // Reset the selection to a single range.
6381 function setSimpleSelection(doc, anchor, head, options) {
6382 setSelection(doc, simpleSelection(anchor, head), options);
6383 }
6384
6385 // Give beforeSelectionChange handlers a change to influence a
6386 // selection update.
6387 function filterSelectionChange(doc, sel, options) {
6388 var obj = {
6389 ranges: sel.ranges,
6390 update: function(ranges) {
6391 var this$1 = this;
6392
6393 this.ranges = [];
6394 for (var i = 0; i < ranges.length; i++)
6395 { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
6396 clipPos(doc, ranges[i].head)); }
6397 },
6398 origin: options && options.origin
6399 };
6400 signal(doc, "beforeSelectionChange", doc, obj);
6401 if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj); }
6402 if (obj.ranges != sel.ranges) { return normalizeSelection(obj.ranges, obj.ranges.length - 1) }
6403 else { return sel }
6404 }
6405
6406 function setSelectionReplaceHistory(doc, sel, options) {
6407 var done = doc.history.done, last = lst(done);
6408 if (last && last.ranges) {
6409 done[done.length - 1] = sel;
6410 setSelectionNoUndo(doc, sel, options);
6411 } else {
6412 setSelection(doc, sel, options);
6413 }
6414 }
6415
6416 // Set a new selection.
6417 function setSelection(doc, sel, options) {
6418 setSelectionNoUndo(doc, sel, options);
6419 addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
6420 }
6421
6422 function setSelectionNoUndo(doc, sel, options) {
6423 if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
6424 { sel = filterSelectionChange(doc, sel, options); }
6425
6426 var bias = options && options.bias ||
6427 (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
6428 setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
6429
6430 if (!(options && options.scroll === false) && doc.cm)
6431 { ensureCursorVisible(doc.cm); }
6432 }
6433
6434 function setSelectionInner(doc, sel) {
6435 if (sel.equals(doc.sel)) { return }
6436
6437 doc.sel = sel;
6438
6439 if (doc.cm) {
6440 doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
6441 signalCursorActivity(doc.cm);
6442 }
6443 signalLater(doc, "cursorActivity", doc);
6444 }
6445
6446 // Verify that the selection does not partially select any atomic
6447 // marked ranges.
6448 function reCheckSelection(doc) {
6449 setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false));
6450 }
6451
6452 // Return a selection that does not partially select any atomic
6453 // ranges.
6454 function skipAtomicInSelection(doc, sel, bias, mayClear) {
6455 var out;
6456 for (var i = 0; i < sel.ranges.length; i++) {
6457 var range = sel.ranges[i];
6458 var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
6459 var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
6460 var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
6461 if (out || newAnchor != range.anchor || newHead != range.head) {
6462 if (!out) { out = sel.ranges.slice(0, i); }
6463 out[i] = new Range(newAnchor, newHead);
6464 }
6465 }
6466 return out ? normalizeSelection(out, sel.primIndex) : sel
6467 }
6468
6469 function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
6470 var line = getLine(doc, pos.line);
6471 if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
6472 var sp = line.markedSpans[i], m = sp.marker;
6473 if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
6474 (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
6475 if (mayClear) {
6476 signal(m, "beforeCursorEnter");
6477 if (m.explicitlyCleared) {
6478 if (!line.markedSpans) { break }
6479 else {--i; continue}
6480 }
6481 }
6482 if (!m.atomic) { continue }
6483
6484 if (oldPos) {
6485 var near = m.find(dir < 0 ? 1 : -1), diff = (void 0);
6486 if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)
6487 { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); }
6488 if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
6489 { return skipAtomicInner(doc, near, pos, dir, mayClear) }
6490 }
6491
6492 var far = m.find(dir < 0 ? -1 : 1);
6493 if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)
6494 { far = movePos(doc, far, dir, far.line == pos.line ? line : null); }
6495 return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null
6496 }
6497 } }
6498 return pos
6499 }
6500
6501 // Ensure a given position is not inside an atomic range.
6502 function skipAtomic(doc, pos, oldPos, bias, mayClear) {
6503 var dir = bias || 1;
6504 var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
6505 (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
6506 skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
6507 (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
6508 if (!found) {
6509 doc.cantEdit = true;
6510 return Pos(doc.first, 0)
6511 }
6512 return found
6513 }
6514
6515 function movePos(doc, pos, dir, line) {
6516 if (dir < 0 && pos.ch == 0) {
6517 if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) }
6518 else { return null }
6519 } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
6520 if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) }
6521 else { return null }
6522 } else {
6523 return new Pos(pos.line, pos.ch + dir)
6524 }
6525 }
6526
6527 function selectAll(cm) {
6528 cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);
6529 }
6530
6531 // UPDATING
6532
6533 // Allow "beforeChange" event handlers to influence a change
6534 function filterChange(doc, change, update) {
6535 var obj = {
6536 canceled: false,
6537 from: change.from,
6538 to: change.to,
6539 text: change.text,
6540 origin: change.origin,
6541 cancel: function () { return obj.canceled = true; }
6542 };
6543 if (update) { obj.update = function (from, to, text, origin) {
6544 if (from) { obj.from = clipPos(doc, from); }
6545 if (to) { obj.to = clipPos(doc, to); }
6546 if (text) { obj.text = text; }
6547 if (origin !== undefined) { obj.origin = origin; }
6548 }; }
6549 signal(doc, "beforeChange", doc, obj);
6550 if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj); }
6551
6552 if (obj.canceled) { return null }
6553 return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}
6554 }
6555
6556 // Apply a change to a document, and add it to the document's
6557 // history, and propagating it to all linked documents.
6558 function makeChange(doc, change, ignoreReadOnly) {
6559 if (doc.cm) {
6560 if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) }
6561 if (doc.cm.state.suppressEdits) { return }
6562 }
6563
6564 if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
6565 change = filterChange(doc, change, true);
6566 if (!change) { return }
6567 }
6568
6569 // Possibly split or suppress the update based on the presence
6570 // of read-only spans in its range.
6571 var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
6572 if (split) {
6573 for (var i = split.length - 1; i >= 0; --i)
6574 { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}); }
6575 } else {
6576 makeChangeInner(doc, change);
6577 }
6578 }
6579
6580 function makeChangeInner(doc, change) {
6581 if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return }
6582 var selAfter = computeSelAfterChange(doc, change);
6583 addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
6584
6585 makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
6586 var rebased = [];
6587
6588 linkedDocs(doc, function (doc, sharedHist) {
6589 if (!sharedHist && indexOf(rebased, doc.history) == -1) {
6590 rebaseHist(doc.history, change);
6591 rebased.push(doc.history);
6592 }
6593 makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
6594 });
6595 }
6596
6597 // Revert a change stored in a document's history.
6598 function makeChangeFromHistory(doc, type, allowSelectionOnly) {
6599 if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) { return }
6600
6601 var hist = doc.history, event, selAfter = doc.sel;
6602 var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
6603
6604 // Verify that there is a useable event (so that ctrl-z won't
6605 // needlessly clear selection events)
6606 var i = 0;
6607 for (; i < source.length; i++) {
6608 event = source[i];
6609 if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
6610 { break }
6611 }
6612 if (i == source.length) { return }
6613 hist.lastOrigin = hist.lastSelOrigin = null;
6614
6615 for (;;) {
6616 event = source.pop();
6617 if (event.ranges) {
6618 pushSelectionToHistory(event, dest);
6619 if (allowSelectionOnly && !event.equals(doc.sel)) {
6620 setSelection(doc, event, {clearRedo: false});
6621 return
6622 }
6623 selAfter = event;
6624 }
6625 else { break }
6626 }
6627
6628 // Build up a reverse change object to add to the opposite history
6629 // stack (redo when undoing, and vice versa).
6630 var antiChanges = [];
6631 pushSelectionToHistory(selAfter, dest);
6632 dest.push({changes: antiChanges, generation: hist.generation});
6633 hist.generation = event.generation || ++hist.maxGeneration;
6634
6635 var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
6636
6637 var loop = function ( i ) {
6638 var change = event.changes[i];
6639 change.origin = type;
6640 if (filter && !filterChange(doc, change, false)) {
6641 source.length = 0;
6642 return {}
6643 }
6644
6645 antiChanges.push(historyChangeFromChange(doc, change));
6646
6647 var after = i ? computeSelAfterChange(doc, change) : lst(source);
6648 makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
6649 if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); }
6650 var rebased = [];
6651
6652 // Propagate to the linked documents
6653 linkedDocs(doc, function (doc, sharedHist) {
6654 if (!sharedHist && indexOf(rebased, doc.history) == -1) {
6655 rebaseHist(doc.history, change);
6656 rebased.push(doc.history);
6657 }
6658 makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
6659 });
6660 };
6661
6662 for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) {
6663 var returned = loop( i$1 );
6664
6665 if ( returned ) return returned.v;
6666 }
6667 }
6668
6669 // Sub-views need their line numbers shifted when text is added
6670 // above or below them in the parent document.
6671 function shiftDoc(doc, distance) {
6672 if (distance == 0) { return }
6673 doc.first += distance;
6674 doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range(
6675 Pos(range.anchor.line + distance, range.anchor.ch),
6676 Pos(range.head.line + distance, range.head.ch)
6677 ); }), doc.sel.primIndex);
6678 if (doc.cm) {
6679 regChange(doc.cm, doc.first, doc.first - distance, distance);
6680 for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
6681 { regLineChange(doc.cm, l, "gutter"); }
6682 }
6683 }
6684
6685 // More lower-level change function, handling only a single document
6686 // (not linked ones).
6687 function makeChangeSingleDoc(doc, change, selAfter, spans) {
6688 if (doc.cm && !doc.cm.curOp)
6689 { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) }
6690
6691 if (change.to.line < doc.first) {
6692 shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
6693 return
6694 }
6695 if (change.from.line > doc.lastLine()) { return }
6696
6697 // Clip the change to the size of this doc
6698 if (change.from.line < doc.first) {
6699 var shift = change.text.length - 1 - (doc.first - change.from.line);
6700 shiftDoc(doc, shift);
6701 change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
6702 text: [lst(change.text)], origin: change.origin};
6703 }
6704 var last = doc.lastLine();
6705 if (change.to.line > last) {
6706 change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
6707 text: [change.text[0]], origin: change.origin};
6708 }
6709
6710 change.removed = getBetween(doc, change.from, change.to);
6711
6712 if (!selAfter) { selAfter = computeSelAfterChange(doc, change); }
6713 if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); }
6714 else { updateDoc(doc, change, spans); }
6715 setSelectionNoUndo(doc, selAfter, sel_dontScroll);
6716 }
6717
6718 // Handle the interaction of a change to a document with the editor
6719 // that this document is part of.
6720 function makeChangeSingleDocInEditor(cm, change, spans) {
6721 var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
6722
6723 var recomputeMaxLength = false, checkWidthStart = from.line;
6724 if (!cm.options.lineWrapping) {
6725 checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
6726 doc.iter(checkWidthStart, to.line + 1, function (line) {
6727 if (line == display.maxLine) {
6728 recomputeMaxLength = true;
6729 return true
6730 }
6731 });
6732 }
6733
6734 if (doc.sel.contains(change.from, change.to) > -1)
6735 { signalCursorActivity(cm); }
6736
6737 updateDoc(doc, change, spans, estimateHeight(cm));
6738
6739 if (!cm.options.lineWrapping) {
6740 doc.iter(checkWidthStart, from.line + change.text.length, function (line) {
6741 var len = lineLength(line);
6742 if (len > display.maxLineLength) {
6743 display.maxLine = line;
6744 display.maxLineLength = len;
6745 display.maxLineChanged = true;
6746 recomputeMaxLength = false;
6747 }
6748 });
6749 if (recomputeMaxLength) { cm.curOp.updateMaxLine = true; }
6750 }
6751
6752 retreatFrontier(doc, from.line);
6753 startWorker(cm, 400);
6754
6755 var lendiff = change.text.length - (to.line - from.line) - 1;
6756 // Remember that these lines changed, for updating the display
6757 if (change.full)
6758 { regChange(cm); }
6759 else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
6760 { regLineChange(cm, from.line, "text"); }
6761 else
6762 { regChange(cm, from.line, to.line + 1, lendiff); }
6763
6764 var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
6765 if (changeHandler || changesHandler) {
6766 var obj = {
6767 from: from, to: to,
6768 text: change.text,
6769 removed: change.removed,
6770 origin: change.origin
6771 };
6772 if (changeHandler) { signalLater(cm, "change", cm, obj); }
6773 if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); }
6774 }
6775 cm.display.selForContextMenu = null;
6776 }
6777
6778 function replaceRange(doc, code, from, to, origin) {
6779 if (!to) { to = from; }
6780 if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }
6781 if (typeof code == "string") { code = doc.splitLines(code); }
6782 makeChange(doc, {from: from, to: to, text: code, origin: origin});
6783 }
6784
6785 // Rebasing/resetting history to deal with externally-sourced changes
6786
6787 function rebaseHistSelSingle(pos, from, to, diff) {
6788 if (to < pos.line) {
6789 pos.line += diff;
6790 } else if (from < pos.line) {
6791 pos.line = from;
6792 pos.ch = 0;
6793 }
6794 }
6795
6796 // Tries to rebase an array of history events given a change in the
6797 // document. If the change touches the same lines as the event, the
6798 // event, and everything 'behind' it, is discarded. If the change is
6799 // before the event, the event's positions are updated. Uses a
6800 // copy-on-write scheme for the positions, to avoid having to
6801 // reallocate them all on every rebase, but also avoid problems with
6802 // shared position objects being unsafely updated.
6803 function rebaseHistArray(array, from, to, diff) {
6804 for (var i = 0; i < array.length; ++i) {
6805 var sub = array[i], ok = true;
6806 if (sub.ranges) {
6807 if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
6808 for (var j = 0; j < sub.ranges.length; j++) {
6809 rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
6810 rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
6811 }
6812 continue
6813 }
6814 for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) {
6815 var cur = sub.changes[j$1];
6816 if (to < cur.from.line) {
6817 cur.from = Pos(cur.from.line + diff, cur.from.ch);
6818 cur.to = Pos(cur.to.line + diff, cur.to.ch);
6819 } else if (from <= cur.to.line) {
6820 ok = false;
6821 break
6822 }
6823 }
6824 if (!ok) {
6825 array.splice(0, i + 1);
6826 i = 0;
6827 }
6828 }
6829 }
6830
6831 function rebaseHist(hist, change) {
6832 var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
6833 rebaseHistArray(hist.done, from, to, diff);
6834 rebaseHistArray(hist.undone, from, to, diff);
6835 }
6836
6837 // Utility for applying a change to a line by handle or number,
6838 // returning the number and optionally registering the line as
6839 // changed.
6840 function changeLine(doc, handle, changeType, op) {
6841 var no = handle, line = handle;
6842 if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)); }
6843 else { no = lineNo(handle); }
6844 if (no == null) { return null }
6845 if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType); }
6846 return line
6847 }
6848
6849 // The document is represented as a BTree consisting of leaves, with
6850 // chunk of lines in them, and branches, with up to ten leaves or
6851 // other branch nodes below them. The top node is always a branch
6852 // node, and is the document object itself (meaning it has
6853 // additional methods and properties).
6854 //
6855 // All nodes have parent links. The tree is used both to go from
6856 // line numbers to line objects, and to go from objects to numbers.
6857 // It also indexes by height, and is used to convert between height
6858 // and line object, and to find the total height of the document.
6859 //
6860 // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
6861
6862 function LeafChunk(lines) {
6863 var this$1 = this;
6864
6865 this.lines = lines;
6866 this.parent = null;
6867 var height = 0;
6868 for (var i = 0; i < lines.length; ++i) {
6869 lines[i].parent = this$1;
6870 height += lines[i].height;
6871 }
6872 this.height = height;
6873 }
6874
6875 LeafChunk.prototype = {
6876 chunkSize: function chunkSize() { return this.lines.length },
6877
6878 // Remove the n lines at offset 'at'.
6879 removeInner: function removeInner(at, n) {
6880 var this$1 = this;
6881
6882 for (var i = at, e = at + n; i < e; ++i) {
6883 var line = this$1.lines[i];
6884 this$1.height -= line.height;
6885 cleanUpLine(line);
6886 signalLater(line, "delete");
6887 }
6888 this.lines.splice(at, n);
6889 },
6890
6891 // Helper used to collapse a small branch into a single leaf.
6892 collapse: function collapse(lines) {
6893 lines.push.apply(lines, this.lines);
6894 },
6895
6896 // Insert the given array of lines at offset 'at', count them as
6897 // having the given height.
6898 insertInner: function insertInner(at, lines, height) {
6899 var this$1 = this;
6900
6901 this.height += height;
6902 this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
6903 for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1; }
6904 },
6905
6906 // Used to iterate over a part of the tree.
6907 iterN: function iterN(at, n, op) {
6908 var this$1 = this;
6909
6910 for (var e = at + n; at < e; ++at)
6911 { if (op(this$1.lines[at])) { return true } }
6912 }
6913 };
6914
6915 function BranchChunk(children) {
6916 var this$1 = this;
6917
6918 this.children = children;
6919 var size = 0, height = 0;
6920 for (var i = 0; i < children.length; ++i) {
6921 var ch = children[i];
6922 size += ch.chunkSize(); height += ch.height;
6923 ch.parent = this$1;
6924 }
6925 this.size = size;
6926 this.height = height;
6927 this.parent = null;
6928 }
6929
6930 BranchChunk.prototype = {
6931 chunkSize: function chunkSize() { return this.size },
6932
6933 removeInner: function removeInner(at, n) {
6934 var this$1 = this;
6935
6936 this.size -= n;
6937 for (var i = 0; i < this.children.length; ++i) {
6938 var child = this$1.children[i], sz = child.chunkSize();
6939 if (at < sz) {
6940 var rm = Math.min(n, sz - at), oldHeight = child.height;
6941 child.removeInner(at, rm);
6942 this$1.height -= oldHeight - child.height;
6943 if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null; }
6944 if ((n -= rm) == 0) { break }
6945 at = 0;
6946 } else { at -= sz; }
6947 }
6948 // If the result is smaller than 25 lines, ensure that it is a
6949 // single leaf node.
6950 if (this.size - n < 25 &&
6951 (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
6952 var lines = [];
6953 this.collapse(lines);
6954 this.children = [new LeafChunk(lines)];
6955 this.children[0].parent = this;
6956 }
6957 },
6958
6959 collapse: function collapse(lines) {
6960 var this$1 = this;
6961
6962 for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines); }
6963 },
6964
6965 insertInner: function insertInner(at, lines, height) {
6966 var this$1 = this;
6967
6968 this.size += lines.length;
6969 this.height += height;
6970 for (var i = 0; i < this.children.length; ++i) {
6971 var child = this$1.children[i], sz = child.chunkSize();
6972 if (at <= sz) {
6973 child.insertInner(at, lines, height);
6974 if (child.lines && child.lines.length > 50) {
6975 // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.
6976 // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.
6977 var remaining = child.lines.length % 25 + 25;
6978 for (var pos = remaining; pos < child.lines.length;) {
6979 var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));
6980 child.height -= leaf.height;
6981 this$1.children.splice(++i, 0, leaf);
6982 leaf.parent = this$1;
6983 }
6984 child.lines = child.lines.slice(0, remaining);
6985 this$1.maybeSpill();
6986 }
6987 break
6988 }
6989 at -= sz;
6990 }
6991 },
6992
6993 // When a node has grown, check whether it should be split.
6994 maybeSpill: function maybeSpill() {
6995 if (this.children.length <= 10) { return }
6996 var me = this;
6997 do {
6998 var spilled = me.children.splice(me.children.length - 5, 5);
6999 var sibling = new BranchChunk(spilled);
7000 if (!me.parent) { // Become the parent node
7001 var copy = new BranchChunk(me.children);
7002 copy.parent = me;
7003 me.children = [copy, sibling];
7004 me = copy;
7005 } else {
7006 me.size -= sibling.size;
7007 me.height -= sibling.height;
7008 var myIndex = indexOf(me.parent.children, me);
7009 me.parent.children.splice(myIndex + 1, 0, sibling);
7010 }
7011 sibling.parent = me.parent;
7012 } while (me.children.length > 10)
7013 me.parent.maybeSpill();
7014 },
7015
7016 iterN: function iterN(at, n, op) {
7017 var this$1 = this;
7018
7019 for (var i = 0; i < this.children.length; ++i) {
7020 var child = this$1.children[i], sz = child.chunkSize();
7021 if (at < sz) {
7022 var used = Math.min(n, sz - at);
7023 if (child.iterN(at, used, op)) { return true }
7024 if ((n -= used) == 0) { break }
7025 at = 0;
7026 } else { at -= sz; }
7027 }
7028 }
7029 };
7030
7031 // Line widgets are block elements displayed above or below a line.
7032
7033 var LineWidget = function(doc, node, options) {
7034 var this$1 = this;
7035
7036 if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))
7037 { this$1[opt] = options[opt]; } } }
7038 this.doc = doc;
7039 this.node = node;
7040 };
7041
7042 LineWidget.prototype.clear = function () {
7043 var this$1 = this;
7044
7045 var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
7046 if (no == null || !ws) { return }
7047 for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1); } }
7048 if (!ws.length) { line.widgets = null; }
7049 var height = widgetHeight(this);
7050 updateLineHeight(line, Math.max(0, line.height - height));
7051 if (cm) {
7052 runInOp(cm, function () {
7053 adjustScrollWhenAboveVisible(cm, line, -height);
7054 regLineChange(cm, no, "widget");
7055 });
7056 signalLater(cm, "lineWidgetCleared", cm, this, no);
7057 }
7058 };
7059
7060 LineWidget.prototype.changed = function () {
7061 var this$1 = this;
7062
7063 var oldH = this.height, cm = this.doc.cm, line = this.line;
7064 this.height = null;
7065 var diff = widgetHeight(this) - oldH;
7066 if (!diff) { return }
7067 updateLineHeight(line, line.height + diff);
7068 if (cm) {
7069 runInOp(cm, function () {
7070 cm.curOp.forceUpdate = true;
7071 adjustScrollWhenAboveVisible(cm, line, diff);
7072 signalLater(cm, "lineWidgetChanged", cm, this$1, lineNo(line));
7073 });
7074 }
7075 };
7076 eventMixin(LineWidget);
7077
7078 function adjustScrollWhenAboveVisible(cm, line, diff) {
7079 if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
7080 { addToScrollTop(cm, diff); }
7081 }
7082
7083 function addLineWidget(doc, handle, node, options) {
7084 var widget = new LineWidget(doc, node, options);
7085 var cm = doc.cm;
7086 if (cm && widget.noHScroll) { cm.display.alignWidgets = true; }
7087 changeLine(doc, handle, "widget", function (line) {
7088 var widgets = line.widgets || (line.widgets = []);
7089 if (widget.insertAt == null) { widgets.push(widget); }
7090 else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); }
7091 widget.line = line;
7092 if (cm && !lineIsHidden(doc, line)) {
7093 var aboveVisible = heightAtLine(line) < doc.scrollTop;
7094 updateLineHeight(line, line.height + widgetHeight(widget));
7095 if (aboveVisible) { addToScrollTop(cm, widget.height); }
7096 cm.curOp.forceUpdate = true;
7097 }
7098 return true
7099 });
7100 signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle));
7101 return widget
7102 }
7103
7104 // TEXTMARKERS
7105
7106 // Created with markText and setBookmark methods. A TextMarker is a
7107 // handle that can be used to clear or find a marked position in the
7108 // document. Line objects hold arrays (markedSpans) containing
7109 // {from, to, marker} object pointing to such marker objects, and
7110 // indicating that such a marker is present on that line. Multiple
7111 // lines may point to the same marker when it spans across lines.
7112 // The spans will have null for their from/to properties when the
7113 // marker continues beyond the start/end of the line. Markers have
7114 // links back to the lines they currently touch.
7115
7116 // Collapsed markers have unique ids, in order to be able to order
7117 // them, which is needed for uniquely determining an outer marker
7118 // when they overlap (they may nest, but not partially overlap).
7119 var nextMarkerId = 0;
7120
7121 var TextMarker = function(doc, type) {
7122 this.lines = [];
7123 this.type = type;
7124 this.doc = doc;
7125 this.id = ++nextMarkerId;
7126 };
7127
7128 // Clear the marker.
7129 TextMarker.prototype.clear = function () {
7130 var this$1 = this;
7131
7132 if (this.explicitlyCleared) { return }
7133 var cm = this.doc.cm, withOp = cm && !cm.curOp;
7134 if (withOp) { startOperation(cm); }
7135 if (hasHandler(this, "clear")) {
7136 var found = this.find();
7137 if (found) { signalLater(this, "clear", found.from, found.to); }
7138 }
7139 var min = null, max = null;
7140 for (var i = 0; i < this.lines.length; ++i) {
7141 var line = this$1.lines[i];
7142 var span = getMarkedSpanFor(line.markedSpans, this$1);
7143 if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text"); }
7144 else if (cm) {
7145 if (span.to != null) { max = lineNo(line); }
7146 if (span.from != null) { min = lineNo(line); }
7147 }
7148 line.markedSpans = removeMarkedSpan(line.markedSpans, span);
7149 if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm)
7150 { updateLineHeight(line, textHeight(cm.display)); }
7151 }
7152 if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {
7153 var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual);
7154 if (len > cm.display.maxLineLength) {
7155 cm.display.maxLine = visual;
7156 cm.display.maxLineLength = len;
7157 cm.display.maxLineChanged = true;
7158 }
7159 } }
7160
7161 if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1); }
7162 this.lines.length = 0;
7163 this.explicitlyCleared = true;
7164 if (this.atomic && this.doc.cantEdit) {
7165 this.doc.cantEdit = false;
7166 if (cm) { reCheckSelection(cm.doc); }
7167 }
7168 if (cm) { signalLater(cm, "markerCleared", cm, this, min, max); }
7169 if (withOp) { endOperation(cm); }
7170 if (this.parent) { this.parent.clear(); }
7171 };
7172
7173 // Find the position of the marker in the document. Returns a {from,
7174 // to} object by default. Side can be passed to get a specific side
7175 // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
7176 // Pos objects returned contain a line object, rather than a line
7177 // number (used to prevent looking up the same line twice).
7178 TextMarker.prototype.find = function (side, lineObj) {
7179 var this$1 = this;
7180
7181 if (side == null && this.type == "bookmark") { side = 1; }
7182 var from, to;
7183 for (var i = 0; i < this.lines.length; ++i) {
7184 var line = this$1.lines[i];
7185 var span = getMarkedSpanFor(line.markedSpans, this$1);
7186 if (span.from != null) {
7187 from = Pos(lineObj ? line : lineNo(line), span.from);
7188 if (side == -1) { return from }
7189 }
7190 if (span.to != null) {
7191 to = Pos(lineObj ? line : lineNo(line), span.to);
7192 if (side == 1) { return to }
7193 }
7194 }
7195 return from && {from: from, to: to}
7196 };
7197
7198 // Signals that the marker's widget changed, and surrounding layout
7199 // should be recomputed.
7200 TextMarker.prototype.changed = function () {
7201 var this$1 = this;
7202
7203 var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
7204 if (!pos || !cm) { return }
7205 runInOp(cm, function () {
7206 var line = pos.line, lineN = lineNo(pos.line);
7207 var view = findViewForLine(cm, lineN);
7208 if (view) {
7209 clearLineMeasurementCacheFor(view);
7210 cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
7211 }
7212 cm.curOp.updateMaxLine = true;
7213 if (!lineIsHidden(widget.doc, line) && widget.height != null) {
7214 var oldHeight = widget.height;
7215 widget.height = null;
7216 var dHeight = widgetHeight(widget) - oldHeight;
7217 if (dHeight)
7218 { updateLineHeight(line, line.height + dHeight); }
7219 }
7220 signalLater(cm, "markerChanged", cm, this$1);
7221 });
7222 };
7223
7224 TextMarker.prototype.attachLine = function (line) {
7225 if (!this.lines.length && this.doc.cm) {
7226 var op = this.doc.cm.curOp;
7227 if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
7228 { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); }
7229 }
7230 this.lines.push(line);
7231 };
7232
7233 TextMarker.prototype.detachLine = function (line) {
7234 this.lines.splice(indexOf(this.lines, line), 1);
7235 if (!this.lines.length && this.doc.cm) {
7236 var op = this.doc.cm.curOp;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
7237 }
7238 };
7239 eventMixin(TextMarker);
7240
7241 // Create a marker, wire it up to the right lines, and
7242 function markText(doc, from, to, options, type) {
7243 // Shared markers (across linked documents) are handled separately
7244 // (markTextShared will call out to this again, once per
7245 // document).
7246 if (options && options.shared) { return markTextShared(doc, from, to, options, type) }
7247 // Ensure we are in an operation.
7248 if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) }
7249
7250 var marker = new TextMarker(doc, type), diff = cmp(from, to);
7251 if (options) { copyObj(options, marker, false); }
7252 // Don't connect empty markers unless clearWhenEmpty is false
7253 if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
7254 { return marker }
7255 if (marker.replacedWith) {
7256 // Showing up as a widget implies collapsed (widget replaces text)
7257 marker.collapsed = true;
7258 marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget");
7259 if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true"); }
7260 if (options.insertLeft) { marker.widgetNode.insertLeft = true; }
7261 }
7262 if (marker.collapsed) {
7263 if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
7264 from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
7265 { throw new Error("Inserting collapsed marker partially overlapping an existing one") }
7266 seeCollapsedSpans();
7267 }
7268
7269 if (marker.addToHistory)
7270 { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); }
7271
7272 var curLine = from.line, cm = doc.cm, updateMaxLine;
7273 doc.iter(curLine, to.line + 1, function (line) {
7274 if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
7275 { updateMaxLine = true; }
7276 if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); }
7277 addMarkedSpan(line, new MarkedSpan(marker,
7278 curLine == from.line ? from.ch : null,
7279 curLine == to.line ? to.ch : null));
7280 ++curLine;
7281 });
7282 // lineIsHidden depends on the presence of the spans, so needs a second pass
7283 if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) {
7284 if (lineIsHidden(doc, line)) { updateLineHeight(line, 0); }
7285 }); }
7286
7287 if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }); }
7288
7289 if (marker.readOnly) {
7290 seeReadOnlySpans();
7291 if (doc.history.done.length || doc.history.undone.length)
7292 { doc.clearHistory(); }
7293 }
7294 if (marker.collapsed) {
7295 marker.id = ++nextMarkerId;
7296 marker.atomic = true;
7297 }
7298 if (cm) {
7299 // Sync editor state
7300 if (updateMaxLine) { cm.curOp.updateMaxLine = true; }
7301 if (marker.collapsed)
7302 { regChange(cm, from.line, to.line + 1); }
7303 else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
7304 { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text"); } }
7305 if (marker.atomic) { reCheckSelection(cm.doc); }
7306 signalLater(cm, "markerAdded", cm, marker);
7307 }
7308 return marker
7309 }
7310
7311 // SHARED TEXTMARKERS
7312
7313 // A shared marker spans multiple linked documents. It is
7314 // implemented as a meta-marker-object controlling multiple normal
7315 // markers.
7316 var SharedTextMarker = function(markers, primary) {
7317 var this$1 = this;
7318
7319 this.markers = markers;
7320 this.primary = primary;
7321 for (var i = 0; i < markers.length; ++i)
7322 { markers[i].parent = this$1; }
7323 };
7324
7325 SharedTextMarker.prototype.clear = function () {
7326 var this$1 = this;
7327
7328 if (this.explicitlyCleared) { return }
7329 this.explicitlyCleared = true;
7330 for (var i = 0; i < this.markers.length; ++i)
7331 { this$1.markers[i].clear(); }
7332 signalLater(this, "clear");
7333 };
7334
7335 SharedTextMarker.prototype.find = function (side, lineObj) {
7336 return this.primary.find(side, lineObj)
7337 };
7338 eventMixin(SharedTextMarker);
7339
7340 function markTextShared(doc, from, to, options, type) {
7341 options = copyObj(options);
7342 options.shared = false;
7343 var markers = [markText(doc, from, to, options, type)], primary = markers[0];
7344 var widget = options.widgetNode;
7345 linkedDocs(doc, function (doc) {
7346 if (widget) { options.widgetNode = widget.cloneNode(true); }
7347 markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
7348 for (var i = 0; i < doc.linked.length; ++i)
7349 { if (doc.linked[i].isParent) { return } }
7350 primary = lst(markers);
7351 });
7352 return new SharedTextMarker(markers, primary)
7353 }
7354
7355 function findSharedMarkers(doc) {
7356 return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; })
7357 }
7358
7359 function copySharedMarkers(doc, markers) {
7360 for (var i = 0; i < markers.length; i++) {
7361 var marker = markers[i], pos = marker.find();
7362 var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
7363 if (cmp(mFrom, mTo)) {
7364 var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
7365 marker.markers.push(subMark);
7366 subMark.parent = marker;
7367 }
7368 }
7369 }
7370
7371 function detachSharedMarkers(markers) {
7372 var loop = function ( i ) {
7373 var marker = markers[i], linked = [marker.primary.doc];
7374 linkedDocs(marker.primary.doc, function (d) { return linked.push(d); });
7375 for (var j = 0; j < marker.markers.length; j++) {
7376 var subMarker = marker.markers[j];
7377 if (indexOf(linked, subMarker.doc) == -1) {
7378 subMarker.parent = null;
7379 marker.markers.splice(j--, 1);
7380 }
7381 }
7382 };
7383
7384 for (var i = 0; i < markers.length; i++) loop( i );
7385 }
7386
7387 var nextDocId = 0;
7388 var Doc = function(text, mode, firstLine, lineSep, direction) {
7389 if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) }
7390 if (firstLine == null) { firstLine = 0; }
7391
7392 BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
7393 this.first = firstLine;
7394 this.scrollTop = this.scrollLeft = 0;
7395 this.cantEdit = false;
7396 this.cleanGeneration = 1;
7397 this.modeFrontier = this.highlightFrontier = firstLine;
7398 var start = Pos(firstLine, 0);
7399 this.sel = simpleSelection(start);
7400 this.history = new History(null);
7401 this.id = ++nextDocId;
7402 this.modeOption = mode;
7403 this.lineSep = lineSep;
7404 this.direction = (direction == "rtl") ? "rtl" : "ltr";
7405 this.extend = false;
7406
7407 if (typeof text == "string") { text = this.splitLines(text); }
7408 updateDoc(this, {from: start, to: start, text: text});
7409 setSelection(this, simpleSelection(start), sel_dontScroll);
7410 };
7411
7412 Doc.prototype = createObj(BranchChunk.prototype, {
7413 constructor: Doc,
7414 // Iterate over the document. Supports two forms -- with only one
7415 // argument, it calls that for each line in the document. With
7416 // three, it iterates over the range given by the first two (with
7417 // the second being non-inclusive).
7418 iter: function(from, to, op) {
7419 if (op) { this.iterN(from - this.first, to - from, op); }
7420 else { this.iterN(this.first, this.first + this.size, from); }
7421 },
7422
7423 // Non-public interface for adding and removing lines.
7424 insert: function(at, lines) {
7425 var height = 0;
7426 for (var i = 0; i < lines.length; ++i) { height += lines[i].height; }
7427 this.insertInner(at - this.first, lines, height);
7428 },
7429 remove: function(at, n) { this.removeInner(at - this.first, n); },
7430
7431 // From here, the methods are part of the public interface. Most
7432 // are also available from CodeMirror (editor) instances.
7433
7434 getValue: function(lineSep) {
7435 var lines = getLines(this, this.first, this.first + this.size);
7436 if (lineSep === false) { return lines }
7437 return lines.join(lineSep || this.lineSeparator())
7438 },
7439 setValue: docMethodOp(function(code) {
7440 var top = Pos(this.first, 0), last = this.first + this.size - 1;
7441 makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
7442 text: this.splitLines(code), origin: "setValue", full: true}, true);
7443 if (this.cm) { scrollToCoords(this.cm, 0, 0); }
7444 setSelection(this, simpleSelection(top), sel_dontScroll);
7445 }),
7446 replaceRange: function(code, from, to, origin) {
7447 from = clipPos(this, from);
7448 to = to ? clipPos(this, to) : from;
7449 replaceRange(this, code, from, to, origin);
7450 },
7451 getRange: function(from, to, lineSep) {
7452 var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
7453 if (lineSep === false) { return lines }
7454 return lines.join(lineSep || this.lineSeparator())
7455 },
7456
7457 getLine: function(line) {var l = this.getLineHandle(line); return l && l.text},
7458
7459 getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }},
7460 getLineNumber: function(line) {return lineNo(line)},
7461
7462 getLineHandleVisualStart: function(line) {
7463 if (typeof line == "number") { line = getLine(this, line); }
7464 return visualLine(line)
7465 },
7466
7467 lineCount: function() {return this.size},
7468 firstLine: function() {return this.first},
7469 lastLine: function() {return this.first + this.size - 1},
7470
7471 clipPos: function(pos) {return clipPos(this, pos)},
7472
7473 getCursor: function(start) {
7474 var range$$1 = this.sel.primary(), pos;
7475 if (start == null || start == "head") { pos = range$$1.head; }
7476 else if (start == "anchor") { pos = range$$1.anchor; }
7477 else if (start == "end" || start == "to" || start === false) { pos = range$$1.to(); }
7478 else { pos = range$$1.from(); }
7479 return pos
7480 },
7481 listSelections: function() { return this.sel.ranges },
7482 somethingSelected: function() {return this.sel.somethingSelected()},
7483
7484 setCursor: docMethodOp(function(line, ch, options) {
7485 setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
7486 }),
7487 setSelection: docMethodOp(function(anchor, head, options) {
7488 setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
7489 }),
7490 extendSelection: docMethodOp(function(head, other, options) {
7491 extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
7492 }),
7493 extendSelections: docMethodOp(function(heads, options) {
7494 extendSelections(this, clipPosArray(this, heads), options);
7495 }),
7496 extendSelectionsBy: docMethodOp(function(f, options) {
7497 var heads = map(this.sel.ranges, f);
7498 extendSelections(this, clipPosArray(this, heads), options);
7499 }),
7500 setSelections: docMethodOp(function(ranges, primary, options) {
7501 var this$1 = this;
7502
7503 if (!ranges.length) { return }
7504 var out = [];
7505 for (var i = 0; i < ranges.length; i++)
7506 { out[i] = new Range(clipPos(this$1, ranges[i].anchor),
7507 clipPos(this$1, ranges[i].head)); }
7508 if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); }
7509 setSelection(this, normalizeSelection(out, primary), options);
7510 }),
7511 addSelection: docMethodOp(function(anchor, head, options) {
7512 var ranges = this.sel.ranges.slice(0);
7513 ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
7514 setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
7515 }),
7516
7517 getSelection: function(lineSep) {
7518 var this$1 = this;
7519
7520 var ranges = this.sel.ranges, lines;
7521 for (var i = 0; i < ranges.length; i++) {
7522 var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
7523 lines = lines ? lines.concat(sel) : sel;
7524 }
7525 if (lineSep === false) { return lines }
7526 else { return lines.join(lineSep || this.lineSeparator()) }
7527 },
7528 getSelections: function(lineSep) {
7529 var this$1 = this;
7530
7531 var parts = [], ranges = this.sel.ranges;
7532 for (var i = 0; i < ranges.length; i++) {
7533 var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
7534 if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()); }
7535 parts[i] = sel;
7536 }
7537 return parts
7538 },
7539 replaceSelection: function(code, collapse, origin) {
7540 var dup = [];
7541 for (var i = 0; i < this.sel.ranges.length; i++)
7542 { dup[i] = code; }
7543 this.replaceSelections(dup, collapse, origin || "+input");
7544 },
7545 replaceSelections: docMethodOp(function(code, collapse, origin) {
7546 var this$1 = this;
7547
7548 var changes = [], sel = this.sel;
7549 for (var i = 0; i < sel.ranges.length; i++) {
7550 var range$$1 = sel.ranges[i];
7551 changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this$1.splitLines(code[i]), origin: origin};
7552 }
7553 var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
7554 for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)
7555 { makeChange(this$1, changes[i$1]); }
7556 if (newSel) { setSelectionReplaceHistory(this, newSel); }
7557 else if (this.cm) { ensureCursorVisible(this.cm); }
7558 }),
7559 undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
7560 redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
7561 undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
7562 redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
7563
7564 setExtending: function(val) {this.extend = val;},
7565 getExtending: function() {return this.extend},
7566
7567 historySize: function() {
7568 var hist = this.history, done = 0, undone = 0;
7569 for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done; } }
7570 for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }
7571 return {undo: done, redo: undone}
7572 },
7573 clearHistory: function() {this.history = new History(this.history.maxGeneration);},
7574
7575 markClean: function() {
7576 this.cleanGeneration = this.changeGeneration(true);
7577 },
7578 changeGeneration: function(forceSplit) {
7579 if (forceSplit)
7580 { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; }
7581 return this.history.generation
7582 },
7583 isClean: function (gen) {
7584 return this.history.generation == (gen || this.cleanGeneration)
7585 },
7586
7587 getHistory: function() {
7588 return {done: copyHistoryArray(this.history.done),
7589 undone: copyHistoryArray(this.history.undone)}
7590 },
7591 setHistory: function(histData) {
7592 var hist = this.history = new History(this.history.maxGeneration);
7593 hist.done = copyHistoryArray(histData.done.slice(0), null, true);
7594 hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
7595 },
7596
7597 setGutterMarker: docMethodOp(function(line, gutterID, value) {
7598 return changeLine(this, line, "gutter", function (line) {
7599 var markers = line.gutterMarkers || (line.gutterMarkers = {});
7600 markers[gutterID] = value;
7601 if (!value && isEmpty(markers)) { line.gutterMarkers = null; }
7602 return true
7603 })
7604 }),
7605
7606 clearGutter: docMethodOp(function(gutterID) {
7607 var this$1 = this;
7608
7609 this.iter(function (line) {
7610 if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
7611 changeLine(this$1, line, "gutter", function () {
7612 line.gutterMarkers[gutterID] = null;
7613 if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null; }
7614 return true
7615 });
7616 }
7617 });
7618 }),
7619
7620 lineInfo: function(line) {
7621 var n;
7622 if (typeof line == "number") {
7623 if (!isLine(this, line)) { return null }
7624 n = line;
7625 line = getLine(this, line);
7626 if (!line) { return null }
7627 } else {
7628 n = lineNo(line);
7629 if (n == null) { return null }
7630 }
7631 return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
7632 textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
7633 widgets: line.widgets}
7634 },
7635
7636 addLineClass: docMethodOp(function(handle, where, cls) {
7637 return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
7638 var prop = where == "text" ? "textClass"
7639 : where == "background" ? "bgClass"
7640 : where == "gutter" ? "gutterClass" : "wrapClass";
7641 if (!line[prop]) { line[prop] = cls; }
7642 else if (classTest(cls).test(line[prop])) { return false }
7643 else { line[prop] += " " + cls; }
7644 return true
7645 })
7646 }),
7647 removeLineClass: docMethodOp(function(handle, where, cls) {
7648 return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
7649 var prop = where == "text" ? "textClass"
7650 : where == "background" ? "bgClass"
7651 : where == "gutter" ? "gutterClass" : "wrapClass";
7652 var cur = line[prop];
7653 if (!cur) { return false }
7654 else if (cls == null) { line[prop] = null; }
7655 else {
7656 var found = cur.match(classTest(cls));
7657 if (!found) { return false }
7658 var end = found.index + found[0].length;
7659 line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
7660 }
7661 return true
7662 })
7663 }),
7664
7665 addLineWidget: docMethodOp(function(handle, node, options) {
7666 return addLineWidget(this, handle, node, options)
7667 }),
7668 removeLineWidget: function(widget) { widget.clear(); },
7669
7670 markText: function(from, to, options) {
7671 return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range")
7672 },
7673 setBookmark: function(pos, options) {
7674 var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
7675 insertLeft: options && options.insertLeft,
7676 clearWhenEmpty: false, shared: options && options.shared,
7677 handleMouseEvents: options && options.handleMouseEvents};
7678 pos = clipPos(this, pos);
7679 return markText(this, pos, pos, realOpts, "bookmark")
7680 },
7681 findMarksAt: function(pos) {
7682 pos = clipPos(this, pos);
7683 var markers = [], spans = getLine(this, pos.line).markedSpans;
7684 if (spans) { for (var i = 0; i < spans.length; ++i) {
7685 var span = spans[i];
7686 if ((span.from == null || span.from <= pos.ch) &&
7687 (span.to == null || span.to >= pos.ch))
7688 { markers.push(span.marker.parent || span.marker); }
7689 } }
7690 return markers
7691 },
7692 findMarks: function(from, to, filter) {
7693 from = clipPos(this, from); to = clipPos(this, to);
7694 var found = [], lineNo$$1 = from.line;
7695 this.iter(from.line, to.line + 1, function (line) {
7696 var spans = line.markedSpans;
7697 if (spans) { for (var i = 0; i < spans.length; i++) {
7698 var span = spans[i];
7699 if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to ||
7700 span.from == null && lineNo$$1 != from.line ||
7701 span.from != null && lineNo$$1 == to.line && span.from >= to.ch) &&
7702 (!filter || filter(span.marker)))
7703 { found.push(span.marker.parent || span.marker); }
7704 } }
7705 ++lineNo$$1;
7706 });
7707 return found
7708 },
7709 getAllMarks: function() {
7710 var markers = [];
7711 this.iter(function (line) {
7712 var sps = line.markedSpans;
7713 if (sps) { for (var i = 0; i < sps.length; ++i)
7714 { if (sps[i].from != null) { markers.push(sps[i].marker); } } }
7715 });
7716 return markers
7717 },
7718
7719 posFromIndex: function(off) {
7720 var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length;
7721 this.iter(function (line) {
7722 var sz = line.text.length + sepSize;
7723 if (sz > off) { ch = off; return true }
7724 off -= sz;
7725 ++lineNo$$1;
7726 });
7727 return clipPos(this, Pos(lineNo$$1, ch))
7728 },
7729 indexFromPos: function (coords) {
7730 coords = clipPos(this, coords);
7731 var index = coords.ch;
7732 if (coords.line < this.first || coords.ch < 0) { return 0 }
7733 var sepSize = this.lineSeparator().length;
7734 this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value
7735 index += line.text.length + sepSize;
7736 });
7737 return index
7738 },
7739
7740 copy: function(copyHistory) {
7741 var doc = new Doc(getLines(this, this.first, this.first + this.size),
7742 this.modeOption, this.first, this.lineSep, this.direction);
7743 doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
7744 doc.sel = this.sel;
7745 doc.extend = false;
7746 if (copyHistory) {
7747 doc.history.undoDepth = this.history.undoDepth;
7748 doc.setHistory(this.getHistory());
7749 }
7750 return doc
7751 },
7752
7753 linkedDoc: function(options) {
7754 if (!options) { options = {}; }
7755 var from = this.first, to = this.first + this.size;
7756 if (options.from != null && options.from > from) { from = options.from; }
7757 if (options.to != null && options.to < to) { to = options.to; }
7758 var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction);
7759 if (options.sharedHist) { copy.history = this.history
7760 ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
7761 copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
7762 copySharedMarkers(copy, findSharedMarkers(this));
7763 return copy
7764 },
7765 unlinkDoc: function(other) {
7766 var this$1 = this;
7767
7768 if (other instanceof CodeMirror$1) { other = other.doc; }
7769 if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {
7770 var link = this$1.linked[i];
7771 if (link.doc != other) { continue }
7772 this$1.linked.splice(i, 1);
7773 other.unlinkDoc(this$1);
7774 detachSharedMarkers(findSharedMarkers(this$1));
7775 break
7776 } }
7777 // If the histories were shared, split them again
7778 if (other.history == this.history) {
7779 var splitIds = [other.id];
7780 linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true);
7781 other.history = new History(null);
7782 other.history.done = copyHistoryArray(this.history.done, splitIds);
7783 other.history.undone = copyHistoryArray(this.history.undone, splitIds);
7784 }
7785 },
7786 iterLinkedDocs: function(f) {linkedDocs(this, f);},
7787
7788 getMode: function() {return this.mode},
7789 getEditor: function() {return this.cm},
7790
7791 splitLines: function(str) {
7792 if (this.lineSep) { return str.split(this.lineSep) }
7793 return splitLinesAuto(str)
7794 },
7795 lineSeparator: function() { return this.lineSep || "\n" },
7796
7797 setDirection: docMethodOp(function (dir) {
7798 if (dir != "rtl") { dir = "ltr"; }
7799 if (dir == this.direction) { return }
7800 this.direction = dir;
7801 this.iter(function (line) { return line.order = null; });
7802 if (this.cm) { directionChanged(this.cm); }
7803 })
7804 });
7805
7806 // Public alias.
7807 Doc.prototype.eachLine = Doc.prototype.iter;
7808
7809 // Kludge to work around strange IE behavior where it'll sometimes
7810 // re-fire a series of drag-related events right after the drop (#1551)
7811 var lastDrop = 0;
7812
7813 function onDrop(e) {
7814 var cm = this;
7815 clearDragCursor(cm);
7816 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
7817 { return }
7818 e_preventDefault(e);
7819 if (ie) { lastDrop = +new Date; }
7820 var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
7821 if (!pos || cm.isReadOnly()) { return }
7822 // Might be a file drop, in which case we simply extract the text
7823 // and insert it.
7824 if (files && files.length && window.FileReader && window.File) {
7825 var n = files.length, text = Array(n), read = 0;
7826 var loadFile = function (file, i) {
7827 if (cm.options.allowDropFileTypes &&
7828 indexOf(cm.options.allowDropFileTypes, file.type) == -1)
7829 { return }
7830
7831 var reader = new FileReader;
7832 reader.onload = operation(cm, function () {
7833 var content = reader.result;
7834 if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = ""; }
7835 text[i] = content;
7836 if (++read == n) {
7837 pos = clipPos(cm.doc, pos);
7838 var change = {from: pos, to: pos,
7839 text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
7840 origin: "paste"};
7841 makeChange(cm.doc, change);
7842 setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
7843 }
7844 });
7845 reader.readAsText(file);
7846 };
7847 for (var i = 0; i < n; ++i) { loadFile(files[i], i); }
7848 } else { // Normal drop
7849 // Don't do a replace if the drop happened inside of the selected text.
7850 if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
7851 cm.state.draggingText(e);
7852 // Ensure the editor is re-focused
7853 setTimeout(function () { return cm.display.input.focus(); }, 20);
7854 return
7855 }
7856 try {
7857 var text$1 = e.dataTransfer.getData("Text");
7858 if (text$1) {
7859 var selected;
7860 if (cm.state.draggingText && !cm.state.draggingText.copy)
7861 { selected = cm.listSelections(); }
7862 setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
7863 if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1)
7864 { replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag"); } }
7865 cm.replaceSelection(text$1, "around", "paste");
7866 cm.display.input.focus();
7867 }
7868 }
7869 catch(e){}
7870 }
7871 }
7872
7873 function onDragStart(cm, e) {
7874 if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return }
7875 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return }
7876
7877 e.dataTransfer.setData("Text", cm.getSelection());
7878 e.dataTransfer.effectAllowed = "copyMove";
7879
7880 // Use dummy image instead of default browsers image.
7881 // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
7882 if (e.dataTransfer.setDragImage && !safari) {
7883 var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
7884 img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
7885 if (presto) {
7886 img.width = img.height = 1;
7887 cm.display.wrapper.appendChild(img);
7888 // Force a relayout, or Opera won't use our image for some obscure reason
7889 img._top = img.offsetTop;
7890 }
7891 e.dataTransfer.setDragImage(img, 0, 0);
7892 if (presto) { img.parentNode.removeChild(img); }
7893 }
7894 }
7895
7896 function onDragOver(cm, e) {
7897 var pos = posFromMouse(cm, e);
7898 if (!pos) { return }
7899 var frag = document.createDocumentFragment();
7900 drawSelectionCursor(cm, pos, frag);
7901 if (!cm.display.dragCursor) {
7902 cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
7903 cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
7904 }
7905 removeChildrenAndAdd(cm.display.dragCursor, frag);
7906 }
7907
7908 function clearDragCursor(cm) {
7909 if (cm.display.dragCursor) {
7910 cm.display.lineSpace.removeChild(cm.display.dragCursor);
7911 cm.display.dragCursor = null;
7912 }
7913 }
7914
7915 // These must be handled carefully, because naively registering a
7916 // handler for each editor will cause the editors to never be
7917 // garbage collected.
7918
7919 function forEachCodeMirror(f) {
7920 if (!document.getElementsByClassName) { return }
7921 var byClass = document.getElementsByClassName("CodeMirror");
7922 for (var i = 0; i < byClass.length; i++) {
7923 var cm = byClass[i].CodeMirror;
7924 if (cm) { f(cm); }
7925 }
7926 }
7927
7928 var globalsRegistered = false;
7929 function ensureGlobalHandlers() {
7930 if (globalsRegistered) { return }
7931 registerGlobalHandlers();
7932 globalsRegistered = true;
7933 }
7934 function registerGlobalHandlers() {
7935 // When the window resizes, we need to refresh active editors.
7936 var resizeTimer;
7937 on(window, "resize", function () {
7938 if (resizeTimer == null) { resizeTimer = setTimeout(function () {
7939 resizeTimer = null;
7940 forEachCodeMirror(onResize);
7941 }, 100); }
7942 });
7943 // When the window loses focus, we want to show the editor as blurred
7944 on(window, "blur", function () { return forEachCodeMirror(onBlur); });
7945 }
7946 // Called when the window resizes
7947 function onResize(cm) {
7948 var d = cm.display;
7949 if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)
7950 { return }
7951 // Might be a text scaling operation, clear size caches.
7952 d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
7953 d.scrollbarsClipped = false;
7954 cm.setSize();
7955 }
7956
7957 var keyNames = {
7958 3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
7959 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
7960 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
7961 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
7962 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete",
7963 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
7964 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
7965 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
7966 };
7967
7968 // Number keys
7969 for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); }
7970 // Alphabetic keys
7971 for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); }
7972 // Function keys
7973 for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2; }
7974
7975 var keyMap = {};
7976
7977 keyMap.basic = {
7978 "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
7979 "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
7980 "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
7981 "Tab": "defaultTab", "Shift-Tab": "indentAuto",
7982 "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
7983 "Esc": "singleSelection"
7984 };
7985 // Note that the save and find-related commands aren't defined by
7986 // default. User code or addons can define them. Unknown commands
7987 // are simply ignored.
7988 keyMap.pcDefault = {
7989 "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
7990 "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
7991 "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
7992 "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
7993 "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
7994 "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
7995 "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
7996 fallthrough: "basic"
7997 };
7998 // Very basic readline/emacs-style bindings, which are standard on Mac.
7999 keyMap.emacsy = {
8000 "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
8001 "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
8002 "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
8003 "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars",
8004 "Ctrl-O": "openLine"
8005 };
8006 keyMap.macDefault = {
8007 "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
8008 "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
8009 "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
8010 "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
8011 "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
8012 "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
8013 "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
8014 fallthrough: ["basic", "emacsy"]
8015 };
8016 keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
8017
8018 // KEYMAP DISPATCH
8019
8020 function normalizeKeyName(name) {
8021 var parts = name.split(/-(?!$)/);
8022 name = parts[parts.length - 1];
8023 var alt, ctrl, shift, cmd;
8024 for (var i = 0; i < parts.length - 1; i++) {
8025 var mod = parts[i];
8026 if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true; }
8027 else if (/^a(lt)?$/i.test(mod)) { alt = true; }
8028 else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; }
8029 else if (/^s(hift)?$/i.test(mod)) { shift = true; }
8030 else { throw new Error("Unrecognized modifier name: " + mod) }
8031 }
8032 if (alt) { name = "Alt-" + name; }
8033 if (ctrl) { name = "Ctrl-" + name; }
8034 if (cmd) { name = "Cmd-" + name; }
8035 if (shift) { name = "Shift-" + name; }
8036 return name
8037 }
8038
8039 // This is a kludge to keep keymaps mostly working as raw objects
8040 // (backwards compatibility) while at the same time support features
8041 // like normalization and multi-stroke key bindings. It compiles a
8042 // new normalized keymap, and then updates the old object to reflect
8043 // this.
8044 function normalizeKeyMap(keymap) {
8045 var copy = {};
8046 for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) {
8047 var value = keymap[keyname];
8048 if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue }
8049 if (value == "...") { delete keymap[keyname]; continue }
8050
8051 var keys = map(keyname.split(" "), normalizeKeyName);
8052 for (var i = 0; i < keys.length; i++) {
8053 var val = (void 0), name = (void 0);
8054 if (i == keys.length - 1) {
8055 name = keys.join(" ");
8056 val = value;
8057 } else {
8058 name = keys.slice(0, i + 1).join(" ");
8059 val = "...";
8060 }
8061 var prev = copy[name];
8062 if (!prev) { copy[name] = val; }
8063 else if (prev != val) { throw new Error("Inconsistent bindings for " + name) }
8064 }
8065 delete keymap[keyname];
8066 } }
8067 for (var prop in copy) { keymap[prop] = copy[prop]; }
8068 return keymap
8069 }
8070
8071 function lookupKey(key, map$$1, handle, context) {
8072 map$$1 = getKeyMap(map$$1);
8073 var found = map$$1.call ? map$$1.call(key, context) : map$$1[key];
8074 if (found === false) { return "nothing" }
8075 if (found === "...") { return "multi" }
8076 if (found != null && handle(found)) { return "handled" }
8077
8078 if (map$$1.fallthrough) {
8079 if (Object.prototype.toString.call(map$$1.fallthrough) != "[object Array]")
8080 { return lookupKey(key, map$$1.fallthrough, handle, context) }
8081 for (var i = 0; i < map$$1.fallthrough.length; i++) {
8082 var result = lookupKey(key, map$$1.fallthrough[i], handle, context);
8083 if (result) { return result }
8084 }
8085 }
8086 }
8087
8088 // Modifier key presses don't count as 'real' key presses for the
8089 // purpose of keymap fallthrough.
8090 function isModifierKey(value) {
8091 var name = typeof value == "string" ? value : keyNames[value.keyCode];
8092 return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"
8093 }
8094
8095 function addModifierNames(name, event, noShift) {
8096 var base = name;
8097 if (event.altKey && base != "Alt") { name = "Alt-" + name; }
8098 if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; }
8099 if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name; }
8100 if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; }
8101 return name
8102 }
8103
8104 // Look up the name of a key as indicated by an event object.
8105 function keyName(event, noShift) {
8106 if (presto && event.keyCode == 34 && event["char"]) { return false }
8107 var name = keyNames[event.keyCode];
8108 if (name == null || event.altGraphKey) { return false }
8109 return addModifierNames(name, event, noShift)
8110 }
8111
8112 function getKeyMap(val) {
8113 return typeof val == "string" ? keyMap[val] : val
8114 }
8115
8116 // Helper for deleting text near the selection(s), used to implement
8117 // backspace, delete, and similar functionality.
8118 function deleteNearSelection(cm, compute) {
8119 var ranges = cm.doc.sel.ranges, kill = [];
8120 // Build up a set of ranges to kill first, merging overlapping
8121 // ranges.
8122 for (var i = 0; i < ranges.length; i++) {
8123 var toKill = compute(ranges[i]);
8124 while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
8125 var replaced = kill.pop();
8126 if (cmp(replaced.from, toKill.from) < 0) {
8127 toKill.from = replaced.from;
8128 break
8129 }
8130 }
8131 kill.push(toKill);
8132 }
8133 // Next, remove those actual ranges.
8134 runInOp(cm, function () {
8135 for (var i = kill.length - 1; i >= 0; i--)
8136 { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); }
8137 ensureCursorVisible(cm);
8138 });
8139 }
8140
8141 // Commands are parameter-less actions that can be performed on an
8142 // editor, mostly used for keybindings.
8143 var commands = {
8144 selectAll: selectAll,
8145 singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); },
8146 killLine: function (cm) { return deleteNearSelection(cm, function (range) {
8147 if (range.empty()) {
8148 var len = getLine(cm.doc, range.head.line).text.length;
8149 if (range.head.ch == len && range.head.line < cm.lastLine())
8150 { return {from: range.head, to: Pos(range.head.line + 1, 0)} }
8151 else
8152 { return {from: range.head, to: Pos(range.head.line, len)} }
8153 } else {
8154 return {from: range.from(), to: range.to()}
8155 }
8156 }); },
8157 deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({
8158 from: Pos(range.from().line, 0),
8159 to: clipPos(cm.doc, Pos(range.to().line + 1, 0))
8160 }); }); },
8161 delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({
8162 from: Pos(range.from().line, 0), to: range.from()
8163 }); }); },
8164 delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) {
8165 var top = cm.charCoords(range.head, "div").top + 5;
8166 var leftPos = cm.coordsChar({left: 0, top: top}, "div");
8167 return {from: leftPos, to: range.from()}
8168 }); },
8169 delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) {
8170 var top = cm.charCoords(range.head, "div").top + 5;
8171 var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
8172 return {from: range.from(), to: rightPos }
8173 }); },
8174 undo: function (cm) { return cm.undo(); },
8175 redo: function (cm) { return cm.redo(); },
8176 undoSelection: function (cm) { return cm.undoSelection(); },
8177 redoSelection: function (cm) { return cm.redoSelection(); },
8178 goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); },
8179 goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); },
8180 goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); },
8181 {origin: "+move", bias: 1}
8182 ); },
8183 goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); },
8184 {origin: "+move", bias: 1}
8185 ); },
8186 goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); },
8187 {origin: "+move", bias: -1}
8188 ); },
8189 goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) {
8190 var top = cm.cursorCoords(range.head, "div").top + 5;
8191 return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")
8192 }, sel_move); },
8193 goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) {
8194 var top = cm.cursorCoords(range.head, "div").top + 5;
8195 return cm.coordsChar({left: 0, top: top}, "div")
8196 }, sel_move); },
8197 goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) {
8198 var top = cm.cursorCoords(range.head, "div").top + 5;
8199 var pos = cm.coordsChar({left: 0, top: top}, "div");
8200 if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) }
8201 return pos
8202 }, sel_move); },
8203 goLineUp: function (cm) { return cm.moveV(-1, "line"); },
8204 goLineDown: function (cm) { return cm.moveV(1, "line"); },
8205 goPageUp: function (cm) { return cm.moveV(-1, "page"); },
8206 goPageDown: function (cm) { return cm.moveV(1, "page"); },
8207 goCharLeft: function (cm) { return cm.moveH(-1, "char"); },
8208 goCharRight: function (cm) { return cm.moveH(1, "char"); },
8209 goColumnLeft: function (cm) { return cm.moveH(-1, "column"); },
8210 goColumnRight: function (cm) { return cm.moveH(1, "column"); },
8211 goWordLeft: function (cm) { return cm.moveH(-1, "word"); },
8212 goGroupRight: function (cm) { return cm.moveH(1, "group"); },
8213 goGroupLeft: function (cm) { return cm.moveH(-1, "group"); },
8214 goWordRight: function (cm) { return cm.moveH(1, "word"); },
8215 delCharBefore: function (cm) { return cm.deleteH(-1, "char"); },
8216 delCharAfter: function (cm) { return cm.deleteH(1, "char"); },
8217 delWordBefore: function (cm) { return cm.deleteH(-1, "word"); },
8218 delWordAfter: function (cm) { return cm.deleteH(1, "word"); },
8219 delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); },
8220 delGroupAfter: function (cm) { return cm.deleteH(1, "group"); },
8221 indentAuto: function (cm) { return cm.indentSelection("smart"); },
8222 indentMore: function (cm) { return cm.indentSelection("add"); },
8223 indentLess: function (cm) { return cm.indentSelection("subtract"); },
8224 insertTab: function (cm) { return cm.replaceSelection("\t"); },
8225 insertSoftTab: function (cm) {
8226 var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
8227 for (var i = 0; i < ranges.length; i++) {
8228 var pos = ranges[i].from();
8229 var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
8230 spaces.push(spaceStr(tabSize - col % tabSize));
8231 }
8232 cm.replaceSelections(spaces);
8233 },
8234 defaultTab: function (cm) {
8235 if (cm.somethingSelected()) { cm.indentSelection("add"); }
8236 else { cm.execCommand("insertTab"); }
8237 },
8238 // Swap the two chars left and right of each selection's head.
8239 // Move cursor behind the two swapped characters afterwards.
8240 //
8241 // Doesn't consider line feeds a character.
8242 // Doesn't scan more than one line above to find a character.
8243 // Doesn't do anything on an empty line.
8244 // Doesn't do anything with non-empty selections.
8245 transposeChars: function (cm) { return runInOp(cm, function () {
8246 var ranges = cm.listSelections(), newSel = [];
8247 for (var i = 0; i < ranges.length; i++) {
8248 if (!ranges[i].empty()) { continue }
8249 var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
8250 if (line) {
8251 if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); }
8252 if (cur.ch > 0) {
8253 cur = new Pos(cur.line, cur.ch + 1);
8254 cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
8255 Pos(cur.line, cur.ch - 2), cur, "+transpose");
8256 } else if (cur.line > cm.doc.first) {
8257 var prev = getLine(cm.doc, cur.line - 1).text;
8258 if (prev) {
8259 cur = new Pos(cur.line, 1);
8260 cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
8261 prev.charAt(prev.length - 1),
8262 Pos(cur.line - 1, prev.length - 1), cur, "+transpose");
8263 }
8264 }
8265 }
8266 newSel.push(new Range(cur, cur));
8267 }
8268 cm.setSelections(newSel);
8269 }); },
8270 newlineAndIndent: function (cm) { return runInOp(cm, function () {
8271 var sels = cm.listSelections();
8272 for (var i = sels.length - 1; i >= 0; i--)
8273 { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input"); }
8274 sels = cm.listSelections();
8275 for (var i$1 = 0; i$1 < sels.length; i$1++)
8276 { cm.indentLine(sels[i$1].from().line, null, true); }
8277 ensureCursorVisible(cm);
8278 }); },
8279 openLine: function (cm) { return cm.replaceSelection("\n", "start"); },
8280 toggleOverwrite: function (cm) { return cm.toggleOverwrite(); }
8281 };
8282
8283
8284 function lineStart(cm, lineN) {
8285 var line = getLine(cm.doc, lineN);
8286 var visual = visualLine(line);
8287 if (visual != line) { lineN = lineNo(visual); }
8288 return endOfLine(true, cm, visual, lineN, 1)
8289 }
8290 function lineEnd(cm, lineN) {
8291 var line = getLine(cm.doc, lineN);
8292 var visual = visualLineEnd(line);
8293 if (visual != line) { lineN = lineNo(visual); }
8294 return endOfLine(true, cm, line, lineN, -1)
8295 }
8296 function lineStartSmart(cm, pos) {
8297 var start = lineStart(cm, pos.line);
8298 var line = getLine(cm.doc, start.line);
8299 var order = getOrder(line, cm.doc.direction);
8300 if (!order || order[0].level == 0) {
8301 var firstNonWS = Math.max(0, line.text.search(/\S/));
8302 var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
8303 return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)
8304 }
8305 return start
8306 }
8307
8308 // Run a handler that was bound to a key.
8309 function doHandleBinding(cm, bound, dropShift) {
8310 if (typeof bound == "string") {
8311 bound = commands[bound];
8312 if (!bound) { return false }
8313 }
8314 // Ensure previous input has been read, so that the handler sees a
8315 // consistent view of the document
8316 cm.display.input.ensurePolled();
8317 var prevShift = cm.display.shift, done = false;
8318 try {
8319 if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
8320 if (dropShift) { cm.display.shift = false; }
8321 done = bound(cm) != Pass;
8322 } finally {
8323 cm.display.shift = prevShift;
8324 cm.state.suppressEdits = false;
8325 }
8326 return done
8327 }
8328
8329 function lookupKeyForEditor(cm, name, handle) {
8330 for (var i = 0; i < cm.state.keyMaps.length; i++) {
8331 var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
8332 if (result) { return result }
8333 }
8334 return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
8335 || lookupKey(name, cm.options.keyMap, handle, cm)
8336 }
8337
8338 // Note that, despite the name, this function is also used to check
8339 // for bound mouse clicks.
8340
8341 var stopSeq = new Delayed;
8342 function dispatchKey(cm, name, e, handle) {
8343 var seq = cm.state.keySeq;
8344 if (seq) {
8345 if (isModifierKey(name)) { return "handled" }
8346 stopSeq.set(50, function () {
8347 if (cm.state.keySeq == seq) {
8348 cm.state.keySeq = null;
8349 cm.display.input.reset();
8350 }
8351 });
8352 name = seq + " " + name;
8353 }
8354 var result = lookupKeyForEditor(cm, name, handle);
8355
8356 if (result == "multi")
8357 { cm.state.keySeq = name; }
8358 if (result == "handled")
8359 { signalLater(cm, "keyHandled", cm, name, e); }
8360
8361 if (result == "handled" || result == "multi") {
8362 e_preventDefault(e);
8363 restartBlink(cm);
8364 }
8365
8366 if (seq && !result && /\'$/.test(name)) {
8367 e_preventDefault(e);
8368 return true
8369 }
8370 return !!result
8371 }
8372
8373 // Handle a key from the keydown event.
8374 function handleKeyBinding(cm, e) {
8375 var name = keyName(e, true);
8376 if (!name) { return false }
8377
8378 if (e.shiftKey && !cm.state.keySeq) {
8379 // First try to resolve full name (including 'Shift-'). Failing
8380 // that, see if there is a cursor-motion command (starting with
8381 // 'go') bound to the keyname without 'Shift-'.
8382 return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); })
8383 || dispatchKey(cm, name, e, function (b) {
8384 if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
8385 { return doHandleBinding(cm, b) }
8386 })
8387 } else {
8388 return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); })
8389 }
8390 }
8391
8392 // Handle a key from the keypress event
8393 function handleCharBinding(cm, e, ch) {
8394 return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); })
8395 }
8396
8397 var lastStoppedKey = null;
8398 function onKeyDown(e) {
8399 var cm = this;
8400 cm.curOp.focus = activeElt();
8401 if (signalDOMEvent(cm, e)) { return }
8402 // IE does strange things with escape.
8403 if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; }
8404 var code = e.keyCode;
8405 cm.display.shift = code == 16 || e.shiftKey;
8406 var handled = handleKeyBinding(cm, e);
8407 if (presto) {
8408 lastStoppedKey = handled ? code : null;
8409 // Opera has no cut event... we try to at least catch the key combo
8410 if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
8411 { cm.replaceSelection("", null, "cut"); }
8412 }
8413
8414 // Turn mouse into crosshair when Alt is held on Mac.
8415 if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
8416 { showCrossHair(cm); }
8417 }
8418
8419 function showCrossHair(cm) {
8420 var lineDiv = cm.display.lineDiv;
8421 addClass(lineDiv, "CodeMirror-crosshair");
8422
8423 function up(e) {
8424 if (e.keyCode == 18 || !e.altKey) {
8425 rmClass(lineDiv, "CodeMirror-crosshair");
8426 off(document, "keyup", up);
8427 off(document, "mouseover", up);
8428 }
8429 }
8430 on(document, "keyup", up);
8431 on(document, "mouseover", up);
8432 }
8433
8434 function onKeyUp(e) {
8435 if (e.keyCode == 16) { this.doc.sel.shift = false; }
8436 signalDOMEvent(this, e);
8437 }
8438
8439 function onKeyPress(e) {
8440 var cm = this;
8441 if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }
8442 var keyCode = e.keyCode, charCode = e.charCode;
8443 if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}
8444 if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return }
8445 var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
8446 // Some browsers fire keypress events for backspace
8447 if (ch == "\x08") { return }
8448 if (handleCharBinding(cm, e, ch)) { return }
8449 cm.display.input.onKeyPress(e);
8450 }
8451
8452 var DOUBLECLICK_DELAY = 400;
8453
8454 var PastClick = function(time, pos, button) {
8455 this.time = time;
8456 this.pos = pos;
8457 this.button = button;
8458 };
8459
8460 PastClick.prototype.compare = function (time, pos, button) {
8461 return this.time + DOUBLECLICK_DELAY > time &&
8462 cmp(pos, this.pos) == 0 && button == this.button
8463 };
8464
8465 var lastClick;
8466 var lastDoubleClick;
8467 function clickRepeat(pos, button) {
8468 var now = +new Date;
8469 if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) {
8470 lastClick = lastDoubleClick = null;
8471 return "triple"
8472 } else if (lastClick && lastClick.compare(now, pos, button)) {
8473 lastDoubleClick = new PastClick(now, pos, button);
8474 lastClick = null;
8475 return "double"
8476 } else {
8477 lastClick = new PastClick(now, pos, button);
8478 lastDoubleClick = null;
8479 return "single"
8480 }
8481 }
8482
8483 // A mouse down can be a single click, double click, triple click,
8484 // start of selection drag, start of text drag, new cursor
8485 // (ctrl-click), rectangle drag (alt-drag), or xwin
8486 // middle-click-paste. Or it might be a click on something we should
8487 // not interfere with, such as a scrollbar or widget.
8488 function onMouseDown(e) {
8489 var cm = this, display = cm.display;
8490 if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return }
8491 display.input.ensurePolled();
8492 display.shift = e.shiftKey;
8493
8494 if (eventInWidget(display, e)) {
8495 if (!webkit) {
8496 // Briefly turn off draggability, to allow widgets to do
8497 // normal dragging things.
8498 display.scroller.draggable = false;
8499 setTimeout(function () { return display.scroller.draggable = true; }, 100);
8500 }
8501 return
8502 }
8503 if (clickInGutter(cm, e)) { return }
8504 var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single";
8505 window.focus();
8506
8507 // #3261: make sure, that we're not starting a second selection
8508 if (button == 1 && cm.state.selectingText)
8509 { cm.state.selectingText(e); }
8510
8511 if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return }
8512
8513 if (button == 1) {
8514 if (pos) { leftButtonDown(cm, pos, repeat, e); }
8515 else if (e_target(e) == display.scroller) { e_preventDefault(e); }
8516 } else if (button == 2) {
8517 if (pos) { extendSelection(cm.doc, pos); }
8518 setTimeout(function () { return display.input.focus(); }, 20);
8519 } else if (button == 3) {
8520 if (captureRightClick) { onContextMenu(cm, e); }
8521 else { delayBlurEvent(cm); }
8522 }
8523 }
8524
8525 function handleMappedButton(cm, button, pos, repeat, event) {
8526 var name = "Click";
8527 if (repeat == "double") { name = "Double" + name; }
8528 else if (repeat == "triple") { name = "Triple" + name; }
8529 name = (button == 1 ? "Left" : button == 2 ? "Middle" : "Right") + name;
8530
8531 return dispatchKey(cm, addModifierNames(name, event), event, function (bound) {
8532 if (typeof bound == "string") { bound = commands[bound]; }
8533 if (!bound) { return false }
8534 var done = false;
8535 try {
8536 if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
8537 done = bound(cm, pos) != Pass;
8538 } finally {
8539 cm.state.suppressEdits = false;
8540 }
8541 return done
8542 })
8543 }
8544
8545 function configureMouse(cm, repeat, event) {
8546 var option = cm.getOption("configureMouse");
8547 var value = option ? option(cm, repeat, event) : {};
8548 if (value.unit == null) {
8549 var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey;
8550 value.unit = rect ? "rectangle" : repeat == "single" ? "char" : repeat == "double" ? "word" : "line";
8551 }
8552 if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey; }
8553 if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey; }
8554 if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey); }
8555 return value
8556 }
8557
8558 function leftButtonDown(cm, pos, repeat, event) {
8559 if (ie) { setTimeout(bind(ensureFocus, cm), 0); }
8560 else { cm.curOp.focus = activeElt(); }
8561
8562 var behavior = configureMouse(cm, repeat, event);
8563
8564 var sel = cm.doc.sel, contained;
8565 if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
8566 repeat == "single" && (contained = sel.contains(pos)) > -1 &&
8567 (cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) &&
8568 (cmp(contained.to(), pos) > 0 || pos.xRel < 0))
8569 { leftButtonStartDrag(cm, event, pos, behavior); }
8570 else
8571 { leftButtonSelect(cm, event, pos, behavior); }
8572 }
8573
8574 // Start a text drag. When it ends, see if any dragging actually
8575 // happen, and treat as a click if it didn't.
8576 function leftButtonStartDrag(cm, event, pos, behavior) {
8577 var display = cm.display, moved = false;
8578 var dragEnd = operation(cm, function (e) {
8579 if (webkit) { display.scroller.draggable = false; }
8580 cm.state.draggingText = false;
8581 off(document, "mouseup", dragEnd);
8582 off(document, "mousemove", mouseMove);
8583 off(display.scroller, "dragstart", dragStart);
8584 off(display.scroller, "drop", dragEnd);
8585 if (!moved) {
8586 e_preventDefault(e);
8587 if (!behavior.addNew)
8588 { extendSelection(cm.doc, pos, null, null, behavior.extend); }
8589 // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
8590 if (webkit || ie && ie_version == 9)
8591 { setTimeout(function () {document.body.focus(); display.input.focus();}, 20); }
8592 else
8593 { display.input.focus(); }
8594 }
8595 });
8596 var mouseMove = function(e2) {
8597 moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10;
8598 };
8599 var dragStart = function () { return moved = true; };
8600 // Let the drag handler handle this.
8601 if (webkit) { display.scroller.draggable = true; }
8602 cm.state.draggingText = dragEnd;
8603 dragEnd.copy = !behavior.moveOnDrag;
8604 // IE's approach to draggable
8605 if (display.scroller.dragDrop) { display.scroller.dragDrop(); }
8606 on(document, "mouseup", dragEnd);
8607 on(document, "mousemove", mouseMove);
8608 on(display.scroller, "dragstart", dragStart);
8609 on(display.scroller, "drop", dragEnd);
8610
8611 delayBlurEvent(cm);
8612 setTimeout(function () { return display.input.focus(); }, 20);
8613 }
8614
8615 function rangeForUnit(cm, pos, unit) {
8616 if (unit == "char") { return new Range(pos, pos) }
8617 if (unit == "word") { return cm.findWordAt(pos) }
8618 if (unit == "line") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) }
8619 var result = unit(cm, pos);
8620 return new Range(result.from, result.to)
8621 }
8622
8623 // Normal selection, as opposed to text dragging.
8624 function leftButtonSelect(cm, event, start, behavior) {
8625 var display = cm.display, doc = cm.doc;
8626 e_preventDefault(event);
8627
8628 var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
8629 if (behavior.addNew && !behavior.extend) {
8630 ourIndex = doc.sel.contains(start);
8631 if (ourIndex > -1)
8632 { ourRange = ranges[ourIndex]; }
8633 else
8634 { ourRange = new Range(start, start); }
8635 } else {
8636 ourRange = doc.sel.primary();
8637 ourIndex = doc.sel.primIndex;
8638 }
8639
8640 if (behavior.unit == "rectangle") {
8641 if (!behavior.addNew) { ourRange = new Range(start, start); }
8642 start = posFromMouse(cm, event, true, true);
8643 ourIndex = -1;
8644 } else {
8645 var range$$1 = rangeForUnit(cm, start, behavior.unit);
8646 if (behavior.extend)
8647 { ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); }
8648 else
8649 { ourRange = range$$1; }
8650 }
8651
8652 if (!behavior.addNew) {
8653 ourIndex = 0;
8654 setSelection(doc, new Selection([ourRange], 0), sel_mouse);
8655 startSel = doc.sel;
8656 } else if (ourIndex == -1) {
8657 ourIndex = ranges.length;
8658 setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
8659 {scroll: false, origin: "*mouse"});
8660 } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) {
8661 setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
8662 {scroll: false, origin: "*mouse"});
8663 startSel = doc.sel;
8664 } else {
8665 replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
8666 }
8667
8668 var lastPos = start;
8669 function extendTo(pos) {
8670 if (cmp(lastPos, pos) == 0) { return }
8671 lastPos = pos;
8672
8673 if (behavior.unit == "rectangle") {
8674 var ranges = [], tabSize = cm.options.tabSize;
8675 var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
8676 var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
8677 var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
8678 for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
8679 line <= end; line++) {
8680 var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
8681 if (left == right)
8682 { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); }
8683 else if (text.length > leftPos)
8684 { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); }
8685 }
8686 if (!ranges.length) { ranges.push(new Range(start, start)); }
8687 setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
8688 {origin: "*mouse", scroll: false});
8689 cm.scrollIntoView(pos);
8690 } else {
8691 var oldRange = ourRange;
8692 var range$$1 = rangeForUnit(cm, pos, behavior.unit);
8693 var anchor = oldRange.anchor, head;
8694 if (cmp(range$$1.anchor, anchor) > 0) {
8695 head = range$$1.head;
8696 anchor = minPos(oldRange.from(), range$$1.anchor);
8697 } else {
8698 head = range$$1.anchor;
8699 anchor = maxPos(oldRange.to(), range$$1.head);
8700 }
8701 var ranges$1 = startSel.ranges.slice(0);
8702 ranges$1[ourIndex] = new Range(clipPos(doc, anchor), head);
8703 setSelection(doc, normalizeSelection(ranges$1, ourIndex), sel_mouse);
8704 }
8705 }
8706
8707 var editorSize = display.wrapper.getBoundingClientRect();
8708 // Used to ensure timeout re-tries don't fire when another extend
8709 // happened in the meantime (clearTimeout isn't reliable -- at
8710 // least on Chrome, the timeouts still happen even when cleared,
8711 // if the clear happens after their scheduled firing time).
8712 var counter = 0;
8713
8714 function extend(e) {
8715 var curCount = ++counter;
8716 var cur = posFromMouse(cm, e, true, behavior.unit == "rectangle");
8717 if (!cur) { return }
8718 if (cmp(cur, lastPos) != 0) {
8719 cm.curOp.focus = activeElt();
8720 extendTo(cur);
8721 var visible = visibleLines(display, doc);
8722 if (cur.line >= visible.to || cur.line < visible.from)
8723 { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); }
8724 } else {
8725 var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
8726 if (outside) { setTimeout(operation(cm, function () {
8727 if (counter != curCount) { return }
8728 display.scroller.scrollTop += outside;
8729 extend(e);
8730 }), 50); }
8731 }
8732 }
8733
8734 function done(e) {
8735 cm.state.selectingText = false;
8736 counter = Infinity;
8737 e_preventDefault(e);
8738 display.input.focus();
8739 off(document, "mousemove", move);
8740 off(document, "mouseup", up);
8741 doc.history.lastSelOrigin = null;
8742 }
8743
8744 var move = operation(cm, function (e) {
8745 if (!e_button(e)) { done(e); }
8746 else { extend(e); }
8747 });
8748 var up = operation(cm, done);
8749 cm.state.selectingText = up;
8750 on(document, "mousemove", move);
8751 on(document, "mouseup", up);
8752 }
8753
8754
8755 // Determines whether an event happened in the gutter, and fires the
8756 // handlers for the corresponding event.
8757 function gutterEvent(cm, e, type, prevent) {
8758 var mX, mY;
8759 try { mX = e.clientX; mY = e.clientY; }
8760 catch(e) { return false }
8761 if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
8762 if (prevent) { e_preventDefault(e); }
8763
8764 var display = cm.display;
8765 var lineBox = display.lineDiv.getBoundingClientRect();
8766
8767 if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }
8768 mY -= lineBox.top - display.viewOffset;
8769
8770 for (var i = 0; i < cm.options.gutters.length; ++i) {
8771 var g = display.gutters.childNodes[i];
8772 if (g && g.getBoundingClientRect().right >= mX) {
8773 var line = lineAtHeight(cm.doc, mY);
8774 var gutter = cm.options.gutters[i];
8775 signal(cm, type, cm, line, gutter, e);
8776 return e_defaultPrevented(e)
8777 }
8778 }
8779 }
8780
8781 function clickInGutter(cm, e) {
8782 return gutterEvent(cm, e, "gutterClick", true)
8783 }
8784
8785 // CONTEXT MENU HANDLING
8786
8787 // To make the context menu work, we need to briefly unhide the
8788 // textarea (making it as unobtrusive as possible) to let the
8789 // right-click take effect on it.
8790 function onContextMenu(cm, e) {
8791 if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return }
8792 if (signalDOMEvent(cm, e, "contextmenu")) { return }
8793 cm.display.input.onContextMenu(e);
8794 }
8795
8796 function contextMenuInGutter(cm, e) {
8797 if (!hasHandler(cm, "gutterContextMenu")) { return false }
8798 return gutterEvent(cm, e, "gutterContextMenu", false)
8799 }
8800
8801 function themeChanged(cm) {
8802 cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
8803 cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
8804 clearCaches(cm);
8805 }
8806
8807 var Init = {toString: function(){return "CodeMirror.Init"}};
8808
8809 var defaults = {};
8810 var optionHandlers = {};
8811
8812 function defineOptions(CodeMirror) {
8813 var optionHandlers = CodeMirror.optionHandlers;
8814
8815 function option(name, deflt, handle, notOnInit) {
8816 CodeMirror.defaults[name] = deflt;
8817 if (handle) { optionHandlers[name] =
8818 notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old); }} : handle; }
8819 }
8820
8821 CodeMirror.defineOption = option;
8822
8823 // Passed to option handlers when there is no old value.
8824 CodeMirror.Init = Init;
8825
8826 // These two are, on init, called from the constructor because they
8827 // have to be initialized before the editor can start at all.
8828 option("value", "", function (cm, val) { return cm.setValue(val); }, true);
8829 option("mode", null, function (cm, val) {
8830 cm.doc.modeOption = val;
8831 loadMode(cm);
8832 }, true);
8833
8834 option("indentUnit", 2, loadMode, true);
8835 option("indentWithTabs", false);
8836 option("smartIndent", true);
8837 option("tabSize", 4, function (cm) {
8838 resetModeState(cm);
8839 clearCaches(cm);
8840 regChange(cm);
8841 }, true);
8842 option("lineSeparator", null, function (cm, val) {
8843 cm.doc.lineSep = val;
8844 if (!val) { return }
8845 var newBreaks = [], lineNo = cm.doc.first;
8846 cm.doc.iter(function (line) {
8847 for (var pos = 0;;) {
8848 var found = line.text.indexOf(val, pos);
8849 if (found == -1) { break }
8850 pos = found + val.length;
8851 newBreaks.push(Pos(lineNo, found));
8852 }
8853 lineNo++;
8854 });
8855 for (var i = newBreaks.length - 1; i >= 0; i--)
8856 { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }
8857 });
8858 option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) {
8859 cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
8860 if (old != Init) { cm.refresh(); }
8861 });
8862 option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true);
8863 option("electricChars", true);
8864 option("inputStyle", mobile ? "contenteditable" : "textarea", function () {
8865 throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME
8866 }, true);
8867 option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true);
8868 option("rtlMoveVisually", !windows);
8869 option("wholeLineUpdateBefore", true);
8870
8871 option("theme", "default", function (cm) {
8872 themeChanged(cm);
8873 guttersChanged(cm);
8874 }, true);
8875 option("keyMap", "default", function (cm, val, old) {
8876 var next = getKeyMap(val);
8877 var prev = old != Init && getKeyMap(old);
8878 if (prev && prev.detach) { prev.detach(cm, next); }
8879 if (next.attach) { next.attach(cm, prev || null); }
8880 });
8881 option("extraKeys", null);
8882 option("configureMouse", null);
8883
8884 option("lineWrapping", false, wrappingChanged, true);
8885 option("gutters", [], function (cm) {
8886 setGuttersForLineNumbers(cm.options);
8887 guttersChanged(cm);
8888 }, true);
8889 option("fixedGutter", true, function (cm, val) {
8890 cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
8891 cm.refresh();
8892 }, true);
8893 option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true);
8894 option("scrollbarStyle", "native", function (cm) {
8895 initScrollbars(cm);
8896 updateScrollbars(cm);
8897 cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
8898 cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
8899 }, true);
8900 option("lineNumbers", false, function (cm) {
8901 setGuttersForLineNumbers(cm.options);
8902 guttersChanged(cm);
8903 }, true);
8904 option("firstLineNumber", 1, guttersChanged, true);
8905 option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true);
8906 option("showCursorWhenSelecting", false, updateSelection, true);
8907
8908 option("resetSelectionOnContextMenu", true);
8909 option("lineWiseCopyCut", true);
8910 option("pasteLinesPerSelection", true);
8911
8912 option("readOnly", false, function (cm, val) {
8913 if (val == "nocursor") {
8914 onBlur(cm);
8915 cm.display.input.blur();
8916 }
8917 cm.display.input.readOnlyChanged(val);
8918 });
8919 option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);
8920 option("dragDrop", true, dragDropChanged);
8921 option("allowDropFileTypes", null);
8922
8923 option("cursorBlinkRate", 530);
8924 option("cursorScrollMargin", 0);
8925 option("cursorHeight", 1, updateSelection, true);
8926 option("singleCursorHeightPerLine", true, updateSelection, true);
8927 option("workTime", 100);
8928 option("workDelay", 100);
8929 option("flattenSpans", true, resetModeState, true);
8930 option("addModeClass", false, resetModeState, true);
8931 option("pollInterval", 100);
8932 option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; });
8933 option("historyEventDelay", 1250);
8934 option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true);
8935 option("maxHighlightLength", 10000, resetModeState, true);
8936 option("moveInputWithCursor", true, function (cm, val) {
8937 if (!val) { cm.display.input.resetPosition(); }
8938 });
8939
8940 option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; });
8941 option("autofocus", null);
8942 option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true);
8943 }
8944
8945 function guttersChanged(cm) {
8946 updateGutters(cm);
8947 regChange(cm);
8948 alignHorizontally(cm);
8949 }
8950
8951 function dragDropChanged(cm, value, old) {
8952 var wasOn = old && old != Init;
8953 if (!value != !wasOn) {
8954 var funcs = cm.display.dragFunctions;
8955 var toggle = value ? on : off;
8956 toggle(cm.display.scroller, "dragstart", funcs.start);
8957 toggle(cm.display.scroller, "dragenter", funcs.enter);
8958 toggle(cm.display.scroller, "dragover", funcs.over);
8959 toggle(cm.display.scroller, "dragleave", funcs.leave);
8960 toggle(cm.display.scroller, "drop", funcs.drop);
8961 }
8962 }
8963
8964 function wrappingChanged(cm) {
8965 if (cm.options.lineWrapping) {
8966 addClass(cm.display.wrapper, "CodeMirror-wrap");
8967 cm.display.sizer.style.minWidth = "";
8968 cm.display.sizerWidth = null;
8969 } else {
8970 rmClass(cm.display.wrapper, "CodeMirror-wrap");
8971 findMaxLine(cm);
8972 }
8973 estimateLineHeights(cm);
8974 regChange(cm);
8975 clearCaches(cm);
8976 setTimeout(function () { return updateScrollbars(cm); }, 100);
8977 }
8978
8979 // A CodeMirror instance represents an editor. This is the object
8980 // that user code is usually dealing with.
8981
8982 function CodeMirror$1(place, options) {
8983 var this$1 = this;
8984
8985 if (!(this instanceof CodeMirror$1)) { return new CodeMirror$1(place, options) }
8986
8987 this.options = options = options ? copyObj(options) : {};
8988 // Determine effective options based on given values and defaults.
8989 copyObj(defaults, options, false);
8990 setGuttersForLineNumbers(options);
8991
8992 var doc = options.value;
8993 if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); }
8994 this.doc = doc;
8995
8996 var input = new CodeMirror$1.inputStyles[options.inputStyle](this);
8997 var display = this.display = new Display(place, doc, input);
8998 display.wrapper.CodeMirror = this;
8999 updateGutters(this);
9000 themeChanged(this);
9001 if (options.lineWrapping)
9002 { this.display.wrapper.className += " CodeMirror-wrap"; }
9003 initScrollbars(this);
9004
9005 this.state = {
9006 keyMaps: [], // stores maps added by addKeyMap
9007 overlays: [], // highlighting overlays, as added by addOverlay
9008 modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
9009 overwrite: false,
9010 delayingBlurEvent: false,
9011 focused: false,
9012 suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
9013 pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
9014 selectingText: false,
9015 draggingText: false,
9016 highlight: new Delayed(), // stores highlight worker timeout
9017 keySeq: null, // Unfinished key sequence
9018 specialChars: null
9019 };
9020
9021 if (options.autofocus && !mobile) { display.input.focus(); }
9022
9023 // Override magic textarea content restore that IE sometimes does
9024 // on our hidden textarea on reload
9025 if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); }
9026
9027 registerEventHandlers(this);
9028 ensureGlobalHandlers();
9029
9030 startOperation(this);
9031 this.curOp.forceUpdate = true;
9032 attachDoc(this, doc);
9033
9034 if ((options.autofocus && !mobile) || this.hasFocus())
9035 { setTimeout(bind(onFocus, this), 20); }
9036 else
9037 { onBlur(this); }
9038
9039 for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))
9040 { optionHandlers[opt](this$1, options[opt], Init); } }
9041 maybeUpdateLineNumberWidth(this);
9042 if (options.finishInit) { options.finishInit(this); }
9043 for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1); }
9044 endOperation(this);
9045 // Suppress optimizelegibility in Webkit, since it breaks text
9046 // measuring on line wrapping boundaries.
9047 if (webkit && options.lineWrapping &&
9048 getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
9049 { display.lineDiv.style.textRendering = "auto"; }
9050 }
9051
9052 // The default configuration options.
9053 CodeMirror$1.defaults = defaults;
9054 // Functions to run when options are changed.
9055 CodeMirror$1.optionHandlers = optionHandlers;
9056
9057 // Attach the necessary event handlers when initializing the editor
9058 function registerEventHandlers(cm) {
9059 var d = cm.display;
9060 on(d.scroller, "mousedown", operation(cm, onMouseDown));
9061 // Older IE's will not fire a second mousedown for a double click
9062 if (ie && ie_version < 11)
9063 { on(d.scroller, "dblclick", operation(cm, function (e) {
9064 if (signalDOMEvent(cm, e)) { return }
9065 var pos = posFromMouse(cm, e);
9066 if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return }
9067 e_preventDefault(e);
9068 var word = cm.findWordAt(pos);
9069 extendSelection(cm.doc, word.anchor, word.head);
9070 })); }
9071 else
9072 { on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }); }
9073 // Some browsers fire contextmenu *after* opening the menu, at
9074 // which point we can't mess with it anymore. Context menu is
9075 // handled in onMouseDown for these browsers.
9076 if (!captureRightClick) { on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); }); }
9077
9078 // Used to suppress mouse event handling when a touch happens
9079 var touchFinished, prevTouch = {end: 0};
9080 function finishTouch() {
9081 if (d.activeTouch) {
9082 touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000);
9083 prevTouch = d.activeTouch;
9084 prevTouch.end = +new Date;
9085 }
9086 }
9087 function isMouseLikeTouchEvent(e) {
9088 if (e.touches.length != 1) { return false }
9089 var touch = e.touches[0];
9090 return touch.radiusX <= 1 && touch.radiusY <= 1
9091 }
9092 function farAway(touch, other) {
9093 if (other.left == null) { return true }
9094 var dx = other.left - touch.left, dy = other.top - touch.top;
9095 return dx * dx + dy * dy > 20 * 20
9096 }
9097 on(d.scroller, "touchstart", function (e) {
9098 if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e)) {
9099 d.input.ensurePolled();
9100 clearTimeout(touchFinished);
9101 var now = +new Date;
9102 d.activeTouch = {start: now, moved: false,
9103 prev: now - prevTouch.end <= 300 ? prevTouch : null};
9104 if (e.touches.length == 1) {
9105 d.activeTouch.left = e.touches[0].pageX;
9106 d.activeTouch.top = e.touches[0].pageY;
9107 }
9108 }
9109 });
9110 on(d.scroller, "touchmove", function () {
9111 if (d.activeTouch) { d.activeTouch.moved = true; }
9112 });
9113 on(d.scroller, "touchend", function (e) {
9114 var touch = d.activeTouch;
9115 if (touch && !eventInWidget(d, e) && touch.left != null &&
9116 !touch.moved && new Date - touch.start < 300) {
9117 var pos = cm.coordsChar(d.activeTouch, "page"), range;
9118 if (!touch.prev || farAway(touch, touch.prev)) // Single tap
9119 { range = new Range(pos, pos); }
9120 else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
9121 { range = cm.findWordAt(pos); }
9122 else // Triple tap
9123 { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); }
9124 cm.setSelection(range.anchor, range.head);
9125 cm.focus();
9126 e_preventDefault(e);
9127 }
9128 finishTouch();
9129 });
9130 on(d.scroller, "touchcancel", finishTouch);
9131
9132 // Sync scrolling between fake scrollbars and real scrollable
9133 // area, ensure viewport is updated when scrolling.
9134 on(d.scroller, "scroll", function () {
9135 if (d.scroller.clientHeight) {
9136 updateScrollTop(cm, d.scroller.scrollTop);
9137 setScrollLeft(cm, d.scroller.scrollLeft, true);
9138 signal(cm, "scroll", cm);
9139 }
9140 });
9141
9142 // Listen to wheel events in order to try and update the viewport on time.
9143 on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); });
9144 on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); });
9145
9146 // Prevent wrapper from ever scrolling
9147 on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
9148
9149 d.dragFunctions = {
9150 enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e); }},
9151 over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
9152 start: function (e) { return onDragStart(cm, e); },
9153 drop: operation(cm, onDrop),
9154 leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}
9155 };
9156
9157 var inp = d.input.getField();
9158 on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); });
9159 on(inp, "keydown", operation(cm, onKeyDown));
9160 on(inp, "keypress", operation(cm, onKeyPress));
9161 on(inp, "focus", function (e) { return onFocus(cm, e); });
9162 on(inp, "blur", function (e) { return onBlur(cm, e); });
9163 }
9164
9165 var initHooks = [];
9166 CodeMirror$1.defineInitHook = function (f) { return initHooks.push(f); };
9167
9168 // Indent the given line. The how parameter can be "smart",
9169 // "add"/null, "subtract", or "prev". When aggressive is false
9170 // (typically set to true for forced single-line indents), empty
9171 // lines are not indented, and places where the mode returns Pass
9172 // are left alone.
9173 function indentLine(cm, n, how, aggressive) {
9174 var doc = cm.doc, state;
9175 if (how == null) { how = "add"; }
9176 if (how == "smart") {
9177 // Fall back to "prev" when the mode doesn't have an indentation
9178 // method.
9179 if (!doc.mode.indent) { how = "prev"; }
9180 else { state = getContextBefore(cm, n).state; }
9181 }
9182
9183 var tabSize = cm.options.tabSize;
9184 var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
9185 if (line.stateAfter) { line.stateAfter = null; }
9186 var curSpaceString = line.text.match(/^\s*/)[0], indentation;
9187 if (!aggressive && !/\S/.test(line.text)) {
9188 indentation = 0;
9189 how = "not";
9190 } else if (how == "smart") {
9191 indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
9192 if (indentation == Pass || indentation > 150) {
9193 if (!aggressive) { return }
9194 how = "prev";
9195 }
9196 }
9197 if (how == "prev") {
9198 if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize); }
9199 else { indentation = 0; }
9200 } else if (how == "add") {
9201 indentation = curSpace + cm.options.indentUnit;
9202 } else if (how == "subtract") {
9203 indentation = curSpace - cm.options.indentUnit;
9204 } else if (typeof how == "number") {
9205 indentation = curSpace + how;
9206 }
9207 indentation = Math.max(0, indentation);
9208
9209 var indentString = "", pos = 0;
9210 if (cm.options.indentWithTabs)
9211 { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} }
9212 if (pos < indentation) { indentString += spaceStr(indentation - pos); }
9213
9214 if (indentString != curSpaceString) {
9215 replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
9216 line.stateAfter = null;
9217 return true
9218 } else {
9219 // Ensure that, if the cursor was in the whitespace at the start
9220 // of the line, it is moved to the end of that space.
9221 for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) {
9222 var range = doc.sel.ranges[i$1];
9223 if (range.head.line == n && range.head.ch < curSpaceString.length) {
9224 var pos$1 = Pos(n, curSpaceString.length);
9225 replaceOneSelection(doc, i$1, new Range(pos$1, pos$1));
9226 break
9227 }
9228 }
9229 }
9230 }
9231
9232 // This will be set to a {lineWise: bool, text: [string]} object, so
9233 // that, when pasting, we know what kind of selections the copied
9234 // text was made out of.
9235 var lastCopied = null;
9236
9237 function setLastCopied(newLastCopied) {
9238 lastCopied = newLastCopied;
9239 }
9240
9241 function applyTextInput(cm, inserted, deleted, sel, origin) {
9242 var doc = cm.doc;
9243 cm.display.shift = false;
9244 if (!sel) { sel = doc.sel; }
9245
9246 var paste = cm.state.pasteIncoming || origin == "paste";
9247 var textLines = splitLinesAuto(inserted), multiPaste = null;
9248 // When pasing N lines into N selections, insert one line per selection
9249 if (paste && sel.ranges.length > 1) {
9250 if (lastCopied && lastCopied.text.join("\n") == inserted) {
9251 if (sel.ranges.length % lastCopied.text.length == 0) {
9252 multiPaste = [];
9253 for (var i = 0; i < lastCopied.text.length; i++)
9254 { multiPaste.push(doc.splitLines(lastCopied.text[i])); }
9255 }
9256 } else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) {
9257 multiPaste = map(textLines, function (l) { return [l]; });
9258 }
9259 }
9260
9261 var updateInput;
9262 // Normal behavior is to insert the new text into every selection
9263 for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {
9264 var range$$1 = sel.ranges[i$1];
9265 var from = range$$1.from(), to = range$$1.to();
9266 if (range$$1.empty()) {
9267 if (deleted && deleted > 0) // Handle deletion
9268 { from = Pos(from.line, from.ch - deleted); }
9269 else if (cm.state.overwrite && !paste) // Handle overwrite
9270 { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }
9271 else if (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted)
9272 { from = to = Pos(from.line, 0); }
9273 }
9274 updateInput = cm.curOp.updateInput;
9275 var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,
9276 origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")};
9277 makeChange(cm.doc, changeEvent);
9278 signalLater(cm, "inputRead", cm, changeEvent);
9279 }
9280 if (inserted && !paste)
9281 { triggerElectric(cm, inserted); }
9282
9283 ensureCursorVisible(cm);
9284 cm.curOp.updateInput = updateInput;
9285 cm.curOp.typing = true;
9286 cm.state.pasteIncoming = cm.state.cutIncoming = false;
9287 }
9288
9289 function handlePaste(e, cm) {
9290 var pasted = e.clipboardData && e.clipboardData.getData("Text");
9291 if (pasted) {
9292 e.preventDefault();
9293 if (!cm.isReadOnly() && !cm.options.disableInput)
9294 { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }); }
9295 return true
9296 }
9297 }
9298
9299 function triggerElectric(cm, inserted) {
9300 // When an 'electric' character is inserted, immediately trigger a reindent
9301 if (!cm.options.electricChars || !cm.options.smartIndent) { return }
9302 var sel = cm.doc.sel;
9303
9304 for (var i = sel.ranges.length - 1; i >= 0; i--) {
9305 var range$$1 = sel.ranges[i];
9306 if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue }
9307 var mode = cm.getModeAt(range$$1.head);
9308 var indented = false;
9309 if (mode.electricChars) {
9310 for (var j = 0; j < mode.electricChars.length; j++)
9311 { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
9312 indented = indentLine(cm, range$$1.head.line, "smart");
9313 break
9314 } }
9315 } else if (mode.electricInput) {
9316 if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch)))
9317 { indented = indentLine(cm, range$$1.head.line, "smart"); }
9318 }
9319 if (indented) { signalLater(cm, "electricInput", cm, range$$1.head.line); }
9320 }
9321 }
9322
9323 function copyableRanges(cm) {
9324 var text = [], ranges = [];
9325 for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
9326 var line = cm.doc.sel.ranges[i].head.line;
9327 var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
9328 ranges.push(lineRange);
9329 text.push(cm.getRange(lineRange.anchor, lineRange.head));
9330 }
9331 return {text: text, ranges: ranges}
9332 }
9333
9334 function disableBrowserMagic(field, spellcheck) {
9335 field.setAttribute("autocorrect", "off");
9336 field.setAttribute("autocapitalize", "off");
9337 field.setAttribute("spellcheck", !!spellcheck);
9338 }
9339
9340 function hiddenTextarea() {
9341 var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none");
9342 var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
9343 // The textarea is kept positioned near the cursor to prevent the
9344 // fact that it'll be scrolled into view on input from scrolling
9345 // our fake cursor out of view. On webkit, when wrap=off, paste is
9346 // very slow. So make the area wide instead.
9347 if (webkit) { te.style.width = "1000px"; }
9348 else { te.setAttribute("wrap", "off"); }
9349 // If border: 0; -- iOS fails to open keyboard (issue #1287)
9350 if (ios) { te.style.border = "1px solid black"; }
9351 disableBrowserMagic(te);
9352 return div
9353 }
9354
9355 // The publicly visible API. Note that methodOp(f) means
9356 // 'wrap f in an operation, performed on its `this` parameter'.
9357
9358 // This is not the complete set of editor methods. Most of the
9359 // methods defined on the Doc type are also injected into
9360 // CodeMirror.prototype, for backwards compatibility and
9361 // convenience.
9362
9363 var addEditorMethods = function(CodeMirror) {
9364 var optionHandlers = CodeMirror.optionHandlers;
9365
9366 var helpers = CodeMirror.helpers = {};
9367
9368 CodeMirror.prototype = {
9369 constructor: CodeMirror,
9370 focus: function(){window.focus(); this.display.input.focus();},
9371
9372 setOption: function(option, value) {
9373 var options = this.options, old = options[option];
9374 if (options[option] == value && option != "mode") { return }
9375 options[option] = value;
9376 if (optionHandlers.hasOwnProperty(option))
9377 { operation(this, optionHandlers[option])(this, value, old); }
9378 signal(this, "optionChange", this, option);
9379 },
9380
9381 getOption: function(option) {return this.options[option]},
9382 getDoc: function() {return this.doc},
9383
9384 addKeyMap: function(map$$1, bottom) {
9385 this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map$$1));
9386 },
9387 removeKeyMap: function(map$$1) {
9388 var maps = this.state.keyMaps;
9389 for (var i = 0; i < maps.length; ++i)
9390 { if (maps[i] == map$$1 || maps[i].name == map$$1) {
9391 maps.splice(i, 1);
9392 return true
9393 } }
9394 },
9395
9396 addOverlay: methodOp(function(spec, options) {
9397 var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
9398 if (mode.startState) { throw new Error("Overlays may not be stateful.") }
9399 insertSorted(this.state.overlays,
9400 {mode: mode, modeSpec: spec, opaque: options && options.opaque,
9401 priority: (options && options.priority) || 0},
9402 function (overlay) { return overlay.priority; });
9403 this.state.modeGen++;
9404 regChange(this);
9405 }),
9406 removeOverlay: methodOp(function(spec) {
9407 var this$1 = this;
9408
9409 var overlays = this.state.overlays;
9410 for (var i = 0; i < overlays.length; ++i) {
9411 var cur = overlays[i].modeSpec;
9412 if (cur == spec || typeof spec == "string" && cur.name == spec) {
9413 overlays.splice(i, 1);
9414 this$1.state.modeGen++;
9415 regChange(this$1);
9416 return
9417 }
9418 }
9419 }),
9420
9421 indentLine: methodOp(function(n, dir, aggressive) {
9422 if (typeof dir != "string" && typeof dir != "number") {
9423 if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev"; }
9424 else { dir = dir ? "add" : "subtract"; }
9425 }
9426 if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); }
9427 }),
9428 indentSelection: methodOp(function(how) {
9429 var this$1 = this;
9430
9431 var ranges = this.doc.sel.ranges, end = -1;
9432 for (var i = 0; i < ranges.length; i++) {
9433 var range$$1 = ranges[i];
9434 if (!range$$1.empty()) {
9435 var from = range$$1.from(), to = range$$1.to();
9436 var start = Math.max(end, from.line);
9437 end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
9438 for (var j = start; j < end; ++j)
9439 { indentLine(this$1, j, how); }
9440 var newRanges = this$1.doc.sel.ranges;
9441 if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
9442 { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); }
9443 } else if (range$$1.head.line > end) {
9444 indentLine(this$1, range$$1.head.line, how, true);
9445 end = range$$1.head.line;
9446 if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1); }
9447 }
9448 }
9449 }),
9450
9451 // Fetch the parser token for a given character. Useful for hacks
9452 // that want to inspect the mode state (say, for completion).
9453 getTokenAt: function(pos, precise) {
9454 return takeToken(this, pos, precise)
9455 },
9456
9457 getLineTokens: function(line, precise) {
9458 return takeToken(this, Pos(line), precise, true)
9459 },
9460
9461 getTokenTypeAt: function(pos) {
9462 pos = clipPos(this.doc, pos);
9463 var styles = getLineStyles(this, getLine(this.doc, pos.line));
9464 var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
9465 var type;
9466 if (ch == 0) { type = styles[2]; }
9467 else { for (;;) {
9468 var mid = (before + after) >> 1;
9469 if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid; }
9470 else if (styles[mid * 2 + 1] < ch) { before = mid + 1; }
9471 else { type = styles[mid * 2 + 2]; break }
9472 } }
9473 var cut = type ? type.indexOf("overlay ") : -1;
9474 return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1)
9475 },
9476
9477 getModeAt: function(pos) {
9478 var mode = this.doc.mode;
9479 if (!mode.innerMode) { return mode }
9480 return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode
9481 },
9482
9483 getHelper: function(pos, type) {
9484 return this.getHelpers(pos, type)[0]
9485 },
9486
9487 getHelpers: function(pos, type) {
9488 var this$1 = this;
9489
9490 var found = [];
9491 if (!helpers.hasOwnProperty(type)) { return found }
9492 var help = helpers[type], mode = this.getModeAt(pos);
9493 if (typeof mode[type] == "string") {
9494 if (help[mode[type]]) { found.push(help[mode[type]]); }
9495 } else if (mode[type]) {
9496 for (var i = 0; i < mode[type].length; i++) {
9497 var val = help[mode[type][i]];
9498 if (val) { found.push(val); }
9499 }
9500 } else if (mode.helperType && help[mode.helperType]) {
9501 found.push(help[mode.helperType]);
9502 } else if (help[mode.name]) {
9503 found.push(help[mode.name]);
9504 }
9505 for (var i$1 = 0; i$1 < help._global.length; i$1++) {
9506 var cur = help._global[i$1];
9507 if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1)
9508 { found.push(cur.val); }
9509 }
9510 return found
9511 },
9512
9513 getStateAfter: function(line, precise) {
9514 var doc = this.doc;
9515 line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
9516 return getContextBefore(this, line + 1, precise).state
9517 },
9518
9519 cursorCoords: function(start, mode) {
9520 var pos, range$$1 = this.doc.sel.primary();
9521 if (start == null) { pos = range$$1.head; }
9522 else if (typeof start == "object") { pos = clipPos(this.doc, start); }
9523 else { pos = start ? range$$1.from() : range$$1.to(); }
9524 return cursorCoords(this, pos, mode || "page")
9525 },
9526
9527 charCoords: function(pos, mode) {
9528 return charCoords(this, clipPos(this.doc, pos), mode || "page")
9529 },
9530
9531 coordsChar: function(coords, mode) {
9532 coords = fromCoordSystem(this, coords, mode || "page");
9533 return coordsChar(this, coords.left, coords.top)
9534 },
9535
9536 lineAtHeight: function(height, mode) {
9537 height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
9538 return lineAtHeight(this.doc, height + this.display.viewOffset)
9539 },
9540 heightAtLine: function(line, mode, includeWidgets) {
9541 var end = false, lineObj;
9542 if (typeof line == "number") {
9543 var last = this.doc.first + this.doc.size - 1;
9544 if (line < this.doc.first) { line = this.doc.first; }
9545 else if (line > last) { line = last; end = true; }
9546 lineObj = getLine(this.doc, line);
9547 } else {
9548 lineObj = line;
9549 }
9550 return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets || end).top +
9551 (end ? this.doc.height - heightAtLine(lineObj) : 0)
9552 },
9553
9554 defaultTextHeight: function() { return textHeight(this.display) },
9555 defaultCharWidth: function() { return charWidth(this.display) },
9556
9557 getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}},
9558
9559 addWidget: function(pos, node, scroll, vert, horiz) {
9560 var display = this.display;
9561 pos = cursorCoords(this, clipPos(this.doc, pos));
9562 var top = pos.bottom, left = pos.left;
9563 node.style.position = "absolute";
9564 node.setAttribute("cm-ignore-events", "true");
9565 this.display.input.setUneditable(node);
9566 display.sizer.appendChild(node);
9567 if (vert == "over") {
9568 top = pos.top;
9569 } else if (vert == "above" || vert == "near") {
9570 var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
9571 hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
9572 // Default to positioning above (if specified and possible); otherwise default to positioning below
9573 if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
9574 { top = pos.top - node.offsetHeight; }
9575 else if (pos.bottom + node.offsetHeight <= vspace)
9576 { top = pos.bottom; }
9577 if (left + node.offsetWidth > hspace)
9578 { left = hspace - node.offsetWidth; }
9579 }
9580 node.style.top = top + "px";
9581 node.style.left = node.style.right = "";
9582 if (horiz == "right") {
9583 left = display.sizer.clientWidth - node.offsetWidth;
9584 node.style.right = "0px";
9585 } else {
9586 if (horiz == "left") { left = 0; }
9587 else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2; }
9588 node.style.left = left + "px";
9589 }
9590 if (scroll)
9591 { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}); }
9592 },
9593
9594 triggerOnKeyDown: methodOp(onKeyDown),
9595 triggerOnKeyPress: methodOp(onKeyPress),
9596 triggerOnKeyUp: onKeyUp,
9597 triggerOnMouseDown: methodOp(onMouseDown),
9598
9599 execCommand: function(cmd) {
9600 if (commands.hasOwnProperty(cmd))
9601 { return commands[cmd].call(null, this) }
9602 },
9603
9604 triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
9605
9606 findPosH: function(from, amount, unit, visually) {
9607 var this$1 = this;
9608
9609 var dir = 1;
9610 if (amount < 0) { dir = -1; amount = -amount; }
9611 var cur = clipPos(this.doc, from);
9612 for (var i = 0; i < amount; ++i) {
9613 cur = findPosH(this$1.doc, cur, dir, unit, visually);
9614 if (cur.hitSide) { break }
9615 }
9616 return cur
9617 },
9618
9619 moveH: methodOp(function(dir, unit) {
9620 var this$1 = this;
9621
9622 this.extendSelectionsBy(function (range$$1) {
9623 if (this$1.display.shift || this$1.doc.extend || range$$1.empty())
9624 { return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) }
9625 else
9626 { return dir < 0 ? range$$1.from() : range$$1.to() }
9627 }, sel_move);
9628 }),
9629
9630 deleteH: methodOp(function(dir, unit) {
9631 var sel = this.doc.sel, doc = this.doc;
9632 if (sel.somethingSelected())
9633 { doc.replaceSelection("", null, "+delete"); }
9634 else
9635 { deleteNearSelection(this, function (range$$1) {
9636 var other = findPosH(doc, range$$1.head, dir, unit, false);
9637 return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other}
9638 }); }
9639 }),
9640
9641 findPosV: function(from, amount, unit, goalColumn) {
9642 var this$1 = this;
9643
9644 var dir = 1, x = goalColumn;
9645 if (amount < 0) { dir = -1; amount = -amount; }
9646 var cur = clipPos(this.doc, from);
9647 for (var i = 0; i < amount; ++i) {
9648 var coords = cursorCoords(this$1, cur, "div");
9649 if (x == null) { x = coords.left; }
9650 else { coords.left = x; }
9651 cur = findPosV(this$1, coords, dir, unit);
9652 if (cur.hitSide) { break }
9653 }
9654 return cur
9655 },
9656
9657 moveV: methodOp(function(dir, unit) {
9658 var this$1 = this;
9659
9660 var doc = this.doc, goals = [];
9661 var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();
9662 doc.extendSelectionsBy(function (range$$1) {
9663 if (collapse)
9664 { return dir < 0 ? range$$1.from() : range$$1.to() }
9665 var headPos = cursorCoords(this$1, range$$1.head, "div");
9666 if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; }
9667 goals.push(headPos.left);
9668 var pos = findPosV(this$1, headPos, dir, unit);
9669 if (unit == "page" && range$$1 == doc.sel.primary())
9670 { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); }
9671 return pos
9672 }, sel_move);
9673 if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++)
9674 { doc.sel.ranges[i].goalColumn = goals[i]; } }
9675 }),
9676
9677 // Find the word at the given position (as returned by coordsChar).
9678 findWordAt: function(pos) {
9679 var doc = this.doc, line = getLine(doc, pos.line).text;
9680 var start = pos.ch, end = pos.ch;
9681 if (line) {
9682 var helper = this.getHelper(pos, "wordChars");
9683 if ((pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end; }
9684 var startChar = line.charAt(start);
9685 var check = isWordChar(startChar, helper)
9686 ? function (ch) { return isWordChar(ch, helper); }
9687 : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); }
9688 : function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); };
9689 while (start > 0 && check(line.charAt(start - 1))) { --start; }
9690 while (end < line.length && check(line.charAt(end))) { ++end; }
9691 }
9692 return new Range(Pos(pos.line, start), Pos(pos.line, end))
9693 },
9694
9695 toggleOverwrite: function(value) {
9696 if (value != null && value == this.state.overwrite) { return }
9697 if (this.state.overwrite = !this.state.overwrite)
9698 { addClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
9699 else
9700 { rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
9701
9702 signal(this, "overwriteToggle", this, this.state.overwrite);
9703 },
9704 hasFocus: function() { return this.display.input.getField() == activeElt() },
9705 isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) },
9706
9707 scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }),
9708 getScrollInfo: function() {
9709 var scroller = this.display.scroller;
9710 return {left: scroller.scrollLeft, top: scroller.scrollTop,
9711 height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
9712 width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
9713 clientHeight: displayHeight(this), clientWidth: displayWidth(this)}
9714 },
9715
9716 scrollIntoView: methodOp(function(range$$1, margin) {
9717 if (range$$1 == null) {
9718 range$$1 = {from: this.doc.sel.primary().head, to: null};
9719 if (margin == null) { margin = this.options.cursorScrollMargin; }
9720 } else if (typeof range$$1 == "number") {
9721 range$$1 = {from: Pos(range$$1, 0), to: null};
9722 } else if (range$$1.from == null) {
9723 range$$1 = {from: range$$1, to: null};
9724 }
9725 if (!range$$1.to) { range$$1.to = range$$1.from; }
9726 range$$1.margin = margin || 0;
9727
9728 if (range$$1.from.line != null) {
9729 scrollToRange(this, range$$1);
9730 } else {
9731 scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin);
9732 }
9733 }),
9734
9735 setSize: methodOp(function(width, height) {
9736 var this$1 = this;
9737
9738 var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; };
9739 if (width != null) { this.display.wrapper.style.width = interpret(width); }
9740 if (height != null) { this.display.wrapper.style.height = interpret(height); }
9741 if (this.options.lineWrapping) { clearLineMeasurementCache(this); }
9742 var lineNo$$1 = this.display.viewFrom;
9743 this.doc.iter(lineNo$$1, this.display.viewTo, function (line) {
9744 if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)
9745 { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, "widget"); break } } }
9746 ++lineNo$$1;
9747 });
9748 this.curOp.forceUpdate = true;
9749 signal(this, "refresh", this);
9750 }),
9751
9752 operation: function(f){return runInOp(this, f)},
9753 startOperation: function(){return startOperation(this)},
9754 endOperation: function(){return endOperation(this)},
9755
9756 refresh: methodOp(function() {
9757 var oldHeight = this.display.cachedTextHeight;
9758 regChange(this);
9759 this.curOp.forceUpdate = true;
9760 clearCaches(this);
9761 scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);
9762 updateGutterSpace(this);
9763 if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
9764 { estimateLineHeights(this); }
9765 signal(this, "refresh", this);
9766 }),
9767
9768 swapDoc: methodOp(function(doc) {
9769 var old = this.doc;
9770 old.cm = null;
9771 attachDoc(this, doc);
9772 clearCaches(this);
9773 this.display.input.reset();
9774 scrollToCoords(this, doc.scrollLeft, doc.scrollTop);
9775 this.curOp.forceScroll = true;
9776 signalLater(this, "swapDoc", this, old);
9777 return old
9778 }),
9779
9780 getInputField: function(){return this.display.input.getField()},
9781 getWrapperElement: function(){return this.display.wrapper},
9782 getScrollerElement: function(){return this.display.scroller},
9783 getGutterElement: function(){return this.display.gutters}
9784 };
9785 eventMixin(CodeMirror);
9786
9787 CodeMirror.registerHelper = function(type, name, value) {
9788 if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; }
9789 helpers[type][name] = value;
9790 };
9791 CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
9792 CodeMirror.registerHelper(type, name, value);
9793 helpers[type]._global.push({pred: predicate, val: value});
9794 };
9795 };
9796
9797 // Used for horizontal relative motion. Dir is -1 or 1 (left or
9798 // right), unit can be "char", "column" (like char, but doesn't
9799 // cross line boundaries), "word" (across next word), or "group" (to
9800 // the start of next group of word or non-word-non-whitespace
9801 // chars). The visually param controls whether, in right-to-left
9802 // text, direction 1 means to move towards the next index in the
9803 // string, or towards the character to the right of the current
9804 // position. The resulting position will have a hitSide=true
9805 // property if it reached the end of the document.
9806 function findPosH(doc, pos, dir, unit, visually) {
9807 var oldPos = pos;
9808 var origDir = dir;
9809 var lineObj = getLine(doc, pos.line);
9810 function findNextLine() {
9811 var l = pos.line + dir;
9812 if (l < doc.first || l >= doc.first + doc.size) { return false }
9813 pos = new Pos(l, pos.ch, pos.sticky);
9814 return lineObj = getLine(doc, l)
9815 }
9816 function moveOnce(boundToLine) {
9817 var next;
9818 if (visually) {
9819 next = moveVisually(doc.cm, lineObj, pos, dir);
9820 } else {
9821 next = moveLogically(lineObj, pos, dir);
9822 }
9823 if (next == null) {
9824 if (!boundToLine && findNextLine())
9825 { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir); }
9826 else
9827 { return false }
9828 } else {
9829 pos = next;
9830 }
9831 return true
9832 }
9833
9834 if (unit == "char") {
9835 moveOnce();
9836 } else if (unit == "column") {
9837 moveOnce(true);
9838 } else if (unit == "word" || unit == "group") {
9839 var sawType = null, group = unit == "group";
9840 var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
9841 for (var first = true;; first = false) {
9842 if (dir < 0 && !moveOnce(!first)) { break }
9843 var cur = lineObj.text.charAt(pos.ch) || "\n";
9844 var type = isWordChar(cur, helper) ? "w"
9845 : group && cur == "\n" ? "n"
9846 : !group || /\s/.test(cur) ? null
9847 : "p";
9848 if (group && !first && !type) { type = "s"; }
9849 if (sawType && sawType != type) {
9850 if (dir < 0) {dir = 1; moveOnce(); pos.sticky = "after";}
9851 break
9852 }
9853
9854 if (type) { sawType = type; }
9855 if (dir > 0 && !moveOnce(!first)) { break }
9856 }
9857 }
9858 var result = skipAtomic(doc, pos, oldPos, origDir, true);
9859 if (equalCursorPos(oldPos, result)) { result.hitSide = true; }
9860 return result
9861 }
9862
9863 // For relative vertical movement. Dir may be -1 or 1. Unit can be
9864 // "page" or "line". The resulting position will have a hitSide=true
9865 // property if it reached the end of the document.
9866 function findPosV(cm, pos, dir, unit) {
9867 var doc = cm.doc, x = pos.left, y;
9868 if (unit == "page") {
9869 var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
9870 var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3);
9871 y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount;
9872
9873 } else if (unit == "line") {
9874 y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
9875 }
9876 var target;
9877 for (;;) {
9878 target = coordsChar(cm, x, y);
9879 if (!target.outside) { break }
9880 if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break }
9881 y += dir * 5;
9882 }
9883 return target
9884 }
9885
9886 // CONTENTEDITABLE INPUT STYLE
9887
9888 var ContentEditableInput = function(cm) {
9889 this.cm = cm;
9890 this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
9891 this.polling = new Delayed();
9892 this.composing = null;
9893 this.gracePeriod = false;
9894 this.readDOMTimeout = null;
9895 };
9896
9897 ContentEditableInput.prototype.init = function (display) {
9898 var this$1 = this;
9899
9900 var input = this, cm = input.cm;
9901 var div = input.div = display.lineDiv;
9902 disableBrowserMagic(div, cm.options.spellcheck);
9903
9904 on(div, "paste", function (e) {
9905 if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
9906 // IE doesn't fire input events, so we schedule a read for the pasted content in this way
9907 if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }
9908 });
9909
9910 on(div, "compositionstart", function (e) {
9911 this$1.composing = {data: e.data, done: false};
9912 });
9913 on(div, "compositionupdate", function (e) {
9914 if (!this$1.composing) { this$1.composing = {data: e.data, done: false}; }
9915 });
9916 on(div, "compositionend", function (e) {
9917 if (this$1.composing) {
9918 if (e.data != this$1.composing.data) { this$1.readFromDOMSoon(); }
9919 this$1.composing.done = true;
9920 }
9921 });
9922
9923 on(div, "touchstart", function () { return input.forceCompositionEnd(); });
9924
9925 on(div, "input", function () {
9926 if (!this$1.composing) { this$1.readFromDOMSoon(); }
9927 });
9928
9929 function onCopyCut(e) {
9930 if (signalDOMEvent(cm, e)) { return }
9931 if (cm.somethingSelected()) {
9932 setLastCopied({lineWise: false, text: cm.getSelections()});
9933 if (e.type == "cut") { cm.replaceSelection("", null, "cut"); }
9934 } else if (!cm.options.lineWiseCopyCut) {
9935 return
9936 } else {
9937 var ranges = copyableRanges(cm);
9938 setLastCopied({lineWise: true, text: ranges.text});
9939 if (e.type == "cut") {
9940 cm.operation(function () {
9941 cm.setSelections(ranges.ranges, 0, sel_dontScroll);
9942 cm.replaceSelection("", null, "cut");
9943 });
9944 }
9945 }
9946 if (e.clipboardData) {
9947 e.clipboardData.clearData();
9948 var content = lastCopied.text.join("\n");
9949 // iOS exposes the clipboard API, but seems to discard content inserted into it
9950 e.clipboardData.setData("Text", content);
9951 if (e.clipboardData.getData("Text") == content) {
9952 e.preventDefault();
9953 return
9954 }
9955 }
9956 // Old-fashioned briefly-focus-a-textarea hack
9957 var kludge = hiddenTextarea(), te = kludge.firstChild;
9958 cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
9959 te.value = lastCopied.text.join("\n");
9960 var hadFocus = document.activeElement;
9961 selectInput(te);
9962 setTimeout(function () {
9963 cm.display.lineSpace.removeChild(kludge);
9964 hadFocus.focus();
9965 if (hadFocus == div) { input.showPrimarySelection(); }
9966 }, 50);
9967 }
9968 on(div, "copy", onCopyCut);
9969 on(div, "cut", onCopyCut);
9970 };
9971
9972 ContentEditableInput.prototype.prepareSelection = function () {
9973 var result = prepareSelection(this.cm, false);
9974 result.focus = this.cm.state.focused;
9975 return result
9976 };
9977
9978 ContentEditableInput.prototype.showSelection = function (info, takeFocus) {
9979 if (!info || !this.cm.display.view.length) { return }
9980 if (info.focus || takeFocus) { this.showPrimarySelection(); }
9981 this.showMultipleSelections(info);
9982 };
9983
9984 ContentEditableInput.prototype.showPrimarySelection = function () {
9985 var sel = window.getSelection(), cm = this.cm, prim = cm.doc.sel.primary();
9986 var from = prim.from(), to = prim.to();
9987
9988 if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {
9989 sel.removeAllRanges();
9990 return
9991 }
9992
9993 var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
9994 var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset);
9995 if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
9996 cmp(minPos(curAnchor, curFocus), from) == 0 &&
9997 cmp(maxPos(curAnchor, curFocus), to) == 0)
9998 { return }
9999
10000 var view = cm.display.view;
10001 var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) ||
10002 {node: view[0].measure.map[2], offset: 0};
10003 var end = to.line < cm.display.viewTo && posToDOM(cm, to);
10004 if (!end) {
10005 var measure = view[view.length - 1].measure;
10006 var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
10007 end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]};
10008 }
10009
10010 if (!start || !end) {
10011 sel.removeAllRanges();
10012 return
10013 }
10014
10015 var old = sel.rangeCount && sel.getRangeAt(0), rng;
10016 try { rng = range(start.node, start.offset, end.offset, end.node); }
10017 catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
10018 if (rng) {
10019 if (!gecko && cm.state.focused) {
10020 sel.collapse(start.node, start.offset);
10021 if (!rng.collapsed) {
10022 sel.removeAllRanges();
10023 sel.addRange(rng);
10024 }
10025 } else {
10026 sel.removeAllRanges();
10027 sel.addRange(rng);
10028 }
10029 if (old && sel.anchorNode == null) { sel.addRange(old); }
10030 else if (gecko) { this.startGracePeriod(); }
10031 }
10032 this.rememberSelection();
10033 };
10034
10035 ContentEditableInput.prototype.startGracePeriod = function () {
10036 var this$1 = this;
10037
10038 clearTimeout(this.gracePeriod);
10039 this.gracePeriod = setTimeout(function () {
10040 this$1.gracePeriod = false;
10041 if (this$1.selectionChanged())
10042 { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }); }
10043 }, 20);
10044 };
10045
10046 ContentEditableInput.prototype.showMultipleSelections = function (info) {
10047 removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
10048 removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
10049 };
10050
10051 ContentEditableInput.prototype.rememberSelection = function () {
10052 var sel = window.getSelection();
10053 this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
10054 this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
10055 };
10056
10057 ContentEditableInput.prototype.selectionInEditor = function () {
10058 var sel = window.getSelection();
10059 if (!sel.rangeCount) { return false }
10060 var node = sel.getRangeAt(0).commonAncestorContainer;
10061 return contains(this.div, node)
10062 };
10063
10064 ContentEditableInput.prototype.focus = function () {
10065 if (this.cm.options.readOnly != "nocursor") {
10066 if (!this.selectionInEditor())
10067 { this.showSelection(this.prepareSelection(), true); }
10068 this.div.focus();
10069 }
10070 };
10071 ContentEditableInput.prototype.blur = function () { this.div.blur(); };
10072 ContentEditableInput.prototype.getField = function () { return this.div };
10073
10074 ContentEditableInput.prototype.supportsTouch = function () { return true };
10075
10076 ContentEditableInput.prototype.receivedFocus = function () {
10077 var input = this;
10078 if (this.selectionInEditor())
10079 { this.pollSelection(); }
10080 else
10081 { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); }
10082
10083 function poll() {
10084 if (input.cm.state.focused) {
10085 input.pollSelection();
10086 input.polling.set(input.cm.options.pollInterval, poll);
10087 }
10088 }
10089 this.polling.set(this.cm.options.pollInterval, poll);
10090 };
10091
10092 ContentEditableInput.prototype.selectionChanged = function () {
10093 var sel = window.getSelection();
10094 return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
10095 sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
10096 };
10097
10098 ContentEditableInput.prototype.pollSelection = function () {
10099 if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return }
10100 var sel = window.getSelection(), cm = this.cm;
10101 // On Android Chrome (version 56, at least), backspacing into an
10102 // uneditable block element will put the cursor in that element,
10103 // and then, because it's not editable, hide the virtual keyboard.
10104 // Because Android doesn't allow us to actually detect backspace
10105 // presses in a sane way, this code checks for when that happens
10106 // and simulates a backspace press in this case.
10107 if (android && chrome && this.cm.options.gutters.length && isInGutter(sel.anchorNode)) {
10108 this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs});
10109 this.blur();
10110 this.focus();
10111 return
10112 }
10113 if (this.composing) { return }
10114 this.rememberSelection();
10115 var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
10116 var head = domToPos(cm, sel.focusNode, sel.focusOffset);
10117 if (anchor && head) { runInOp(cm, function () {
10118 setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
10119 if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true; }
10120 }); }
10121 };
10122
10123 ContentEditableInput.prototype.pollContent = function () {
10124 if (this.readDOMTimeout != null) {
10125 clearTimeout(this.readDOMTimeout);
10126 this.readDOMTimeout = null;
10127 }
10128
10129 var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
10130 var from = sel.from(), to = sel.to();
10131 if (from.ch == 0 && from.line > cm.firstLine())
10132 { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); }
10133 if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())
10134 { to = Pos(to.line + 1, 0); }
10135 if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }
10136
10137 var fromIndex, fromLine, fromNode;
10138 if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
10139 fromLine = lineNo(display.view[0].line);
10140 fromNode = display.view[0].node;
10141 } else {
10142 fromLine = lineNo(display.view[fromIndex].line);
10143 fromNode = display.view[fromIndex - 1].node.nextSibling;
10144 }
10145 var toIndex = findViewIndex(cm, to.line);
10146 var toLine, toNode;
10147 if (toIndex == display.view.length - 1) {
10148 toLine = display.viewTo - 1;
10149 toNode = display.lineDiv.lastChild;
10150 } else {
10151 toLine = lineNo(display.view[toIndex + 1].line) - 1;
10152 toNode = display.view[toIndex + 1].node.previousSibling;
10153 }
10154
10155 if (!fromNode) { return false }
10156 var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
10157 var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
10158 while (newText.length > 1 && oldText.length > 1) {
10159 if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
10160 else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
10161 else { break }
10162 }
10163
10164 var cutFront = 0, cutEnd = 0;
10165 var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
10166 while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
10167 { ++cutFront; }
10168 var newBot = lst(newText), oldBot = lst(oldText);
10169 var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
10170 oldBot.length - (oldText.length == 1 ? cutFront : 0));
10171 while (cutEnd < maxCutEnd &&
10172 newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
10173 { ++cutEnd; }
10174 // Try to move start of change to start of selection if ambiguous
10175 if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) {
10176 while (cutFront && cutFront > from.ch &&
10177 newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) {
10178 cutFront--;
10179 cutEnd++;
10180 }
10181 }
10182
10183 newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "");
10184 newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "");
10185
10186 var chFrom = Pos(fromLine, cutFront);
10187 var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
10188 if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
10189 replaceRange(cm.doc, newText, chFrom, chTo, "+input");
10190 return true
10191 }
10192 };
10193
10194 ContentEditableInput.prototype.ensurePolled = function () {
10195 this.forceCompositionEnd();
10196 };
10197 ContentEditableInput.prototype.reset = function () {
10198 this.forceCompositionEnd();
10199 };
10200 ContentEditableInput.prototype.forceCompositionEnd = function () {
10201 if (!this.composing) { return }
10202 clearTimeout(this.readDOMTimeout);
10203 this.composing = null;
10204 this.updateFromDOM();
10205 this.div.blur();
10206 this.div.focus();
10207 };
10208 ContentEditableInput.prototype.readFromDOMSoon = function () {
10209 var this$1 = this;
10210
10211 if (this.readDOMTimeout != null) { return }
10212 this.readDOMTimeout = setTimeout(function () {
10213 this$1.readDOMTimeout = null;
10214 if (this$1.composing) {
10215 if (this$1.composing.done) { this$1.composing = null; }
10216 else { return }
10217 }
10218 this$1.updateFromDOM();
10219 }, 80);
10220 };
10221
10222 ContentEditableInput.prototype.updateFromDOM = function () {
10223 var this$1 = this;
10224
10225 if (this.cm.isReadOnly() || !this.pollContent())
10226 { runInOp(this.cm, function () { return regChange(this$1.cm); }); }
10227 };
10228
10229 ContentEditableInput.prototype.setUneditable = function (node) {
10230 node.contentEditable = "false";
10231 };
10232
10233 ContentEditableInput.prototype.onKeyPress = function (e) {
10234 if (e.charCode == 0) { return }
10235 e.preventDefault();
10236 if (!this.cm.isReadOnly())
10237 { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); }
10238 };
10239
10240 ContentEditableInput.prototype.readOnlyChanged = function (val) {
10241 this.div.contentEditable = String(val != "nocursor");
10242 };
10243
10244 ContentEditableInput.prototype.onContextMenu = function () {};
10245 ContentEditableInput.prototype.resetPosition = function () {};
10246
10247 ContentEditableInput.prototype.needsContentAttribute = true;
10248
10249 function posToDOM(cm, pos) {
10250 var view = findViewForLine(cm, pos.line);
10251 if (!view || view.hidden) { return null }
10252 var line = getLine(cm.doc, pos.line);
10253 var info = mapFromLineView(view, line, pos.line);
10254
10255 var order = getOrder(line, cm.doc.direction), side = "left";
10256 if (order) {
10257 var partPos = getBidiPartAt(order, pos.ch);
10258 side = partPos % 2 ? "right" : "left";
10259 }
10260 var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
10261 result.offset = result.collapse == "right" ? result.end : result.start;
10262 return result
10263 }
10264
10265 function isInGutter(node) {
10266 for (var scan = node; scan; scan = scan.parentNode)
10267 { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } }
10268 return false
10269 }
10270
10271 function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
10272
10273 function domTextBetween(cm, from, to, fromLine, toLine) {
10274 var text = "", closing = false, lineSep = cm.doc.lineSeparator();
10275 function recognizeMarker(id) { return function (marker) { return marker.id == id; } }
10276 function close() {
10277 if (closing) {
10278 text += lineSep;
10279 closing = false;
10280 }
10281 }
10282 function addText(str) {
10283 if (str) {
10284 close();
10285 text += str;
10286 }
10287 }
10288 function walk(node) {
10289 if (node.nodeType == 1) {
10290 var cmText = node.getAttribute("cm-text");
10291 if (cmText != null) {
10292 addText(cmText || node.textContent.replace(/\u200b/g, ""));
10293 return
10294 }
10295 var markerID = node.getAttribute("cm-marker"), range$$1;
10296 if (markerID) {
10297 var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
10298 if (found.length && (range$$1 = found[0].find(0)))
10299 { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); }
10300 return
10301 }
10302 if (node.getAttribute("contenteditable") == "false") { return }
10303 var isBlock = /^(pre|div|p)$/i.test(node.nodeName);
10304 if (isBlock) { close(); }
10305 for (var i = 0; i < node.childNodes.length; i++)
10306 { walk(node.childNodes[i]); }
10307 if (isBlock) { closing = true; }
10308 } else if (node.nodeType == 3) {
10309 addText(node.nodeValue);
10310 }
10311 }
10312 for (;;) {
10313 walk(from);
10314 if (from == to) { break }
10315 from = from.nextSibling;
10316 }
10317 return text
10318 }
10319
10320 function domToPos(cm, node, offset) {
10321 var lineNode;
10322 if (node == cm.display.lineDiv) {
10323 lineNode = cm.display.lineDiv.childNodes[offset];
10324 if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) }
10325 node = null; offset = 0;
10326 } else {
10327 for (lineNode = node;; lineNode = lineNode.parentNode) {
10328 if (!lineNode || lineNode == cm.display.lineDiv) { return null }
10329 if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break }
10330 }
10331 }
10332 for (var i = 0; i < cm.display.view.length; i++) {
10333 var lineView = cm.display.view[i];
10334 if (lineView.node == lineNode)
10335 { return locateNodeInLineView(lineView, node, offset) }
10336 }
10337 }
10338
10339 function locateNodeInLineView(lineView, node, offset) {
10340 var wrapper = lineView.text.firstChild, bad = false;
10341 if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) }
10342 if (node == wrapper) {
10343 bad = true;
10344 node = wrapper.childNodes[offset];
10345 offset = 0;
10346 if (!node) {
10347 var line = lineView.rest ? lst(lineView.rest) : lineView.line;
10348 return badPos(Pos(lineNo(line), line.text.length), bad)
10349 }
10350 }
10351
10352 var textNode = node.nodeType == 3 ? node : null, topNode = node;
10353 if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
10354 textNode = node.firstChild;
10355 if (offset) { offset = textNode.nodeValue.length; }
10356 }
10357 while (topNode.parentNode != wrapper) { topNode = topNode.parentNode; }
10358 var measure = lineView.measure, maps = measure.maps;
10359
10360 function find(textNode, topNode, offset) {
10361 for (var i = -1; i < (maps ? maps.length : 0); i++) {
10362 var map$$1 = i < 0 ? measure.map : maps[i];
10363 for (var j = 0; j < map$$1.length; j += 3) {
10364 var curNode = map$$1[j + 2];
10365 if (curNode == textNode || curNode == topNode) {
10366 var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
10367 var ch = map$$1[j] + offset;
10368 if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; }
10369 return Pos(line, ch)
10370 }
10371 }
10372 }
10373 }
10374 var found = find(textNode, topNode, offset);
10375 if (found) { return badPos(found, bad) }
10376
10377 // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
10378 for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
10379 found = find(after, after.firstChild, 0);
10380 if (found)
10381 { return badPos(Pos(found.line, found.ch - dist), bad) }
10382 else
10383 { dist += after.textContent.length; }
10384 }
10385 for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) {
10386 found = find(before, before.firstChild, -1);
10387 if (found)
10388 { return badPos(Pos(found.line, found.ch + dist$1), bad) }
10389 else
10390 { dist$1 += before.textContent.length; }
10391 }
10392 }
10393
10394 // TEXTAREA INPUT STYLE
10395
10396 var TextareaInput = function(cm) {
10397 this.cm = cm;
10398 // See input.poll and input.reset
10399 this.prevInput = "";
10400
10401 // Flag that indicates whether we expect input to appear real soon
10402 // now (after some event like 'keypress' or 'input') and are
10403 // polling intensively.
10404 this.pollingFast = false;
10405 // Self-resetting timeout for the poller
10406 this.polling = new Delayed();
10407 // Used to work around IE issue with selection being forgotten when focus moves away from textarea
10408 this.hasSelection = false;
10409 this.composing = null;
10410 };
10411
10412 TextareaInput.prototype.init = function (display) {
10413 var this$1 = this;
10414
10415 var input = this, cm = this.cm;
10416
10417 // Wraps and hides input textarea
10418 var div = this.wrapper = hiddenTextarea();
10419 // The semihidden textarea that is focused when the editor is
10420 // focused, and receives input.
10421 var te = this.textarea = div.firstChild;
10422 display.wrapper.insertBefore(div, display.wrapper.firstChild);
10423
10424 // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
10425 if (ios) { te.style.width = "0px"; }
10426
10427 on(te, "input", function () {
10428 if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null; }
10429 input.poll();
10430 });
10431
10432 on(te, "paste", function (e) {
10433 if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
10434
10435 cm.state.pasteIncoming = true;
10436 input.fastPoll();
10437 });
10438
10439 function prepareCopyCut(e) {
10440 if (signalDOMEvent(cm, e)) { return }
10441 if (cm.somethingSelected()) {
10442 setLastCopied({lineWise: false, text: cm.getSelections()});
10443 } else if (!cm.options.lineWiseCopyCut) {
10444 return
10445 } else {
10446 var ranges = copyableRanges(cm);
10447 setLastCopied({lineWise: true, text: ranges.text});
10448 if (e.type == "cut") {
10449 cm.setSelections(ranges.ranges, null, sel_dontScroll);
10450 } else {
10451 input.prevInput = "";
10452 te.value = ranges.text.join("\n");
10453 selectInput(te);
10454 }
10455 }
10456 if (e.type == "cut") { cm.state.cutIncoming = true; }
10457 }
10458 on(te, "cut", prepareCopyCut);
10459 on(te, "copy", prepareCopyCut);
10460
10461 on(display.scroller, "paste", function (e) {
10462 if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }
10463 cm.state.pasteIncoming = true;
10464 input.focus();
10465 });
10466
10467 // Prevent normal selection in the editor (we handle our own)
10468 on(display.lineSpace, "selectstart", function (e) {
10469 if (!eventInWidget(display, e)) { e_preventDefault(e); }
10470 });
10471
10472 on(te, "compositionstart", function () {
10473 var start = cm.getCursor("from");
10474 if (input.composing) { input.composing.range.clear(); }
10475 input.composing = {
10476 start: start,
10477 range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
10478 };
10479 });
10480 on(te, "compositionend", function () {
10481 if (input.composing) {
10482 input.poll();
10483 input.composing.range.clear();
10484 input.composing = null;
10485 }
10486 });
10487 };
10488
10489 TextareaInput.prototype.prepareSelection = function () {
10490 // Redraw the selection and/or cursor
10491 var cm = this.cm, display = cm.display, doc = cm.doc;
10492 var result = prepareSelection(cm);
10493
10494 // Move the hidden textarea near the cursor to prevent scrolling artifacts
10495 if (cm.options.moveInputWithCursor) {
10496 var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
10497 var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
10498 result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
10499 headPos.top + lineOff.top - wrapOff.top));
10500 result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
10501 headPos.left + lineOff.left - wrapOff.left));
10502 }
10503
10504 return result
10505 };
10506
10507 TextareaInput.prototype.showSelection = function (drawn) {
10508 var cm = this.cm, display = cm.display;
10509 removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
10510 removeChildrenAndAdd(display.selectionDiv, drawn.selection);
10511 if (drawn.teTop != null) {
10512 this.wrapper.style.top = drawn.teTop + "px";
10513 this.wrapper.style.left = drawn.teLeft + "px";
10514 }
10515 };
10516
10517 // Reset the input to correspond to the selection (or to be empty,
10518 // when not typing and nothing is selected)
10519 TextareaInput.prototype.reset = function (typing) {
10520 if (this.contextMenuPending || this.composing) { return }
10521 var cm = this.cm;
10522 if (cm.somethingSelected()) {
10523 this.prevInput = "";
10524 var content = cm.getSelection();
10525 this.textarea.value = content;
10526 if (cm.state.focused) { selectInput(this.textarea); }
10527 if (ie && ie_version >= 9) { this.hasSelection = content; }
10528 } else if (!typing) {
10529 this.prevInput = this.textarea.value = "";
10530 if (ie && ie_version >= 9) { this.hasSelection = null; }
10531 }
10532 };
10533
10534 TextareaInput.prototype.getField = function () { return this.textarea };
10535
10536 TextareaInput.prototype.supportsTouch = function () { return false };
10537
10538 TextareaInput.prototype.focus = function () {
10539 if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
10540 try { this.textarea.focus(); }
10541 catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
10542 }
10543 };
10544
10545 TextareaInput.prototype.blur = function () { this.textarea.blur(); };
10546
10547 TextareaInput.prototype.resetPosition = function () {
10548 this.wrapper.style.top = this.wrapper.style.left = 0;
10549 };
10550
10551 TextareaInput.prototype.receivedFocus = function () { this.slowPoll(); };
10552
10553 // Poll for input changes, using the normal rate of polling. This
10554 // runs as long as the editor is focused.
10555 TextareaInput.prototype.slowPoll = function () {
10556 var this$1 = this;
10557
10558 if (this.pollingFast) { return }
10559 this.polling.set(this.cm.options.pollInterval, function () {
10560 this$1.poll();
10561 if (this$1.cm.state.focused) { this$1.slowPoll(); }
10562 });
10563 };
10564
10565 // When an event has just come in that is likely to add or change
10566 // something in the input textarea, we poll faster, to ensure that
10567 // the change appears on the screen quickly.
10568 TextareaInput.prototype.fastPoll = function () {
10569 var missed = false, input = this;
10570 input.pollingFast = true;
10571 function p() {
10572 var changed = input.poll();
10573 if (!changed && !missed) {missed = true; input.polling.set(60, p);}
10574 else {input.pollingFast = false; input.slowPoll();}
10575 }
10576 input.polling.set(20, p);
10577 };
10578
10579 // Read input from the textarea, and update the document to match.
10580 // When something is selected, it is present in the textarea, and
10581 // selected (unless it is huge, in which case a placeholder is
10582 // used). When nothing is selected, the cursor sits after previously
10583 // seen text (can be empty), which is stored in prevInput (we must
10584 // not reset the textarea when typing, because that breaks IME).
10585 TextareaInput.prototype.poll = function () {
10586 var this$1 = this;
10587
10588 var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
10589 // Since this is called a *lot*, try to bail out as cheaply as
10590 // possible when it is clear that nothing happened. hasSelection
10591 // will be the case when there is a lot of text in the textarea,
10592 // in which case reading its value would be expensive.
10593 if (this.contextMenuPending || !cm.state.focused ||
10594 (hasSelection(input) && !prevInput && !this.composing) ||
10595 cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
10596 { return false }
10597
10598 var text = input.value;
10599 // If nothing changed, bail.
10600 if (text == prevInput && !cm.somethingSelected()) { return false }
10601 // Work around nonsensical selection resetting in IE9/10, and
10602 // inexplicable appearance of private area unicode characters on
10603 // some key combos in Mac (#2689).
10604 if (ie && ie_version >= 9 && this.hasSelection === text ||
10605 mac && /[\uf700-\uf7ff]/.test(text)) {
10606 cm.display.input.reset();
10607 return false
10608 }
10609
10610 if (cm.doc.sel == cm.display.selForContextMenu) {
10611 var first = text.charCodeAt(0);
10612 if (first == 0x200b && !prevInput) { prevInput = "\u200b"; }
10613 if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") }
10614 }
10615 // Find the part of the input that is actually new
10616 var same = 0, l = Math.min(prevInput.length, text.length);
10617 while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; }
10618
10619 runInOp(cm, function () {
10620 applyTextInput(cm, text.slice(same), prevInput.length - same,
10621 null, this$1.composing ? "*compose" : null);
10622
10623 // Don't leave long text in the textarea, since it makes further polling slow
10624 if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = ""; }
10625 else { this$1.prevInput = text; }
10626
10627 if (this$1.composing) {
10628 this$1.composing.range.clear();
10629 this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"),
10630 {className: "CodeMirror-composing"});
10631 }
10632 });
10633 return true
10634 };
10635
10636 TextareaInput.prototype.ensurePolled = function () {
10637 if (this.pollingFast && this.poll()) { this.pollingFast = false; }
10638 };
10639
10640 TextareaInput.prototype.onKeyPress = function () {
10641 if (ie && ie_version >= 9) { this.hasSelection = null; }
10642 this.fastPoll();
10643 };
10644
10645 TextareaInput.prototype.onContextMenu = function (e) {
10646 var input = this, cm = input.cm, display = cm.display, te = input.textarea;
10647 var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
10648 if (!pos || presto) { return } // Opera is difficult.
10649
10650 // Reset the current text selection only if the click is done outside of the selection
10651 // and 'resetSelectionOnContextMenu' option is true.
10652 var reset = cm.options.resetSelectionOnContextMenu;
10653 if (reset && cm.doc.sel.contains(pos) == -1)
10654 { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); }
10655
10656 var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;
10657 input.wrapper.style.cssText = "position: absolute";
10658 var wrapperBox = input.wrapper.getBoundingClientRect();
10659 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);";
10660 var oldScrollY;
10661 if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712)
10662 display.input.focus();
10663 if (webkit) { window.scrollTo(null, oldScrollY); }
10664 display.input.reset();
10665 // Adds "Select all" to context menu in FF
10666 if (!cm.somethingSelected()) { te.value = input.prevInput = " "; }
10667 input.contextMenuPending = true;
10668 display.selForContextMenu = cm.doc.sel;
10669 clearTimeout(display.detectingSelectAll);
10670
10671 // Select-all will be greyed out if there's nothing to select, so
10672 // this adds a zero-width space so that we can later check whether
10673 // it got selected.
10674 function prepareSelectAllHack() {
10675 if (te.selectionStart != null) {
10676 var selected = cm.somethingSelected();
10677 var extval = "\u200b" + (selected ? te.value : "");
10678 te.value = "\u21da"; // Used to catch context-menu undo
10679 te.value = extval;
10680 input.prevInput = selected ? "" : "\u200b";
10681 te.selectionStart = 1; te.selectionEnd = extval.length;
10682 // Re-set this, in case some other handler touched the
10683 // selection in the meantime.
10684 display.selForContextMenu = cm.doc.sel;
10685 }
10686 }
10687 function rehide() {
10688 input.contextMenuPending = false;
10689 input.wrapper.style.cssText = oldWrapperCSS;
10690 te.style.cssText = oldCSS;
10691 if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); }
10692
10693 // Try to detect the user choosing select-all
10694 if (te.selectionStart != null) {
10695 if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack(); }
10696 var i = 0, poll = function () {
10697 if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
10698 te.selectionEnd > 0 && input.prevInput == "\u200b") {
10699 operation(cm, selectAll)(cm);
10700 } else if (i++ < 10) {
10701 display.detectingSelectAll = setTimeout(poll, 500);
10702 } else {
10703 display.selForContextMenu = null;
10704 display.input.reset();
10705 }
10706 };
10707 display.detectingSelectAll = setTimeout(poll, 200);
10708 }
10709 }
10710
10711 if (ie && ie_version >= 9) { prepareSelectAllHack(); }
10712 if (captureRightClick) {
10713 e_stop(e);
10714 var mouseup = function () {
10715 off(window, "mouseup", mouseup);
10716 setTimeout(rehide, 20);
10717 };
10718 on(window, "mouseup", mouseup);
10719 } else {
10720 setTimeout(rehide, 50);
10721 }
10722 };
10723
10724 TextareaInput.prototype.readOnlyChanged = function (val) {
10725 if (!val) { this.reset(); }
10726 this.textarea.disabled = val == "nocursor";
10727 };
10728
10729 TextareaInput.prototype.setUneditable = function () {};
10730
10731 TextareaInput.prototype.needsContentAttribute = false;
10732
10733 function fromTextArea(textarea, options) {
10734 options = options ? copyObj(options) : {};
10735 options.value = textarea.value;
10736 if (!options.tabindex && textarea.tabIndex)
10737 { options.tabindex = textarea.tabIndex; }
10738 if (!options.placeholder && textarea.placeholder)
10739 { options.placeholder = textarea.placeholder; }
10740 // Set autofocus to true if this textarea is focused, or if it has
10741 // autofocus and no other element is focused.
10742 if (options.autofocus == null) {
10743 var hasFocus = activeElt();
10744 options.autofocus = hasFocus == textarea ||
10745 textarea.getAttribute("autofocus") != null && hasFocus == document.body;
10746 }
10747
10748 function save() {textarea.value = cm.getValue();}
10749
10750 var realSubmit;
10751 if (textarea.form) {
10752 on(textarea.form, "submit", save);
10753 // Deplorable hack to make the submit method do the right thing.
10754 if (!options.leaveSubmitMethodAlone) {
10755 var form = textarea.form;
10756 realSubmit = form.submit;
10757 try {
10758 var wrappedSubmit = form.submit = function () {
10759 save();
10760 form.submit = realSubmit;
10761 form.submit();
10762 form.submit = wrappedSubmit;
10763 };
10764 } catch(e) {}
10765 }
10766 }
10767
10768 options.finishInit = function (cm) {
10769 cm.save = save;
10770 cm.getTextArea = function () { return textarea; };
10771 cm.toTextArea = function () {
10772 cm.toTextArea = isNaN; // Prevent this from being ran twice
10773 save();
10774 textarea.parentNode.removeChild(cm.getWrapperElement());
10775 textarea.style.display = "";
10776 if (textarea.form) {
10777 off(textarea.form, "submit", save);
10778 if (typeof textarea.form.submit == "function")
10779 { textarea.form.submit = realSubmit; }
10780 }
10781 };
10782 };
10783
10784 textarea.style.display = "none";
10785 var cm = CodeMirror$1(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); },
10786 options);
10787 return cm
10788 }
10789
10790 function addLegacyProps(CodeMirror) {
10791 CodeMirror.off = off;
10792 CodeMirror.on = on;
10793 CodeMirror.wheelEventPixels = wheelEventPixels;
10794 CodeMirror.Doc = Doc;
10795 CodeMirror.splitLines = splitLinesAuto;
10796 CodeMirror.countColumn = countColumn;
10797 CodeMirror.findColumn = findColumn;
10798 CodeMirror.isWordChar = isWordCharBasic;
10799 CodeMirror.Pass = Pass;
10800 CodeMirror.signal = signal;
10801 CodeMirror.Line = Line;
10802 CodeMirror.changeEnd = changeEnd;
10803 CodeMirror.scrollbarModel = scrollbarModel;
10804 CodeMirror.Pos = Pos;
10805 CodeMirror.cmpPos = cmp;
10806 CodeMirror.modes = modes;
10807 CodeMirror.mimeModes = mimeModes;
10808 CodeMirror.resolveMode = resolveMode;
10809 CodeMirror.getMode = getMode;
10810 CodeMirror.modeExtensions = modeExtensions;
10811 CodeMirror.extendMode = extendMode;
10812 CodeMirror.copyState = copyState;
10813 CodeMirror.startState = startState;
10814 CodeMirror.innerMode = innerMode;
10815 CodeMirror.commands = commands;
10816 CodeMirror.keyMap = keyMap;
10817 CodeMirror.keyName = keyName;
10818 CodeMirror.isModifierKey = isModifierKey;
10819 CodeMirror.lookupKey = lookupKey;
10820 CodeMirror.normalizeKeyMap = normalizeKeyMap;
10821 CodeMirror.StringStream = StringStream;
10822 CodeMirror.SharedTextMarker = SharedTextMarker;
10823 CodeMirror.TextMarker = TextMarker;
10824 CodeMirror.LineWidget = LineWidget;
10825 CodeMirror.e_preventDefault = e_preventDefault;
10826 CodeMirror.e_stopPropagation = e_stopPropagation;
10827 CodeMirror.e_stop = e_stop;
10828 CodeMirror.addClass = addClass;
10829 CodeMirror.contains = contains;
10830 CodeMirror.rmClass = rmClass;
10831 CodeMirror.keyNames = keyNames;
10832 }
10833
10834 // EDITOR CONSTRUCTOR
10835
10836 defineOptions(CodeMirror$1);
10837
10838 addEditorMethods(CodeMirror$1);
10839
10840 // Set up methods on CodeMirror's prototype to redirect to the editor's document.
10841 var dontDelegate = "iter insert remove copy getEditor constructor".split(" ");
10842 for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
10843 { CodeMirror$1.prototype[prop] = (function(method) {
10844 return function() {return method.apply(this.doc, arguments)}
10845 })(Doc.prototype[prop]); } }
10846
10847 eventMixin(Doc);
10848
10849 // INPUT HANDLING
10850
10851 CodeMirror$1.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
10852
10853 // MODE DEFINITION AND QUERYING
10854
10855 // Extra arguments are stored as the mode's dependencies, which is
10856 // used by (legacy) mechanisms like loadmode.js to automatically
10857 // load a mode. (Preferred mechanism is the require/define calls.)
10858 CodeMirror$1.defineMode = function(name/*, mode, …*/) {
10859 if (!CodeMirror$1.defaults.mode && name != "null") { CodeMirror$1.defaults.mode = name; }
10860 defineMode.apply(this, arguments);
10861 };
10862
10863 CodeMirror$1.defineMIME = defineMIME;
10864
10865 // Minimal default mode.
10866 CodeMirror$1.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });
10867 CodeMirror$1.defineMIME("text/plain", "null");
10868
10869 // EXTENSIONS
10870
10871 CodeMirror$1.defineExtension = function (name, func) {
10872 CodeMirror$1.prototype[name] = func;
10873 };
10874 CodeMirror$1.defineDocExtension = function (name, func) {
10875 Doc.prototype[name] = func;
10876 };
10877
10878 CodeMirror$1.fromTextArea = fromTextArea;
10879
10880 addLegacyProps(CodeMirror$1);
10881
10882 CodeMirror$1.version = "5.29.0";
10883
10884 return CodeMirror$1;
10885
10886 })));
10887
10888 },{}],13:[function(require,module,exports){
10889 // CodeMirror, copyright (c) by Marijn Haverbeke and others
10890 // Distributed under an MIT license: http://codemirror.net/LICENSE
10891
10892 (function(mod) {
10893 if (typeof exports == "object" && typeof module == "object") // CommonJS
10894 mod(require("../../lib/codemirror"));
10895 else if (typeof define == "function" && define.amd) // AMD
10896 define(["../../lib/codemirror"], mod);
10897 else // Plain browser env
10898 mod(CodeMirror);
10899 })(function(CodeMirror) {
10900 "use strict";
10901
10902 CodeMirror.defineMode("css", function(config, parserConfig) {
10903 var inline = parserConfig.inline
10904 if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
10905
10906 var indentUnit = config.indentUnit,
10907 tokenHooks = parserConfig.tokenHooks,
10908 documentTypes = parserConfig.documentTypes || {},
10909 mediaTypes = parserConfig.mediaTypes || {},
10910 mediaFeatures = parserConfig.mediaFeatures || {},
10911 mediaValueKeywords = parserConfig.mediaValueKeywords || {},
10912 propertyKeywords = parserConfig.propertyKeywords || {},
10913 nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
10914 fontProperties = parserConfig.fontProperties || {},
10915 counterDescriptors = parserConfig.counterDescriptors || {},
10916 colorKeywords = parserConfig.colorKeywords || {},
10917 valueKeywords = parserConfig.valueKeywords || {},
10918 allowNested = parserConfig.allowNested,
10919 lineComment = parserConfig.lineComment,
10920 supportsAtComponent = parserConfig.supportsAtComponent === true;
10921
10922 var type, override;
10923 function ret(style, tp) { type = tp; return style; }
10924
10925 // Tokenizers
10926
10927 function tokenBase(stream, state) {
10928 var ch = stream.next();
10929 if (tokenHooks[ch]) {
10930 var result = tokenHooks[ch](stream, state);
10931 if (result !== false) return result;
10932 }
10933 if (ch == "@") {
10934 stream.eatWhile(/[\w\\\-]/);
10935 return ret("def", stream.current());
10936 } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
10937 return ret(null, "compare");
10938 } else if (ch == "\"" || ch == "'") {
10939 state.tokenize = tokenString(ch);
10940 return state.tokenize(stream, state);
10941 } else if (ch == "#") {
10942 stream.eatWhile(/[\w\\\-]/);
10943 return ret("atom", "hash");
10944 } else if (ch == "!") {
10945 stream.match(/^\s*\w*/);
10946 return ret("keyword", "important");
10947 } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
10948 stream.eatWhile(/[\w.%]/);
10949 return ret("number", "unit");
10950 } else if (ch === "-") {
10951 if (/[\d.]/.test(stream.peek())) {
10952 stream.eatWhile(/[\w.%]/);
10953 return ret("number", "unit");
10954 } else if (stream.match(/^-[\w\\\-]+/)) {
10955 stream.eatWhile(/[\w\\\-]/);
10956 if (stream.match(/^\s*:/, false))
10957 return ret("variable-2", "variable-definition");
10958 return ret("variable-2", "variable");
10959 } else if (stream.match(/^\w+-/)) {
10960 return ret("meta", "meta");
10961 }
10962 } else if (/[,+>*\/]/.test(ch)) {
10963 return ret(null, "select-op");
10964 } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
10965 return ret("qualifier", "qualifier");
10966 } else if (/[:;{}\[\]\(\)]/.test(ch)) {
10967 return ret(null, ch);
10968 } else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) ||
10969 (ch == "d" && stream.match("omain(")) ||
10970 (ch == "r" && stream.match("egexp("))) {
10971 stream.backUp(1);
10972 state.tokenize = tokenParenthesized;
10973 return ret("property", "word");
10974 } else if (/[\w\\\-]/.test(ch)) {
10975 stream.eatWhile(/[\w\\\-]/);
10976 return ret("property", "word");
10977 } else {
10978 return ret(null, null);
10979 }
10980 }
10981
10982 function tokenString(quote) {
10983 return function(stream, state) {
10984 var escaped = false, ch;
10985 while ((ch = stream.next()) != null) {
10986 if (ch == quote && !escaped) {
10987 if (quote == ")") stream.backUp(1);
10988 break;
10989 }
10990 escaped = !escaped && ch == "\\";
10991 }
10992 if (ch == quote || !escaped && quote != ")") state.tokenize = null;
10993 return ret("string", "string");
10994 };
10995 }
10996
10997 function tokenParenthesized(stream, state) {
10998 stream.next(); // Must be '('
10999 if (!stream.match(/\s*[\"\')]/, false))
11000 state.tokenize = tokenString(")");
11001 else
11002 state.tokenize = null;
11003 return ret(null, "(");
11004 }
11005
11006 // Context management
11007
11008 function Context(type, indent, prev) {
11009 this.type = type;
11010 this.indent = indent;
11011 this.prev = prev;
11012 }
11013
11014 function pushContext(state, stream, type, indent) {
11015 state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context);
11016 return type;
11017 }
11018
11019 function popContext(state) {
11020 if (state.context.prev)
11021 state.context = state.context.prev;
11022 return state.context.type;
11023 }
11024
11025 function pass(type, stream, state) {
11026 return states[state.context.type](type, stream, state);
11027 }
11028 function popAndPass(type, stream, state, n) {
11029 for (var i = n || 1; i > 0; i--)
11030 state.context = state.context.prev;
11031 return pass(type, stream, state);
11032 }
11033
11034 // Parser
11035
11036 function wordAsValue(stream) {
11037 var word = stream.current().toLowerCase();
11038 if (valueKeywords.hasOwnProperty(word))
11039 override = "atom";
11040 else if (colorKeywords.hasOwnProperty(word))
11041 override = "keyword";
11042 else
11043 override = "variable";
11044 }
11045
11046 var states = {};
11047
11048 states.top = function(type, stream, state) {
11049 if (type == "{") {
11050 return pushContext(state, stream, "block");
11051 } else if (type == "}" && state.context.prev) {
11052 return popContext(state);
11053 } else if (supportsAtComponent && /@component/.test(type)) {
11054 return pushContext(state, stream, "atComponentBlock");
11055 } else if (/^@(-moz-)?document$/.test(type)) {
11056 return pushContext(state, stream, "documentTypes");
11057 } else if (/^@(media|supports|(-moz-)?document|import)$/.test(type)) {
11058 return pushContext(state, stream, "atBlock");
11059 } else if (/^@(font-face|counter-style)/.test(type)) {
11060 state.stateArg = type;
11061 return "restricted_atBlock_before";
11062 } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
11063 return "keyframes";
11064 } else if (type && type.charAt(0) == "@") {
11065 return pushContext(state, stream, "at");
11066 } else if (type == "hash") {
11067 override = "builtin";
11068 } else if (type == "word") {
11069 override = "tag";
11070 } else if (type == "variable-definition") {
11071 return "maybeprop";
11072 } else if (type == "interpolation") {
11073 return pushContext(state, stream, "interpolation");
11074 } else if (type == ":") {
11075 return "pseudo";
11076 } else if (allowNested && type == "(") {
11077 return pushContext(state, stream, "parens");
11078 }
11079 return state.context.type;
11080 };
11081
11082 states.block = function(type, stream, state) {
11083 if (type == "word") {
11084 var word = stream.current().toLowerCase();
11085 if (propertyKeywords.hasOwnProperty(word)) {
11086 override = "property";
11087 return "maybeprop";
11088 } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
11089 override = "string-2";
11090 return "maybeprop";
11091 } else if (allowNested) {
11092 override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag";
11093 return "block";
11094 } else {
11095 override += " error";
11096 return "maybeprop";
11097 }
11098 } else if (type == "meta") {
11099 return "block";
11100 } else if (!allowNested && (type == "hash" || type == "qualifier")) {
11101 override = "error";
11102 return "block";
11103 } else {
11104 return states.top(type, stream, state);
11105 }
11106 };
11107
11108 states.maybeprop = function(type, stream, state) {
11109 if (type == ":") return pushContext(state, stream, "prop");
11110 return pass(type, stream, state);
11111 };
11112
11113 states.prop = function(type, stream, state) {
11114 if (type == ";") return popContext(state);
11115 if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
11116 if (type == "}" || type == "{") return popAndPass(type, stream, state);
11117 if (type == "(") return pushContext(state, stream, "parens");
11118
11119 if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) {
11120 override += " error";
11121 } else if (type == "word") {
11122 wordAsValue(stream);
11123 } else if (type == "interpolation") {
11124 return pushContext(state, stream, "interpolation");
11125 }
11126 return "prop";
11127 };
11128
11129 states.propBlock = function(type, _stream, state) {
11130 if (type == "}") return popContext(state);
11131 if (type == "word") { override = "property"; return "maybeprop"; }
11132 return state.context.type;
11133 };
11134
11135 states.parens = function(type, stream, state) {
11136 if (type == "{" || type == "}") return popAndPass(type, stream, state);
11137 if (type == ")") return popContext(state);
11138 if (type == "(") return pushContext(state, stream, "parens");
11139 if (type == "interpolation") return pushContext(state, stream, "interpolation");
11140 if (type == "word") wordAsValue(stream);
11141 return "parens";
11142 };
11143
11144 states.pseudo = function(type, stream, state) {
11145 if (type == "meta") return "pseudo";
11146
11147 if (type == "word") {
11148 override = "variable-3";
11149 return state.context.type;
11150 }
11151 return pass(type, stream, state);
11152 };
11153
11154 states.documentTypes = function(type, stream, state) {
11155 if (type == "word" && documentTypes.hasOwnProperty(stream.current())) {
11156 override = "tag";
11157 return state.context.type;
11158 } else {
11159 return states.atBlock(type, stream, state);
11160 }
11161 };
11162
11163 states.atBlock = function(type, stream, state) {
11164 if (type == "(") return pushContext(state, stream, "atBlock_parens");
11165 if (type == "}" || type == ";") return popAndPass(type, stream, state);
11166 if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
11167
11168 if (type == "interpolation") return pushContext(state, stream, "interpolation");
11169
11170 if (type == "word") {
11171 var word = stream.current().toLowerCase();
11172 if (word == "only" || word == "not" || word == "and" || word == "or")
11173 override = "keyword";
11174 else if (mediaTypes.hasOwnProperty(word))
11175 override = "attribute";
11176 else if (mediaFeatures.hasOwnProperty(word))
11177 override = "property";
11178 else if (mediaValueKeywords.hasOwnProperty(word))
11179 override = "keyword";
11180 else if (propertyKeywords.hasOwnProperty(word))
11181 override = "property";
11182 else if (nonStandardPropertyKeywords.hasOwnProperty(word))
11183 override = "string-2";
11184 else if (valueKeywords.hasOwnProperty(word))
11185 override = "atom";
11186 else if (colorKeywords.hasOwnProperty(word))
11187 override = "keyword";
11188 else
11189 override = "error";
11190 }
11191 return state.context.type;
11192 };
11193
11194 states.atComponentBlock = function(type, stream, state) {
11195 if (type == "}")
11196 return popAndPass(type, stream, state);
11197 if (type == "{")
11198 return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false);
11199 if (type == "word")
11200 override = "error";
11201 return state.context.type;
11202 };
11203
11204 states.atBlock_parens = function(type, stream, state) {
11205 if (type == ")") return popContext(state);
11206 if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
11207 return states.atBlock(type, stream, state);
11208 };
11209
11210 states.restricted_atBlock_before = function(type, stream, state) {
11211 if (type == "{")
11212 return pushContext(state, stream, "restricted_atBlock");
11213 if (type == "word" && state.stateArg == "@counter-style") {
11214 override = "variable";
11215 return "restricted_atBlock_before";
11216 }
11217 return pass(type, stream, state);
11218 };
11219
11220 states.restricted_atBlock = function(type, stream, state) {
11221 if (type == "}") {
11222 state.stateArg = null;
11223 return popContext(state);
11224 }
11225 if (type == "word") {
11226 if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) ||
11227 (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase())))
11228 override = "error";
11229 else
11230 override = "property";
11231 return "maybeprop";
11232 }
11233 return "restricted_atBlock";
11234 };
11235
11236 states.keyframes = function(type, stream, state) {
11237 if (type == "word") { override = "variable"; return "keyframes"; }
11238 if (type == "{") return pushContext(state, stream, "top");
11239 return pass(type, stream, state);
11240 };
11241
11242 states.at = function(type, stream, state) {
11243 if (type == ";") return popContext(state);
11244 if (type == "{" || type == "}") return popAndPass(type, stream, state);
11245 if (type == "word") override = "tag";
11246 else if (type == "hash") override = "builtin";
11247 return "at";
11248 };
11249
11250 states.interpolation = function(type, stream, state) {
11251 if (type == "}") return popContext(state);
11252 if (type == "{" || type == ";") return popAndPass(type, stream, state);
11253 if (type == "word") override = "variable";
11254 else if (type != "variable" && type != "(" && type != ")") override = "error";
11255 return "interpolation";
11256 };
11257
11258 return {
11259 startState: function(base) {
11260 return {tokenize: null,
11261 state: inline ? "block" : "top",
11262 stateArg: null,
11263 context: new Context(inline ? "block" : "top", base || 0, null)};
11264 },
11265
11266 token: function(stream, state) {
11267 if (!state.tokenize && stream.eatSpace()) return null;
11268 var style = (state.tokenize || tokenBase)(stream, state);
11269 if (style && typeof style == "object") {
11270 type = style[1];
11271 style = style[0];
11272 }
11273 override = style;
11274 if (type != "comment")
11275 state.state = states[state.state](type, stream, state);
11276 return override;
11277 },
11278
11279 indent: function(state, textAfter) {
11280 var cx = state.context, ch = textAfter && textAfter.charAt(0);
11281 var indent = cx.indent;
11282 if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev;
11283 if (cx.prev) {
11284 if (ch == "}" && (cx.type == "block" || cx.type == "top" ||
11285 cx.type == "interpolation" || cx.type == "restricted_atBlock")) {
11286 // Resume indentation from parent context.
11287 cx = cx.prev;
11288 indent = cx.indent;
11289 } else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") ||
11290 ch == "{" && (cx.type == "at" || cx.type == "atBlock")) {
11291 // Dedent relative to current context.
11292 indent = Math.max(0, cx.indent - indentUnit);
11293 }
11294 }
11295 return indent;
11296 },
11297
11298 electricChars: "}",
11299 blockCommentStart: "/*",
11300 blockCommentEnd: "*/",
11301 lineComment: lineComment,
11302 fold: "brace"
11303 };
11304 });
11305
11306 function keySet(array) {
11307 var keys = {};
11308 for (var i = 0; i < array.length; ++i) {
11309 keys[array[i].toLowerCase()] = true;
11310 }
11311 return keys;
11312 }
11313
11314 var documentTypes_ = [
11315 "domain", "regexp", "url", "url-prefix"
11316 ], documentTypes = keySet(documentTypes_);
11317
11318 var mediaTypes_ = [
11319 "all", "aural", "braille", "handheld", "print", "projection", "screen",
11320 "tty", "tv", "embossed"
11321 ], mediaTypes = keySet(mediaTypes_);
11322
11323 var mediaFeatures_ = [
11324 "width", "min-width", "max-width", "height", "min-height", "max-height",
11325 "device-width", "min-device-width", "max-device-width", "device-height",
11326 "min-device-height", "max-device-height", "aspect-ratio",
11327 "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
11328 "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
11329 "max-color", "color-index", "min-color-index", "max-color-index",
11330 "monochrome", "min-monochrome", "max-monochrome", "resolution",
11331 "min-resolution", "max-resolution", "scan", "grid", "orientation",
11332 "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio",
11333 "pointer", "any-pointer", "hover", "any-hover"
11334 ], mediaFeatures = keySet(mediaFeatures_);
11335
11336 var mediaValueKeywords_ = [
11337 "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover",
11338 "interlace", "progressive"
11339 ], mediaValueKeywords = keySet(mediaValueKeywords_);
11340
11341 var propertyKeywords_ = [
11342 "align-content", "align-items", "align-self", "alignment-adjust",
11343 "alignment-baseline", "anchor-point", "animation", "animation-delay",
11344 "animation-direction", "animation-duration", "animation-fill-mode",
11345 "animation-iteration-count", "animation-name", "animation-play-state",
11346 "animation-timing-function", "appearance", "azimuth", "backface-visibility",
11347 "background", "background-attachment", "background-blend-mode", "background-clip",
11348 "background-color", "background-image", "background-origin", "background-position",
11349 "background-repeat", "background-size", "baseline-shift", "binding",
11350 "bleed", "bookmark-label", "bookmark-level", "bookmark-state",
11351 "bookmark-target", "border", "border-bottom", "border-bottom-color",
11352 "border-bottom-left-radius", "border-bottom-right-radius",
11353 "border-bottom-style", "border-bottom-width", "border-collapse",
11354 "border-color", "border-image", "border-image-outset",
11355 "border-image-repeat", "border-image-slice", "border-image-source",
11356 "border-image-width", "border-left", "border-left-color",
11357 "border-left-style", "border-left-width", "border-radius", "border-right",
11358 "border-right-color", "border-right-style", "border-right-width",
11359 "border-spacing", "border-style", "border-top", "border-top-color",
11360 "border-top-left-radius", "border-top-right-radius", "border-top-style",
11361 "border-top-width", "border-width", "bottom", "box-decoration-break",
11362 "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
11363 "caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count",
11364 "column-fill", "column-gap", "column-rule", "column-rule-color",
11365 "column-rule-style", "column-rule-width", "column-span", "column-width",
11366 "columns", "content", "counter-increment", "counter-reset", "crop", "cue",
11367 "cue-after", "cue-before", "cursor", "direction", "display",
11368 "dominant-baseline", "drop-initial-after-adjust",
11369 "drop-initial-after-align", "drop-initial-before-adjust",
11370 "drop-initial-before-align", "drop-initial-size", "drop-initial-value",
11371 "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
11372 "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
11373 "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
11374 "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
11375 "font-stretch", "font-style", "font-synthesis", "font-variant",
11376 "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
11377 "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
11378 "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
11379 "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
11380 "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap",
11381 "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns",
11382 "grid-template-rows", "hanging-punctuation", "height", "hyphens",
11383 "icon", "image-orientation", "image-rendering", "image-resolution",
11384 "inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing",
11385 "line-break", "line-height", "line-stacking", "line-stacking-ruby",
11386 "line-stacking-shift", "line-stacking-strategy", "list-style",
11387 "list-style-image", "list-style-position", "list-style-type", "margin",
11388 "margin-bottom", "margin-left", "margin-right", "margin-top",
11389 "marks", "marquee-direction", "marquee-loop",
11390 "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
11391 "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
11392 "nav-left", "nav-right", "nav-up", "object-fit", "object-position",
11393 "opacity", "order", "orphans", "outline",
11394 "outline-color", "outline-offset", "outline-style", "outline-width",
11395 "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
11396 "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
11397 "page", "page-break-after", "page-break-before", "page-break-inside",
11398 "page-policy", "pause", "pause-after", "pause-before", "perspective",
11399 "perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position",
11400 "presentation-level", "punctuation-trim", "quotes", "region-break-after",
11401 "region-break-before", "region-break-inside", "region-fragment",
11402 "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
11403 "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
11404 "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
11405 "shape-outside", "size", "speak", "speak-as", "speak-header",
11406 "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
11407 "tab-size", "table-layout", "target", "target-name", "target-new",
11408 "target-position", "text-align", "text-align-last", "text-decoration",
11409 "text-decoration-color", "text-decoration-line", "text-decoration-skip",
11410 "text-decoration-style", "text-emphasis", "text-emphasis-color",
11411 "text-emphasis-position", "text-emphasis-style", "text-height",
11412 "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
11413 "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
11414 "text-wrap", "top", "transform", "transform-origin", "transform-style",
11415 "transition", "transition-delay", "transition-duration",
11416 "transition-property", "transition-timing-function", "unicode-bidi",
11417 "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration",
11418 "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
11419 "voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break",
11420 "word-spacing", "word-wrap", "z-index",
11421 // SVG-specific
11422 "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
11423 "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
11424 "color-interpolation", "color-interpolation-filters",
11425 "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
11426 "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
11427 "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
11428 "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
11429 "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
11430 "glyph-orientation-vertical", "text-anchor", "writing-mode"
11431 ], propertyKeywords = keySet(propertyKeywords_);
11432
11433 var nonStandardPropertyKeywords_ = [
11434 "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
11435 "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
11436 "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
11437 "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
11438 "searchfield-results-decoration", "zoom"
11439 ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
11440
11441 var fontProperties_ = [
11442 "font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
11443 "font-stretch", "font-weight", "font-style"
11444 ], fontProperties = keySet(fontProperties_);
11445
11446 var counterDescriptors_ = [
11447 "additive-symbols", "fallback", "negative", "pad", "prefix", "range",
11448 "speak-as", "suffix", "symbols", "system"
11449 ], counterDescriptors = keySet(counterDescriptors_);
11450
11451 var colorKeywords_ = [
11452 "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
11453 "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
11454 "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
11455 "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
11456 "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
11457 "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
11458 "darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
11459 "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
11460 "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
11461 "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
11462 "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
11463 "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
11464 "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
11465 "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
11466 "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
11467 "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
11468 "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
11469 "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
11470 "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
11471 "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
11472 "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
11473 "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown",
11474 "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
11475 "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
11476 "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
11477 "whitesmoke", "yellow", "yellowgreen"
11478 ], colorKeywords = keySet(colorKeywords_);
11479
11480 var valueKeywords_ = [
11481 "above", "absolute", "activeborder", "additive", "activecaption", "afar",
11482 "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
11483 "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
11484 "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page",
11485 "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
11486 "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
11487 "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
11488 "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian",
11489 "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
11490 "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
11491 "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
11492 "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
11493 "compact", "condensed", "contain", "content", "contents",
11494 "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
11495 "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
11496 "decimal-leading-zero", "default", "default-button", "dense", "destination-atop",
11497 "destination-in", "destination-out", "destination-over", "devanagari", "difference",
11498 "disc", "discard", "disclosure-closed", "disclosure-open", "document",
11499 "dot-dash", "dot-dot-dash",
11500 "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
11501 "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
11502 "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
11503 "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
11504 "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
11505 "ethiopic-halehame-gez", "ethiopic-halehame-om-et",
11506 "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
11507 "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
11508 "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
11509 "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
11510 "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove",
11511 "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
11512 "help", "hidden", "hide", "higher", "highlight", "highlighttext",
11513 "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore",
11514 "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
11515 "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
11516 "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert",
11517 "italic", "japanese-formal", "japanese-informal", "justify", "kannada",
11518 "katakana", "katakana-iroha", "keep-all", "khmer",
11519 "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal",
11520 "landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten",
11521 "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem",
11522 "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
11523 "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
11524 "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d",
11525 "media-controls-background", "media-current-time-display",
11526 "media-fullscreen-button", "media-mute-button", "media-play-button",
11527 "media-return-to-realtime-button", "media-rewind-button",
11528 "media-seek-back-button", "media-seek-forward-button", "media-slider",
11529 "media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
11530 "media-volume-slider-container", "media-volume-sliderthumb", "medium",
11531 "menu", "menulist", "menulist-button", "menulist-text",
11532 "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
11533 "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
11534 "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
11535 "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
11536 "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote",
11537 "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
11538 "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
11539 "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
11540 "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d",
11541 "progress", "push-button", "radial-gradient", "radio", "read-only",
11542 "read-write", "read-write-plaintext-only", "rectangle", "region",
11543 "relative", "repeat", "repeating-linear-gradient",
11544 "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse",
11545 "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
11546 "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
11547 "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
11548 "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield",
11549 "searchfield-cancel-button", "searchfield-decoration",
11550 "searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end",
11551 "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
11552 "simp-chinese-formal", "simp-chinese-informal", "single",
11553 "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal",
11554 "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
11555 "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
11556 "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square",
11557 "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
11558 "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table",
11559 "table-caption", "table-cell", "table-column", "table-column-group",
11560 "table-footer-group", "table-header-group", "table-row", "table-row-group",
11561 "tamil",
11562 "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
11563 "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
11564 "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
11565 "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
11566 "trad-chinese-formal", "trad-chinese-informal", "transform",
11567 "translate", "translate3d", "translateX", "translateY", "translateZ",
11568 "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up",
11569 "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
11570 "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
11571 "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
11572 "visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
11573 "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor",
11574 "xx-large", "xx-small"
11575 ], valueKeywords = keySet(valueKeywords_);
11576
11577 var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_)
11578 .concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_)
11579 .concat(valueKeywords_);
11580 CodeMirror.registerHelper("hintWords", "css", allWords);
11581
11582 function tokenCComment(stream, state) {
11583 var maybeEnd = false, ch;
11584 while ((ch = stream.next()) != null) {
11585 if (maybeEnd && ch == "/") {
11586 state.tokenize = null;
11587 break;
11588 }
11589 maybeEnd = (ch == "*");
11590 }
11591 return ["comment", "comment"];
11592 }
11593
11594 CodeMirror.defineMIME("text/css", {
11595 documentTypes: documentTypes,
11596 mediaTypes: mediaTypes,
11597 mediaFeatures: mediaFeatures,
11598 mediaValueKeywords: mediaValueKeywords,
11599 propertyKeywords: propertyKeywords,
11600 nonStandardPropertyKeywords: nonStandardPropertyKeywords,
11601 fontProperties: fontProperties,
11602 counterDescriptors: counterDescriptors,
11603 colorKeywords: colorKeywords,
11604 valueKeywords: valueKeywords,
11605 tokenHooks: {
11606 "/": function(stream, state) {
11607 if (!stream.eat("*")) return false;
11608 state.tokenize = tokenCComment;
11609 return tokenCComment(stream, state);
11610 }
11611 },
11612 name: "css"
11613 });
11614
11615 CodeMirror.defineMIME("text/x-scss", {
11616 mediaTypes: mediaTypes,
11617 mediaFeatures: mediaFeatures,
11618 mediaValueKeywords: mediaValueKeywords,
11619 propertyKeywords: propertyKeywords,
11620 nonStandardPropertyKeywords: nonStandardPropertyKeywords,
11621 colorKeywords: colorKeywords,
11622 valueKeywords: valueKeywords,
11623 fontProperties: fontProperties,
11624 allowNested: true,
11625 lineComment: "//",
11626 tokenHooks: {
11627 "/": function(stream, state) {
11628 if (stream.eat("/")) {
11629 stream.skipToEnd();
11630 return ["comment", "comment"];
11631 } else if (stream.eat("*")) {
11632 state.tokenize = tokenCComment;
11633 return tokenCComment(stream, state);
11634 } else {
11635 return ["operator", "operator"];
11636 }
11637 },
11638 ":": function(stream) {
11639 if (stream.match(/\s*\{/, false))
11640 return [null, null]
11641 return false;
11642 },
11643 "$": function(stream) {
11644 stream.match(/^[\w-]+/);
11645 if (stream.match(/^\s*:/, false))
11646 return ["variable-2", "variable-definition"];
11647 return ["variable-2", "variable"];
11648 },
11649 "#": function(stream) {
11650 if (!stream.eat("{")) return false;
11651 return [null, "interpolation"];
11652 }
11653 },
11654 name: "css",
11655 helperType: "scss"
11656 });
11657
11658 CodeMirror.defineMIME("text/x-less", {
11659 mediaTypes: mediaTypes,
11660 mediaFeatures: mediaFeatures,
11661 mediaValueKeywords: mediaValueKeywords,
11662 propertyKeywords: propertyKeywords,
11663 nonStandardPropertyKeywords: nonStandardPropertyKeywords,
11664 colorKeywords: colorKeywords,
11665 valueKeywords: valueKeywords,
11666 fontProperties: fontProperties,
11667 allowNested: true,
11668 lineComment: "//",
11669 tokenHooks: {
11670 "/": function(stream, state) {
11671 if (stream.eat("/")) {
11672 stream.skipToEnd();
11673 return ["comment", "comment"];
11674 } else if (stream.eat("*")) {
11675 state.tokenize = tokenCComment;
11676 return tokenCComment(stream, state);
11677 } else {
11678 return ["operator", "operator"];
11679 }
11680 },
11681 "@": function(stream) {
11682 if (stream.eat("{")) return [null, "interpolation"];
11683 if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
11684 stream.eatWhile(/[\w\\\-]/);
11685 if (stream.match(/^\s*:/, false))
11686 return ["variable-2", "variable-definition"];
11687 return ["variable-2", "variable"];
11688 },
11689 "&": function() {
11690 return ["atom", "atom"];
11691 }
11692 },
11693 name: "css",
11694 helperType: "less"
11695 });
11696
11697 CodeMirror.defineMIME("text/x-gss", {
11698 documentTypes: documentTypes,
11699 mediaTypes: mediaTypes,
11700 mediaFeatures: mediaFeatures,
11701 propertyKeywords: propertyKeywords,
11702 nonStandardPropertyKeywords: nonStandardPropertyKeywords,
11703 fontProperties: fontProperties,
11704 counterDescriptors: counterDescriptors,
11705 colorKeywords: colorKeywords,
11706 valueKeywords: valueKeywords,
11707 supportsAtComponent: true,
11708 tokenHooks: {
11709 "/": function(stream, state) {
11710 if (!stream.eat("*")) return false;
11711 state.tokenize = tokenCComment;
11712 return tokenCComment(stream, state);
11713 }
11714 },
11715 name: "css",
11716 helperType: "gss"
11717 });
11718
11719 });
11720
11721 },{"../../lib/codemirror":12}],14:[function(require,module,exports){
11722 // CodeMirror, copyright (c) by Marijn Haverbeke and others
11723 // Distributed under an MIT license: http://codemirror.net/LICENSE
11724
11725 (function(mod) {
11726 if (typeof exports == "object" && typeof module == "object") // CommonJS
11727 mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css"));
11728 else if (typeof define == "function" && define.amd) // AMD
11729 define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod);
11730 else // Plain browser env
11731 mod(CodeMirror);
11732 })(function(CodeMirror) {
11733 "use strict";
11734
11735 var defaultTags = {
11736 script: [
11737 ["lang", /(javascript|babel)/i, "javascript"],
11738 ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i, "javascript"],
11739 ["type", /./, "text/plain"],
11740 [null, null, "javascript"]
11741 ],
11742 style: [
11743 ["lang", /^css$/i, "css"],
11744 ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"],
11745 ["type", /./, "text/plain"],
11746 [null, null, "css"]
11747 ]
11748 };
11749
11750 function maybeBackup(stream, pat, style) {
11751 var cur = stream.current(), close = cur.search(pat);
11752 if (close > -1) {
11753 stream.backUp(cur.length - close);
11754 } else if (cur.match(/<\/?$/)) {
11755 stream.backUp(cur.length);
11756 if (!stream.match(pat, false)) stream.match(cur);
11757 }
11758 return style;
11759 }
11760
11761 var attrRegexpCache = {};
11762 function getAttrRegexp(attr) {
11763 var regexp = attrRegexpCache[attr];
11764 if (regexp) return regexp;
11765 return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*");
11766 }
11767
11768 function getAttrValue(text, attr) {
11769 var match = text.match(getAttrRegexp(attr))
11770 return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : ""
11771 }
11772
11773 function getTagRegexp(tagName, anchored) {
11774 return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i");
11775 }
11776
11777 function addTags(from, to) {
11778 for (var tag in from) {
11779 var dest = to[tag] || (to[tag] = []);
11780 var source = from[tag];
11781 for (var i = source.length - 1; i >= 0; i--)
11782 dest.unshift(source[i])
11783 }
11784 }
11785
11786 function findMatchingMode(tagInfo, tagText) {
11787 for (var i = 0; i < tagInfo.length; i++) {
11788 var spec = tagInfo[i];
11789 if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2];
11790 }
11791 }
11792
11793 CodeMirror.defineMode("htmlmixed", function (config, parserConfig) {
11794 var htmlMode = CodeMirror.getMode(config, {
11795 name: "xml",
11796 htmlMode: true,
11797 multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
11798 multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag
11799 });
11800
11801 var tags = {};
11802 var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes;
11803 addTags(defaultTags, tags);
11804 if (configTags) addTags(configTags, tags);
11805 if (configScript) for (var i = configScript.length - 1; i >= 0; i--)
11806 tags.script.unshift(["type", configScript[i].matches, configScript[i].mode])
11807
11808 function html(stream, state) {
11809 var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName
11810 if (tag && !/[<>\s\/]/.test(stream.current()) &&
11811 (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) &&
11812 tags.hasOwnProperty(tagName)) {
11813 state.inTag = tagName + " "
11814 } else if (state.inTag && tag && />$/.test(stream.current())) {
11815 var inTag = /^([\S]+) (.*)/.exec(state.inTag)
11816 state.inTag = null
11817 var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2])
11818 var mode = CodeMirror.getMode(config, modeSpec)
11819 var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false);
11820 state.token = function (stream, state) {
11821 if (stream.match(endTagA, false)) {
11822 state.token = html;
11823 state.localState = state.localMode = null;
11824 return null;
11825 }
11826 return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState));
11827 };
11828 state.localMode = mode;
11829 state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, ""));
11830 } else if (state.inTag) {
11831 state.inTag += stream.current()
11832 if (stream.eol()) state.inTag += " "
11833 }
11834 return style;
11835 };
11836
11837 return {
11838 startState: function () {
11839 var state = CodeMirror.startState(htmlMode);
11840 return {token: html, inTag: null, localMode: null, localState: null, htmlState: state};
11841 },
11842
11843 copyState: function (state) {
11844 var local;
11845 if (state.localState) {
11846 local = CodeMirror.copyState(state.localMode, state.localState);
11847 }
11848 return {token: state.token, inTag: state.inTag,
11849 localMode: state.localMode, localState: local,
11850 htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
11851 },
11852
11853 token: function (stream, state) {
11854 return state.token(stream, state);
11855 },
11856
11857 indent: function (state, textAfter, line) {
11858 if (!state.localMode || /^\s*<\//.test(textAfter))
11859 return htmlMode.indent(state.htmlState, textAfter);
11860 else if (state.localMode.indent)
11861 return state.localMode.indent(state.localState, textAfter, line);
11862 else
11863 return CodeMirror.Pass;
11864 },
11865
11866 innerMode: function (state) {
11867 return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
11868 }
11869 };
11870 }, "xml", "javascript", "css");
11871
11872 CodeMirror.defineMIME("text/html", "htmlmixed");
11873 });
11874
11875 },{"../../lib/codemirror":12,"../css/css":13,"../javascript/javascript":15,"../xml/xml":16}],15:[function(require,module,exports){
11876 // CodeMirror, copyright (c) by Marijn Haverbeke and others
11877 // Distributed under an MIT license: http://codemirror.net/LICENSE
11878
11879 (function(mod) {
11880 if (typeof exports == "object" && typeof module == "object") // CommonJS
11881 mod(require("../../lib/codemirror"));
11882 else if (typeof define == "function" && define.amd) // AMD
11883 define(["../../lib/codemirror"], mod);
11884 else // Plain browser env
11885 mod(CodeMirror);
11886 })(function(CodeMirror) {
11887 "use strict";
11888
11889 CodeMirror.defineMode("javascript", function(config, parserConfig) {
11890 var indentUnit = config.indentUnit;
11891 var statementIndent = parserConfig.statementIndent;
11892 var jsonldMode = parserConfig.jsonld;
11893 var jsonMode = parserConfig.json || jsonldMode;
11894 var isTS = parserConfig.typescript;
11895 var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
11896
11897 // Tokenizer
11898
11899 var keywords = function(){
11900 function kw(type) {return {type: type, style: "keyword"};}
11901 var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
11902 var operator = kw("operator"), atom = {type: "atom", style: "atom"};
11903
11904 var jsKeywords = {
11905 "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
11906 "return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
11907 "var": kw("var"), "const": kw("var"), "let": kw("var"),
11908 "function": kw("function"), "catch": kw("catch"),
11909 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
11910 "in": operator, "typeof": operator, "instanceof": operator,
11911 "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
11912 "this": kw("this"), "class": kw("class"), "super": kw("atom"),
11913 "yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
11914 "await": C
11915 };
11916
11917 // Extend the 'normal' keywords with the TypeScript language extensions
11918 if (isTS) {
11919 var type = {type: "variable", style: "type"};
11920 var tsKeywords = {
11921 // object-like things
11922 "interface": kw("class"),
11923 "implements": C,
11924 "namespace": C,
11925 "module": kw("module"),
11926 "enum": kw("module"),
11927
11928 // scope modifiers
11929 "public": kw("modifier"),
11930 "private": kw("modifier"),
11931 "protected": kw("modifier"),
11932 "abstract": kw("modifier"),
11933 "readonly": kw("modifier"),
11934
11935 // types
11936 "string": type, "number": type, "boolean": type, "any": type
11937 };
11938
11939 for (var attr in tsKeywords) {
11940 jsKeywords[attr] = tsKeywords[attr];
11941 }
11942 }
11943
11944 return jsKeywords;
11945 }();
11946
11947 var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
11948 var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
11949
11950 function readRegexp(stream) {
11951 var escaped = false, next, inSet = false;
11952 while ((next = stream.next()) != null) {
11953 if (!escaped) {
11954 if (next == "/" && !inSet) return;
11955 if (next == "[") inSet = true;
11956 else if (inSet && next == "]") inSet = false;
11957 }
11958 escaped = !escaped && next == "\\";
11959 }
11960 }
11961
11962 // Used as scratch variables to communicate multiple values without
11963 // consing up tons of objects.
11964 var type, content;
11965 function ret(tp, style, cont) {
11966 type = tp; content = cont;
11967 return style;
11968 }
11969 function tokenBase(stream, state) {
11970 var ch = stream.next();
11971 if (ch == '"' || ch == "'") {
11972 state.tokenize = tokenString(ch);
11973 return state.tokenize(stream, state);
11974 } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
11975 return ret("number", "number");
11976 } else if (ch == "." && stream.match("..")) {
11977 return ret("spread", "meta");
11978 } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
11979 return ret(ch);
11980 } else if (ch == "=" && stream.eat(">")) {
11981 return ret("=>", "operator");
11982 } else if (ch == "0" && stream.eat(/x/i)) {
11983 stream.eatWhile(/[\da-f]/i);
11984 return ret("number", "number");
11985 } else if (ch == "0" && stream.eat(/o/i)) {
11986 stream.eatWhile(/[0-7]/i);
11987 return ret("number", "number");
11988 } else if (ch == "0" && stream.eat(/b/i)) {
11989 stream.eatWhile(/[01]/i);
11990 return ret("number", "number");
11991 } else if (/\d/.test(ch)) {
11992 stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
11993 return ret("number", "number");
11994 } else if (ch == "/") {
11995 if (stream.eat("*")) {
11996 state.tokenize = tokenComment;
11997 return tokenComment(stream, state);
11998 } else if (stream.eat("/")) {
11999 stream.skipToEnd();
12000 return ret("comment", "comment");
12001 } else if (expressionAllowed(stream, state, 1)) {
12002 readRegexp(stream);
12003 stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
12004 return ret("regexp", "string-2");
12005 } else {
12006 stream.eatWhile(isOperatorChar);
12007 return ret("operator", "operator", stream.current());
12008 }
12009 } else if (ch == "`") {
12010 state.tokenize = tokenQuasi;
12011 return tokenQuasi(stream, state);
12012 } else if (ch == "#") {
12013 stream.skipToEnd();
12014 return ret("error", "error");
12015 } else if (isOperatorChar.test(ch)) {
12016 if (ch != ">" || !state.lexical || state.lexical.type != ">")
12017 stream.eatWhile(isOperatorChar);
12018 return ret("operator", "operator", stream.current());
12019 } else if (wordRE.test(ch)) {
12020 stream.eatWhile(wordRE);
12021 var word = stream.current()
12022 if (state.lastType != ".") {
12023 if (keywords.propertyIsEnumerable(word)) {
12024 var kw = keywords[word]
12025 return ret(kw.type, kw.style, word)
12026 }
12027 if (word == "async" && stream.match(/^\s*[\(\w]/, false))
12028 return ret("async", "keyword", word)
12029 }
12030 return ret("variable", "variable", word)
12031 }
12032 }
12033
12034 function tokenString(quote) {
12035 return function(stream, state) {
12036 var escaped = false, next;
12037 if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
12038 state.tokenize = tokenBase;
12039 return ret("jsonld-keyword", "meta");
12040 }
12041 while ((next = stream.next()) != null) {
12042 if (next == quote && !escaped) break;
12043 escaped = !escaped && next == "\\";
12044 }
12045 if (!escaped) state.tokenize = tokenBase;
12046 return ret("string", "string");
12047 };
12048 }
12049
12050 function tokenComment(stream, state) {
12051 var maybeEnd = false, ch;
12052 while (ch = stream.next()) {
12053 if (ch == "/" && maybeEnd) {
12054 state.tokenize = tokenBase;
12055 break;
12056 }
12057 maybeEnd = (ch == "*");
12058 }
12059 return ret("comment", "comment");
12060 }
12061
12062 function tokenQuasi(stream, state) {
12063 var escaped = false, next;
12064 while ((next = stream.next()) != null) {
12065 if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
12066 state.tokenize = tokenBase;
12067 break;
12068 }
12069 escaped = !escaped && next == "\\";
12070 }
12071 return ret("quasi", "string-2", stream.current());
12072 }
12073
12074 var brackets = "([{}])";
12075 // This is a crude lookahead trick to try and notice that we're
12076 // parsing the argument patterns for a fat-arrow function before we
12077 // actually hit the arrow token. It only works if the arrow is on
12078 // the same line as the arguments and there's no strange noise
12079 // (comments) in between. Fallback is to only notice when we hit the
12080 // arrow, and not declare the arguments as locals for the arrow
12081 // body.
12082 function findFatArrow(stream, state) {
12083 if (state.fatArrowAt) state.fatArrowAt = null;
12084 var arrow = stream.string.indexOf("=>", stream.start);
12085 if (arrow < 0) return;
12086
12087 if (isTS) { // Try to skip TypeScript return type declarations after the arguments
12088 var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow))
12089 if (m) arrow = m.index
12090 }
12091
12092 var depth = 0, sawSomething = false;
12093 for (var pos = arrow - 1; pos >= 0; --pos) {
12094 var ch = stream.string.charAt(pos);
12095 var bracket = brackets.indexOf(ch);
12096 if (bracket >= 0 && bracket < 3) {
12097 if (!depth) { ++pos; break; }
12098 if (--depth == 0) { if (ch == "(") sawSomething = true; break; }
12099 } else if (bracket >= 3 && bracket < 6) {
12100 ++depth;
12101 } else if (wordRE.test(ch)) {
12102 sawSomething = true;
12103 } else if (/["'\/]/.test(ch)) {
12104 return;
12105 } else if (sawSomething && !depth) {
12106 ++pos;
12107 break;
12108 }
12109 }
12110 if (sawSomething && !depth) state.fatArrowAt = pos;
12111 }
12112
12113 // Parser
12114
12115 var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
12116
12117 function JSLexical(indented, column, type, align, prev, info) {
12118 this.indented = indented;
12119 this.column = column;
12120 this.type = type;
12121 this.prev = prev;
12122 this.info = info;
12123 if (align != null) this.align = align;
12124 }
12125
12126 function inScope(state, varname) {
12127 for (var v = state.localVars; v; v = v.next)
12128 if (v.name == varname) return true;
12129 for (var cx = state.context; cx; cx = cx.prev) {
12130 for (var v = cx.vars; v; v = v.next)
12131 if (v.name == varname) return true;
12132 }
12133 }
12134
12135 function parseJS(state, style, type, content, stream) {
12136 var cc = state.cc;
12137 // Communicate our context to the combinators.
12138 // (Less wasteful than consing up a hundred closures on every call.)
12139 cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
12140
12141 if (!state.lexical.hasOwnProperty("align"))
12142 state.lexical.align = true;
12143
12144 while(true) {
12145 var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
12146 if (combinator(type, content)) {
12147 while(cc.length && cc[cc.length - 1].lex)
12148 cc.pop()();
12149 if (cx.marked) return cx.marked;
12150 if (type == "variable" && inScope(state, content)) return "variable-2";
12151 return style;
12152 }
12153 }
12154 }
12155
12156 // Combinator utils
12157
12158 var cx = {state: null, column: null, marked: null, cc: null};
12159 function pass() {
12160 for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
12161 }
12162 function cont() {
12163 pass.apply(null, arguments);
12164 return true;
12165 }
12166 function register(varname) {
12167 function inList(list) {
12168 for (var v = list; v; v = v.next)
12169 if (v.name == varname) return true;
12170 return false;
12171 }
12172 var state = cx.state;
12173 cx.marked = "def";
12174 if (state.context) {
12175 if (inList(state.localVars)) return;
12176 state.localVars = {name: varname, next: state.localVars};
12177 } else {
12178 if (inList(state.globalVars)) return;
12179 if (parserConfig.globalVars)
12180 state.globalVars = {name: varname, next: state.globalVars};
12181 }
12182 }
12183
12184 // Combinators
12185
12186 var defaultVars = {name: "this", next: {name: "arguments"}};
12187 function pushcontext() {
12188 cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
12189 cx.state.localVars = defaultVars;
12190 }
12191 function popcontext() {
12192 cx.state.localVars = cx.state.context.vars;
12193 cx.state.context = cx.state.context.prev;
12194 }
12195 function pushlex(type, info) {
12196 var result = function() {
12197 var state = cx.state, indent = state.indented;
12198 if (state.lexical.type == "stat") indent = state.lexical.indented;
12199 else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
12200 indent = outer.indented;
12201 state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
12202 };
12203 result.lex = true;
12204 return result;
12205 }
12206 function poplex() {
12207 var state = cx.state;
12208 if (state.lexical.prev) {
12209 if (state.lexical.type == ")")
12210 state.indented = state.lexical.indented;
12211 state.lexical = state.lexical.prev;
12212 }
12213 }
12214 poplex.lex = true;
12215
12216 function expect(wanted) {
12217 function exp(type) {
12218 if (type == wanted) return cont();
12219 else if (wanted == ";") return pass();
12220 else return cont(exp);
12221 };
12222 return exp;
12223 }
12224
12225 function statement(type, value) {
12226 if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
12227 if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
12228 if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
12229 if (type == "{") return cont(pushlex("}"), block, poplex);
12230 if (type == ";") return cont();
12231 if (type == "if") {
12232 if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
12233 cx.state.cc.pop()();
12234 return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse);
12235 }
12236 if (type == "function") return cont(functiondef);
12237 if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
12238 if (type == "variable") {
12239 if (isTS && value == "type") {
12240 cx.marked = "keyword"
12241 return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
12242 } if (isTS && value == "declare") {
12243 cx.marked = "keyword"
12244 return cont(statement)
12245 } else {
12246 return cont(pushlex("stat"), maybelabel);
12247 }
12248 }
12249 if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"),
12250 block, poplex, poplex);
12251 if (type == "case") return cont(expression, expect(":"));
12252 if (type == "default") return cont(expect(":"));
12253 if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
12254 statement, poplex, popcontext);
12255 if (type == "class") return cont(pushlex("form"), className, poplex);
12256 if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
12257 if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
12258 if (type == "module") return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
12259 if (type == "async") return cont(statement)
12260 if (value == "@") return cont(expression, statement)
12261 return pass(pushlex("stat"), expression, expect(";"), poplex);
12262 }
12263 function expression(type) {
12264 return expressionInner(type, false);
12265 }
12266 function expressionNoComma(type) {
12267 return expressionInner(type, true);
12268 }
12269 function parenExpr(type) {
12270 if (type != "(") return pass()
12271 return cont(pushlex(")"), expression, expect(")"), poplex)
12272 }
12273 function expressionInner(type, noComma) {
12274 if (cx.state.fatArrowAt == cx.stream.start) {
12275 var body = noComma ? arrowBodyNoComma : arrowBody;
12276 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
12277 else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
12278 }
12279
12280 var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
12281 if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
12282 if (type == "function") return cont(functiondef, maybeop);
12283 if (type == "class") return cont(pushlex("form"), classExpression, poplex);
12284 if (type == "keyword c" || type == "async") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
12285 if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
12286 if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
12287 if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
12288 if (type == "{") return contCommasep(objprop, "}", null, maybeop);
12289 if (type == "quasi") return pass(quasi, maybeop);
12290 if (type == "new") return cont(maybeTarget(noComma));
12291 return cont();
12292 }
12293 function maybeexpression(type) {
12294 if (type.match(/[;\}\)\],]/)) return pass();
12295 return pass(expression);
12296 }
12297 function maybeexpressionNoComma(type) {
12298 if (type.match(/[;\}\)\],]/)) return pass();
12299 return pass(expressionNoComma);
12300 }
12301
12302 function maybeoperatorComma(type, value) {
12303 if (type == ",") return cont(expression);
12304 return maybeoperatorNoComma(type, value, false);
12305 }
12306 function maybeoperatorNoComma(type, value, noComma) {
12307 var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
12308 var expr = noComma == false ? expression : expressionNoComma;
12309 if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
12310 if (type == "operator") {
12311 if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me);
12312 if (value == "?") return cont(expression, expect(":"), expr);
12313 return cont(expr);
12314 }
12315 if (type == "quasi") { return pass(quasi, me); }
12316 if (type == ";") return;
12317 if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
12318 if (type == ".") return cont(property, me);
12319 if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
12320 if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
12321 }
12322 function quasi(type, value) {
12323 if (type != "quasi") return pass();
12324 if (value.slice(value.length - 2) != "${") return cont(quasi);
12325 return cont(expression, continueQuasi);
12326 }
12327 function continueQuasi(type) {
12328 if (type == "}") {
12329 cx.marked = "string-2";
12330 cx.state.tokenize = tokenQuasi;
12331 return cont(quasi);
12332 }
12333 }
12334 function arrowBody(type) {
12335 findFatArrow(cx.stream, cx.state);
12336 return pass(type == "{" ? statement : expression);
12337 }
12338 function arrowBodyNoComma(type) {
12339 findFatArrow(cx.stream, cx.state);
12340 return pass(type == "{" ? statement : expressionNoComma);
12341 }
12342 function maybeTarget(noComma) {
12343 return function(type) {
12344 if (type == ".") return cont(noComma ? targetNoComma : target);
12345 else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma)
12346 else return pass(noComma ? expressionNoComma : expression);
12347 };
12348 }
12349 function target(_, value) {
12350 if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
12351 }
12352 function targetNoComma(_, value) {
12353 if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
12354 }
12355 function maybelabel(type) {
12356 if (type == ":") return cont(poplex, statement);
12357 return pass(maybeoperatorComma, expect(";"), poplex);
12358 }
12359 function property(type) {
12360 if (type == "variable") {cx.marked = "property"; return cont();}
12361 }
12362 function objprop(type, value) {
12363 if (type == "async") {
12364 cx.marked = "property";
12365 return cont(objprop);
12366 } else if (type == "variable" || cx.style == "keyword") {
12367 cx.marked = "property";
12368 if (value == "get" || value == "set") return cont(getterSetter);
12369 return cont(afterprop);
12370 } else if (type == "number" || type == "string") {
12371 cx.marked = jsonldMode ? "property" : (cx.style + " property");
12372 return cont(afterprop);
12373 } else if (type == "jsonld-keyword") {
12374 return cont(afterprop);
12375 } else if (type == "modifier") {
12376 return cont(objprop)
12377 } else if (type == "[") {
12378 return cont(expression, expect("]"), afterprop);
12379 } else if (type == "spread") {
12380 return cont(expression, afterprop);
12381 } else if (type == ":") {
12382 return pass(afterprop)
12383 }
12384 }
12385 function getterSetter(type) {
12386 if (type != "variable") return pass(afterprop);
12387 cx.marked = "property";
12388 return cont(functiondef);
12389 }
12390 function afterprop(type) {
12391 if (type == ":") return cont(expressionNoComma);
12392 if (type == "(") return pass(functiondef);
12393 }
12394 function commasep(what, end, sep) {
12395 function proceed(type, value) {
12396 if (sep ? sep.indexOf(type) > -1 : type == ",") {
12397 var lex = cx.state.lexical;
12398 if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
12399 return cont(function(type, value) {
12400 if (type == end || value == end) return pass()
12401 return pass(what)
12402 }, proceed);
12403 }
12404 if (type == end || value == end) return cont();
12405 return cont(expect(end));
12406 }
12407 return function(type, value) {
12408 if (type == end || value == end) return cont();
12409 return pass(what, proceed);
12410 };
12411 }
12412 function contCommasep(what, end, info) {
12413 for (var i = 3; i < arguments.length; i++)
12414 cx.cc.push(arguments[i]);
12415 return cont(pushlex(end, info), commasep(what, end), poplex);
12416 }
12417 function block(type) {
12418 if (type == "}") return cont();
12419 return pass(statement, block);
12420 }
12421 function maybetype(type, value) {
12422 if (isTS) {
12423 if (type == ":") return cont(typeexpr);
12424 if (value == "?") return cont(maybetype);
12425 }
12426 }
12427 function typeexpr(type, value) {
12428 if (type == "variable") {
12429 if (value == "keyof") {
12430 cx.marked = "keyword"
12431 return cont(typeexpr)
12432 } else {
12433 cx.marked = "type"
12434 return cont(afterType)
12435 }
12436 }
12437 if (type == "string" || type == "number" || type == "atom") return cont(afterType);
12438 if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)
12439 if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType)
12440 if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
12441 }
12442 function maybeReturnType(type) {
12443 if (type == "=>") return cont(typeexpr)
12444 }
12445 function typeprop(type, value) {
12446 if (type == "variable" || cx.style == "keyword") {
12447 cx.marked = "property"
12448 return cont(typeprop)
12449 } else if (value == "?") {
12450 return cont(typeprop)
12451 } else if (type == ":") {
12452 return cont(typeexpr)
12453 } else if (type == "[") {
12454 return cont(expression, maybetype, expect("]"), typeprop)
12455 }
12456 }
12457 function typearg(type) {
12458 if (type == "variable") return cont(typearg)
12459 else if (type == ":") return cont(typeexpr)
12460 }
12461 function afterType(type, value) {
12462 if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
12463 if (value == "|" || type == ".") return cont(typeexpr)
12464 if (type == "[") return cont(expect("]"), afterType)
12465 if (value == "extends") return cont(typeexpr)
12466 }
12467 function maybeTypeArgs(_, value) {
12468 if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
12469 }
12470 function vardef() {
12471 return pass(pattern, maybetype, maybeAssign, vardefCont);
12472 }
12473 function pattern(type, value) {
12474 if (type == "modifier") return cont(pattern)
12475 if (type == "variable") { register(value); return cont(); }
12476 if (type == "spread") return cont(pattern);
12477 if (type == "[") return contCommasep(pattern, "]");
12478 if (type == "{") return contCommasep(proppattern, "}");
12479 }
12480 function proppattern(type, value) {
12481 if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
12482 register(value);
12483 return cont(maybeAssign);
12484 }
12485 if (type == "variable") cx.marked = "property";
12486 if (type == "spread") return cont(pattern);
12487 if (type == "}") return pass();
12488 return cont(expect(":"), pattern, maybeAssign);
12489 }
12490 function maybeAssign(_type, value) {
12491 if (value == "=") return cont(expressionNoComma);
12492 }
12493 function vardefCont(type) {
12494 if (type == ",") return cont(vardef);
12495 }
12496 function maybeelse(type, value) {
12497 if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
12498 }
12499 function forspec(type) {
12500 if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
12501 }
12502 function forspec1(type) {
12503 if (type == "var") return cont(vardef, expect(";"), forspec2);
12504 if (type == ";") return cont(forspec2);
12505 if (type == "variable") return cont(formaybeinof);
12506 return pass(expression, expect(";"), forspec2);
12507 }
12508 function formaybeinof(_type, value) {
12509 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
12510 return cont(maybeoperatorComma, forspec2);
12511 }
12512 function forspec2(type, value) {
12513 if (type == ";") return cont(forspec3);
12514 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
12515 return pass(expression, expect(";"), forspec3);
12516 }
12517 function forspec3(type) {
12518 if (type != ")") cont(expression);
12519 }
12520 function functiondef(type, value) {
12521 if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
12522 if (type == "variable") {register(value); return cont(functiondef);}
12523 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
12524 if (isTS && value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, functiondef)
12525 }
12526 function funarg(type) {
12527 if (type == "spread" || type == "modifier") return cont(funarg);
12528 return pass(pattern, maybetype, maybeAssign);
12529 }
12530 function classExpression(type, value) {
12531 // Class expressions may have an optional name.
12532 if (type == "variable") return className(type, value);
12533 return classNameAfter(type, value);
12534 }
12535 function className(type, value) {
12536 if (type == "variable") {register(value); return cont(classNameAfter);}
12537 }
12538 function classNameAfter(type, value) {
12539 if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, classNameAfter)
12540 if (value == "extends" || value == "implements" || (isTS && type == ","))
12541 return cont(isTS ? typeexpr : expression, classNameAfter);
12542 if (type == "{") return cont(pushlex("}"), classBody, poplex);
12543 }
12544 function classBody(type, value) {
12545 if (type == "modifier" || type == "async" ||
12546 (type == "variable" &&
12547 (value == "static" || value == "get" || value == "set") &&
12548 cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) {
12549 cx.marked = "keyword";
12550 return cont(classBody);
12551 }
12552 if (type == "variable") {
12553 cx.marked = "property";
12554 return cont(isTS ? classfield : functiondef, classBody);
12555 }
12556 if (type == "[")
12557 return cont(expression, expect("]"), isTS ? classfield : functiondef, classBody)
12558 if (value == "*") {
12559 cx.marked = "keyword";
12560 return cont(classBody);
12561 }
12562 if (type == ";") return cont(classBody);
12563 if (type == "}") return cont();
12564 if (value == "@") return cont(expression, classBody)
12565 }
12566 function classfield(type, value) {
12567 if (value == "?") return cont(classfield)
12568 if (type == ":") return cont(typeexpr, maybeAssign)
12569 if (value == "=") return cont(expressionNoComma)
12570 return pass(functiondef)
12571 }
12572 function afterExport(type, value) {
12573 if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
12574 if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
12575 if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";"));
12576 return pass(statement);
12577 }
12578 function exportField(type, value) {
12579 if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
12580 if (type == "variable") return pass(expressionNoComma, exportField);
12581 }
12582 function afterImport(type) {
12583 if (type == "string") return cont();
12584 return pass(importSpec, maybeMoreImports, maybeFrom);
12585 }
12586 function importSpec(type, value) {
12587 if (type == "{") return contCommasep(importSpec, "}");
12588 if (type == "variable") register(value);
12589 if (value == "*") cx.marked = "keyword";
12590 return cont(maybeAs);
12591 }
12592 function maybeMoreImports(type) {
12593 if (type == ",") return cont(importSpec, maybeMoreImports)
12594 }
12595 function maybeAs(_type, value) {
12596 if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
12597 }
12598 function maybeFrom(_type, value) {
12599 if (value == "from") { cx.marked = "keyword"; return cont(expression); }
12600 }
12601 function arrayLiteral(type) {
12602 if (type == "]") return cont();
12603 return pass(commasep(expressionNoComma, "]"));
12604 }
12605
12606 function isContinuedStatement(state, textAfter) {
12607 return state.lastType == "operator" || state.lastType == "," ||
12608 isOperatorChar.test(textAfter.charAt(0)) ||
12609 /[,.]/.test(textAfter.charAt(0));
12610 }
12611
12612 function expressionAllowed(stream, state, backUp) {
12613 return state.tokenize == tokenBase &&
12614 /^(?:operator|sof|keyword c|case|new|export|default|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
12615 (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
12616 }
12617
12618 // Interface
12619
12620 return {
12621 startState: function(basecolumn) {
12622 var state = {
12623 tokenize: tokenBase,
12624 lastType: "sof",
12625 cc: [],
12626 lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
12627 localVars: parserConfig.localVars,
12628 context: parserConfig.localVars && {vars: parserConfig.localVars},
12629 indented: basecolumn || 0
12630 };
12631 if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
12632 state.globalVars = parserConfig.globalVars;
12633 return state;
12634 },
12635
12636 token: function(stream, state) {
12637 if (stream.sol()) {
12638 if (!state.lexical.hasOwnProperty("align"))
12639 state.lexical.align = false;
12640 state.indented = stream.indentation();
12641 findFatArrow(stream, state);
12642 }
12643 if (state.tokenize != tokenComment && stream.eatSpace()) return null;
12644 var style = state.tokenize(stream, state);
12645 if (type == "comment") return style;
12646 state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
12647 return parseJS(state, style, type, content, stream);
12648 },
12649
12650 indent: function(state, textAfter) {
12651 if (state.tokenize == tokenComment) return CodeMirror.Pass;
12652 if (state.tokenize != tokenBase) return 0;
12653 var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top
12654 // Kludge to prevent 'maybelse' from blocking lexical scope pops
12655 if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
12656 var c = state.cc[i];
12657 if (c == poplex) lexical = lexical.prev;
12658 else if (c != maybeelse) break;
12659 }
12660 while ((lexical.type == "stat" || lexical.type == "form") &&
12661 (firstChar == "}" || ((top = state.cc[state.cc.length - 1]) &&
12662 (top == maybeoperatorComma || top == maybeoperatorNoComma) &&
12663 !/^[,\.=+\-*:?[\(]/.test(textAfter))))
12664 lexical = lexical.prev;
12665 if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
12666 lexical = lexical.prev;
12667 var type = lexical.type, closing = firstChar == type;
12668
12669 if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
12670 else if (type == "form" && firstChar == "{") return lexical.indented;
12671 else if (type == "form") return lexical.indented + indentUnit;
12672 else if (type == "stat")
12673 return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
12674 else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
12675 return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
12676 else if (lexical.align) return lexical.column + (closing ? 0 : 1);
12677 else return lexical.indented + (closing ? 0 : indentUnit);
12678 },
12679
12680 electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
12681 blockCommentStart: jsonMode ? null : "/*",
12682 blockCommentEnd: jsonMode ? null : "*/",
12683 lineComment: jsonMode ? null : "//",
12684 fold: "brace",
12685 closeBrackets: "()[]{}''\"\"``",
12686
12687 helperType: jsonMode ? "json" : "javascript",
12688 jsonldMode: jsonldMode,
12689 jsonMode: jsonMode,
12690
12691 expressionAllowed: expressionAllowed,
12692
12693 skipExpression: function(state) {
12694 var top = state.cc[state.cc.length - 1]
12695 if (top == expression || top == expressionNoComma) state.cc.pop()
12696 }
12697 };
12698 });
12699
12700 CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
12701
12702 CodeMirror.defineMIME("text/javascript", "javascript");
12703 CodeMirror.defineMIME("text/ecmascript", "javascript");
12704 CodeMirror.defineMIME("application/javascript", "javascript");
12705 CodeMirror.defineMIME("application/x-javascript", "javascript");
12706 CodeMirror.defineMIME("application/ecmascript", "javascript");
12707 CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
12708 CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
12709 CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
12710 CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
12711 CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
12712
12713 });
12714
12715 },{"../../lib/codemirror":12}],16:[function(require,module,exports){
12716 // CodeMirror, copyright (c) by Marijn Haverbeke and others
12717 // Distributed under an MIT license: http://codemirror.net/LICENSE
12718
12719 (function(mod) {
12720 if (typeof exports == "object" && typeof module == "object") // CommonJS
12721 mod(require("../../lib/codemirror"));
12722 else if (typeof define == "function" && define.amd) // AMD
12723 define(["../../lib/codemirror"], mod);
12724 else // Plain browser env
12725 mod(CodeMirror);
12726 })(function(CodeMirror) {
12727 "use strict";
12728
12729 var htmlConfig = {
12730 autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
12731 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
12732 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
12733 'track': true, 'wbr': true, 'menuitem': true},
12734 implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
12735 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
12736 'th': true, 'tr': true},
12737 contextGrabbers: {
12738 'dd': {'dd': true, 'dt': true},
12739 'dt': {'dd': true, 'dt': true},
12740 'li': {'li': true},
12741 'option': {'option': true, 'optgroup': true},
12742 'optgroup': {'optgroup': true},
12743 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
12744 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
12745 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
12746 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
12747 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
12748 'rp': {'rp': true, 'rt': true},
12749 'rt': {'rp': true, 'rt': true},
12750 'tbody': {'tbody': true, 'tfoot': true},
12751 'td': {'td': true, 'th': true},
12752 'tfoot': {'tbody': true},
12753 'th': {'td': true, 'th': true},
12754 'thead': {'tbody': true, 'tfoot': true},
12755 'tr': {'tr': true}
12756 },
12757 doNotIndent: {"pre": true},
12758 allowUnquoted: true,
12759 allowMissing: true,
12760 caseFold: true
12761 }
12762
12763 var xmlConfig = {
12764 autoSelfClosers: {},
12765 implicitlyClosed: {},
12766 contextGrabbers: {},
12767 doNotIndent: {},
12768 allowUnquoted: false,
12769 allowMissing: false,
12770 caseFold: false
12771 }
12772
12773 CodeMirror.defineMode("xml", function(editorConf, config_) {
12774 var indentUnit = editorConf.indentUnit
12775 var config = {}
12776 var defaults = config_.htmlMode ? htmlConfig : xmlConfig
12777 for (var prop in defaults) config[prop] = defaults[prop]
12778 for (var prop in config_) config[prop] = config_[prop]
12779
12780 // Return variables for tokenizers
12781 var type, setStyle;
12782
12783 function inText(stream, state) {
12784 function chain(parser) {
12785 state.tokenize = parser;
12786 return parser(stream, state);
12787 }
12788
12789 var ch = stream.next();
12790 if (ch == "<") {
12791 if (stream.eat("!")) {
12792 if (stream.eat("[")) {
12793 if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
12794 else return null;
12795 } else if (stream.match("--")) {
12796 return chain(inBlock("comment", "-->"));
12797 } else if (stream.match("DOCTYPE", true, true)) {
12798 stream.eatWhile(/[\w\._\-]/);
12799 return chain(doctype(1));
12800 } else {
12801 return null;
12802 }
12803 } else if (stream.eat("?")) {
12804 stream.eatWhile(/[\w\._\-]/);
12805 state.tokenize = inBlock("meta", "?>");
12806 return "meta";
12807 } else {
12808 type = stream.eat("/") ? "closeTag" : "openTag";
12809 state.tokenize = inTag;
12810 return "tag bracket";
12811 }
12812 } else if (ch == "&") {
12813 var ok;
12814 if (stream.eat("#")) {
12815 if (stream.eat("x")) {
12816 ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
12817 } else {
12818 ok = stream.eatWhile(/[\d]/) && stream.eat(";");
12819 }
12820 } else {
12821 ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
12822 }
12823 return ok ? "atom" : "error";
12824 } else {
12825 stream.eatWhile(/[^&<]/);
12826 return null;
12827 }
12828 }
12829 inText.isInText = true;
12830
12831 function inTag(stream, state) {
12832 var ch = stream.next();
12833 if (ch == ">" || (ch == "/" && stream.eat(">"))) {
12834 state.tokenize = inText;
12835 type = ch == ">" ? "endTag" : "selfcloseTag";
12836 return "tag bracket";
12837 } else if (ch == "=") {
12838 type = "equals";
12839 return null;
12840 } else if (ch == "<") {
12841 state.tokenize = inText;
12842 state.state = baseState;
12843 state.tagName = state.tagStart = null;
12844 var next = state.tokenize(stream, state);
12845 return next ? next + " tag error" : "tag error";
12846 } else if (/[\'\"]/.test(ch)) {
12847 state.tokenize = inAttribute(ch);
12848 state.stringStartCol = stream.column();
12849 return state.tokenize(stream, state);
12850 } else {
12851 stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
12852 return "word";
12853 }
12854 }
12855
12856 function inAttribute(quote) {
12857 var closure = function(stream, state) {
12858 while (!stream.eol()) {
12859 if (stream.next() == quote) {
12860 state.tokenize = inTag;
12861 break;
12862 }
12863 }
12864 return "string";
12865 };
12866 closure.isInAttribute = true;
12867 return closure;
12868 }
12869
12870 function inBlock(style, terminator) {
12871 return function(stream, state) {
12872 while (!stream.eol()) {
12873 if (stream.match(terminator)) {
12874 state.tokenize = inText;
12875 break;
12876 }
12877 stream.next();
12878 }
12879 return style;
12880 };
12881 }
12882 function doctype(depth) {
12883 return function(stream, state) {
12884 var ch;
12885 while ((ch = stream.next()) != null) {
12886 if (ch == "<") {
12887 state.tokenize = doctype(depth + 1);
12888 return state.tokenize(stream, state);
12889 } else if (ch == ">") {
12890 if (depth == 1) {
12891 state.tokenize = inText;
12892 break;
12893 } else {
12894 state.tokenize = doctype(depth - 1);
12895 return state.tokenize(stream, state);
12896 }
12897 }
12898 }
12899 return "meta";
12900 };
12901 }
12902
12903 function Context(state, tagName, startOfLine) {
12904 this.prev = state.context;
12905 this.tagName = tagName;
12906 this.indent = state.indented;
12907 this.startOfLine = startOfLine;
12908 if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
12909 this.noIndent = true;
12910 }
12911 function popContext(state) {
12912 if (state.context) state.context = state.context.prev;
12913 }
12914 function maybePopContext(state, nextTagName) {
12915 var parentTagName;
12916 while (true) {
12917 if (!state.context) {
12918 return;
12919 }
12920 parentTagName = state.context.tagName;
12921 if (!config.contextGrabbers.hasOwnProperty(parentTagName) ||
12922 !config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
12923 return;
12924 }
12925 popContext(state);
12926 }
12927 }
12928
12929 function baseState(type, stream, state) {
12930 if (type == "openTag") {
12931 state.tagStart = stream.column();
12932 return tagNameState;
12933 } else if (type == "closeTag") {
12934 return closeTagNameState;
12935 } else {
12936 return baseState;
12937 }
12938 }
12939 function tagNameState(type, stream, state) {
12940 if (type == "word") {
12941 state.tagName = stream.current();
12942 setStyle = "tag";
12943 return attrState;
12944 } else {
12945 setStyle = "error";
12946 return tagNameState;
12947 }
12948 }
12949 function closeTagNameState(type, stream, state) {
12950 if (type == "word") {
12951 var tagName = stream.current();
12952 if (state.context && state.context.tagName != tagName &&
12953 config.implicitlyClosed.hasOwnProperty(state.context.tagName))
12954 popContext(state);
12955 if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {
12956 setStyle = "tag";
12957 return closeState;
12958 } else {
12959 setStyle = "tag error";
12960 return closeStateErr;
12961 }
12962 } else {
12963 setStyle = "error";
12964 return closeStateErr;
12965 }
12966 }
12967
12968 function closeState(type, _stream, state) {
12969 if (type != "endTag") {
12970 setStyle = "error";
12971 return closeState;
12972 }
12973 popContext(state);
12974 return baseState;
12975 }
12976 function closeStateErr(type, stream, state) {
12977 setStyle = "error";
12978 return closeState(type, stream, state);
12979 }
12980
12981 function attrState(type, _stream, state) {
12982 if (type == "word") {
12983 setStyle = "attribute";
12984 return attrEqState;
12985 } else if (type == "endTag" || type == "selfcloseTag") {
12986 var tagName = state.tagName, tagStart = state.tagStart;
12987 state.tagName = state.tagStart = null;
12988 if (type == "selfcloseTag" ||
12989 config.autoSelfClosers.hasOwnProperty(tagName)) {
12990 maybePopContext(state, tagName);
12991 } else {
12992 maybePopContext(state, tagName);
12993 state.context = new Context(state, tagName, tagStart == state.indented);
12994 }
12995 return baseState;
12996 }
12997 setStyle = "error";
12998 return attrState;
12999 }
13000 function attrEqState(type, stream, state) {
13001 if (type == "equals") return attrValueState;
13002 if (!config.allowMissing) setStyle = "error";
13003 return attrState(type, stream, state);
13004 }
13005 function attrValueState(type, stream, state) {
13006 if (type == "string") return attrContinuedState;
13007 if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;}
13008 setStyle = "error";
13009 return attrState(type, stream, state);
13010 }
13011 function attrContinuedState(type, stream, state) {
13012 if (type == "string") return attrContinuedState;
13013 return attrState(type, stream, state);
13014 }
13015
13016 return {
13017 startState: function(baseIndent) {
13018 var state = {tokenize: inText,
13019 state: baseState,
13020 indented: baseIndent || 0,
13021 tagName: null, tagStart: null,
13022 context: null}
13023 if (baseIndent != null) state.baseIndent = baseIndent
13024 return state
13025 },
13026
13027 token: function(stream, state) {
13028 if (!state.tagName && stream.sol())
13029 state.indented = stream.indentation();
13030
13031 if (stream.eatSpace()) return null;
13032 type = null;
13033 var style = state.tokenize(stream, state);
13034 if ((style || type) && style != "comment") {
13035 setStyle = null;
13036 state.state = state.state(type || style, stream, state);
13037 if (setStyle)
13038 style = setStyle == "error" ? style + " error" : setStyle;
13039 }
13040 return style;
13041 },
13042
13043 indent: function(state, textAfter, fullLine) {
13044 var context = state.context;
13045 // Indent multi-line strings (e.g. css).
13046 if (state.tokenize.isInAttribute) {
13047 if (state.tagStart == state.indented)
13048 return state.stringStartCol + 1;
13049 else
13050 return state.indented + indentUnit;
13051 }
13052 if (context && context.noIndent) return CodeMirror.Pass;
13053 if (state.tokenize != inTag && state.tokenize != inText)
13054 return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
13055 // Indent the starts of attribute names.
13056 if (state.tagName) {
13057 if (config.multilineTagIndentPastTag !== false)
13058 return state.tagStart + state.tagName.length + 2;
13059 else
13060 return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1);
13061 }
13062 if (config.alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
13063 var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
13064 if (tagAfter && tagAfter[1]) { // Closing tag spotted
13065 while (context) {
13066 if (context.tagName == tagAfter[2]) {
13067 context = context.prev;
13068 break;
13069 } else if (config.implicitlyClosed.hasOwnProperty(context.tagName)) {
13070 context = context.prev;
13071 } else {
13072 break;
13073 }
13074 }
13075 } else if (tagAfter) { // Opening tag spotted
13076 while (context) {
13077 var grabbers = config.contextGrabbers[context.tagName];
13078 if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
13079 context = context.prev;
13080 else
13081 break;
13082 }
13083 }
13084 while (context && context.prev && !context.startOfLine)
13085 context = context.prev;
13086 if (context) return context.indent + indentUnit;
13087 else return state.baseIndent || 0;
13088 },
13089
13090 electricInput: /<\/[\s\w:]+>$/,
13091 blockCommentStart: "<!--",
13092 blockCommentEnd: "-->",
13093
13094 configuration: config.htmlMode ? "html" : "xml",
13095 helperType: config.htmlMode ? "html" : "xml",
13096
13097 skipAttribute: function(state) {
13098 if (state.state == attrValueState)
13099 state.state = attrState
13100 }
13101 };
13102 });
13103
13104 CodeMirror.defineMIME("text/xml", "xml");
13105 CodeMirror.defineMIME("application/xml", "xml");
13106 if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
13107 CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
13108
13109 });
13110
13111 },{"../../lib/codemirror":12}],17:[function(require,module,exports){
13112 (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);};};}});
13113
13114
13115 },{}],18:[function(require,module,exports){
13116 /*
13117
13118 Style HTML
13119 ---------------
13120
13121 Written by Nochum Sossonko, (nsossonko@hotmail.com)
13122
13123 Based on code initially developed by: Einar Lielmanis, <elfz@laacz.lv>
13124 http://jsbeautifier.org/
13125
13126
13127 You are free to use this in any way you want, in case you find this useful or working for you.
13128
13129 Usage:
13130 style_html(html_source);
13131
13132 style_html(html_source, options);
13133
13134 The options are:
13135 indent_size (default 4) — indentation size,
13136 indent_char (default space) — character to indent with,
13137 max_char (default 70) - maximum amount of characters per line,
13138 brace_style (default "collapse") - "collapse" | "expand" | "end-expand"
13139 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.
13140 unformatted (defaults to inline tags) - list of tags, that shouldn't be reformatted
13141 indent_scripts (default normal) - "keep"|"separate"|"normal"
13142
13143 e.g.
13144
13145 style_html(html_source, {
13146 'indent_size': 2,
13147 'indent_char': ' ',
13148 'max_char': 78,
13149 'brace_style': 'expand',
13150 'unformatted': ['a', 'sub', 'sup', 'b', 'i', 'u']
13151 });
13152 */
13153
13154 function style_html(html_source, options) {
13155 //Wrapper function to invoke all the necessary constructors and deal with the output.
13156
13157 var multi_parser,
13158 indent_size,
13159 indent_character,
13160 max_char,
13161 brace_style,
13162 unformatted;
13163
13164 options = options || {};
13165 indent_size = options.indent_size || 4;
13166 indent_character = options.indent_char || ' ';
13167 brace_style = options.brace_style || 'collapse';
13168 max_char = options.max_char == 0 ? Infinity : options.max_char || 70;
13169 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'];
13170
13171 function Parser() {
13172
13173 this.pos = 0; //Parser position
13174 this.token = '';
13175 this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT
13176 this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values
13177 parent: 'parent1',
13178 parentcount: 1,
13179 parent1: ''
13180 };
13181 this.tag_type = '';
13182 this.token_text = this.last_token = this.last_text = this.token_type = '';
13183
13184 this.Utils = { //Uilities made available to the various functions
13185 whitespace: "\n\r\t ".split(''),
13186 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
13187 extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them
13188 in_array: function (what, arr) {
13189 for (var i=0; i<arr.length; i++) {
13190 if (what === arr[i]) {
13191 return true;
13192 }
13193 }
13194 return false;
13195 }
13196 }
13197
13198 this.get_content = function () { //function to capture regular content between tags
13199
13200 var input_char = '',
13201 content = [],
13202 space = false; //if a space is needed
13203
13204 while (this.input.charAt(this.pos) !== '<') {
13205 if (this.pos >= this.input.length) {
13206 return content.length?content.join(''):['', 'TK_EOF'];
13207 }
13208
13209 input_char = this.input.charAt(this.pos);
13210 this.pos++;
13211 this.line_char_count++;
13212
13213 if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
13214 if (content.length) {
13215 space = true;
13216 }
13217 this.line_char_count--;
13218 continue; //don't want to insert unnecessary space
13219 }
13220 else if (space) {
13221 if (this.line_char_count >= this.max_char) { //insert a line when the max_char is reached
13222 content.push('\n');
13223 for (var i=0; i<this.indent_level; i++) {
13224 content.push(this.indent_string);
13225 }
13226 this.line_char_count = 0;
13227 }
13228 else{
13229 content.push(' ');
13230 this.line_char_count++;
13231 }
13232 space = false;
13233 }
13234 content.push(input_char); //letter at-a-time (or string) inserted to an array
13235 }
13236 return content.length?content.join(''):'';
13237 }
13238
13239 this.get_contents_to = function (name) { //get the full content of a script or style to pass to js_beautify
13240 if (this.pos == this.input.length) {
13241 return ['', 'TK_EOF'];
13242 }
13243 var input_char = '';
13244 var content = '';
13245 var reg_match = new RegExp('\<\/' + name + '\\s*\>', 'igm');
13246 reg_match.lastIndex = this.pos;
13247 var reg_array = reg_match.exec(this.input);
13248 var end_script = reg_array?reg_array.index:this.input.length; //absolute end of script
13249 if(this.pos < end_script) { //get everything in between the script tags
13250 content = this.input.substring(this.pos, end_script);
13251 this.pos = end_script;
13252 }
13253 return content;
13254 }
13255
13256 this.record_tag = function (tag){ //function to record a tag and its parent in this.tags Object
13257 if (this.tags[tag + 'count']) { //check for the existence of this tag type
13258 this.tags[tag + 'count']++;
13259 this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
13260 }
13261 else { //otherwise initialize this tag type
13262 this.tags[tag + 'count'] = 1;
13263 this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
13264 }
13265 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)
13266 this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1')
13267 }
13268
13269 this.retrieve_tag = function (tag) { //function to retrieve the opening tag to the corresponding closer
13270 if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it
13271 var temp_parent = this.tags.parent; //check to see if it's a closable tag.
13272 while (temp_parent) { //till we reach '' (the initial value);
13273 if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it
13274 break;
13275 }
13276 temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree
13277 }
13278 if (temp_parent) { //if we caught something
13279 this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly
13280 this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent
13281 }
13282 delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference...
13283 delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself
13284 if (this.tags[tag + 'count'] == 1) {
13285 delete this.tags[tag + 'count'];
13286 }
13287 else {
13288 this.tags[tag + 'count']--;
13289 }
13290 }
13291 }
13292
13293 this.get_tag = function () { //function to get a full tag and parse its type
13294 var input_char = '',
13295 content = [],
13296 space = false,
13297 tag_start, tag_end;
13298
13299 do {
13300 if (this.pos >= this.input.length) {
13301 return content.length?content.join(''):['', 'TK_EOF'];
13302 }
13303
13304 input_char = this.input.charAt(this.pos);
13305 this.pos++;
13306 this.line_char_count++;
13307
13308 if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space
13309 space = true;
13310 this.line_char_count--;
13311 continue;
13312 }
13313
13314 if (input_char === "'" || input_char === '"') {
13315 if (!content[1] || content[1] !== '!') { //if we're in a comment strings don't get treated specially
13316 input_char += this.get_unformatted(input_char);
13317 space = true;
13318 }
13319 }
13320
13321 if (input_char === '=') { //no space before =
13322 space = false;
13323 }
13324
13325 if (content.length && content[content.length-1] !== '=' && input_char !== '>'
13326 && space) { //no space after = or before >
13327 if (this.line_char_count >= this.max_char) {
13328 this.print_newline(false, content);
13329 this.line_char_count = 0;
13330 }
13331 else {
13332 content.push(' ');
13333 this.line_char_count++;
13334 }
13335 space = false;
13336 }
13337 if (input_char === '<') {
13338 tag_start = this.pos - 1;
13339 }
13340 content.push(input_char); //inserts character at-a-time (or string)
13341 } while (input_char !== '>');
13342
13343 var tag_complete = content.join('');
13344 var tag_index;
13345 if (tag_complete.indexOf(' ') != -1) { //if there's whitespace, thats where the tag name ends
13346 tag_index = tag_complete.indexOf(' ');
13347 }
13348 else { //otherwise go with the tag ending
13349 tag_index = tag_complete.indexOf('>');
13350 }
13351 var tag_check = tag_complete.substring(1, tag_index).toLowerCase();
13352 if (tag_complete.charAt(tag_complete.length-2) === '/' ||
13353 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 /)
13354 this.tag_type = 'SINGLE';
13355 }
13356 else if (tag_check === 'script') { //for later script handling
13357 this.record_tag(tag_check);
13358 this.tag_type = 'SCRIPT';
13359 }
13360 else if (tag_check === 'style') { //for future style handling (for now it justs uses get_content)
13361 this.record_tag(tag_check);
13362 this.tag_type = 'STYLE';
13363 }
13364 else if (this.Utils.in_array(tag_check, unformatted)) { // do not reformat the "unformatted" tags
13365 var comment = this.get_unformatted('</'+tag_check+'>', tag_complete); //...delegate to get_unformatted function
13366 content.push(comment);
13367 // Preserve collapsed whitespace either before or after this tag.
13368 if (tag_start > 0 && this.Utils.in_array(this.input.charAt(tag_start - 1), this.Utils.whitespace)){
13369 content.splice(0, 0, this.input.charAt(tag_start - 1));
13370 }
13371 tag_end = this.pos - 1;
13372 if (this.Utils.in_array(this.input.charAt(tag_end + 1), this.Utils.whitespace)){
13373 content.push(this.input.charAt(tag_end + 1));
13374 }
13375 this.tag_type = 'SINGLE';
13376 }
13377 else if (tag_check.charAt(0) === '!') { //peek for <!-- comment
13378 if (tag_check.indexOf('[if') != -1) { //peek for <!--[if conditional comment
13379 if (tag_complete.indexOf('!IE') != -1) { //this type needs a closing --> so...
13380 var comment = this.get_unformatted('-->', tag_complete); //...delegate to get_unformatted
13381 content.push(comment);
13382 }
13383 this.tag_type = 'START';
13384 }
13385 else if (tag_check.indexOf('[endif') != -1) {//peek for <!--[endif end conditional comment
13386 this.tag_type = 'END';
13387 this.unindent();
13388 }
13389 else if (tag_check.indexOf('[cdata[') != -1) { //if it's a <[cdata[ comment...
13390 var comment = this.get_unformatted(']]>', tag_complete); //...delegate to get_unformatted function
13391 content.push(comment);
13392 this.tag_type = 'SINGLE'; //<![CDATA[ comments are treated like single tags
13393 }
13394 else {
13395 var comment = this.get_unformatted('-->', tag_complete);
13396 content.push(comment);
13397 this.tag_type = 'SINGLE';
13398 }
13399 }
13400 else {
13401 if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending
13402 this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors
13403 this.tag_type = 'END';
13404 }
13405 else { //otherwise it's a start-tag
13406 this.record_tag(tag_check); //push it on the tag stack
13407 this.tag_type = 'START';
13408 }
13409 if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line
13410 this.print_newline(true, this.output);
13411 }
13412 }
13413 return content.join(''); //returns fully formatted tag
13414 }
13415
13416 this.get_unformatted = function (delimiter, orig_tag) { //function to return unformatted content in its entirety
13417
13418 if (orig_tag && orig_tag.toLowerCase().indexOf(delimiter) != -1) {
13419 return '';
13420 }
13421 var input_char = '';
13422 var content = '';
13423 var space = true;
13424 do {
13425
13426 if (this.pos >= this.input.length) {
13427 return content;
13428 }
13429
13430 input_char = this.input.charAt(this.pos);
13431 this.pos++
13432
13433 if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
13434 if (!space) {
13435 this.line_char_count--;
13436 continue;
13437 }
13438 if (input_char === '\n' || input_char === '\r') {
13439 content += '\n';
13440 /* 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'
13441 for (var i=0; i<this.indent_level; i++) {
13442 content += this.indent_string;
13443 }
13444 space = false; //...and make sure other indentation is erased
13445 */
13446 this.line_char_count = 0;
13447 continue;
13448 }
13449 }
13450 content += input_char;
13451 this.line_char_count++;
13452 space = true;
13453
13454
13455 } while (content.toLowerCase().indexOf(delimiter) == -1);
13456 return content;
13457 }
13458
13459 this.get_token = function () { //initial handler for token-retrieval
13460 var token;
13461
13462 if (this.last_token === 'TK_TAG_SCRIPT' || this.last_token === 'TK_TAG_STYLE') { //check if we need to format javascript
13463 var type = this.last_token.substr(7)
13464 token = this.get_contents_to(type);
13465 if (typeof token !== 'string') {
13466 return token;
13467 }
13468 return [token, 'TK_' + type];
13469 }
13470 if (this.current_mode === 'CONTENT') {
13471 token = this.get_content();
13472 if (typeof token !== 'string') {
13473 return token;
13474 }
13475 else {
13476 return [token, 'TK_CONTENT'];
13477 }
13478 }
13479
13480 if (this.current_mode === 'TAG') {
13481 token = this.get_tag();
13482 if (typeof token !== 'string') {
13483 return token;
13484 }
13485 else {
13486 var tag_name_type = 'TK_TAG_' + this.tag_type;
13487 return [token, tag_name_type];
13488 }
13489 }
13490 }
13491
13492 this.get_full_indent = function (level) {
13493 level = this.indent_level + level || 0;
13494 if (level < 1)
13495 return '';
13496
13497 return Array(level + 1).join(this.indent_string);
13498 }
13499
13500
13501 this.printer = function (js_source, indent_character, indent_size, max_char, brace_style) { //handles input/output and some other printing functions
13502
13503 this.input = js_source || ''; //gets the input for the Parser
13504 this.output = [];
13505 this.indent_character = indent_character;
13506 this.indent_string = '';
13507 this.indent_size = indent_size;
13508 this.brace_style = brace_style;
13509 this.indent_level = 0;
13510 this.max_char = max_char;
13511 this.line_char_count = 0; //count to see if max_char was exceeded
13512
13513 for (var i=0; i<this.indent_size; i++) {
13514 this.indent_string += this.indent_character;
13515 }
13516
13517 this.print_newline = function (ignore, arr) {
13518 this.line_char_count = 0;
13519 if (!arr || !arr.length) {
13520 return;
13521 }
13522 if (!ignore) { //we might want the extra line
13523 while (this.Utils.in_array(arr[arr.length-1], this.Utils.whitespace)) {
13524 arr.pop();
13525 }
13526 }
13527 arr.push('\n');
13528 for (var i=0; i<this.indent_level; i++) {
13529 arr.push(this.indent_string);
13530 }
13531 }
13532
13533 this.print_token = function (text) {
13534 this.output.push(text);
13535 }
13536
13537 this.indent = function () {
13538 this.indent_level++;
13539 }
13540
13541 this.unindent = function () {
13542 if (this.indent_level > 0) {
13543 this.indent_level--;
13544 }
13545 }
13546 }
13547 return this;
13548 }
13549
13550 /*_____________________--------------------_____________________*/
13551
13552 multi_parser = new Parser(); //wrapping functions Parser
13553 multi_parser.printer(html_source, indent_character, indent_size, max_char, brace_style); //initialize starting values
13554
13555 while (true) {
13556 var t = multi_parser.get_token();
13557 multi_parser.token_text = t[0];
13558 multi_parser.token_type = t[1];
13559
13560 if (multi_parser.token_type === 'TK_EOF') {
13561 break;
13562 }
13563
13564 switch (multi_parser.token_type) {
13565 case 'TK_TAG_START':
13566 multi_parser.print_newline(false, multi_parser.output);
13567 multi_parser.print_token(multi_parser.token_text);
13568 multi_parser.indent();
13569 multi_parser.current_mode = 'CONTENT';
13570 break;
13571 case 'TK_TAG_STYLE':
13572 case 'TK_TAG_SCRIPT':
13573 multi_parser.print_newline(false, multi_parser.output);
13574 multi_parser.print_token(multi_parser.token_text);
13575 multi_parser.current_mode = 'CONTENT';
13576 break;
13577 case 'TK_TAG_END':
13578 //Print new line only if the tag has no content and has child
13579 if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') {
13580 var tag_name = multi_parser.token_text.match(/\w+/)[0];
13581 var tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length -1].match(/<\s*(\w+)/);
13582 if (tag_extracted_from_last_output === null || tag_extracted_from_last_output[1] !== tag_name)
13583 multi_parser.print_newline(true, multi_parser.output);
13584 }
13585 multi_parser.print_token(multi_parser.token_text);
13586 multi_parser.current_mode = 'CONTENT';
13587 break;
13588 case 'TK_TAG_SINGLE':
13589 // Don't add a newline before elements that should remain unformatted.
13590 var tag_check = multi_parser.token_text.match(/^\s*<([a-z]+)/i);
13591 if (!tag_check || !multi_parser.Utils.in_array(tag_check[1], unformatted)){
13592 multi_parser.print_newline(false, multi_parser.output);
13593 }
13594 multi_parser.print_token(multi_parser.token_text);
13595 multi_parser.current_mode = 'CONTENT';
13596 break;
13597 case 'TK_CONTENT':
13598 if (multi_parser.token_text !== '') {
13599 multi_parser.print_token(multi_parser.token_text);
13600 }
13601 multi_parser.current_mode = 'TAG';
13602 break;
13603 case 'TK_STYLE':
13604 case 'TK_SCRIPT':
13605 if (multi_parser.token_text !== '') {
13606 multi_parser.output.push('\n');
13607 var text = multi_parser.token_text;
13608 if (multi_parser.token_type == 'TK_SCRIPT') {
13609 var _beautifier = typeof js_beautify == 'function' && js_beautify;
13610 } else if (multi_parser.token_type == 'TK_STYLE') {
13611 var _beautifier = typeof css_beautify == 'function' && css_beautify;
13612 }
13613
13614 if (options.indent_scripts == "keep") {
13615 var script_indent_level = 0;
13616 } else if (options.indent_scripts == "separate") {
13617 var script_indent_level = -multi_parser.indent_level;
13618 } else {
13619 var script_indent_level = 1;
13620 }
13621
13622 var indentation = multi_parser.get_full_indent(script_indent_level);
13623 if (_beautifier) {
13624 // call the Beautifier if avaliable
13625 text = _beautifier(text.replace(/^\s*/, indentation), options);
13626 } else {
13627 // simply indent the string otherwise
13628 var white = text.match(/^\s*/)[0];
13629 var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1;
13630 var reindent = multi_parser.get_full_indent(script_indent_level -_level);
13631 text = text.replace(/^\s*/, indentation)
13632 .replace(/\r\n|\r|\n/g, '\n' + reindent)
13633 .replace(/\s*$/, '');
13634 }
13635 if (text) {
13636 multi_parser.print_token(text);
13637 multi_parser.print_newline(true, multi_parser.output);
13638 }
13639 }
13640 multi_parser.current_mode = 'TAG';
13641 break;
13642 }
13643 multi_parser.last_token = multi_parser.token_type;
13644 multi_parser.last_text = multi_parser.token_text;
13645 }
13646 return multi_parser.output.join('');
13647 }
13648
13649 module.exports = {
13650 prettyPrint: style_html
13651 };
13652 },{}],19:[function(require,module,exports){
13653 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;
13654
13655
13656 },{}],20:[function(require,module,exports){
13657 (function (global, factory) {
13658 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
13659 typeof define === 'function' && define.amd ? define(factory) :
13660 (global.preactRenderToString = factory());
13661 }(this, (function () {
13662
13663 var NON_DIMENSION_PROPS = {
13664 boxFlex: 1, boxFlexGroup: 1, columnCount: 1, fillOpacity: 1, flex: 1, flexGrow: 1,
13665 flexPositive: 1, flexShrink: 1, flexNegative: 1, fontWeight: 1, lineClamp: 1, lineHeight: 1,
13666 opacity: 1, order: 1, orphans: 1, strokeOpacity: 1, widows: 1, zIndex: 1, zoom: 1
13667 };
13668
13669 var ESC = {
13670 '<': '&lt;',
13671 '>': '&gt;',
13672 '"': '&quot;',
13673 '&': '&amp;'
13674 };
13675
13676 var objectKeys = Object.keys || function (obj) {
13677 var keys = [];
13678 for (var i in obj) {
13679 if (obj.hasOwnProperty(i)) keys.push(i);
13680 }return keys;
13681 };
13682
13683 var encodeEntities = function (s) {
13684 return String(s).replace(/[<>"&]/g, escapeChar);
13685 };
13686
13687 var escapeChar = function (a) {
13688 return ESC[a] || a;
13689 };
13690
13691 var falsey = function (v) {
13692 return v == null || v === false;
13693 };
13694
13695 var memoize = function (fn) {
13696 var mem = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
13697 return function (v) {
13698 return mem[v] || (mem[v] = fn(v));
13699 };
13700 };
13701
13702 var indent = function (s, char) {
13703 return String(s).replace(/(\n+)/g, '$1' + (char || '\t'));
13704 };
13705
13706 var isLargeString = function (s, length, ignoreLines) {
13707 return String(s).length > (length || 40) || !ignoreLines && String(s).indexOf('\n') !== -1 || String(s).indexOf('<') !== -1;
13708 };
13709
13710 function styleObjToCss(s) {
13711 var str = '';
13712 for (var prop in s) {
13713 var val = s[prop];
13714 if (val != null) {
13715 if (str) str += ' ';
13716 str += jsToCss(prop);
13717 str += ': ';
13718 str += val;
13719 if (typeof val === 'number' && !NON_DIMENSION_PROPS[prop]) {
13720 str += 'px';
13721 }
13722 str += ';';
13723 }
13724 }
13725 return str || undefined;
13726 }
13727
13728 function hashToClassName(c) {
13729 var str = '';
13730 for (var prop in c) {
13731 if (c[prop]) {
13732 if (str) str += ' ';
13733 str += prop;
13734 }
13735 }
13736 return str;
13737 }
13738
13739 var jsToCss = memoize(function (s) {
13740 return s.replace(/([A-Z])/g, '-$1').toLowerCase();
13741 });
13742
13743 function assign(obj, props) {
13744 for (var i in props) {
13745 obj[i] = props[i];
13746 }return obj;
13747 }
13748
13749 function getNodeProps(vnode) {
13750 var defaultProps = vnode.nodeName.defaultProps,
13751 props = assign({}, defaultProps || vnode.attributes);
13752 if (defaultProps) assign(props, vnode.attributes);
13753 if (vnode.children) props.children = vnode.children;
13754 return props;
13755 }
13756
13757 var SHALLOW = { shallow: true };
13758
13759 var UNNAMED = [];
13760
13761 var EMPTY = {};
13762
13763 var VOID_ELEMENTS = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
13764
13765 renderToString.render = renderToString;
13766
13767 var shallowRender = function (vnode, context) {
13768 return renderToString(vnode, context, SHALLOW);
13769 };
13770
13771 function renderToString(vnode, context, opts, inner, isSvgMode) {
13772 var _ref = vnode || EMPTY;
13773
13774 var nodeName = _ref.nodeName;
13775 var attributes = _ref.attributes;
13776 var children = _ref.children;
13777 var isComponent = false;
13778 context = context || {};
13779 opts = opts || {};
13780
13781 var pretty = opts.pretty,
13782 indentChar = typeof pretty === 'string' ? pretty : '\t';
13783
13784 if (vnode == null || vnode === false) {
13785 return '';
13786 }
13787
13788 if (!nodeName) {
13789 return encodeEntities(vnode);
13790 }
13791
13792 if (typeof nodeName === 'function') {
13793 isComponent = true;
13794 if (opts.shallow && (inner || opts.renderRootComponent === false)) {
13795 nodeName = getComponentName(nodeName);
13796 } else {
13797 var props = getNodeProps(vnode),
13798 rendered = void 0;
13799
13800 if (!nodeName.prototype || typeof nodeName.prototype.render !== 'function') {
13801 rendered = nodeName(props, context);
13802 } else {
13803 var c = new nodeName(props, context);
13804
13805 c._disable = c.__x = true;
13806 c.props = props;
13807 c.context = context;
13808 if (c.componentWillMount) c.componentWillMount();
13809 rendered = c.render(c.props, c.state, c.context);
13810
13811 if (c.getChildContext) {
13812 context = assign(assign({}, context), c.getChildContext());
13813 }
13814 }
13815
13816 return renderToString(rendered, context, opts, opts.shallowHighOrder !== false);
13817 }
13818 }
13819
13820 var s = '',
13821 html = void 0;
13822
13823 if (attributes) {
13824 var attrs = objectKeys(attributes);
13825
13826 if (opts && opts.sortAttributes === true) attrs.sort();
13827
13828 for (var i = 0; i < attrs.length; i++) {
13829 var name = attrs[i],
13830 v = attributes[name];
13831 if (name === 'children') continue;
13832 if (!(opts && opts.allAttributes) && (name === 'key' || name === 'ref')) continue;
13833
13834 if (name === 'className') {
13835 if (attributes['class']) continue;
13836 name = 'class';
13837 } else if (isSvgMode && name.match(/^xlink\:?(.+)/)) {
13838 name = name.toLowerCase().replace(/^xlink\:?(.+)/, 'xlink:$1');
13839 }
13840
13841 if (name === 'class' && v && typeof v === 'object') {
13842 v = hashToClassName(v);
13843 } else if (name === 'style' && v && typeof v === 'object') {
13844 v = styleObjToCss(v);
13845 }
13846
13847 var hooked = opts.attributeHook && opts.attributeHook(name, v, context, opts, isComponent);
13848 if (hooked || hooked === '') {
13849 s += hooked;
13850 continue;
13851 }
13852
13853 if (name === 'dangerouslySetInnerHTML') {
13854 html = v && v.__html;
13855 } else if ((v || v === 0 || v === '') && typeof v !== 'function') {
13856 if (v === true || v === '') {
13857 v = name;
13858
13859 if (!opts || !opts.xml) {
13860 s += ' ' + name;
13861 continue;
13862 }
13863 }
13864 s += ' ' + name + '="' + encodeEntities(v) + '"';
13865 }
13866 }
13867 }
13868
13869 var sub = s.replace(/^\n\s*/, ' ');
13870 if (sub !== s && !~sub.indexOf('\n')) s = sub;else if (pretty && ~s.indexOf('\n')) s += '\n';
13871
13872 s = '<' + nodeName + s + '>';
13873
13874 if (VOID_ELEMENTS.indexOf(nodeName) > -1) {
13875 s = s.replace(/>$/, ' />');
13876 }
13877
13878 if (html) {
13879 if (pretty && isLargeString(html)) {
13880 html = '\n' + indentChar + indent(html, indentChar);
13881 }
13882 s += html;
13883 } else {
13884 var len = children && children.length,
13885 pieces = [],
13886 hasLarge = ~s.indexOf('\n');
13887 for (var _i = 0; _i < len; _i++) {
13888 var child = children[_i];
13889 if (!falsey(child)) {
13890 var childSvgMode = nodeName === 'svg' ? true : nodeName === 'foreignObject' ? false : isSvgMode,
13891 ret = renderToString(child, context, opts, true, childSvgMode);
13892 if (!hasLarge && pretty && isLargeString(ret)) hasLarge = true;
13893 if (ret) pieces.push(ret);
13894 }
13895 }
13896 if (pretty && hasLarge) {
13897 for (var _i2 = pieces.length; _i2--;) {
13898 pieces[_i2] = '\n' + indentChar + indent(pieces[_i2], indentChar);
13899 }
13900 }
13901 if (pieces.length) {
13902 s += pieces.join('');
13903 } else if (opts && opts.xml) {
13904 return s.substring(0, s.length - 1) + ' />';
13905 }
13906 }
13907
13908 if (opts.jsx || VOID_ELEMENTS.indexOf(nodeName) === -1) {
13909 if (pretty && ~s.indexOf('\n')) s += '\n';
13910 s += '</' + nodeName + '>';
13911 }
13912
13913 return s;
13914 }
13915
13916 function getComponentName(component) {
13917 var proto = component.prototype,
13918 ctor = proto && proto.constructor;
13919 return component.displayName || component.name || proto && (proto.displayName || proto.name) || getFallbackComponentName(component);
13920 }
13921
13922 function getFallbackComponentName(component) {
13923 var str = Function.prototype.toString.call(component),
13924 name = (str.match(/^\s*function\s+([^\( ]+)/) || EMPTY)[1];
13925 if (!name) {
13926 var index = -1;
13927 for (var i = UNNAMED.length; i--;) {
13928 if (UNNAMED[i] === component) {
13929 index = i;
13930 break;
13931 }
13932 }
13933
13934 if (index < 0) {
13935 index = UNNAMED.push(component) - 1;
13936 }
13937 name = 'UnnamedComponent' + index;
13938 }
13939 return name;
13940 }
13941 renderToString.shallowRender = shallowRender;
13942
13943 return renderToString;
13944
13945 })));
13946
13947
13948 },{}],21:[function(require,module,exports){
13949 !function() {
13950 'use strict';
13951 function VNode() {}
13952 function h(nodeName, attributes) {
13953 var lastSimple, child, simple, i, children = EMPTY_CHILDREN;
13954 for (i = arguments.length; i-- > 2; ) stack.push(arguments[i]);
13955 if (attributes && null != attributes.children) {
13956 if (!stack.length) stack.push(attributes.children);
13957 delete attributes.children;
13958 }
13959 while (stack.length) if ((child = stack.pop()) && void 0 !== child.pop) for (i = child.length; i--; ) stack.push(child[i]); else {
13960 if ('boolean' == typeof child) child = null;
13961 if (simple = 'function' != typeof nodeName) if (null == child) child = ''; else if ('number' == typeof child) child = String(child); else if ('string' != typeof child) simple = !1;
13962 if (simple && lastSimple) children[children.length - 1] += child; else if (children === EMPTY_CHILDREN) children = [ child ]; else children.push(child);
13963 lastSimple = simple;
13964 }
13965 var p = new VNode();
13966 p.nodeName = nodeName;
13967 p.children = children;
13968 p.attributes = null == attributes ? void 0 : attributes;
13969 p.key = null == attributes ? void 0 : attributes.key;
13970 if (void 0 !== options.vnode) options.vnode(p);
13971 return p;
13972 }
13973 function extend(obj, props) {
13974 for (var i in props) obj[i] = props[i];
13975 return obj;
13976 }
13977 function cloneElement(vnode, props) {
13978 return h(vnode.nodeName, extend(extend({}, vnode.attributes), props), arguments.length > 2 ? [].slice.call(arguments, 2) : vnode.children);
13979 }
13980 function enqueueRender(component) {
13981 if (!component.__d && (component.__d = !0) && 1 == items.push(component)) (options.debounceRendering || defer)(rerender);
13982 }
13983 function rerender() {
13984 var p, list = items;
13985 items = [];
13986 while (p = list.pop()) if (p.__d) renderComponent(p);
13987 }
13988 function isSameNodeType(node, vnode, hydrating) {
13989 if ('string' == typeof vnode || 'number' == typeof vnode) return void 0 !== node.splitText;
13990 if ('string' == typeof vnode.nodeName) return !node._componentConstructor && isNamedNode(node, vnode.nodeName); else return hydrating || node._componentConstructor === vnode.nodeName;
13991 }
13992 function isNamedNode(node, nodeName) {
13993 return node.__n === nodeName || node.nodeName.toLowerCase() === nodeName.toLowerCase();
13994 }
13995 function getNodeProps(vnode) {
13996 var props = extend({}, vnode.attributes);
13997 props.children = vnode.children;
13998 var defaultProps = vnode.nodeName.defaultProps;
13999 if (void 0 !== defaultProps) for (var i in defaultProps) if (void 0 === props[i]) props[i] = defaultProps[i];
14000 return props;
14001 }
14002 function createNode(nodeName, isSvg) {
14003 var node = isSvg ? document.createElementNS('http://www.w3.org/2000/svg', nodeName) : document.createElement(nodeName);
14004 node.__n = nodeName;
14005 return node;
14006 }
14007 function removeNode(node) {
14008 var parentNode = node.parentNode;
14009 if (parentNode) parentNode.removeChild(node);
14010 }
14011 function setAccessor(node, name, old, value, isSvg) {
14012 if ('className' === name) name = 'class';
14013 if ('key' === name) ; else if ('ref' === name) {
14014 if (old) old(null);
14015 if (value) value(node);
14016 } else if ('class' === name && !isSvg) node.className = value || ''; else if ('style' === name) {
14017 if (!value || 'string' == typeof value || 'string' == typeof old) node.style.cssText = value || '';
14018 if (value && 'object' == typeof value) {
14019 if ('string' != typeof old) for (var i in old) if (!(i in value)) node.style[i] = '';
14020 for (var i in value) node.style[i] = 'number' == typeof value[i] && !1 === IS_NON_DIMENSIONAL.test(i) ? value[i] + 'px' : value[i];
14021 }
14022 } else if ('dangerouslySetInnerHTML' === name) {
14023 if (value) node.innerHTML = value.__html || '';
14024 } else if ('o' == name[0] && 'n' == name[1]) {
14025 var useCapture = name !== (name = name.replace(/Capture$/, ''));
14026 name = name.toLowerCase().substring(2);
14027 if (value) {
14028 if (!old) node.addEventListener(name, eventProxy, useCapture);
14029 } else node.removeEventListener(name, eventProxy, useCapture);
14030 (node.__l || (node.__l = {}))[name] = value;
14031 } else if ('list' !== name && 'type' !== name && !isSvg && name in node) {
14032 setProperty(node, name, null == value ? '' : value);
14033 if (null == value || !1 === value) node.removeAttribute(name);
14034 } else {
14035 var ns = isSvg && name !== (name = name.replace(/^xlink\:?/, ''));
14036 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);
14037 }
14038 }
14039 function setProperty(node, name, value) {
14040 try {
14041 node[name] = value;
14042 } catch (e) {}
14043 }
14044 function eventProxy(e) {
14045 return this.__l[e.type](options.event && options.event(e) || e);
14046 }
14047 function flushMounts() {
14048 var c;
14049 while (c = mounts.pop()) {
14050 if (options.afterMount) options.afterMount(c);
14051 if (c.componentDidMount) c.componentDidMount();
14052 }
14053 }
14054 function diff(dom, vnode, context, mountAll, parent, componentRoot) {
14055 if (!diffLevel++) {
14056 isSvgMode = null != parent && void 0 !== parent.ownerSVGElement;
14057 hydrating = null != dom && !('__preactattr_' in dom);
14058 }
14059 var ret = idiff(dom, vnode, context, mountAll, componentRoot);
14060 if (parent && ret.parentNode !== parent) parent.appendChild(ret);
14061 if (!--diffLevel) {
14062 hydrating = !1;
14063 if (!componentRoot) flushMounts();
14064 }
14065 return ret;
14066 }
14067 function idiff(dom, vnode, context, mountAll, componentRoot) {
14068 var out = dom, prevSvgMode = isSvgMode;
14069 if (null == vnode || 'boolean' == typeof vnode) vnode = '';
14070 if ('string' == typeof vnode || 'number' == typeof vnode) {
14071 if (dom && void 0 !== dom.splitText && dom.parentNode && (!dom._component || componentRoot)) {
14072 if (dom.nodeValue != vnode) dom.nodeValue = vnode;
14073 } else {
14074 out = document.createTextNode(vnode);
14075 if (dom) {
14076 if (dom.parentNode) dom.parentNode.replaceChild(out, dom);
14077 recollectNodeTree(dom, !0);
14078 }
14079 }
14080 out.__preactattr_ = !0;
14081 return out;
14082 }
14083 var vnodeName = vnode.nodeName;
14084 if ('function' == typeof vnodeName) return buildComponentFromVNode(dom, vnode, context, mountAll);
14085 isSvgMode = 'svg' === vnodeName ? !0 : 'foreignObject' === vnodeName ? !1 : isSvgMode;
14086 vnodeName = String(vnodeName);
14087 if (!dom || !isNamedNode(dom, vnodeName)) {
14088 out = createNode(vnodeName, isSvgMode);
14089 if (dom) {
14090 while (dom.firstChild) out.appendChild(dom.firstChild);
14091 if (dom.parentNode) dom.parentNode.replaceChild(out, dom);
14092 recollectNodeTree(dom, !0);
14093 }
14094 }
14095 var fc = out.firstChild, props = out.__preactattr_, vchildren = vnode.children;
14096 if (null == props) {
14097 props = out.__preactattr_ = {};
14098 for (var a = out.attributes, i = a.length; i--; ) props[a[i].name] = a[i].value;
14099 }
14100 if (!hydrating && vchildren && 1 === vchildren.length && 'string' == typeof vchildren[0] && null != fc && void 0 !== fc.splitText && null == fc.nextSibling) {
14101 if (fc.nodeValue != vchildren[0]) fc.nodeValue = vchildren[0];
14102 } else if (vchildren && vchildren.length || null != fc) innerDiffNode(out, vchildren, context, mountAll, hydrating || null != props.dangerouslySetInnerHTML);
14103 diffAttributes(out, vnode.attributes, props);
14104 isSvgMode = prevSvgMode;
14105 return out;
14106 }
14107 function innerDiffNode(dom, vchildren, context, mountAll, isHydrating) {
14108 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;
14109 if (0 !== len) for (var i = 0; i < len; i++) {
14110 var _child = originalChildren[i], props = _child.__preactattr_, key = vlen && props ? _child._component ? _child._component.__k : props.key : null;
14111 if (null != key) {
14112 keyedLen++;
14113 keyed[key] = _child;
14114 } else if (props || (void 0 !== _child.splitText ? isHydrating ? _child.nodeValue.trim() : !0 : isHydrating)) children[childrenLen++] = _child;
14115 }
14116 if (0 !== vlen) for (var i = 0; i < vlen; i++) {
14117 vchild = vchildren[i];
14118 child = null;
14119 var key = vchild.key;
14120 if (null != key) {
14121 if (keyedLen && void 0 !== keyed[key]) {
14122 child = keyed[key];
14123 keyed[key] = void 0;
14124 keyedLen--;
14125 }
14126 } else if (!child && min < childrenLen) for (j = min; j < childrenLen; j++) if (void 0 !== children[j] && isSameNodeType(c = children[j], vchild, isHydrating)) {
14127 child = c;
14128 children[j] = void 0;
14129 if (j === childrenLen - 1) childrenLen--;
14130 if (j === min) min++;
14131 break;
14132 }
14133 child = idiff(child, vchild, context, mountAll);
14134 f = originalChildren[i];
14135 if (child && child !== dom && child !== f) if (null == f) dom.appendChild(child); else if (child === f.nextSibling) removeNode(f); else dom.insertBefore(child, f);
14136 }
14137 if (keyedLen) for (var i in keyed) if (void 0 !== keyed[i]) recollectNodeTree(keyed[i], !1);
14138 while (min <= childrenLen) if (void 0 !== (child = children[childrenLen--])) recollectNodeTree(child, !1);
14139 }
14140 function recollectNodeTree(node, unmountOnly) {
14141 var component = node._component;
14142 if (component) unmountComponent(component); else {
14143 if (null != node.__preactattr_ && node.__preactattr_.ref) node.__preactattr_.ref(null);
14144 if (!1 === unmountOnly || null == node.__preactattr_) removeNode(node);
14145 removeChildren(node);
14146 }
14147 }
14148 function removeChildren(node) {
14149 node = node.lastChild;
14150 while (node) {
14151 var next = node.previousSibling;
14152 recollectNodeTree(node, !0);
14153 node = next;
14154 }
14155 }
14156 function diffAttributes(dom, attrs, old) {
14157 var name;
14158 for (name in old) if ((!attrs || null == attrs[name]) && null != old[name]) setAccessor(dom, name, old[name], old[name] = void 0, isSvgMode);
14159 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);
14160 }
14161 function collectComponent(component) {
14162 var name = component.constructor.name;
14163 (components[name] || (components[name] = [])).push(component);
14164 }
14165 function createComponent(Ctor, props, context) {
14166 var inst, list = components[Ctor.name];
14167 if (Ctor.prototype && Ctor.prototype.render) {
14168 inst = new Ctor(props, context);
14169 Component.call(inst, props, context);
14170 } else {
14171 inst = new Component(props, context);
14172 inst.constructor = Ctor;
14173 inst.render = doRender;
14174 }
14175 if (list) for (var i = list.length; i--; ) if (list[i].constructor === Ctor) {
14176 inst.__b = list[i].__b;
14177 list.splice(i, 1);
14178 break;
14179 }
14180 return inst;
14181 }
14182 function doRender(props, state, context) {
14183 return this.constructor(props, context);
14184 }
14185 function setComponentProps(component, props, opts, context, mountAll) {
14186 if (!component.__x) {
14187 component.__x = !0;
14188 if (component.__r = props.ref) delete props.ref;
14189 if (component.__k = props.key) delete props.key;
14190 if (!component.base || mountAll) {
14191 if (component.componentWillMount) component.componentWillMount();
14192 } else if (component.componentWillReceiveProps) component.componentWillReceiveProps(props, context);
14193 if (context && context !== component.context) {
14194 if (!component.__c) component.__c = component.context;
14195 component.context = context;
14196 }
14197 if (!component.__p) component.__p = component.props;
14198 component.props = props;
14199 component.__x = !1;
14200 if (0 !== opts) if (1 === opts || !1 !== options.syncComponentUpdates || !component.base) renderComponent(component, 1, mountAll); else enqueueRender(component);
14201 if (component.__r) component.__r(component);
14202 }
14203 }
14204 function renderComponent(component, opts, mountAll, isChild) {
14205 if (!component.__x) {
14206 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;
14207 if (isUpdate) {
14208 component.props = previousProps;
14209 component.state = previousState;
14210 component.context = previousContext;
14211 if (2 !== opts && component.shouldComponentUpdate && !1 === component.shouldComponentUpdate(props, state, context)) skip = !0; else if (component.componentWillUpdate) component.componentWillUpdate(props, state, context);
14212 component.props = props;
14213 component.state = state;
14214 component.context = context;
14215 }
14216 component.__p = component.__s = component.__c = component.__b = null;
14217 component.__d = !1;
14218 if (!skip) {
14219 rendered = component.render(props, state, context);
14220 if (component.getChildContext) context = extend(extend({}, context), component.getChildContext());
14221 var toUnmount, base, childComponent = rendered && rendered.nodeName;
14222 if ('function' == typeof childComponent) {
14223 var childProps = getNodeProps(rendered);
14224 inst = initialChildComponent;
14225 if (inst && inst.constructor === childComponent && childProps.key == inst.__k) setComponentProps(inst, childProps, 1, context, !1); else {
14226 toUnmount = inst;
14227 component._component = inst = createComponent(childComponent, childProps, context);
14228 inst.__b = inst.__b || nextBase;
14229 inst.__u = component;
14230 setComponentProps(inst, childProps, 0, context, !1);
14231 renderComponent(inst, 1, mountAll, !0);
14232 }
14233 base = inst.base;
14234 } else {
14235 cbase = initialBase;
14236 toUnmount = initialChildComponent;
14237 if (toUnmount) cbase = component._component = null;
14238 if (initialBase || 1 === opts) {
14239 if (cbase) cbase._component = null;
14240 base = diff(cbase, rendered, context, mountAll || !isUpdate, initialBase && initialBase.parentNode, !0);
14241 }
14242 }
14243 if (initialBase && base !== initialBase && inst !== initialChildComponent) {
14244 var baseParent = initialBase.parentNode;
14245 if (baseParent && base !== baseParent) {
14246 baseParent.replaceChild(base, initialBase);
14247 if (!toUnmount) {
14248 initialBase._component = null;
14249 recollectNodeTree(initialBase, !1);
14250 }
14251 }
14252 }
14253 if (toUnmount) unmountComponent(toUnmount);
14254 component.base = base;
14255 if (base && !isChild) {
14256 var componentRef = component, t = component;
14257 while (t = t.__u) (componentRef = t).base = base;
14258 base._component = componentRef;
14259 base._componentConstructor = componentRef.constructor;
14260 }
14261 }
14262 if (!isUpdate || mountAll) mounts.unshift(component); else if (!skip) {
14263 if (component.componentDidUpdate) component.componentDidUpdate(previousProps, previousState, previousContext);
14264 if (options.afterUpdate) options.afterUpdate(component);
14265 }
14266 if (null != component.__h) while (component.__h.length) component.__h.pop().call(component);
14267 if (!diffLevel && !isChild) flushMounts();
14268 }
14269 }
14270 function buildComponentFromVNode(dom, vnode, context, mountAll) {
14271 var c = dom && dom._component, originalComponent = c, oldDom = dom, isDirectOwner = c && dom._componentConstructor === vnode.nodeName, isOwner = isDirectOwner, props = getNodeProps(vnode);
14272 while (c && !isOwner && (c = c.__u)) isOwner = c.constructor === vnode.nodeName;
14273 if (c && isOwner && (!mountAll || c._component)) {
14274 setComponentProps(c, props, 3, context, mountAll);
14275 dom = c.base;
14276 } else {
14277 if (originalComponent && !isDirectOwner) {
14278 unmountComponent(originalComponent);
14279 dom = oldDom = null;
14280 }
14281 c = createComponent(vnode.nodeName, props, context);
14282 if (dom && !c.__b) {
14283 c.__b = dom;
14284 oldDom = null;
14285 }
14286 setComponentProps(c, props, 1, context, mountAll);
14287 dom = c.base;
14288 if (oldDom && dom !== oldDom) {
14289 oldDom._component = null;
14290 recollectNodeTree(oldDom, !1);
14291 }
14292 }
14293 return dom;
14294 }
14295 function unmountComponent(component) {
14296 if (options.beforeUnmount) options.beforeUnmount(component);
14297 var base = component.base;
14298 component.__x = !0;
14299 if (component.componentWillUnmount) component.componentWillUnmount();
14300 component.base = null;
14301 var inner = component._component;
14302 if (inner) unmountComponent(inner); else if (base) {
14303 if (base.__preactattr_ && base.__preactattr_.ref) base.__preactattr_.ref(null);
14304 component.__b = base;
14305 removeNode(base);
14306 collectComponent(component);
14307 removeChildren(base);
14308 }
14309 if (component.__r) component.__r(null);
14310 }
14311 function Component(props, context) {
14312 this.__d = !0;
14313 this.context = context;
14314 this.props = props;
14315 this.state = this.state || {};
14316 }
14317 function render(vnode, parent, merge) {
14318 return diff(merge, vnode, {}, !1, parent, !1);
14319 }
14320 var options = {};
14321 var stack = [];
14322 var EMPTY_CHILDREN = [];
14323 var defer = 'function' == typeof Promise ? Promise.resolve().then.bind(Promise.resolve()) : setTimeout;
14324 var IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i;
14325 var items = [];
14326 var mounts = [];
14327 var diffLevel = 0;
14328 var isSvgMode = !1;
14329 var hydrating = !1;
14330 var components = {};
14331 extend(Component.prototype, {
14332 setState: function(state, callback) {
14333 var s = this.state;
14334 if (!this.__s) this.__s = extend({}, s);
14335 extend(s, 'function' == typeof state ? state(s, this.props) : state);
14336 if (callback) (this.__h = this.__h || []).push(callback);
14337 enqueueRender(this);
14338 },
14339 forceUpdate: function(callback) {
14340 if (callback) (this.__h = this.__h || []).push(callback);
14341 renderComponent(this, 2);
14342 },
14343 render: function() {}
14344 });
14345 var preact = {
14346 h: h,
14347 createElement: h,
14348 cloneElement: cloneElement,
14349 Component: Component,
14350 render: render,
14351 rerender: rerender,
14352 options: options
14353 };
14354 if ('undefined' != typeof module) module.exports = preact; else self.preact = preact;
14355 }();
14356
14357 },{}]},{},[2]);
14358 ; })();