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

14,544 lines 552.5 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`
1678 // satisfies `pred`. Supports `from` being greater than `to`.
1679 function findFirst(pred, from, to) {
1680 // At any point we are certain `to` satisfies `pred`, don't know
1681 // whether `from` does.
1682 var dir = from > to ? -1 : 1;
1683 for (;;) {
1684 if (from == to) { return from }
1685 var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF);
1686 if (mid == from) { return pred(mid) ? from : to }
1687 if (pred(mid)) { to = mid; }
1688 else { from = mid + dir; }
1689 }
1690 }
1691
1692 // The display handles the DOM integration, both for input reading
1693 // and content drawing. It holds references to DOM nodes and
1694 // display-related state.
1695
1696 function Display(place, doc, input) {
1697 var d = this;
1698 this.input = input;
1699
1700 // Covers bottom-right square when both scrollbars are present.
1701 d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
1702 d.scrollbarFiller.setAttribute("cm-not-content", "true");
1703 // Covers bottom of gutter when coverGutterNextToScrollbar is on
1704 // and h scrollbar is present.
1705 d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
1706 d.gutterFiller.setAttribute("cm-not-content", "true");
1707 // Will contain the actual code, positioned to cover the viewport.
1708 d.lineDiv = eltP("div", null, "CodeMirror-code");
1709 // Elements are added to these to represent selection and cursors.
1710 d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
1711 d.cursorDiv = elt("div", null, "CodeMirror-cursors");
1712 // A visibility: hidden element used to find the size of things.
1713 d.measure = elt("div", null, "CodeMirror-measure");
1714 // When lines outside of the viewport are measured, they are drawn in this.
1715 d.lineMeasure = elt("div", null, "CodeMirror-measure");
1716 // Wraps everything that needs to exist inside the vertically-padded coordinate system
1717 d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
1718 null, "position: relative; outline: none");
1719 var lines = eltP("div", [d.lineSpace], "CodeMirror-lines");
1720 // Moved around its parent to cover visible view.
1721 d.mover = elt("div", [lines], null, "position: relative");
1722 // Set to the height of the document, allowing scrolling.
1723 d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
1724 d.sizerWidth = null;
1725 // Behavior of elts with overflow: auto and padding is
1726 // inconsistent across browsers. This is used to ensure the
1727 // scrollable area is big enough.
1728 d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
1729 // Will contain the gutters, if any.
1730 d.gutters = elt("div", null, "CodeMirror-gutters");
1731 d.lineGutter = null;
1732 // Actual scrollable element.
1733 d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
1734 d.scroller.setAttribute("tabIndex", "-1");
1735 // The element in which the editor lives.
1736 d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
1737
1738 // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
1739 if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
1740 if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; }
1741
1742 if (place) {
1743 if (place.appendChild) { place.appendChild(d.wrapper); }
1744 else { place(d.wrapper); }
1745 }
1746
1747 // Current rendered range (may be bigger than the view window).
1748 d.viewFrom = d.viewTo = doc.first;
1749 d.reportedViewFrom = d.reportedViewTo = doc.first;
1750 // Information about the rendered lines.
1751 d.view = [];
1752 d.renderedView = null;
1753 // Holds info about a single rendered line when it was rendered
1754 // for measurement, while not in view.
1755 d.externalMeasured = null;
1756 // Empty space (in pixels) above the view
1757 d.viewOffset = 0;
1758 d.lastWrapHeight = d.lastWrapWidth = 0;
1759 d.updateLineNumbers = null;
1760
1761 d.nativeBarWidth = d.barHeight = d.barWidth = 0;
1762 d.scrollbarsClipped = false;
1763
1764 // Used to only resize the line number gutter when necessary (when
1765 // the amount of lines crosses a boundary that makes its width change)
1766 d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
1767 // Set to true when a non-horizontal-scrolling line widget is
1768 // added. As an optimization, line widget aligning is skipped when
1769 // this is false.
1770 d.alignWidgets = false;
1771
1772 d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
1773
1774 // Tracks the maximum line length so that the horizontal scrollbar
1775 // can be kept static when scrolling.
1776 d.maxLine = null;
1777 d.maxLineLength = 0;
1778 d.maxLineChanged = false;
1779
1780 // Used for measuring wheel scrolling granularity
1781 d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
1782
1783 // True when shift is held down.
1784 d.shift = false;
1785
1786 // Used to track whether anything happened since the context menu
1787 // was opened.
1788 d.selForContextMenu = null;
1789
1790 d.activeTouch = null;
1791
1792 input.init(d);
1793 }
1794
1795 // Find the line object corresponding to the given line number.
1796 function getLine(doc, n) {
1797 n -= doc.first;
1798 if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
1799 var chunk = doc;
1800 while (!chunk.lines) {
1801 for (var i = 0;; ++i) {
1802 var child = chunk.children[i], sz = child.chunkSize();
1803 if (n < sz) { chunk = child; break }
1804 n -= sz;
1805 }
1806 }
1807 return chunk.lines[n]
1808 }
1809
1810 // Get the part of a document between two positions, as an array of
1811 // strings.
1812 function getBetween(doc, start, end) {
1813 var out = [], n = start.line;
1814 doc.iter(start.line, end.line + 1, function (line) {
1815 var text = line.text;
1816 if (n == end.line) { text = text.slice(0, end.ch); }
1817 if (n == start.line) { text = text.slice(start.ch); }
1818 out.push(text);
1819 ++n;
1820 });
1821 return out
1822 }
1823 // Get the lines between from and to, as array of strings.
1824 function getLines(doc, from, to) {
1825 var out = [];
1826 doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value
1827 return out
1828 }
1829
1830 // Update the height of a line, propagating the height change
1831 // upwards to parent nodes.
1832 function updateLineHeight(line, height) {
1833 var diff = height - line.height;
1834 if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } }
1835 }
1836
1837 // Given a line object, find its line number by walking up through
1838 // its parent links.
1839 function lineNo(line) {
1840 if (line.parent == null) { return null }
1841 var cur = line.parent, no = indexOf(cur.lines, line);
1842 for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
1843 for (var i = 0;; ++i) {
1844 if (chunk.children[i] == cur) { break }
1845 no += chunk.children[i].chunkSize();
1846 }
1847 }
1848 return no + cur.first
1849 }
1850
1851 // Find the line at the given vertical position, using the height
1852 // information in the document tree.
1853 function lineAtHeight(chunk, h) {
1854 var n = chunk.first;
1855 outer: do {
1856 for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
1857 var child = chunk.children[i$1], ch = child.height;
1858 if (h < ch) { chunk = child; continue outer }
1859 h -= ch;
1860 n += child.chunkSize();
1861 }
1862 return n
1863 } while (!chunk.lines)
1864 var i = 0;
1865 for (; i < chunk.lines.length; ++i) {
1866 var line = chunk.lines[i], lh = line.height;
1867 if (h < lh) { break }
1868 h -= lh;
1869 }
1870 return n + i
1871 }
1872
1873 function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
1874
1875 function lineNumberFor(options, i) {
1876 return String(options.lineNumberFormatter(i + options.firstLineNumber))
1877 }
1878
1879 // A Pos instance represents a position within the text.
1880 function Pos(line, ch, sticky) {
1881 if ( sticky === void 0 ) sticky = null;
1882
1883 if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }
1884 this.line = line;
1885 this.ch = ch;
1886 this.sticky = sticky;
1887 }
1888
1889 // Compare two positions, return 0 if they are the same, a negative
1890 // number when a is less, and a positive number otherwise.
1891 function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
1892
1893 function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }
1894
1895 function copyPos(x) {return Pos(x.line, x.ch)}
1896 function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
1897 function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
1898
1899 // Most of the external API clips given positions to make sure they
1900 // actually exist within the document.
1901 function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
1902 function clipPos(doc, pos) {
1903 if (pos.line < doc.first) { return Pos(doc.first, 0) }
1904 var last = doc.first + doc.size - 1;
1905 if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
1906 return clipToLen(pos, getLine(doc, pos.line).text.length)
1907 }
1908 function clipToLen(pos, linelen) {
1909 var ch = pos.ch;
1910 if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
1911 else if (ch < 0) { return Pos(pos.line, 0) }
1912 else { return pos }
1913 }
1914 function clipPosArray(doc, array) {
1915 var out = [];
1916 for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); }
1917 return out
1918 }
1919
1920 // Optimize some code when these features are not used.
1921 var sawReadOnlySpans = false;
1922 var sawCollapsedSpans = false;
1923
1924 function seeReadOnlySpans() {
1925 sawReadOnlySpans = true;
1926 }
1927
1928 function seeCollapsedSpans() {
1929 sawCollapsedSpans = true;
1930 }
1931
1932 // TEXTMARKER SPANS
1933
1934 function MarkedSpan(marker, from, to) {
1935 this.marker = marker;
1936 this.from = from; this.to = to;
1937 }
1938
1939 // Search an array of spans for a span matching the given marker.
1940 function getMarkedSpanFor(spans, marker) {
1941 if (spans) { for (var i = 0; i < spans.length; ++i) {
1942 var span = spans[i];
1943 if (span.marker == marker) { return span }
1944 } }
1945 }
1946 // Remove a span from an array, returning undefined if no spans are
1947 // left (we don't store arrays for lines without spans).
1948 function removeMarkedSpan(spans, span) {
1949 var r;
1950 for (var i = 0; i < spans.length; ++i)
1951 { if (spans[i] != span) { (r || (r = [])).push(spans[i]); } }
1952 return r
1953 }
1954 // Add a span to a line.
1955 function addMarkedSpan(line, span) {
1956 line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
1957 span.marker.attachLine(line);
1958 }
1959
1960 // Used for the algorithm that adjusts markers for a change in the
1961 // document. These functions cut an array of spans at a given
1962 // character position, returning an array of remaining chunks (or
1963 // undefined if nothing remains).
1964 function markedSpansBefore(old, startCh, isInsert) {
1965 var nw;
1966 if (old) { for (var i = 0; i < old.length; ++i) {
1967 var span = old[i], marker = span.marker;
1968 var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
1969 if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
1970 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));
1971 }
1972 } }
1973 return nw
1974 }
1975 function markedSpansAfter(old, endCh, isInsert) {
1976 var nw;
1977 if (old) { for (var i = 0; i < old.length; ++i) {
1978 var span = old[i], marker = span.marker;
1979 var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
1980 if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
1981 var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
1982 span.to == null ? null : span.to - endCh));
1983 }
1984 } }
1985 return nw
1986 }
1987
1988 // Given a change object, compute the new set of marker spans that
1989 // cover the line in which the change took place. Removes spans
1990 // entirely within the change, reconnects spans belonging to the
1991 // same marker that appear on both sides of the change, and cuts off
1992 // spans partially within the change. Returns an array of span
1993 // arrays with one element for each line in (after) the change.
1994 function stretchSpansOverChange(doc, change) {
1995 if (change.full) { return null }
1996 var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
1997 var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
1998 if (!oldFirst && !oldLast) { return null }
1999
2000 var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
2001 // Get the spans that 'stick out' on both sides
2002 var first = markedSpansBefore(oldFirst, startCh, isInsert);
2003 var last = markedSpansAfter(oldLast, endCh, isInsert);
2004
2005 // Next, merge those two ends
2006 var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
2007 if (first) {
2008 // Fix up .to properties of first
2009 for (var i = 0; i < first.length; ++i) {
2010 var span = first[i];
2011 if (span.to == null) {
2012 var found = getMarkedSpanFor(last, span.marker);
2013 if (!found) { span.to = startCh; }
2014 else if (sameLine) { span.to = found.to == null ? null : found.to + offset; }
2015 }
2016 }
2017 }
2018 if (last) {
2019 // Fix up .from in last (or move them into first in case of sameLine)
2020 for (var i$1 = 0; i$1 < last.length; ++i$1) {
2021 var span$1 = last[i$1];
2022 if (span$1.to != null) { span$1.to += offset; }
2023 if (span$1.from == null) {
2024 var found$1 = getMarkedSpanFor(first, span$1.marker);
2025 if (!found$1) {
2026 span$1.from = offset;
2027 if (sameLine) { (first || (first = [])).push(span$1); }
2028 }
2029 } else {
2030 span$1.from += offset;
2031 if (sameLine) { (first || (first = [])).push(span$1); }
2032 }
2033 }
2034 }
2035 // Make sure we didn't create any zero-length spans
2036 if (first) { first = clearEmptySpans(first); }
2037 if (last && last != first) { last = clearEmptySpans(last); }
2038
2039 var newMarkers = [first];
2040 if (!sameLine) {
2041 // Fill gap with whole-line-spans
2042 var gap = change.text.length - 2, gapMarkers;
2043 if (gap > 0 && first)
2044 { for (var i$2 = 0; i$2 < first.length; ++i$2)
2045 { if (first[i$2].to == null)
2046 { (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } }
2047 for (var i$3 = 0; i$3 < gap; ++i$3)
2048 { newMarkers.push(gapMarkers); }
2049 newMarkers.push(last);
2050 }
2051 return newMarkers
2052 }
2053
2054 // Remove spans that are empty and don't have a clearWhenEmpty
2055 // option of false.
2056 function clearEmptySpans(spans) {
2057 for (var i = 0; i < spans.length; ++i) {
2058 var span = spans[i];
2059 if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
2060 { spans.splice(i--, 1); }
2061 }
2062 if (!spans.length) { return null }
2063 return spans
2064 }
2065
2066 // Used to 'clip' out readOnly ranges when making a change.
2067 function removeReadOnlyRanges(doc, from, to) {
2068 var markers = null;
2069 doc.iter(from.line, to.line + 1, function (line) {
2070 if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
2071 var mark = line.markedSpans[i].marker;
2072 if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
2073 { (markers || (markers = [])).push(mark); }
2074 } }
2075 });
2076 if (!markers) { return null }
2077 var parts = [{from: from, to: to}];
2078 for (var i = 0; i < markers.length; ++i) {
2079 var mk = markers[i], m = mk.find(0);
2080 for (var j = 0; j < parts.length; ++j) {
2081 var p = parts[j];
2082 if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
2083 var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
2084 if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
2085 { newParts.push({from: p.from, to: m.from}); }
2086 if (dto > 0 || !mk.inclusiveRight && !dto)
2087 { newParts.push({from: m.to, to: p.to}); }
2088 parts.splice.apply(parts, newParts);
2089 j += newParts.length - 3;
2090 }
2091 }
2092 return parts
2093 }
2094
2095 // Connect or disconnect spans from a line.
2096 function detachMarkedSpans(line) {
2097 var spans = line.markedSpans;
2098 if (!spans) { return }
2099 for (var i = 0; i < spans.length; ++i)
2100 { spans[i].marker.detachLine(line); }
2101 line.markedSpans = null;
2102 }
2103 function attachMarkedSpans(line, spans) {
2104 if (!spans) { return }
2105 for (var i = 0; i < spans.length; ++i)
2106 { spans[i].marker.attachLine(line); }
2107 line.markedSpans = spans;
2108 }
2109
2110 // Helpers used when computing which overlapping collapsed span
2111 // counts as the larger one.
2112 function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
2113 function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
2114
2115 // Returns a number indicating which of two overlapping collapsed
2116 // spans is larger (and thus includes the other). Falls back to
2117 // comparing ids when the spans cover exactly the same range.
2118 function compareCollapsedMarkers(a, b) {
2119 var lenDiff = a.lines.length - b.lines.length;
2120 if (lenDiff != 0) { return lenDiff }
2121 var aPos = a.find(), bPos = b.find();
2122 var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
2123 if (fromCmp) { return -fromCmp }
2124 var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
2125 if (toCmp) { return toCmp }
2126 return b.id - a.id
2127 }
2128
2129 // Find out whether a line ends or starts in a collapsed span. If
2130 // so, return the marker for that span.
2131 function collapsedSpanAtSide(line, start) {
2132 var sps = sawCollapsedSpans && line.markedSpans, found;
2133 if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
2134 sp = sps[i];
2135 if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
2136 (!found || compareCollapsedMarkers(found, sp.marker) < 0))
2137 { found = sp.marker; }
2138 } }
2139 return found
2140 }
2141 function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
2142 function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
2143
2144 // Test whether there exists a collapsed span that partially
2145 // overlaps (covers the start or end, but not both) of a new span.
2146 // Such overlap is not allowed.
2147 function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) {
2148 var line = getLine(doc, lineNo$$1);
2149 var sps = sawCollapsedSpans && line.markedSpans;
2150 if (sps) { for (var i = 0; i < sps.length; ++i) {
2151 var sp = sps[i];
2152 if (!sp.marker.collapsed) { continue }
2153 var found = sp.marker.find(0);
2154 var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
2155 var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
2156 if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
2157 if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
2158 fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
2159 { return true }
2160 } }
2161 }
2162
2163 // A visual line is a line as drawn on the screen. Folding, for
2164 // example, can cause multiple logical lines to appear on the same
2165 // visual line. This finds the start of the visual line that the
2166 // given line is part of (usually that is the line itself).
2167 function visualLine(line) {
2168 var merged;
2169 while (merged = collapsedSpanAtStart(line))
2170 { line = merged.find(-1, true).line; }
2171 return line
2172 }
2173
2174 function visualLineEnd(line) {
2175 var merged;
2176 while (merged = collapsedSpanAtEnd(line))
2177 { line = merged.find(1, true).line; }
2178 return line
2179 }
2180
2181 // Returns an array of logical lines that continue the visual line
2182 // started by the argument, or undefined if there are no such lines.
2183 function visualLineContinued(line) {
2184 var merged, lines;
2185 while (merged = collapsedSpanAtEnd(line)) {
2186 line = merged.find(1, true).line
2187 ;(lines || (lines = [])).push(line);
2188 }
2189 return lines
2190 }
2191
2192 // Get the line number of the start of the visual line that the
2193 // given line number is part of.
2194 function visualLineNo(doc, lineN) {
2195 var line = getLine(doc, lineN), vis = visualLine(line);
2196 if (line == vis) { return lineN }
2197 return lineNo(vis)
2198 }
2199
2200 // Get the line number of the start of the next visual line after
2201 // the given line.
2202 function visualLineEndNo(doc, lineN) {
2203 if (lineN > doc.lastLine()) { return lineN }
2204 var line = getLine(doc, lineN), merged;
2205 if (!lineIsHidden(doc, line)) { return lineN }
2206 while (merged = collapsedSpanAtEnd(line))
2207 { line = merged.find(1, true).line; }
2208 return lineNo(line) + 1
2209 }
2210
2211 // Compute whether a line is hidden. Lines count as hidden when they
2212 // are part of a visual line that starts with another line, or when
2213 // they are entirely covered by collapsed, non-widget span.
2214 function lineIsHidden(doc, line) {
2215 var sps = sawCollapsedSpans && line.markedSpans;
2216 if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
2217 sp = sps[i];
2218 if (!sp.marker.collapsed) { continue }
2219 if (sp.from == null) { return true }
2220 if (sp.marker.widgetNode) { continue }
2221 if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
2222 { return true }
2223 } }
2224 }
2225 function lineIsHiddenInner(doc, line, span) {
2226 if (span.to == null) {
2227 var end = span.marker.find(1, true);
2228 return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
2229 }
2230 if (span.marker.inclusiveRight && span.to == line.text.length)
2231 { return true }
2232 for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {
2233 sp = line.markedSpans[i];
2234 if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
2235 (sp.to == null || sp.to != span.from) &&
2236 (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
2237 lineIsHiddenInner(doc, line, sp)) { return true }
2238 }
2239 }
2240
2241 // Find the height above the given line.
2242 function heightAtLine(lineObj) {
2243 lineObj = visualLine(lineObj);
2244
2245 var h = 0, chunk = lineObj.parent;
2246 for (var i = 0; i < chunk.lines.length; ++i) {
2247 var line = chunk.lines[i];
2248 if (line == lineObj) { break }
2249 else { h += line.height; }
2250 }
2251 for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
2252 for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
2253 var cur = p.children[i$1];
2254 if (cur == chunk) { break }
2255 else { h += cur.height; }
2256 }
2257 }
2258 return h
2259 }
2260
2261 // Compute the character length of a line, taking into account
2262 // collapsed ranges (see markText) that might hide parts, and join
2263 // other lines onto it.
2264 function lineLength(line) {
2265 if (line.height == 0) { return 0 }
2266 var len = line.text.length, merged, cur = line;
2267 while (merged = collapsedSpanAtStart(cur)) {
2268 var found = merged.find(0, true);
2269 cur = found.from.line;
2270 len += found.from.ch - found.to.ch;
2271 }
2272 cur = line;
2273 while (merged = collapsedSpanAtEnd(cur)) {
2274 var found$1 = merged.find(0, true);
2275 len -= cur.text.length - found$1.from.ch;
2276 cur = found$1.to.line;
2277 len += cur.text.length - found$1.to.ch;
2278 }
2279 return len
2280 }
2281
2282 // Find the longest line in the document.
2283 function findMaxLine(cm) {
2284 var d = cm.display, doc = cm.doc;
2285 d.maxLine = getLine(doc, doc.first);
2286 d.maxLineLength = lineLength(d.maxLine);
2287 d.maxLineChanged = true;
2288 doc.iter(function (line) {
2289 var len = lineLength(line);
2290 if (len > d.maxLineLength) {
2291 d.maxLineLength = len;
2292 d.maxLine = line;
2293 }
2294 });
2295 }
2296
2297 // BIDI HELPERS
2298
2299 function iterateBidiSections(order, from, to, f) {
2300 if (!order) { return f(from, to, "ltr", 0) }
2301 var found = false;
2302 for (var i = 0; i < order.length; ++i) {
2303 var part = order[i];
2304 if (part.from < to && part.to > from || from == to && part.to == from) {
2305 f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i);
2306 found = true;
2307 }
2308 }
2309 if (!found) { f(from, to, "ltr"); }
2310 }
2311
2312 var bidiOther = null;
2313 function getBidiPartAt(order, ch, sticky) {
2314 var found;
2315 bidiOther = null;
2316 for (var i = 0; i < order.length; ++i) {
2317 var cur = order[i];
2318 if (cur.from < ch && cur.to > ch) { return i }
2319 if (cur.to == ch) {
2320 if (cur.from != cur.to && sticky == "before") { found = i; }
2321 else { bidiOther = i; }
2322 }
2323 if (cur.from == ch) {
2324 if (cur.from != cur.to && sticky != "before") { found = i; }
2325 else { bidiOther = i; }
2326 }
2327 }
2328 return found != null ? found : bidiOther
2329 }
2330
2331 // Bidirectional ordering algorithm
2332 // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
2333 // that this (partially) implements.
2334
2335 // One-char codes used for character types:
2336 // L (L): Left-to-Right
2337 // R (R): Right-to-Left
2338 // r (AL): Right-to-Left Arabic
2339 // 1 (EN): European Number
2340 // + (ES): European Number Separator
2341 // % (ET): European Number Terminator
2342 // n (AN): Arabic Number
2343 // , (CS): Common Number Separator
2344 // m (NSM): Non-Spacing Mark
2345 // b (BN): Boundary Neutral
2346 // s (B): Paragraph Separator
2347 // t (S): Segment Separator
2348 // w (WS): Whitespace
2349 // N (ON): Other Neutrals
2350
2351 // Returns null if characters are ordered as they appear
2352 // (left-to-right), or an array of sections ({from, to, level}
2353 // objects) in the order in which they occur visually.
2354 var bidiOrdering = (function() {
2355 // Character types for codepoints 0 to 0xff
2356 var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
2357 // Character types for codepoints 0x600 to 0x6f9
2358 var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";
2359 function charType(code) {
2360 if (code <= 0xf7) { return lowTypes.charAt(code) }
2361 else if (0x590 <= code && code <= 0x5f4) { return "R" }
2362 else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
2363 else if (0x6ee <= code && code <= 0x8ac) { return "r" }
2364 else if (0x2000 <= code && code <= 0x200b) { return "w" }
2365 else if (code == 0x200c) { return "b" }
2366 else { return "L" }
2367 }
2368
2369 var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
2370 var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
2371
2372 function BidiSpan(level, from, to) {
2373 this.level = level;
2374 this.from = from; this.to = to;
2375 }
2376
2377 return function(str, direction) {
2378 var outerType = direction == "ltr" ? "L" : "R";
2379
2380 if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false }
2381 var len = str.length, types = [];
2382 for (var i = 0; i < len; ++i)
2383 { types.push(charType(str.charCodeAt(i))); }
2384
2385 // W1. Examine each non-spacing mark (NSM) in the level run, and
2386 // change the type of the NSM to the type of the previous
2387 // character. If the NSM is at the start of the level run, it will
2388 // get the type of sor.
2389 for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
2390 var type = types[i$1];
2391 if (type == "m") { types[i$1] = prev; }
2392 else { prev = type; }
2393 }
2394
2395 // W2. Search backwards from each instance of a European number
2396 // until the first strong type (R, L, AL, or sor) is found. If an
2397 // AL is found, change the type of the European number to Arabic
2398 // number.
2399 // W3. Change all ALs to R.
2400 for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
2401 var type$1 = types[i$2];
2402 if (type$1 == "1" && cur == "r") { types[i$2] = "n"; }
2403 else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R"; } }
2404 }
2405
2406 // W4. A single European separator between two European numbers
2407 // changes to a European number. A single common separator between
2408 // two numbers of the same type changes to that type.
2409 for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
2410 var type$2 = types[i$3];
2411 if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1"; }
2412 else if (type$2 == "," && prev$1 == types[i$3+1] &&
2413 (prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1; }
2414 prev$1 = type$2;
2415 }
2416
2417 // W5. A sequence of European terminators adjacent to European
2418 // numbers changes to all European numbers.
2419 // W6. Otherwise, separators and terminators change to Other
2420 // Neutral.
2421 for (var i$4 = 0; i$4 < len; ++i$4) {
2422 var type$3 = types[i$4];
2423 if (type$3 == ",") { types[i$4] = "N"; }
2424 else if (type$3 == "%") {
2425 var end = (void 0);
2426 for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
2427 var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
2428 for (var j = i$4; j < end; ++j) { types[j] = replace; }
2429 i$4 = end - 1;
2430 }
2431 }
2432
2433 // W7. Search backwards from each instance of a European number
2434 // until the first strong type (R, L, or sor) is found. If an L is
2435 // found, then change the type of the European number to L.
2436 for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
2437 var type$4 = types[i$5];
2438 if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L"; }
2439 else if (isStrong.test(type$4)) { cur$1 = type$4; }
2440 }
2441
2442 // N1. A sequence of neutrals takes the direction of the
2443 // surrounding strong text if the text on both sides has the same
2444 // direction. European and Arabic numbers act as if they were R in
2445 // terms of their influence on neutrals. Start-of-level-run (sor)
2446 // and end-of-level-run (eor) are used at level run boundaries.
2447 // N2. Any remaining neutrals take the embedding direction.
2448 for (var i$6 = 0; i$6 < len; ++i$6) {
2449 if (isNeutral.test(types[i$6])) {
2450 var end$1 = (void 0);
2451 for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
2452 var before = (i$6 ? types[i$6-1] : outerType) == "L";
2453 var after = (end$1 < len ? types[end$1] : outerType) == "L";
2454 var replace$1 = before == after ? (before ? "L" : "R") : outerType;
2455 for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }
2456 i$6 = end$1 - 1;
2457 }
2458 }
2459
2460 // Here we depart from the documented algorithm, in order to avoid
2461 // building up an actual levels array. Since there are only three
2462 // levels (0, 1, 2) in an implementation that doesn't take
2463 // explicit embedding into account, we can build up the order on
2464 // the fly, without following the level-based algorithm.
2465 var order = [], m;
2466 for (var i$7 = 0; i$7 < len;) {
2467 if (countsAsLeft.test(types[i$7])) {
2468 var start = i$7;
2469 for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
2470 order.push(new BidiSpan(0, start, i$7));
2471 } else {
2472 var pos = i$7, at = order.length;
2473 for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
2474 for (var j$2 = pos; j$2 < i$7;) {
2475 if (countsAsNum.test(types[j$2])) {
2476 if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); }
2477 var nstart = j$2;
2478 for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
2479 order.splice(at, 0, new BidiSpan(2, nstart, j$2));
2480 pos = j$2;
2481 } else { ++j$2; }
2482 }
2483 if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }
2484 }
2485 }
2486 if (direction == "ltr") {
2487 if (order[0].level == 1 && (m = str.match(/^\s+/))) {
2488 order[0].from = m[0].length;
2489 order.unshift(new BidiSpan(0, 0, m[0].length));
2490 }
2491 if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
2492 lst(order).to -= m[0].length;
2493 order.push(new BidiSpan(0, len - m[0].length, len));
2494 }
2495 }
2496
2497 return direction == "rtl" ? order.reverse() : order
2498 }
2499 })();
2500
2501 // Get the bidi ordering for the given line (and cache it). Returns
2502 // false for lines that are fully left-to-right, and an array of
2503 // BidiSpan objects otherwise.
2504 function getOrder(line, direction) {
2505 var order = line.order;
2506 if (order == null) { order = line.order = bidiOrdering(line.text, direction); }
2507 return order
2508 }
2509
2510 // EVENT HANDLING
2511
2512 // Lightweight event framework. on/off also work on DOM nodes,
2513 // registering native DOM handlers.
2514
2515 var noHandlers = [];
2516
2517 var on = function(emitter, type, f) {
2518 if (emitter.addEventListener) {
2519 emitter.addEventListener(type, f, false);
2520 } else if (emitter.attachEvent) {
2521 emitter.attachEvent("on" + type, f);
2522 } else {
2523 var map$$1 = emitter._handlers || (emitter._handlers = {});
2524 map$$1[type] = (map$$1[type] || noHandlers).concat(f);
2525 }
2526 };
2527
2528 function getHandlers(emitter, type) {
2529 return emitter._handlers && emitter._handlers[type] || noHandlers
2530 }
2531
2532 function off(emitter, type, f) {
2533 if (emitter.removeEventListener) {
2534 emitter.removeEventListener(type, f, false);
2535 } else if (emitter.detachEvent) {
2536 emitter.detachEvent("on" + type, f);
2537 } else {
2538 var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type];
2539 if (arr) {
2540 var index = indexOf(arr, f);
2541 if (index > -1)
2542 { map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }
2543 }
2544 }
2545 }
2546
2547 function signal(emitter, type /*, values...*/) {
2548 var handlers = getHandlers(emitter, type);
2549 if (!handlers.length) { return }
2550 var args = Array.prototype.slice.call(arguments, 2);
2551 for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }
2552 }
2553
2554 // The DOM events that CodeMirror handles can be overridden by
2555 // registering a (non-DOM) handler on the editor for the event name,
2556 // and preventDefault-ing the event in that handler.
2557 function signalDOMEvent(cm, e, override) {
2558 if (typeof e == "string")
2559 { e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }
2560 signal(cm, override || e.type, cm, e);
2561 return e_defaultPrevented(e) || e.codemirrorIgnore
2562 }
2563
2564 function signalCursorActivity(cm) {
2565 var arr = cm._handlers && cm._handlers.cursorActivity;
2566 if (!arr) { return }
2567 var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
2568 for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
2569 { set.push(arr[i]); } }
2570 }
2571
2572 function hasHandler(emitter, type) {
2573 return getHandlers(emitter, type).length > 0
2574 }
2575
2576 // Add on and off methods to a constructor's prototype, to make
2577 // registering events on such objects more convenient.
2578 function eventMixin(ctor) {
2579 ctor.prototype.on = function(type, f) {on(this, type, f);};
2580 ctor.prototype.off = function(type, f) {off(this, type, f);};
2581 }
2582
2583 // Due to the fact that we still support jurassic IE versions, some
2584 // compatibility wrappers are needed.
2585
2586 function e_preventDefault(e) {
2587 if (e.preventDefault) { e.preventDefault(); }
2588 else { e.returnValue = false; }
2589 }
2590 function e_stopPropagation(e) {
2591 if (e.stopPropagation) { e.stopPropagation(); }
2592 else { e.cancelBubble = true; }
2593 }
2594 function e_defaultPrevented(e) {
2595 return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
2596 }
2597 function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
2598
2599 function e_target(e) {return e.target || e.srcElement}
2600 function e_button(e) {
2601 var b = e.which;
2602 if (b == null) {
2603 if (e.button & 1) { b = 1; }
2604 else if (e.button & 2) { b = 3; }
2605 else if (e.button & 4) { b = 2; }
2606 }
2607 if (mac && e.ctrlKey && b == 1) { b = 3; }
2608 return b
2609 }
2610
2611 // Detect drag-and-drop
2612 var dragAndDrop = function() {
2613 // There is *some* kind of drag-and-drop support in IE6-8, but I
2614 // couldn't get it to work yet.
2615 if (ie && ie_version < 9) { return false }
2616 var div = elt('div');
2617 return "draggable" in div || "dragDrop" in div
2618 }();
2619
2620 var zwspSupported;
2621 function zeroWidthElement(measure) {
2622 if (zwspSupported == null) {
2623 var test = elt("span", "\u200b");
2624 removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
2625 if (measure.firstChild.offsetHeight != 0)
2626 { zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }
2627 }
2628 var node = zwspSupported ? elt("span", "\u200b") :
2629 elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
2630 node.setAttribute("cm-text", "");
2631 return node
2632 }
2633
2634 // Feature-detect IE's crummy client rect reporting for bidi text
2635 var badBidiRects;
2636 function hasBadBidiRects(measure) {
2637 if (badBidiRects != null) { return badBidiRects }
2638 var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
2639 var r0 = range(txt, 0, 1).getBoundingClientRect();
2640 var r1 = range(txt, 1, 2).getBoundingClientRect();
2641 removeChildren(measure);
2642 if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)
2643 return badBidiRects = (r1.right - r0.right < 3)
2644 }
2645
2646 // See if "".split is the broken IE version, if so, provide an
2647 // alternative way to split lines.
2648 var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) {
2649 var pos = 0, result = [], l = string.length;
2650 while (pos <= l) {
2651 var nl = string.indexOf("\n", pos);
2652 if (nl == -1) { nl = string.length; }
2653 var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
2654 var rt = line.indexOf("\r");
2655 if (rt != -1) {
2656 result.push(line.slice(0, rt));
2657 pos += rt + 1;
2658 } else {
2659 result.push(line);
2660 pos = nl + 1;
2661 }
2662 }
2663 return result
2664 } : function (string) { return string.split(/\r\n?|\n/); };
2665
2666 var hasSelection = window.getSelection ? function (te) {
2667 try { return te.selectionStart != te.selectionEnd }
2668 catch(e) { return false }
2669 } : function (te) {
2670 var range$$1;
2671 try {range$$1 = te.ownerDocument.selection.createRange();}
2672 catch(e) {}
2673 if (!range$$1 || range$$1.parentElement() != te) { return false }
2674 return range$$1.compareEndPoints("StartToEnd", range$$1) != 0
2675 };
2676
2677 var hasCopyEvent = (function () {
2678 var e = elt("div");
2679 if ("oncopy" in e) { return true }
2680 e.setAttribute("oncopy", "return;");
2681 return typeof e.oncopy == "function"
2682 })();
2683
2684 var badZoomedRects = null;
2685 function hasBadZoomedRects(measure) {
2686 if (badZoomedRects != null) { return badZoomedRects }
2687 var node = removeChildrenAndAdd(measure, elt("span", "x"));
2688 var normal = node.getBoundingClientRect();
2689 var fromRange = range(node, 0, 1).getBoundingClientRect();
2690 return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
2691 }
2692
2693 // Known modes, by name and by MIME
2694 var modes = {};
2695 var mimeModes = {};
2696
2697 // Extra arguments are stored as the mode's dependencies, which is
2698 // used by (legacy) mechanisms like loadmode.js to automatically
2699 // load a mode. (Preferred mechanism is the require/define calls.)
2700 function defineMode(name, mode) {
2701 if (arguments.length > 2)
2702 { mode.dependencies = Array.prototype.slice.call(arguments, 2); }
2703 modes[name] = mode;
2704 }
2705
2706 function defineMIME(mime, spec) {
2707 mimeModes[mime] = spec;
2708 }
2709
2710 // Given a MIME type, a {name, ...options} config object, or a name
2711 // string, return a mode config object.
2712 function resolveMode(spec) {
2713 if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
2714 spec = mimeModes[spec];
2715 } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
2716 var found = mimeModes[spec.name];
2717 if (typeof found == "string") { found = {name: found}; }
2718 spec = createObj(found, spec);
2719 spec.name = found.name;
2720 } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
2721 return resolveMode("application/xml")
2722 } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
2723 return resolveMode("application/json")
2724 }
2725 if (typeof spec == "string") { return {name: spec} }
2726 else { return spec || {name: "null"} }
2727 }
2728
2729 // Given a mode spec (anything that resolveMode accepts), find and
2730 // initialize an actual mode object.
2731 function getMode(options, spec) {
2732 spec = resolveMode(spec);
2733 var mfactory = modes[spec.name];
2734 if (!mfactory) { return getMode(options, "text/plain") }
2735 var modeObj = mfactory(options, spec);
2736 if (modeExtensions.hasOwnProperty(spec.name)) {
2737 var exts = modeExtensions[spec.name];
2738 for (var prop in exts) {
2739 if (!exts.hasOwnProperty(prop)) { continue }
2740 if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; }
2741 modeObj[prop] = exts[prop];
2742 }
2743 }
2744 modeObj.name = spec.name;
2745 if (spec.helperType) { modeObj.helperType = spec.helperType; }
2746 if (spec.modeProps) { for (var prop$1 in spec.modeProps)
2747 { modeObj[prop$1] = spec.modeProps[prop$1]; } }
2748
2749 return modeObj
2750 }
2751
2752 // This can be used to attach properties to mode objects from
2753 // outside the actual mode definition.
2754 var modeExtensions = {};
2755 function extendMode(mode, properties) {
2756 var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
2757 copyObj(properties, exts);
2758 }
2759
2760 function copyState(mode, state) {
2761 if (state === true) { return state }
2762 if (mode.copyState) { return mode.copyState(state) }
2763 var nstate = {};
2764 for (var n in state) {
2765 var val = state[n];
2766 if (val instanceof Array) { val = val.concat([]); }
2767 nstate[n] = val;
2768 }
2769 return nstate
2770 }
2771
2772 // Given a mode and a state (for that mode), find the inner mode and
2773 // state at the position that the state refers to.
2774 function innerMode(mode, state) {
2775 var info;
2776 while (mode.innerMode) {
2777 info = mode.innerMode(state);
2778 if (!info || info.mode == mode) { break }
2779 state = info.state;
2780 mode = info.mode;
2781 }
2782 return info || {mode: mode, state: state}
2783 }
2784
2785 function startState(mode, a1, a2) {
2786 return mode.startState ? mode.startState(a1, a2) : true
2787 }
2788
2789 // STRING STREAM
2790
2791 // Fed to the mode parsers, provides helper functions to make
2792 // parsers more succinct.
2793
2794 var StringStream = function(string, tabSize, lineOracle) {
2795 this.pos = this.start = 0;
2796 this.string = string;
2797 this.tabSize = tabSize || 8;
2798 this.lastColumnPos = this.lastColumnValue = 0;
2799 this.lineStart = 0;
2800 this.lineOracle = lineOracle;
2801 };
2802
2803 StringStream.prototype.eol = function () {return this.pos >= this.string.length};
2804 StringStream.prototype.sol = function () {return this.pos == this.lineStart};
2805 StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
2806 StringStream.prototype.next = function () {
2807 if (this.pos < this.string.length)
2808 { return this.string.charAt(this.pos++) }
2809 };
2810 StringStream.prototype.eat = function (match) {
2811 var ch = this.string.charAt(this.pos);
2812 var ok;
2813 if (typeof match == "string") { ok = ch == match; }
2814 else { ok = ch && (match.test ? match.test(ch) : match(ch)); }
2815 if (ok) {++this.pos; return ch}
2816 };
2817 StringStream.prototype.eatWhile = function (match) {
2818 var start = this.pos;
2819 while (this.eat(match)){}
2820 return this.pos > start
2821 };
2822 StringStream.prototype.eatSpace = function () {
2823 var this$1 = this;
2824
2825 var start = this.pos;
2826 while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos; }
2827 return this.pos > start
2828 };
2829 StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};
2830 StringStream.prototype.skipTo = function (ch) {
2831 var found = this.string.indexOf(ch, this.pos);
2832 if (found > -1) {this.pos = found; return true}
2833 };
2834 StringStream.prototype.backUp = function (n) {this.pos -= n;};
2835 StringStream.prototype.column = function () {
2836 if (this.lastColumnPos < this.start) {
2837 this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
2838 this.lastColumnPos = this.start;
2839 }
2840 return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
2841 };
2842 StringStream.prototype.indentation = function () {
2843 return countColumn(this.string, null, this.tabSize) -
2844 (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
2845 };
2846 StringStream.prototype.match = function (pattern, consume, caseInsensitive) {
2847 if (typeof pattern == "string") {
2848 var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };
2849 var substr = this.string.substr(this.pos, pattern.length);
2850 if (cased(substr) == cased(pattern)) {
2851 if (consume !== false) { this.pos += pattern.length; }
2852 return true
2853 }
2854 } else {
2855 var match = this.string.slice(this.pos).match(pattern);
2856 if (match && match.index > 0) { return null }
2857 if (match && consume !== false) { this.pos += match[0].length; }
2858 return match
2859 }
2860 };
2861 StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};
2862 StringStream.prototype.hideFirstChars = function (n, inner) {
2863 this.lineStart += n;
2864 try { return inner() }
2865 finally { this.lineStart -= n; }
2866 };
2867 StringStream.prototype.lookAhead = function (n) {
2868 var oracle = this.lineOracle;
2869 return oracle && oracle.lookAhead(n)
2870 };
2871 StringStream.prototype.baseToken = function () {
2872 var oracle = this.lineOracle;
2873 return oracle && oracle.baseToken(this.pos)
2874 };
2875
2876 var SavedContext = function(state, lookAhead) {
2877 this.state = state;
2878 this.lookAhead = lookAhead;
2879 };
2880
2881 var Context = function(doc, state, line, lookAhead) {
2882 this.state = state;
2883 this.doc = doc;
2884 this.line = line;
2885 this.maxLookAhead = lookAhead || 0;
2886 this.baseTokens = null;
2887 this.baseTokenPos = 1;
2888 };
2889
2890 Context.prototype.lookAhead = function (n) {
2891 var line = this.doc.getLine(this.line + n);
2892 if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; }
2893 return line
2894 };
2895
2896 Context.prototype.baseToken = function (n) {
2897 var this$1 = this;
2898
2899 if (!this.baseTokens) { return null }
2900 while (this.baseTokens[this.baseTokenPos] <= n)
2901 { this$1.baseTokenPos += 2; }
2902 var type = this.baseTokens[this.baseTokenPos + 1];
2903 return {type: type && type.replace(/( |^)overlay .*/, ""),
2904 size: this.baseTokens[this.baseTokenPos] - n}
2905 };
2906
2907 Context.prototype.nextLine = function () {
2908 this.line++;
2909 if (this.maxLookAhead > 0) { this.maxLookAhead--; }
2910 };
2911
2912 Context.fromSaved = function (doc, saved, line) {
2913 if (saved instanceof SavedContext)
2914 { return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) }
2915 else
2916 { return new Context(doc, copyState(doc.mode, saved), line) }
2917 };
2918
2919 Context.prototype.save = function (copy) {
2920 var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state;
2921 return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state
2922 };
2923
2924
2925 // Compute a style array (an array starting with a mode generation
2926 // -- for invalidation -- followed by pairs of end positions and
2927 // style strings), which is used to highlight the tokens on the
2928 // line.
2929 function highlightLine(cm, line, context, forceToEnd) {
2930 // A styles array always starts with a number identifying the
2931 // mode/overlays that it is based on (for easy invalidation).
2932 var st = [cm.state.modeGen], lineClasses = {};
2933 // Compute the base array of styles
2934 runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); },
2935 lineClasses, forceToEnd);
2936 var state = context.state;
2937
2938 // Run overlays, adjust style array.
2939 var loop = function ( o ) {
2940 context.baseTokens = st;
2941 var overlay = cm.state.overlays[o], i = 1, at = 0;
2942 context.state = true;
2943 runMode(cm, line.text, overlay.mode, context, function (end, style) {
2944 var start = i;
2945 // Ensure there's a token end at the current position, and that i points at it
2946 while (at < end) {
2947 var i_end = st[i];
2948 if (i_end > end)
2949 { st.splice(i, 1, end, st[i+1], i_end); }
2950 i += 2;
2951 at = Math.min(end, i_end);
2952 }
2953 if (!style) { return }
2954 if (overlay.opaque) {
2955 st.splice(start, i - start, end, "overlay " + style);
2956 i = start + 2;
2957 } else {
2958 for (; start < i; start += 2) {
2959 var cur = st[start+1];
2960 st[start+1] = (cur ? cur + " " : "") + "overlay " + style;
2961 }
2962 }
2963 }, lineClasses);
2964 context.state = state;
2965 context.baseTokens = null;
2966 context.baseTokenPos = 1;
2967 };
2968
2969 for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );
2970
2971 return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
2972 }
2973
2974 function getLineStyles(cm, line, updateFrontier) {
2975 if (!line.styles || line.styles[0] != cm.state.modeGen) {
2976 var context = getContextBefore(cm, lineNo(line));
2977 var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state);
2978 var result = highlightLine(cm, line, context);
2979 if (resetState) { context.state = resetState; }
2980 line.stateAfter = context.save(!resetState);
2981 line.styles = result.styles;
2982 if (result.classes) { line.styleClasses = result.classes; }
2983 else if (line.styleClasses) { line.styleClasses = null; }
2984 if (updateFrontier === cm.doc.highlightFrontier)
2985 { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }
2986 }
2987 return line.styles
2988 }
2989
2990 function getContextBefore(cm, n, precise) {
2991 var doc = cm.doc, display = cm.display;
2992 if (!doc.mode.startState) { return new Context(doc, true, n) }
2993 var start = findStartLine(cm, n, precise);
2994 var saved = start > doc.first && getLine(doc, start - 1).stateAfter;
2995 var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start);
2996
2997 doc.iter(start, n, function (line) {
2998 processLine(cm, line.text, context);
2999 var pos = context.line;
3000 line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null;
3001 context.nextLine();
3002 });
3003 if (precise) { doc.modeFrontier = context.line; }
3004 return context
3005 }
3006
3007 // Lightweight form of highlight -- proceed over this line and
3008 // update state, but don't save a style array. Used for lines that
3009 // aren't currently visible.
3010 function processLine(cm, text, context, startAt) {
3011 var mode = cm.doc.mode;
3012 var stream = new StringStream(text, cm.options.tabSize, context);
3013 stream.start = stream.pos = startAt || 0;
3014 if (text == "") { callBlankLine(mode, context.state); }
3015 while (!stream.eol()) {
3016 readToken(mode, stream, context.state);
3017 stream.start = stream.pos;
3018 }
3019 }
3020
3021 function callBlankLine(mode, state) {
3022 if (mode.blankLine) { return mode.blankLine(state) }
3023 if (!mode.innerMode) { return }
3024 var inner = innerMode(mode, state);
3025 if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
3026 }
3027
3028 function readToken(mode, stream, state, inner) {
3029 for (var i = 0; i < 10; i++) {
3030 if (inner) { inner[0] = innerMode(mode, state).mode; }
3031 var style = mode.token(stream, state);
3032 if (stream.pos > stream.start) { return style }
3033 }
3034 throw new Error("Mode " + mode.name + " failed to advance stream.")
3035 }
3036
3037 var Token = function(stream, type, state) {
3038 this.start = stream.start; this.end = stream.pos;
3039 this.string = stream.current();
3040 this.type = type || null;
3041 this.state = state;
3042 };
3043
3044 // Utility for getTokenAt and getLineTokens
3045 function takeToken(cm, pos, precise, asArray) {
3046 var doc = cm.doc, mode = doc.mode, style;
3047 pos = clipPos(doc, pos);
3048 var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise);
3049 var stream = new StringStream(line.text, cm.options.tabSize, context), tokens;
3050 if (asArray) { tokens = []; }
3051 while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
3052 stream.start = stream.pos;
3053 style = readToken(mode, stream, context.state);
3054 if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); }
3055 }
3056 return asArray ? tokens : new Token(stream, style, context.state)
3057 }
3058
3059 function extractLineClasses(type, output) {
3060 if (type) { for (;;) {
3061 var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
3062 if (!lineClass) { break }
3063 type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
3064 var prop = lineClass[1] ? "bgClass" : "textClass";
3065 if (output[prop] == null)
3066 { output[prop] = lineClass[2]; }
3067 else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
3068 { output[prop] += " " + lineClass[2]; }
3069 } }
3070 return type
3071 }
3072
3073 // Run the given mode's parser over a line, calling f for each token.
3074 function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {
3075 var flattenSpans = mode.flattenSpans;
3076 if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; }
3077 var curStart = 0, curStyle = null;
3078 var stream = new StringStream(text, cm.options.tabSize, context), style;
3079 var inner = cm.options.addModeClass && [null];
3080 if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); }
3081 while (!stream.eol()) {
3082 if (stream.pos > cm.options.maxHighlightLength) {
3083 flattenSpans = false;
3084 if (forceToEnd) { processLine(cm, text, context, stream.pos); }
3085 stream.pos = text.length;
3086 style = null;
3087 } else {
3088 style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses);
3089 }
3090 if (inner) {
3091 var mName = inner[0].name;
3092 if (mName) { style = "m-" + (style ? mName + " " + style : mName); }
3093 }
3094 if (!flattenSpans || curStyle != style) {
3095 while (curStart < stream.start) {
3096 curStart = Math.min(stream.start, curStart + 5000);
3097 f(curStart, curStyle);
3098 }
3099 curStyle = style;
3100 }
3101 stream.start = stream.pos;
3102 }
3103 while (curStart < stream.pos) {
3104 // Webkit seems to refuse to render text nodes longer than 57444
3105 // characters, and returns inaccurate measurements in nodes
3106 // starting around 5000 chars.
3107 var pos = Math.min(stream.pos, curStart + 5000);
3108 f(pos, curStyle);
3109 curStart = pos;
3110 }
3111 }
3112
3113 // Finds the line to start with when starting a parse. Tries to
3114 // find a line with a stateAfter, so that it can start with a
3115 // valid state. If that fails, it returns the line with the
3116 // smallest indentation, which tends to need the least context to
3117 // parse correctly.
3118 function findStartLine(cm, n, precise) {
3119 var minindent, minline, doc = cm.doc;
3120 var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
3121 for (var search = n; search > lim; --search) {
3122 if (search <= doc.first) { return doc.first }
3123 var line = getLine(doc, search - 1), after = line.stateAfter;
3124 if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))
3125 { return search }
3126 var indented = countColumn(line.text, null, cm.options.tabSize);
3127 if (minline == null || minindent > indented) {
3128 minline = search - 1;
3129 minindent = indented;
3130 }
3131 }
3132 return minline
3133 }
3134
3135 function retreatFrontier(doc, n) {
3136 doc.modeFrontier = Math.min(doc.modeFrontier, n);
3137 if (doc.highlightFrontier < n - 10) { return }
3138 var start = doc.first;
3139 for (var line = n - 1; line > start; line--) {
3140 var saved = getLine(doc, line).stateAfter;
3141 // change is on 3
3142 // state on line 1 looked ahead 2 -- so saw 3
3143 // test 1 + 2 < 3 should cover this
3144 if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {
3145 start = line + 1;
3146 break
3147 }
3148 }
3149 doc.highlightFrontier = Math.min(doc.highlightFrontier, start);
3150 }
3151
3152 // LINE DATA STRUCTURE
3153
3154 // Line objects. These hold state related to a line, including
3155 // highlighting info (the styles array).
3156 var Line = function(text, markedSpans, estimateHeight) {
3157 this.text = text;
3158 attachMarkedSpans(this, markedSpans);
3159 this.height = estimateHeight ? estimateHeight(this) : 1;
3160 };
3161
3162 Line.prototype.lineNo = function () { return lineNo(this) };
3163 eventMixin(Line);
3164
3165 // Change the content (text, markers) of a line. Automatically
3166 // invalidates cached information and tries to re-estimate the
3167 // line's height.
3168 function updateLine(line, text, markedSpans, estimateHeight) {
3169 line.text = text;
3170 if (line.stateAfter) { line.stateAfter = null; }
3171 if (line.styles) { line.styles = null; }
3172 if (line.order != null) { line.order = null; }
3173 detachMarkedSpans(line);
3174 attachMarkedSpans(line, markedSpans);
3175 var estHeight = estimateHeight ? estimateHeight(line) : 1;
3176 if (estHeight != line.height) { updateLineHeight(line, estHeight); }
3177 }
3178
3179 // Detach a line from the document tree and its markers.
3180 function cleanUpLine(line) {
3181 line.parent = null;
3182 detachMarkedSpans(line);
3183 }
3184
3185 // Convert a style as returned by a mode (either null, or a string
3186 // containing one or more styles) to a CSS style. This is cached,
3187 // and also looks for line-wide styles.
3188 var styleToClassCache = {};
3189 var styleToClassCacheWithMode = {};
3190 function interpretTokenStyle(style, options) {
3191 if (!style || /^\s*$/.test(style)) { return null }
3192 var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
3193 return cache[style] ||
3194 (cache[style] = style.replace(/\S+/g, "cm-$&"))
3195 }
3196
3197 // Render the DOM representation of the text of a line. Also builds
3198 // up a 'line map', which points at the DOM nodes that represent
3199 // specific stretches of text, and is used by the measuring code.
3200 // The returned object contains the DOM node, this map, and
3201 // information about line-wide styles that were set by the mode.
3202 function buildLineContent(cm, lineView) {
3203 // The padding-right forces the element to have a 'border', which
3204 // is needed on Webkit to be able to get line-level bounding
3205 // rectangles for it (in measureChar).
3206 var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null);
3207 var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content,
3208 col: 0, pos: 0, cm: cm,
3209 trailingSpace: false,
3210 splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")};
3211 lineView.measure = {};
3212
3213 // Iterate over the logical lines that make up this visual line.
3214 for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
3215 var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0);
3216 builder.pos = 0;
3217 builder.addToken = buildToken;
3218 // Optionally wire in some hacks into the token-rendering
3219 // algorithm, to deal with browser quirks.
3220 if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction)))
3221 { builder.addToken = buildTokenBadBidi(builder.addToken, order); }
3222 builder.map = [];
3223 var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
3224 insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
3225 if (line.styleClasses) {
3226 if (line.styleClasses.bgClass)
3227 { builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); }
3228 if (line.styleClasses.textClass)
3229 { builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); }
3230 }
3231
3232 // Ensure at least a single node is present, for measuring.
3233 if (builder.map.length == 0)
3234 { builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); }
3235
3236 // Store the map and a cache object for the current logical line
3237 if (i == 0) {
3238 lineView.measure.map = builder.map;
3239 lineView.measure.cache = {};
3240 } else {
3241 (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)
3242 ;(lineView.measure.caches || (lineView.measure.caches = [])).push({});
3243 }
3244 }
3245
3246 // See issue #2901
3247 if (webkit) {
3248 var last = builder.content.lastChild;
3249 if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
3250 { builder.content.className = "cm-tab-wrap-hack"; }
3251 }
3252
3253 signal(cm, "renderLine", cm, lineView.line, builder.pre);
3254 if (builder.pre.className)
3255 { builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); }
3256
3257 return builder
3258 }
3259
3260 function defaultSpecialCharPlaceholder(ch) {
3261 var token = elt("span", "\u2022", "cm-invalidchar");
3262 token.title = "\\u" + ch.charCodeAt(0).toString(16);
3263 token.setAttribute("aria-label", token.title);
3264 return token
3265 }
3266
3267 // Build up the DOM representation for a single token, and add it to
3268 // the line map. Takes care to render special characters separately.
3269 function buildToken(builder, text, style, startStyle, endStyle, title, css) {
3270 if (!text) { return }
3271 var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;
3272 var special = builder.cm.state.specialChars, mustWrap = false;
3273 var content;
3274 if (!special.test(text)) {
3275 builder.col += text.length;
3276 content = document.createTextNode(displayText);
3277 builder.map.push(builder.pos, builder.pos + text.length, content);
3278 if (ie && ie_version < 9) { mustWrap = true; }
3279 builder.pos += text.length;
3280 } else {
3281 content = document.createDocumentFragment();
3282 var pos = 0;
3283 while (true) {
3284 special.lastIndex = pos;
3285 var m = special.exec(text);
3286 var skipped = m ? m.index - pos : text.length - pos;
3287 if (skipped) {
3288 var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
3289 if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])); }
3290 else { content.appendChild(txt); }
3291 builder.map.push(builder.pos, builder.pos + skipped, txt);
3292 builder.col += skipped;
3293 builder.pos += skipped;
3294 }
3295 if (!m) { break }
3296 pos += skipped + 1;
3297 var txt$1 = (void 0);
3298 if (m[0] == "\t") {
3299 var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
3300 txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
3301 txt$1.setAttribute("role", "presentation");
3302 txt$1.setAttribute("cm-text", "\t");
3303 builder.col += tabWidth;
3304 } else if (m[0] == "\r" || m[0] == "\n") {
3305 txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
3306 txt$1.setAttribute("cm-text", m[0]);
3307 builder.col += 1;
3308 } else {
3309 txt$1 = builder.cm.options.specialCharPlaceholder(m[0]);
3310 txt$1.setAttribute("cm-text", m[0]);
3311 if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])); }
3312 else { content.appendChild(txt$1); }
3313 builder.col += 1;
3314 }
3315 builder.map.push(builder.pos, builder.pos + 1, txt$1);
3316 builder.pos++;
3317 }
3318 }
3319 builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32;
3320 if (style || startStyle || endStyle || mustWrap || css) {
3321 var fullStyle = style || "";
3322 if (startStyle) { fullStyle += startStyle; }
3323 if (endStyle) { fullStyle += endStyle; }
3324 var token = elt("span", [content], fullStyle, css);
3325 if (title) { token.title = title; }
3326 return builder.content.appendChild(token)
3327 }
3328 builder.content.appendChild(content);
3329 }
3330
3331 function splitSpaces(text, trailingBefore) {
3332 if (text.length > 1 && !/ /.test(text)) { return text }
3333 var spaceBefore = trailingBefore, result = "";
3334 for (var i = 0; i < text.length; i++) {
3335 var ch = text.charAt(i);
3336 if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))
3337 { ch = "\u00a0"; }
3338 result += ch;
3339 spaceBefore = ch == " ";
3340 }
3341 return result
3342 }
3343
3344 // Work around nonsense dimensions being reported for stretches of
3345 // right-to-left text.
3346 function buildTokenBadBidi(inner, order) {
3347 return function (builder, text, style, startStyle, endStyle, title, css) {
3348 style = style ? style + " cm-force-border" : "cm-force-border";
3349 var start = builder.pos, end = start + text.length;
3350 for (;;) {
3351 // Find the part that overlaps with the start of this text
3352 var part = (void 0);
3353 for (var i = 0; i < order.length; i++) {
3354 part = order[i];
3355 if (part.to > start && part.from <= start) { break }
3356 }
3357 if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, title, css) }
3358 inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);
3359 startStyle = null;
3360 text = text.slice(part.to - start);
3361 start = part.to;
3362 }
3363 }
3364 }
3365
3366 function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
3367 var widget = !ignoreWidget && marker.widgetNode;
3368 if (widget) { builder.map.push(builder.pos, builder.pos + size, widget); }
3369 if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
3370 if (!widget)
3371 { widget = builder.content.appendChild(document.createElement("span")); }
3372 widget.setAttribute("cm-marker", marker.id);
3373 }
3374 if (widget) {
3375 builder.cm.display.input.setUneditable(widget);
3376 builder.content.appendChild(widget);
3377 }
3378 builder.pos += size;
3379 builder.trailingSpace = false;
3380 }
3381
3382 // Outputs a number of spans to make up a line, taking highlighting
3383 // and marked text into account.
3384 function insertLineContent(line, builder, styles) {
3385 var spans = line.markedSpans, allText = line.text, at = 0;
3386 if (!spans) {
3387 for (var i$1 = 1; i$1 < styles.length; i$1+=2)
3388 { builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); }
3389 return
3390 }
3391
3392 var len = allText.length, pos = 0, i = 1, text = "", style, css;
3393 var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
3394 for (;;) {
3395 if (nextChange == pos) { // Update current marker set
3396 spanStyle = spanEndStyle = spanStartStyle = title = css = "";
3397 collapsed = null; nextChange = Infinity;
3398 var foundBookmarks = [], endStyles = (void 0);
3399 for (var j = 0; j < spans.length; ++j) {
3400 var sp = spans[j], m = sp.marker;
3401 if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
3402 foundBookmarks.push(m);
3403 } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
3404 if (sp.to != null && sp.to != pos && nextChange > sp.to) {
3405 nextChange = sp.to;
3406 spanEndStyle = "";
3407 }
3408 if (m.className) { spanStyle += " " + m.className; }
3409 if (m.css) { css = (css ? css + ";" : "") + m.css; }
3410 if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle; }
3411 if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); }
3412 if (m.title && !title) { title = m.title; }
3413 if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
3414 { collapsed = sp; }
3415 } else if (sp.from > pos && nextChange > sp.from) {
3416 nextChange = sp.from;
3417 }
3418 }
3419 if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)
3420 { if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1]; } } }
3421
3422 if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)
3423 { buildCollapsedSpan(builder, 0, foundBookmarks[j$2]); } }
3424 if (collapsed && (collapsed.from || 0) == pos) {
3425 buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
3426 collapsed.marker, collapsed.from == null);
3427 if (collapsed.to == null) { return }
3428 if (collapsed.to == pos) { collapsed = false; }
3429 }
3430 }
3431 if (pos >= len) { break }
3432
3433 var upto = Math.min(len, nextChange);
3434 while (true) {
3435 if (text) {
3436 var end = pos + text.length;
3437 if (!collapsed) {
3438 var tokenText = end > upto ? text.slice(0, upto - pos) : text;
3439 builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
3440 spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
3441 }
3442 if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
3443 pos = end;
3444 spanStartStyle = "";
3445 }
3446 text = allText.slice(at, at = styles[i++]);
3447 style = interpretTokenStyle(styles[i++], builder.cm.options);
3448 }
3449 }
3450 }
3451
3452
3453 // These objects are used to represent the visible (currently drawn)
3454 // part of the document. A LineView may correspond to multiple
3455 // logical lines, if those are connected by collapsed ranges.
3456 function LineView(doc, line, lineN) {
3457 // The starting line
3458 this.line = line;
3459 // Continuing lines, if any
3460 this.rest = visualLineContinued(line);
3461 // Number of logical lines in this visual line
3462 this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
3463 this.node = this.text = null;
3464 this.hidden = lineIsHidden(doc, line);
3465 }
3466
3467 // Create a range of LineView objects for the given lines.
3468 function buildViewArray(cm, from, to) {
3469 var array = [], nextPos;
3470 for (var pos = from; pos < to; pos = nextPos) {
3471 var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
3472 nextPos = pos + view.size;
3473 array.push(view);
3474 }
3475 return array
3476 }
3477
3478 var operationGroup = null;
3479
3480 function pushOperation(op) {
3481 if (operationGroup) {
3482 operationGroup.ops.push(op);
3483 } else {
3484 op.ownsGroup = operationGroup = {
3485 ops: [op],
3486 delayedCallbacks: []
3487 };
3488 }
3489 }
3490
3491 function fireCallbacksForOps(group) {
3492 // Calls delayed callbacks and cursorActivity handlers until no
3493 // new ones appear
3494 var callbacks = group.delayedCallbacks, i = 0;
3495 do {
3496 for (; i < callbacks.length; i++)
3497 { callbacks[i].call(null); }
3498 for (var j = 0; j < group.ops.length; j++) {
3499 var op = group.ops[j];
3500 if (op.cursorActivityHandlers)
3501 { while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
3502 { op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } }
3503 }
3504 } while (i < callbacks.length)
3505 }
3506
3507 function finishOperation(op, endCb) {
3508 var group = op.ownsGroup;
3509 if (!group) { return }
3510
3511 try { fireCallbacksForOps(group); }
3512 finally {
3513 operationGroup = null;
3514 endCb(group);
3515 }
3516 }
3517
3518 var orphanDelayedCallbacks = null;
3519
3520 // Often, we want to signal events at a point where we are in the
3521 // middle of some work, but don't want the handler to start calling
3522 // other methods on the editor, which might be in an inconsistent
3523 // state or simply not expect any other events to happen.
3524 // signalLater looks whether there are any handlers, and schedules
3525 // them to be executed when the last operation ends, or, if no
3526 // operation is active, when a timeout fires.
3527 function signalLater(emitter, type /*, values...*/) {
3528 var arr = getHandlers(emitter, type);
3529 if (!arr.length) { return }
3530 var args = Array.prototype.slice.call(arguments, 2), list;
3531 if (operationGroup) {
3532 list = operationGroup.delayedCallbacks;
3533 } else if (orphanDelayedCallbacks) {
3534 list = orphanDelayedCallbacks;
3535 } else {
3536 list = orphanDelayedCallbacks = [];
3537 setTimeout(fireOrphanDelayed, 0);
3538 }
3539 var loop = function ( i ) {
3540 list.push(function () { return arr[i].apply(null, args); });
3541 };
3542
3543 for (var i = 0; i < arr.length; ++i)
3544 loop( i );
3545 }
3546
3547 function fireOrphanDelayed() {
3548 var delayed = orphanDelayedCallbacks;
3549 orphanDelayedCallbacks = null;
3550 for (var i = 0; i < delayed.length; ++i) { delayed[i](); }
3551 }
3552
3553 // When an aspect of a line changes, a string is added to
3554 // lineView.changes. This updates the relevant part of the line's
3555 // DOM structure.
3556 function updateLineForChanges(cm, lineView, lineN, dims) {
3557 for (var j = 0; j < lineView.changes.length; j++) {
3558 var type = lineView.changes[j];
3559 if (type == "text") { updateLineText(cm, lineView); }
3560 else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims); }
3561 else if (type == "class") { updateLineClasses(cm, lineView); }
3562 else if (type == "widget") { updateLineWidgets(cm, lineView, dims); }
3563 }
3564 lineView.changes = null;
3565 }
3566
3567 // Lines with gutter elements, widgets or a background class need to
3568 // be wrapped, and have the extra elements added to the wrapper div
3569 function ensureLineWrapped(lineView) {
3570 if (lineView.node == lineView.text) {
3571 lineView.node = elt("div", null, null, "position: relative");
3572 if (lineView.text.parentNode)
3573 { lineView.text.parentNode.replaceChild(lineView.node, lineView.text); }
3574 lineView.node.appendChild(lineView.text);
3575 if (ie && ie_version < 8) { lineView.node.style.zIndex = 2; }
3576 }
3577 return lineView.node
3578 }
3579
3580 function updateLineBackground(cm, lineView) {
3581 var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
3582 if (cls) { cls += " CodeMirror-linebackground"; }
3583 if (lineView.background) {
3584 if (cls) { lineView.background.className = cls; }
3585 else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
3586 } else if (cls) {
3587 var wrap = ensureLineWrapped(lineView);
3588 lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
3589 cm.display.input.setUneditable(lineView.background);
3590 }
3591 }
3592
3593 // Wrapper around buildLineContent which will reuse the structure
3594 // in display.externalMeasured when possible.
3595 function getLineContent(cm, lineView) {
3596 var ext = cm.display.externalMeasured;
3597 if (ext && ext.line == lineView.line) {
3598 cm.display.externalMeasured = null;
3599 lineView.measure = ext.measure;
3600 return ext.built
3601 }
3602 return buildLineContent(cm, lineView)
3603 }
3604
3605 // Redraw the line's text. Interacts with the background and text
3606 // classes because the mode may output tokens that influence these
3607 // classes.
3608 function updateLineText(cm, lineView) {
3609 var cls = lineView.text.className;
3610 var built = getLineContent(cm, lineView);
3611 if (lineView.text == lineView.node) { lineView.node = built.pre; }
3612 lineView.text.parentNode.replaceChild(built.pre, lineView.text);
3613 lineView.text = built.pre;
3614 if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
3615 lineView.bgClass = built.bgClass;
3616 lineView.textClass = built.textClass;
3617 updateLineClasses(cm, lineView);
3618 } else if (cls) {
3619 lineView.text.className = cls;
3620 }
3621 }
3622
3623 function updateLineClasses(cm, lineView) {
3624 updateLineBackground(cm, lineView);
3625 if (lineView.line.wrapClass)
3626 { ensureLineWrapped(lineView).className = lineView.line.wrapClass; }
3627 else if (lineView.node != lineView.text)
3628 { lineView.node.className = ""; }
3629 var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
3630 lineView.text.className = textClass || "";
3631 }
3632
3633 function updateLineGutter(cm, lineView, lineN, dims) {
3634 if (lineView.gutter) {
3635 lineView.node.removeChild(lineView.gutter);
3636 lineView.gutter = null;
3637 }
3638 if (lineView.gutterBackground) {
3639 lineView.node.removeChild(lineView.gutterBackground);
3640 lineView.gutterBackground = null;
3641 }
3642 if (lineView.line.gutterClass) {
3643 var wrap = ensureLineWrapped(lineView);
3644 lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
3645 ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px"));
3646 cm.display.input.setUneditable(lineView.gutterBackground);
3647 wrap.insertBefore(lineView.gutterBackground, lineView.text);
3648 }
3649 var markers = lineView.line.gutterMarkers;
3650 if (cm.options.lineNumbers || markers) {
3651 var wrap$1 = ensureLineWrapped(lineView);
3652 var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"));
3653 cm.display.input.setUneditable(gutterWrap);
3654 wrap$1.insertBefore(gutterWrap, lineView.text);
3655 if (lineView.line.gutterClass)
3656 { gutterWrap.className += " " + lineView.line.gutterClass; }
3657 if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
3658 { lineView.lineNumber = gutterWrap.appendChild(
3659 elt("div", lineNumberFor(cm.options, lineN),
3660 "CodeMirror-linenumber CodeMirror-gutter-elt",
3661 ("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))); }
3662 if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) {
3663 var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
3664 if (found)
3665 { gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
3666 ("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))); }
3667 } }
3668 }
3669 }
3670
3671 function updateLineWidgets(cm, lineView, dims) {
3672 if (lineView.alignable) { lineView.alignable = null; }
3673 for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {
3674 next = node.nextSibling;
3675 if (node.className == "CodeMirror-linewidget")
3676 { lineView.node.removeChild(node); }
3677 }
3678 insertLineWidgets(cm, lineView, dims);
3679 }
3680
3681 // Build a line's DOM representation from scratch
3682 function buildLineElement(cm, lineView, lineN, dims) {
3683 var built = getLineContent(cm, lineView);
3684 lineView.text = lineView.node = built.pre;
3685 if (built.bgClass) { lineView.bgClass = built.bgClass; }
3686 if (built.textClass) { lineView.textClass = built.textClass; }
3687
3688 updateLineClasses(cm, lineView);
3689 updateLineGutter(cm, lineView, lineN, dims);
3690 insertLineWidgets(cm, lineView, dims);
3691 return lineView.node
3692 }
3693
3694 // A lineView may contain multiple logical lines (when merged by
3695 // collapsed spans). The widgets for all of them need to be drawn.
3696 function insertLineWidgets(cm, lineView, dims) {
3697 insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
3698 if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
3699 { insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } }
3700 }
3701
3702 function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
3703 if (!line.widgets) { return }
3704 var wrap = ensureLineWrapped(lineView);
3705 for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
3706 var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
3707 if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); }
3708 positionLineWidget(widget, node, lineView, dims);
3709 cm.display.input.setUneditable(node);
3710 if (allowAbove && widget.above)
3711 { wrap.insertBefore(node, lineView.gutter || lineView.text); }
3712 else
3713 { wrap.appendChild(node); }
3714 signalLater(widget, "redraw");
3715 }
3716 }
3717
3718 function positionLineWidget(widget, node, lineView, dims) {
3719 if (widget.noHScroll) {
3720 (lineView.alignable || (lineView.alignable = [])).push(node);
3721 var width = dims.wrapperWidth;
3722 node.style.left = dims.fixedPos + "px";
3723 if (!widget.coverGutter) {
3724 width -= dims.gutterTotalWidth;
3725 node.style.paddingLeft = dims.gutterTotalWidth + "px";
3726 }
3727 node.style.width = width + "px";
3728 }
3729 if (widget.coverGutter) {
3730 node.style.zIndex = 5;
3731 node.style.position = "relative";
3732 if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px"; }
3733 }
3734 }
3735
3736 function widgetHeight(widget) {
3737 if (widget.height != null) { return widget.height }
3738 var cm = widget.doc.cm;
3739 if (!cm) { return 0 }
3740 if (!contains(document.body, widget.node)) {
3741 var parentStyle = "position: relative;";
3742 if (widget.coverGutter)
3743 { parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; }
3744 if (widget.noHScroll)
3745 { parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; }
3746 removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
3747 }
3748 return widget.height = widget.node.parentNode.offsetHeight
3749 }
3750
3751 // Return true when the given mouse event happened in a widget
3752 function eventInWidget(display, e) {
3753 for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
3754 if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
3755 (n.parentNode == display.sizer && n != display.mover))
3756 { return true }
3757 }
3758 }
3759
3760 // POSITION MEASUREMENT
3761
3762 function paddingTop(display) {return display.lineSpace.offsetTop}
3763 function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}
3764 function paddingH(display) {
3765 if (display.cachedPaddingH) { return display.cachedPaddingH }
3766 var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
3767 var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
3768 var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
3769 if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; }
3770 return data
3771 }
3772
3773 function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
3774 function displayWidth(cm) {
3775 return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth
3776 }
3777 function displayHeight(cm) {
3778 return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight
3779 }
3780
3781 // Ensure the lineView.wrapping.heights array is populated. This is
3782 // an array of bottom offsets for the lines that make up a drawn
3783 // line. When lineWrapping is on, there might be more than one
3784 // height.
3785 function ensureLineHeights(cm, lineView, rect) {
3786 var wrapping = cm.options.lineWrapping;
3787 var curWidth = wrapping && displayWidth(cm);
3788 if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
3789 var heights = lineView.measure.heights = [];
3790 if (wrapping) {
3791 lineView.measure.width = curWidth;
3792 var rects = lineView.text.firstChild.getClientRects();
3793 for (var i = 0; i < rects.length - 1; i++) {
3794 var cur = rects[i], next = rects[i + 1];
3795 if (Math.abs(cur.bottom - next.bottom) > 2)
3796 { heights.push((cur.bottom + next.top) / 2 - rect.top); }
3797 }
3798 }
3799 heights.push(rect.bottom - rect.top);
3800 }
3801 }
3802
3803 // Find a line map (mapping character offsets to text nodes) and a
3804 // measurement cache for the given line number. (A line view might
3805 // contain multiple lines when collapsed ranges are present.)
3806 function mapFromLineView(lineView, line, lineN) {
3807 if (lineView.line == line)
3808 { return {map: lineView.measure.map, cache: lineView.measure.cache} }
3809 for (var i = 0; i < lineView.rest.length; i++)
3810 { if (lineView.rest[i] == line)
3811 { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
3812 for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
3813 { if (lineNo(lineView.rest[i$1]) > lineN)
3814 { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
3815 }
3816
3817 // Render a line into the hidden node display.externalMeasured. Used
3818 // when measurement is needed for a line that's not in the viewport.
3819 function updateExternalMeasurement(cm, line) {
3820 line = visualLine(line);
3821 var lineN = lineNo(line);
3822 var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
3823 view.lineN = lineN;
3824 var built = view.built = buildLineContent(cm, view);
3825 view.text = built.pre;
3826 removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
3827 return view
3828 }
3829
3830 // Get a {top, bottom, left, right} box (in line-local coordinates)
3831 // for a given character.
3832 function measureChar(cm, line, ch, bias) {
3833 return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)
3834 }
3835
3836 // Find a line view that corresponds to the given line number.
3837 function findViewForLine(cm, lineN) {
3838 if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
3839 { return cm.display.view[findViewIndex(cm, lineN)] }
3840 var ext = cm.display.externalMeasured;
3841 if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
3842 { return ext }
3843 }
3844
3845 // Measurement can be split in two steps, the set-up work that
3846 // applies to the whole line, and the measurement of the actual
3847 // character. Functions like coordsChar, that need to do a lot of
3848 // measurements in a row, can thus ensure that the set-up work is
3849 // only done once.
3850 function prepareMeasureForLine(cm, line) {
3851 var lineN = lineNo(line);
3852 var view = findViewForLine(cm, lineN);
3853 if (view && !view.text) {
3854 view = null;
3855 } else if (view && view.changes) {
3856 updateLineForChanges(cm, view, lineN, getDimensions(cm));
3857 cm.curOp.forceUpdate = true;
3858 }
3859 if (!view)
3860 { view = updateExternalMeasurement(cm, line); }
3861
3862 var info = mapFromLineView(view, line, lineN);
3863 return {
3864 line: line, view: view, rect: null,
3865 map: info.map, cache: info.cache, before: info.before,
3866 hasHeights: false
3867 }
3868 }
3869
3870 // Given a prepared measurement object, measures the position of an
3871 // actual character (or fetches it from the cache).
3872 function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
3873 if (prepared.before) { ch = -1; }
3874 var key = ch + (bias || ""), found;
3875 if (prepared.cache.hasOwnProperty(key)) {
3876 found = prepared.cache[key];
3877 } else {
3878 if (!prepared.rect)
3879 { prepared.rect = prepared.view.text.getBoundingClientRect(); }
3880 if (!prepared.hasHeights) {
3881 ensureLineHeights(cm, prepared.view, prepared.rect);
3882 prepared.hasHeights = true;
3883 }
3884 found = measureCharInner(cm, prepared, ch, bias);
3885 if (!found.bogus) { prepared.cache[key] = found; }
3886 }
3887 return {left: found.left, right: found.right,
3888 top: varHeight ? found.rtop : found.top,
3889 bottom: varHeight ? found.rbottom : found.bottom}
3890 }
3891
3892 var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
3893
3894 function nodeAndOffsetInLineMap(map$$1, ch, bias) {
3895 var node, start, end, collapse, mStart, mEnd;
3896 // First, search the line map for the text node corresponding to,
3897 // or closest to, the target character.
3898 for (var i = 0; i < map$$1.length; i += 3) {
3899 mStart = map$$1[i];
3900 mEnd = map$$1[i + 1];
3901 if (ch < mStart) {
3902 start = 0; end = 1;
3903 collapse = "left";
3904 } else if (ch < mEnd) {
3905 start = ch - mStart;
3906 end = start + 1;
3907 } else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) {
3908 end = mEnd - mStart;
3909 start = end - 1;
3910 if (ch >= mEnd) { collapse = "right"; }
3911 }
3912 if (start != null) {
3913 node = map$$1[i + 2];
3914 if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
3915 { collapse = bias; }
3916 if (bias == "left" && start == 0)
3917 { while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) {
3918 node = map$$1[(i -= 3) + 2];
3919 collapse = "left";
3920 } }
3921 if (bias == "right" && start == mEnd - mStart)
3922 { while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) {
3923 node = map$$1[(i += 3) + 2];
3924 collapse = "right";
3925 } }
3926 break
3927 }
3928 }
3929 return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}
3930 }
3931
3932 function getUsefulRect(rects, bias) {
3933 var rect = nullRect;
3934 if (bias == "left") { for (var i = 0; i < rects.length; i++) {
3935 if ((rect = rects[i]).left != rect.right) { break }
3936 } } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {
3937 if ((rect = rects[i$1]).left != rect.right) { break }
3938 } }
3939 return rect
3940 }
3941
3942 function measureCharInner(cm, prepared, ch, bias) {
3943 var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
3944 var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
3945
3946 var rect;
3947 if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
3948 for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned
3949 while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start; }
3950 while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end; }
3951 if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)
3952 { rect = node.parentNode.getBoundingClientRect(); }
3953 else
3954 { rect = getUsefulRect(range(node, start, end).getClientRects(), bias); }
3955 if (rect.left || rect.right || start == 0) { break }
3956 end = start;
3957 start = start - 1;
3958 collapse = "right";
3959 }
3960 if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect); }
3961 } else { // If it is a widget, simply get the box for the whole widget.
3962 if (start > 0) { collapse = bias = "right"; }
3963 var rects;
3964 if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
3965 { rect = rects[bias == "right" ? rects.length - 1 : 0]; }
3966 else
3967 { rect = node.getBoundingClientRect(); }
3968 }
3969 if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
3970 var rSpan = node.parentNode.getClientRects()[0];
3971 if (rSpan)
3972 { rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; }
3973 else
3974 { rect = nullRect; }
3975 }
3976
3977 var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
3978 var mid = (rtop + rbot) / 2;
3979 var heights = prepared.view.measure.heights;
3980 var i = 0;
3981 for (; i < heights.length - 1; i++)
3982 { if (mid < heights[i]) { break } }
3983 var top = i ? heights[i - 1] : 0, bot = heights[i];
3984 var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
3985 right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
3986 top: top, bottom: bot};
3987 if (!rect.left && !rect.right) { result.bogus = true; }
3988 if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
3989
3990 return result
3991 }
3992
3993 // Work around problem with bounding client rects on ranges being
3994 // returned incorrectly when zoomed on IE10 and below.
3995 function maybeUpdateRectForZooming(measure, rect) {
3996 if (!window.screen || screen.logicalXDPI == null ||
3997 screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
3998 { return rect }
3999 var scaleX = screen.logicalXDPI / screen.deviceXDPI;
4000 var scaleY = screen.logicalYDPI / screen.deviceYDPI;
4001 return {left: rect.left * scaleX, right: rect.right * scaleX,
4002 top: rect.top * scaleY, bottom: rect.bottom * scaleY}
4003 }
4004
4005 function clearLineMeasurementCacheFor(lineView) {
4006 if (lineView.measure) {
4007 lineView.measure.cache = {};
4008 lineView.measure.heights = null;
4009 if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
4010 { lineView.measure.caches[i] = {}; } }
4011 }
4012 }
4013
4014 function clearLineMeasurementCache(cm) {
4015 cm.display.externalMeasure = null;
4016 removeChildren(cm.display.lineMeasure);
4017 for (var i = 0; i < cm.display.view.length; i++)
4018 { clearLineMeasurementCacheFor(cm.display.view[i]); }
4019 }
4020
4021 function clearCaches(cm) {
4022 clearLineMeasurementCache(cm);
4023 cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
4024 if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true; }
4025 cm.display.lineNumChars = null;
4026 }
4027
4028 function pageScrollX() {
4029 // Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206
4030 // which causes page_Offset and bounding client rects to use
4031 // different reference viewports and invalidate our calculations.
4032 if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }
4033 return window.pageXOffset || (document.documentElement || document.body).scrollLeft
4034 }
4035 function pageScrollY() {
4036 if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }
4037 return window.pageYOffset || (document.documentElement || document.body).scrollTop
4038 }
4039
4040 function widgetTopHeight(lineObj) {
4041 var height = 0;
4042 if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
4043 { height += widgetHeight(lineObj.widgets[i]); } } }
4044 return height
4045 }
4046
4047 // Converts a {top, bottom, left, right} box from line-local
4048 // coordinates into another coordinate system. Context may be one of
4049 // "line", "div" (display.lineDiv), "local"./null (editor), "window",
4050 // or "page".
4051 function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
4052 if (!includeWidgets) {
4053 var height = widgetTopHeight(lineObj);
4054 rect.top += height; rect.bottom += height;
4055 }
4056 if (context == "line") { return rect }
4057 if (!context) { context = "local"; }
4058 var yOff = heightAtLine(lineObj);
4059 if (context == "local") { yOff += paddingTop(cm.display); }
4060 else { yOff -= cm.display.viewOffset; }
4061 if (context == "page" || context == "window") {
4062 var lOff = cm.display.lineSpace.getBoundingClientRect();
4063 yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
4064 var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
4065 rect.left += xOff; rect.right += xOff;
4066 }
4067 rect.top += yOff; rect.bottom += yOff;
4068 return rect
4069 }
4070
4071 // Coverts a box from "div" coords to another coordinate system.
4072 // Context may be "window", "page", "div", or "local"./null.
4073 function fromCoordSystem(cm, coords, context) {
4074 if (context == "div") { return coords }
4075 var left = coords.left, top = coords.top;
4076 // First move into "page" coordinate system
4077 if (context == "page") {
4078 left -= pageScrollX();
4079 top -= pageScrollY();
4080 } else if (context == "local" || !context) {
4081 var localBox = cm.display.sizer.getBoundingClientRect();
4082 left += localBox.left;
4083 top += localBox.top;
4084 }
4085
4086 var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
4087 return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}
4088 }
4089
4090 function charCoords(cm, pos, context, lineObj, bias) {
4091 if (!lineObj) { lineObj = getLine(cm.doc, pos.line); }
4092 return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)
4093 }
4094
4095 // Returns a box for a given cursor position, which may have an
4096 // 'other' property containing the position of the secondary cursor
4097 // on a bidi boundary.
4098 // A cursor Pos(line, char, "before") is on the same visual line as `char - 1`
4099 // and after `char - 1` in writing order of `char - 1`
4100 // A cursor Pos(line, char, "after") is on the same visual line as `char`
4101 // and before `char` in writing order of `char`
4102 // Examples (upper-case letters are RTL, lower-case are LTR):
4103 // Pos(0, 1, ...)
4104 // before after
4105 // ab a|b a|b
4106 // aB a|B aB|
4107 // Ab |Ab A|b
4108 // AB B|A B|A
4109 // Every position after the last character on a line is considered to stick
4110 // to the last character on the line.
4111 function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
4112 lineObj = lineObj || getLine(cm.doc, pos.line);
4113 if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
4114 function get(ch, right) {
4115 var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
4116 if (right) { m.left = m.right; } else { m.right = m.left; }
4117 return intoCoordSystem(cm, lineObj, m, context)
4118 }
4119 var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky;
4120 if (ch >= lineObj.text.length) {
4121 ch = lineObj.text.length;
4122 sticky = "before";
4123 } else if (ch <= 0) {
4124 ch = 0;
4125 sticky = "after";
4126 }
4127 if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") }
4128
4129 function getBidi(ch, partPos, invert) {
4130 var part = order[partPos], right = part.level == 1;
4131 return get(invert ? ch - 1 : ch, right != invert)
4132 }
4133 var partPos = getBidiPartAt(order, ch, sticky);
4134 var other = bidiOther;
4135 var val = getBidi(ch, partPos, sticky == "before");
4136 if (other != null) { val.other = getBidi(ch, other, sticky != "before"); }
4137 return val
4138 }
4139
4140 // Used to cheaply estimate the coordinates for a position. Used for
4141 // intermediate scroll updates.
4142 function estimateCoords(cm, pos) {
4143 var left = 0;
4144 pos = clipPos(cm.doc, pos);
4145 if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch; }
4146 var lineObj = getLine(cm.doc, pos.line);
4147 var top = heightAtLine(lineObj) + paddingTop(cm.display);
4148 return {left: left, right: left, top: top, bottom: top + lineObj.height}
4149 }
4150
4151 // Positions returned by coordsChar contain some extra information.
4152 // xRel is the relative x position of the input coordinates compared
4153 // to the found position (so xRel > 0 means the coordinates are to
4154 // the right of the character position, for example). When outside
4155 // is true, that means the coordinates lie outside the line's
4156 // vertical range.
4157 function PosWithInfo(line, ch, sticky, outside, xRel) {
4158 var pos = Pos(line, ch, sticky);
4159 pos.xRel = xRel;
4160 if (outside) { pos.outside = true; }
4161 return pos
4162 }
4163
4164 // Compute the character position closest to the given coordinates.
4165 // Input must be lineSpace-local ("div" coordinate system).
4166 function coordsChar(cm, x, y) {
4167 var doc = cm.doc;
4168 y += cm.display.viewOffset;
4169 if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) }
4170 var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
4171 if (lineN > last)
4172 { return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) }
4173 if (x < 0) { x = 0; }
4174
4175 var lineObj = getLine(doc, lineN);
4176 for (;;) {
4177 var found = coordsCharInner(cm, lineObj, lineN, x, y);
4178 var merged = collapsedSpanAtEnd(lineObj);
4179 var mergedPos = merged && merged.find(0, true);
4180 if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
4181 { lineN = lineNo(lineObj = mergedPos.to.line); }
4182 else
4183 { return found }
4184 }
4185 }
4186
4187 function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
4188 y -= widgetTopHeight(lineObj);
4189 var end = lineObj.text.length;
4190 var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0);
4191 end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end);
4192 return {begin: begin, end: end}
4193 }
4194
4195 function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
4196 if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
4197 var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top;
4198 return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)
4199 }
4200
4201 // Returns true if the given side of a box is after the given
4202 // coordinates, in top-to-bottom, left-to-right order.
4203 function boxIsAfter(box, x, y, left) {
4204 return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
4205 }
4206
4207 function coordsCharInner(cm, lineObj, lineNo$$1, x, y) {
4208 // Move y into line-local coordinate space
4209 y -= heightAtLine(lineObj);
4210 var preparedMeasure = prepareMeasureForLine(cm, lineObj);
4211 // When directly calling `measureCharPrepared`, we have to adjust
4212 // for the widgets at this line.
4213 var widgetHeight$$1 = widgetTopHeight(lineObj);
4214 var begin = 0, end = lineObj.text.length, ltr = true;
4215
4216 var order = getOrder(lineObj, cm.doc.direction);
4217 // If the line isn't plain left-to-right text, first figure out
4218 // which bidi section the coordinates fall into.
4219 if (order) {
4220 var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
4221 (cm, lineObj, lineNo$$1, preparedMeasure, order, x, y);
4222 ltr = part.level != 1;
4223 // The awkward -1 offsets are needed because findFirst (called
4224 // on these below) will treat its first bound as inclusive,
4225 // second as exclusive, but we want to actually address the
4226 // characters in the part's range
4227 begin = ltr ? part.from : part.to - 1;
4228 end = ltr ? part.to : part.from - 1;
4229 }
4230
4231 // A binary search to find the first character whose bounding box
4232 // starts after the coordinates. If we run across any whose box wrap
4233 // the coordinates, store that.
4234 var chAround = null, boxAround = null;
4235 var ch = findFirst(function (ch) {
4236 var box = measureCharPrepared(cm, preparedMeasure, ch);
4237 box.top += widgetHeight$$1; box.bottom += widgetHeight$$1;
4238 if (!boxIsAfter(box, x, y, false)) { return false }
4239 if (box.top <= y && box.left <= x) {
4240 chAround = ch;
4241 boxAround = box;
4242 }
4243 return true
4244 }, begin, end);
4245
4246 var baseX, sticky, outside = false;
4247 // If a box around the coordinates was found, use that
4248 if (boxAround) {
4249 // Distinguish coordinates nearer to the left or right side of the box
4250 var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr;
4251 ch = chAround + (atStart ? 0 : 1);
4252 sticky = atStart ? "after" : "before";
4253 baseX = atLeft ? boxAround.left : boxAround.right;
4254 } else {
4255 // (Adjust for extended bound, if necessary.)
4256 if (!ltr && (ch == end || ch == begin)) { ch++; }
4257 // To determine which side to associate with, get the box to the
4258 // left of the character and compare it's vertical position to the
4259 // coordinates
4260 sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
4261 (measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight$$1 <= y) == ltr ?
4262 "after" : "before";
4263 // Now get accurate coordinates for this place, in order to get a
4264 // base X position
4265 var coords = cursorCoords(cm, Pos(lineNo$$1, ch, sticky), "line", lineObj, preparedMeasure);
4266 baseX = coords.left;
4267 outside = y < coords.top || y >= coords.bottom;
4268 }
4269
4270 ch = skipExtendingChars(lineObj.text, ch, 1);
4271 return PosWithInfo(lineNo$$1, ch, sticky, outside, x - baseX)
4272 }
4273
4274 function coordsBidiPart(cm, lineObj, lineNo$$1, preparedMeasure, order, x, y) {
4275 // Bidi parts are sorted left-to-right, and in a non-line-wrapping
4276 // situation, we can take this ordering to correspond to the visual
4277 // ordering. This finds the first part whose end is after the given
4278 // coordinates.
4279 var index = findFirst(function (i) {
4280 var part = order[i], ltr = part.level != 1;
4281 return boxIsAfter(cursorCoords(cm, Pos(lineNo$$1, ltr ? part.to : part.from, ltr ? "before" : "after"),
4282 "line", lineObj, preparedMeasure), x, y, true)
4283 }, 0, order.length - 1);
4284 var part = order[index];
4285 // If this isn't the first part, the part's start is also after
4286 // the coordinates, and the coordinates aren't on the same line as
4287 // that start, move one part back.
4288 if (index > 0) {
4289 var ltr = part.level != 1;
4290 var start = cursorCoords(cm, Pos(lineNo$$1, ltr ? part.from : part.to, ltr ? "after" : "before"),
4291 "line", lineObj, preparedMeasure);
4292 if (boxIsAfter(start, x, y, true) && start.top > y)
4293 { part = order[index - 1]; }
4294 }
4295 return part
4296 }
4297
4298 function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {
4299 // In a wrapped line, rtl text on wrapping boundaries can do things
4300 // that don't correspond to the ordering in our `order` array at
4301 // all, so a binary search doesn't work, and we want to return a
4302 // part that only spans one line so that the binary search in
4303 // coordsCharInner is safe. As such, we first find the extent of the
4304 // wrapped line, and then do a flat search in which we discard any
4305 // spans that aren't on the line.
4306 var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);
4307 var begin = ref.begin;
4308 var end = ref.end;
4309 if (/\s/.test(lineObj.text.charAt(end - 1))) { end--; }
4310 var part = null, closestDist = null;
4311 for (var i = 0; i < order.length; i++) {
4312 var p = order[i];
4313 if (p.from >= end || p.to <= begin) { continue }
4314 var ltr = p.level != 1;
4315 var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right;
4316 // Weigh against spans ending before this, so that they are only
4317 // picked if nothing ends after
4318 var dist = endX < x ? x - endX + 1e9 : endX - x;
4319 if (!part || closestDist > dist) {
4320 part = p;
4321 closestDist = dist;
4322 }
4323 }
4324 if (!part) { part = order[order.length - 1]; }
4325 // Clip the part to the wrapped line.
4326 if (part.from < begin) { part = {from: begin, to: part.to, level: part.level}; }
4327 if (part.to > end) { part = {from: part.from, to: end, level: part.level}; }
4328 return part
4329 }
4330
4331 var measureText;
4332 // Compute the default text height.
4333 function textHeight(display) {
4334 if (display.cachedTextHeight != null) { return display.cachedTextHeight }
4335 if (measureText == null) {
4336 measureText = elt("pre");
4337 // Measure a bunch of lines, for browsers that compute
4338 // fractional heights.
4339 for (var i = 0; i < 49; ++i) {
4340 measureText.appendChild(document.createTextNode("x"));
4341 measureText.appendChild(elt("br"));
4342 }
4343 measureText.appendChild(document.createTextNode("x"));
4344 }
4345 removeChildrenAndAdd(display.measure, measureText);
4346 var height = measureText.offsetHeight / 50;
4347 if (height > 3) { display.cachedTextHeight = height; }
4348 removeChildren(display.measure);
4349 return height || 1
4350 }
4351
4352 // Compute the default character width.
4353 function charWidth(display) {
4354 if (display.cachedCharWidth != null) { return display.cachedCharWidth }
4355 var anchor = elt("span", "xxxxxxxxxx");
4356 var pre = elt("pre", [anchor]);
4357 removeChildrenAndAdd(display.measure, pre);
4358 var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
4359 if (width > 2) { display.cachedCharWidth = width; }
4360 return width || 10
4361 }
4362
4363 // Do a bulk-read of the DOM positions and sizes needed to draw the
4364 // view, so that we don't interleave reading and writing to the DOM.
4365 function getDimensions(cm) {
4366 var d = cm.display, left = {}, width = {};
4367 var gutterLeft = d.gutters.clientLeft;
4368 for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
4369 left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
4370 width[cm.options.gutters[i]] = n.clientWidth;
4371 }
4372 return {fixedPos: compensateForHScroll(d),
4373 gutterTotalWidth: d.gutters.offsetWidth,
4374 gutterLeft: left,
4375 gutterWidth: width,
4376 wrapperWidth: d.wrapper.clientWidth}
4377 }
4378
4379 // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
4380 // but using getBoundingClientRect to get a sub-pixel-accurate
4381 // result.
4382 function compensateForHScroll(display) {
4383 return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left
4384 }
4385
4386 // Returns a function that estimates the height of a line, to use as
4387 // first approximation until the line becomes visible (and is thus
4388 // properly measurable).
4389 function estimateHeight(cm) {
4390 var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
4391 var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
4392 return function (line) {
4393 if (lineIsHidden(cm.doc, line)) { return 0 }
4394
4395 var widgetsHeight = 0;
4396 if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {
4397 if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height; }
4398 } }
4399
4400 if (wrapping)
4401 { return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }
4402 else
4403 { return widgetsHeight + th }
4404 }
4405 }
4406
4407 function estimateLineHeights(cm) {
4408 var doc = cm.doc, est = estimateHeight(cm);
4409 doc.iter(function (line) {
4410 var estHeight = est(line);
4411 if (estHeight != line.height) { updateLineHeight(line, estHeight); }
4412 });
4413 }
4414
4415 // Given a mouse event, find the corresponding position. If liberal
4416 // is false, it checks whether a gutter or scrollbar was clicked,
4417 // and returns null if it was. forRect is used by rectangular
4418 // selections, and tries to estimate a character position even for
4419 // coordinates beyond the right of the text.
4420 function posFromMouse(cm, e, liberal, forRect) {
4421 var display = cm.display;
4422 if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null }
4423
4424 var x, y, space = display.lineSpace.getBoundingClientRect();
4425 // Fails unpredictably on IE[67] when mouse is dragged around quickly.
4426 try { x = e.clientX - space.left; y = e.clientY - space.top; }
4427 catch (e) { return null }
4428 var coords = coordsChar(cm, x, y), line;
4429 if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
4430 var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
4431 coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
4432 }
4433 return coords
4434 }
4435
4436 // Find the view element corresponding to a given line. Return null
4437 // when the line isn't visible.
4438 function findViewIndex(cm, n) {
4439 if (n >= cm.display.viewTo) { return null }
4440 n -= cm.display.viewFrom;
4441 if (n < 0) { return null }
4442 var view = cm.display.view;
4443 for (var i = 0; i < view.length; i++) {
4444 n -= view[i].size;
4445 if (n < 0) { return i }
4446 }
4447 }
4448
4449 function updateSelection(cm) {
4450 cm.display.input.showSelection(cm.display.input.prepareSelection());
4451 }
4452
4453 function prepareSelection(cm, primary) {
4454 if ( primary === void 0 ) primary = true;
4455
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 && 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 function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
4493
4494 // Draws the given range as a highlighted selection
4495 function drawSelectionRange(cm, range$$1, output) {
4496 var display = cm.display, doc = cm.doc;
4497 var fragment = document.createDocumentFragment();
4498 var padding = paddingH(cm.display), leftSide = padding.left;
4499 var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
4500 var docLTR = doc.direction == "ltr";
4501
4502 function add(left, top, width, bottom) {
4503 if (top < 0) { top = 0; }
4504 top = Math.round(top);
4505 bottom = Math.round(bottom);
4506 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")));
4507 }
4508
4509 function drawForLine(line, fromArg, toArg) {
4510 var lineObj = getLine(doc, line);
4511 var lineLen = lineObj.text.length;
4512 var start, end;
4513 function coords(ch, bias) {
4514 return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
4515 }
4516
4517 function wrapX(pos, dir, side) {
4518 var extent = wrappedLineExtentChar(cm, lineObj, null, pos);
4519 var prop = (dir == "ltr") == (side == "after") ? "left" : "right";
4520 var ch = side == "after" ? extent.begin : extent.end - (/\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1);
4521 return coords(ch, prop)[prop]
4522 }
4523
4524 var order = getOrder(lineObj, doc.direction);
4525 iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {
4526 var ltr = dir == "ltr";
4527 var fromPos = coords(from, ltr ? "left" : "right");
4528 var toPos = coords(to - 1, ltr ? "right" : "left");
4529
4530 var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen;
4531 var first = i == 0, last = !order || i == order.length - 1;
4532 if (toPos.top - fromPos.top <= 3) { // Single line
4533 var openLeft = (docLTR ? openStart : openEnd) && first;
4534 var openRight = (docLTR ? openEnd : openStart) && last;
4535 var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left;
4536 var right = openRight ? rightSide : (ltr ? toPos : fromPos).right;
4537 add(left, fromPos.top, right - left, fromPos.bottom);
4538 } else { // Multiple lines
4539 var topLeft, topRight, botLeft, botRight;
4540 if (ltr) {
4541 topLeft = docLTR && openStart && first ? leftSide : fromPos.left;
4542 topRight = docLTR ? rightSide : wrapX(from, dir, "before");
4543 botLeft = docLTR ? leftSide : wrapX(to, dir, "after");
4544 botRight = docLTR && openEnd && last ? rightSide : toPos.right;
4545 } else {
4546 topLeft = !docLTR ? leftSide : wrapX(from, dir, "before");
4547 topRight = !docLTR && openStart && first ? rightSide : fromPos.right;
4548 botLeft = !docLTR && openEnd && last ? leftSide : toPos.left;
4549 botRight = !docLTR ? rightSide : wrapX(to, dir, "after");
4550 }
4551 add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom);
4552 if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top); }
4553 add(botLeft, toPos.top, botRight - botLeft, toPos.bottom);
4554 }
4555
4556 if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos; }
4557 if (cmpCoords(toPos, start) < 0) { start = toPos; }
4558 if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos; }
4559 if (cmpCoords(toPos, end) < 0) { end = toPos; }
4560 });
4561 return {start: start, end: end}
4562 }
4563
4564 var sFrom = range$$1.from(), sTo = range$$1.to();
4565 if (sFrom.line == sTo.line) {
4566 drawForLine(sFrom.line, sFrom.ch, sTo.ch);
4567 } else {
4568 var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
4569 var singleVLine = visualLine(fromLine) == visualLine(toLine);
4570 var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
4571 var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
4572 if (singleVLine) {
4573 if (leftEnd.top < rightStart.top - 2) {
4574 add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
4575 add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
4576 } else {
4577 add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
4578 }
4579 }
4580 if (leftEnd.bottom < rightStart.top)
4581 { add(leftSide, leftEnd.bottom, null, rightStart.top); }
4582 }
4583
4584 output.appendChild(fragment);
4585 }
4586
4587 // Cursor-blinking
4588 function restartBlink(cm) {
4589 if (!cm.state.focused) { return }
4590 var display = cm.display;
4591 clearInterval(display.blinker);
4592 var on = true;
4593 display.cursorDiv.style.visibility = "";
4594 if (cm.options.cursorBlinkRate > 0)
4595 { display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; },
4596 cm.options.cursorBlinkRate); }
4597 else if (cm.options.cursorBlinkRate < 0)
4598 { display.cursorDiv.style.visibility = "hidden"; }
4599 }
4600
4601 function ensureFocus(cm) {
4602 if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
4603 }
4604
4605 function delayBlurEvent(cm) {
4606 cm.state.delayingBlurEvent = true;
4607 setTimeout(function () { if (cm.state.delayingBlurEvent) {
4608 cm.state.delayingBlurEvent = false;
4609 onBlur(cm);
4610 } }, 100);
4611 }
4612
4613 function onFocus(cm, e) {
4614 if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; }
4615
4616 if (cm.options.readOnly == "nocursor") { return }
4617 if (!cm.state.focused) {
4618 signal(cm, "focus", cm, e);
4619 cm.state.focused = true;
4620 addClass(cm.display.wrapper, "CodeMirror-focused");
4621 // This test prevents this from firing when a context
4622 // menu is closed (since the input reset would kill the
4623 // select-all detection hack)
4624 if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
4625 cm.display.input.reset();
4626 if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730
4627 }
4628 cm.display.input.receivedFocus();
4629 }
4630 restartBlink(cm);
4631 }
4632 function onBlur(cm, e) {
4633 if (cm.state.delayingBlurEvent) { return }
4634
4635 if (cm.state.focused) {
4636 signal(cm, "blur", cm, e);
4637 cm.state.focused = false;
4638 rmClass(cm.display.wrapper, "CodeMirror-focused");
4639 }
4640 clearInterval(cm.display.blinker);
4641 setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false; } }, 150);
4642 }
4643
4644 // Read the actual heights of the rendered lines, and update their
4645 // stored heights to match.
4646 function updateHeightsInViewport(cm) {
4647 var display = cm.display;
4648 var prevBottom = display.lineDiv.offsetTop;
4649 for (var i = 0; i < display.view.length; i++) {
4650 var cur = display.view[i], height = (void 0);
4651 if (cur.hidden) { continue }
4652 if (ie && ie_version < 8) {
4653 var bot = cur.node.offsetTop + cur.node.offsetHeight;
4654 height = bot - prevBottom;
4655 prevBottom = bot;
4656 } else {
4657 var box = cur.node.getBoundingClientRect();
4658 height = box.bottom - box.top;
4659 }
4660 var diff = cur.line.height - height;
4661 if (height < 2) { height = textHeight(display); }
4662 if (diff > .005 || diff < -.005) {
4663 updateLineHeight(cur.line, height);
4664 updateWidgetHeight(cur.line);
4665 if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
4666 { updateWidgetHeight(cur.rest[j]); } }
4667 }
4668 }
4669 }
4670
4671 // Read and store the height of line widgets associated with the
4672 // given line.
4673 function updateWidgetHeight(line) {
4674 if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i)
4675 { line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight; } }
4676 }
4677
4678 // Compute the lines that are visible in a given viewport (defaults
4679 // the the current scroll position). viewport may contain top,
4680 // height, and ensure (see op.scrollToPos) properties.
4681 function visibleLines(display, doc, viewport) {
4682 var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
4683 top = Math.floor(top - paddingTop(display));
4684 var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
4685
4686 var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
4687 // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
4688 // forces those lines into the viewport (if possible).
4689 if (viewport && viewport.ensure) {
4690 var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
4691 if (ensureFrom < from) {
4692 from = ensureFrom;
4693 to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
4694 } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
4695 from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
4696 to = ensureTo;
4697 }
4698 }
4699 return {from: from, to: Math.max(to, from + 1)}
4700 }
4701
4702 // Re-align line numbers and gutter marks to compensate for
4703 // horizontal scrolling.
4704 function alignHorizontally(cm) {
4705 var display = cm.display, view = display.view;
4706 if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
4707 var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
4708 var gutterW = display.gutters.offsetWidth, left = comp + "px";
4709 for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {
4710 if (cm.options.fixedGutter) {
4711 if (view[i].gutter)
4712 { view[i].gutter.style.left = left; }
4713 if (view[i].gutterBackground)
4714 { view[i].gutterBackground.style.left = left; }
4715 }
4716 var align = view[i].alignable;
4717 if (align) { for (var j = 0; j < align.length; j++)
4718 { align[j].style.left = left; } }
4719 } }
4720 if (cm.options.fixedGutter)
4721 { display.gutters.style.left = (comp + gutterW) + "px"; }
4722 }
4723
4724 // Used to ensure that the line number gutter is still the right
4725 // size for the current document size. Returns true when an update
4726 // is needed.
4727 function maybeUpdateLineNumberWidth(cm) {
4728 if (!cm.options.lineNumbers) { return false }
4729 var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
4730 if (last.length != display.lineNumChars) {
4731 var test = display.measure.appendChild(elt("div", [elt("div", last)],
4732 "CodeMirror-linenumber CodeMirror-gutter-elt"));
4733 var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
4734 display.lineGutter.style.width = "";
4735 display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
4736 display.lineNumWidth = display.lineNumInnerWidth + padding;
4737 display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
4738 display.lineGutter.style.width = display.lineNumWidth + "px";
4739 updateGutterSpace(cm);
4740 return true
4741 }
4742 return false
4743 }
4744
4745 // SCROLLING THINGS INTO VIEW
4746
4747 // If an editor sits on the top or bottom of the window, partially
4748 // scrolled out of view, this ensures that the cursor is visible.
4749 function maybeScrollWindow(cm, rect) {
4750 if (signalDOMEvent(cm, "scrollCursorIntoView")) { return }
4751
4752 var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
4753 if (rect.top + box.top < 0) { doScroll = true; }
4754 else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; }
4755 if (doScroll != null && !phantom) {
4756 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;"));
4757 cm.display.lineSpace.appendChild(scrollNode);
4758 scrollNode.scrollIntoView(doScroll);
4759 cm.display.lineSpace.removeChild(scrollNode);
4760 }
4761 }
4762
4763 // Scroll a given position into view (immediately), verifying that
4764 // it actually became visible (as line heights are accurately
4765 // measured, the position of something may 'drift' during drawing).
4766 function scrollPosIntoView(cm, pos, end, margin) {
4767 if (margin == null) { margin = 0; }
4768 var rect;
4769 if (!cm.options.lineWrapping && pos == end) {
4770 // Set pos and end to the cursor positions around the character pos sticks to
4771 // If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch
4772 // If pos == Pos(_, 0, "before"), pos and end are unchanged
4773 pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos;
4774 end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos;
4775 }
4776 for (var limit = 0; limit < 5; limit++) {
4777 var changed = false;
4778 var coords = cursorCoords(cm, pos);
4779 var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
4780 rect = {left: Math.min(coords.left, endCoords.left),
4781 top: Math.min(coords.top, endCoords.top) - margin,
4782 right: Math.max(coords.left, endCoords.left),
4783 bottom: Math.max(coords.bottom, endCoords.bottom) + margin};
4784 var scrollPos = calculateScrollPos(cm, rect);
4785 var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
4786 if (scrollPos.scrollTop != null) {
4787 updateScrollTop(cm, scrollPos.scrollTop);
4788 if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true; }
4789 }
4790 if (scrollPos.scrollLeft != null) {
4791 setScrollLeft(cm, scrollPos.scrollLeft);
4792 if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true; }
4793 }
4794 if (!changed) { break }
4795 }
4796 return rect
4797 }
4798
4799 // Scroll a given set of coordinates into view (immediately).
4800 function scrollIntoView(cm, rect) {
4801 var scrollPos = calculateScrollPos(cm, rect);
4802 if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop); }
4803 if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); }
4804 }
4805
4806 // Calculate a new scroll position needed to scroll the given
4807 // rectangle into view. Returns an object with scrollTop and
4808 // scrollLeft properties. When these are undefined, the
4809 // vertical/horizontal position does not need to be adjusted.
4810 function calculateScrollPos(cm, rect) {
4811 var display = cm.display, snapMargin = textHeight(cm.display);
4812 if (rect.top < 0) { rect.top = 0; }
4813 var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
4814 var screen = displayHeight(cm), result = {};
4815 if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen; }
4816 var docBottom = cm.doc.height + paddingVert(display);
4817 var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin;
4818 if (rect.top < screentop) {
4819 result.scrollTop = atTop ? 0 : rect.top;
4820 } else if (rect.bottom > screentop + screen) {
4821 var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen);
4822 if (newTop != screentop) { result.scrollTop = newTop; }
4823 }
4824
4825 var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
4826 var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
4827 var tooWide = rect.right - rect.left > screenw;
4828 if (tooWide) { rect.right = rect.left + screenw; }
4829 if (rect.left < 10)
4830 { result.scrollLeft = 0; }
4831 else if (rect.left < screenleft)
4832 { result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); }
4833 else if (rect.right > screenw + screenleft - 3)
4834 { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }
4835 return result
4836 }
4837
4838 // Store a relative adjustment to the scroll position in the current
4839 // operation (to be applied when the operation finishes).
4840 function addToScrollTop(cm, top) {
4841 if (top == null) { return }
4842 resolveScrollToPos(cm);
4843 cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
4844 }
4845
4846 // Make sure that at the end of the operation the current cursor is
4847 // shown.
4848 function ensureCursorVisible(cm) {
4849 resolveScrollToPos(cm);
4850 var cur = cm.getCursor();
4851 cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin};
4852 }
4853
4854 function scrollToCoords(cm, x, y) {
4855 if (x != null || y != null) { resolveScrollToPos(cm); }
4856 if (x != null) { cm.curOp.scrollLeft = x; }
4857 if (y != null) { cm.curOp.scrollTop = y; }
4858 }
4859
4860 function scrollToRange(cm, range$$1) {
4861 resolveScrollToPos(cm);
4862 cm.curOp.scrollToPos = range$$1;
4863 }
4864
4865 // When an operation has its scrollToPos property set, and another
4866 // scroll action is applied before the end of the operation, this
4867 // 'simulates' scrolling that position into view in a cheap way, so
4868 // that the effect of intermediate scroll commands is not ignored.
4869 function resolveScrollToPos(cm) {
4870 var range$$1 = cm.curOp.scrollToPos;
4871 if (range$$1) {
4872 cm.curOp.scrollToPos = null;
4873 var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to);
4874 scrollToCoordsRange(cm, from, to, range$$1.margin);
4875 }
4876 }
4877
4878 function scrollToCoordsRange(cm, from, to, margin) {
4879 var sPos = calculateScrollPos(cm, {
4880 left: Math.min(from.left, to.left),
4881 top: Math.min(from.top, to.top) - margin,
4882 right: Math.max(from.right, to.right),
4883 bottom: Math.max(from.bottom, to.bottom) + margin
4884 });
4885 scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop);
4886 }
4887
4888 // Sync the scrollable area and scrollbars, ensure the viewport
4889 // covers the visible area.
4890 function updateScrollTop(cm, val) {
4891 if (Math.abs(cm.doc.scrollTop - val) < 2) { return }
4892 if (!gecko) { updateDisplaySimple(cm, {top: val}); }
4893 setScrollTop(cm, val, true);
4894 if (gecko) { updateDisplaySimple(cm); }
4895 startWorker(cm, 100);
4896 }
4897
4898 function setScrollTop(cm, val, forceScroll) {
4899 val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val);
4900 if (cm.display.scroller.scrollTop == val && !forceScroll) { return }
4901 cm.doc.scrollTop = val;
4902 cm.display.scrollbars.setScrollTop(val);
4903 if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val; }
4904 }
4905
4906 // Sync scroller and scrollbar, ensure the gutter elements are
4907 // aligned.
4908 function setScrollLeft(cm, val, isScroller, forceScroll) {
4909 val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
4910 if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }
4911 cm.doc.scrollLeft = val;
4912 alignHorizontally(cm);
4913 if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val; }
4914 cm.display.scrollbars.setScrollLeft(val);
4915 }
4916
4917 // SCROLLBARS
4918
4919 // Prepare DOM reads needed to update the scrollbars. Done in one
4920 // shot to minimize update/measure roundtrips.
4921 function measureForScrollbars(cm) {
4922 var d = cm.display, gutterW = d.gutters.offsetWidth;
4923 var docH = Math.round(cm.doc.height + paddingVert(cm.display));
4924 return {
4925 clientHeight: d.scroller.clientHeight,
4926 viewHeight: d.wrapper.clientHeight,
4927 scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
4928 viewWidth: d.wrapper.clientWidth,
4929 barLeft: cm.options.fixedGutter ? gutterW : 0,
4930 docHeight: docH,
4931 scrollHeight: docH + scrollGap(cm) + d.barHeight,
4932 nativeBarWidth: d.nativeBarWidth,
4933 gutterWidth: gutterW
4934 }
4935 }
4936
4937 var NativeScrollbars = function(place, scroll, cm) {
4938 this.cm = cm;
4939 var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
4940 var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
4941 place(vert); place(horiz);
4942
4943 on(vert, "scroll", function () {
4944 if (vert.clientHeight) { scroll(vert.scrollTop, "vertical"); }
4945 });
4946 on(horiz, "scroll", function () {
4947 if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal"); }
4948 });
4949
4950 this.checkedZeroWidth = false;
4951 // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
4952 if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; }
4953 };
4954
4955 NativeScrollbars.prototype.update = function (measure) {
4956 var needsH = measure.scrollWidth > measure.clientWidth + 1;
4957 var needsV = measure.scrollHeight > measure.clientHeight + 1;
4958 var sWidth = measure.nativeBarWidth;
4959
4960 if (needsV) {
4961 this.vert.style.display = "block";
4962 this.vert.style.bottom = needsH ? sWidth + "px" : "0";
4963 var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
4964 // A bug in IE8 can cause this value to be negative, so guard it.
4965 this.vert.firstChild.style.height =
4966 Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
4967 } else {
4968 this.vert.style.display = "";
4969 this.vert.firstChild.style.height = "0";
4970 }
4971
4972 if (needsH) {
4973 this.horiz.style.display = "block";
4974 this.horiz.style.right = needsV ? sWidth + "px" : "0";
4975 this.horiz.style.left = measure.barLeft + "px";
4976 var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
4977 this.horiz.firstChild.style.width =
4978 Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
4979 } else {
4980 this.horiz.style.display = "";
4981 this.horiz.firstChild.style.width = "0";
4982 }
4983
4984 if (!this.checkedZeroWidth && measure.clientHeight > 0) {
4985 if (sWidth == 0) { this.zeroWidthHack(); }
4986 this.checkedZeroWidth = true;
4987 }
4988
4989 return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
4990 };
4991
4992 NativeScrollbars.prototype.setScrollLeft = function (pos) {
4993 if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos; }
4994 if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz"); }
4995 };
4996
4997 NativeScrollbars.prototype.setScrollTop = function (pos) {
4998 if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos; }
4999 if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, "vert"); }
5000 };
5001
5002 NativeScrollbars.prototype.zeroWidthHack = function () {
5003 var w = mac && !mac_geMountainLion ? "12px" : "18px";
5004 this.horiz.style.height = this.vert.style.width = w;
5005 this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
5006 this.disableHoriz = new Delayed;
5007 this.disableVert = new Delayed;
5008 };
5009
5010 NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) {
5011 bar.style.pointerEvents = "auto";
5012 function maybeDisable() {
5013 // To find out whether the scrollbar is still visible, we
5014 // check whether the element under the pixel in the bottom
5015 // right corner of the scrollbar box is the scrollbar box
5016 // itself (when the bar is still visible) or its filler child
5017 // (when the bar is hidden). If it is still visible, we keep
5018 // it enabled, if it's hidden, we disable pointer events.
5019 var box = bar.getBoundingClientRect();
5020 var elt$$1 = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)
5021 : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1);
5022 if (elt$$1 != bar) { bar.style.pointerEvents = "none"; }
5023 else { delay.set(1000, maybeDisable); }
5024 }
5025 delay.set(1000, maybeDisable);
5026 };
5027
5028 NativeScrollbars.prototype.clear = function () {
5029 var parent = this.horiz.parentNode;
5030 parent.removeChild(this.horiz);
5031 parent.removeChild(this.vert);
5032 };
5033
5034 var NullScrollbars = function () {};
5035
5036 NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} };
5037 NullScrollbars.prototype.setScrollLeft = function () {};
5038 NullScrollbars.prototype.setScrollTop = function () {};
5039 NullScrollbars.prototype.clear = function () {};
5040
5041 function updateScrollbars(cm, measure) {
5042 if (!measure) { measure = measureForScrollbars(cm); }
5043 var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
5044 updateScrollbarsInner(cm, measure);
5045 for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
5046 if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
5047 { updateHeightsInViewport(cm); }
5048 updateScrollbarsInner(cm, measureForScrollbars(cm));
5049 startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
5050 }
5051 }
5052
5053 // Re-synchronize the fake scrollbars with the actual size of the
5054 // content.
5055 function updateScrollbarsInner(cm, measure) {
5056 var d = cm.display;
5057 var sizes = d.scrollbars.update(measure);
5058
5059 d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
5060 d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
5061 d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent";
5062
5063 if (sizes.right && sizes.bottom) {
5064 d.scrollbarFiller.style.display = "block";
5065 d.scrollbarFiller.style.height = sizes.bottom + "px";
5066 d.scrollbarFiller.style.width = sizes.right + "px";
5067 } else { d.scrollbarFiller.style.display = ""; }
5068 if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
5069 d.gutterFiller.style.display = "block";
5070 d.gutterFiller.style.height = sizes.bottom + "px";
5071 d.gutterFiller.style.width = measure.gutterWidth + "px";
5072 } else { d.gutterFiller.style.display = ""; }
5073 }
5074
5075 var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
5076
5077 function initScrollbars(cm) {
5078 if (cm.display.scrollbars) {
5079 cm.display.scrollbars.clear();
5080 if (cm.display.scrollbars.addClass)
5081 { rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
5082 }
5083
5084 cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {
5085 cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
5086 // Prevent clicks in the scrollbars from killing focus
5087 on(node, "mousedown", function () {
5088 if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); }
5089 });
5090 node.setAttribute("cm-not-content", "true");
5091 }, function (pos, axis) {
5092 if (axis == "horizontal") { setScrollLeft(cm, pos); }
5093 else { updateScrollTop(cm, pos); }
5094 }, cm);
5095 if (cm.display.scrollbars.addClass)
5096 { addClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
5097 }
5098
5099 // Operations are used to wrap a series of changes to the editor
5100 // state in such a way that each change won't have to update the
5101 // cursor and display (which would be awkward, slow, and
5102 // error-prone). Instead, display updates are batched and then all
5103 // combined and executed at once.
5104
5105 var nextOpId = 0;
5106 // Start a new operation.
5107 function startOperation(cm) {
5108 cm.curOp = {
5109 cm: cm,
5110 viewChanged: false, // Flag that indicates that lines might need to be redrawn
5111 startHeight: cm.doc.height, // Used to detect need to update scrollbar
5112 forceUpdate: false, // Used to force a redraw
5113 updateInput: null, // Whether to reset the input textarea
5114 typing: false, // Whether this reset should be careful to leave existing text (for compositing)
5115 changeObjs: null, // Accumulated changes, for firing change events
5116 cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
5117 cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
5118 selectionChanged: false, // Whether the selection needs to be redrawn
5119 updateMaxLine: false, // Set when the widest line needs to be determined anew
5120 scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
5121 scrollToPos: null, // Used to scroll to a specific position
5122 focus: false,
5123 id: ++nextOpId // Unique ID
5124 };
5125 pushOperation(cm.curOp);
5126 }
5127
5128 // Finish an operation, updating the display and signalling delayed events
5129 function endOperation(cm) {
5130 var op = cm.curOp;
5131 finishOperation(op, function (group) {
5132 for (var i = 0; i < group.ops.length; i++)
5133 { group.ops[i].cm.curOp = null; }
5134 endOperations(group);
5135 });
5136 }
5137
5138 // The DOM updates done when an operation finishes are batched so
5139 // that the minimum number of relayouts are required.
5140 function endOperations(group) {
5141 var ops = group.ops;
5142 for (var i = 0; i < ops.length; i++) // Read DOM
5143 { endOperation_R1(ops[i]); }
5144 for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)
5145 { endOperation_W1(ops[i$1]); }
5146 for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM
5147 { endOperation_R2(ops[i$2]); }
5148 for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)
5149 { endOperation_W2(ops[i$3]); }
5150 for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM
5151 { endOperation_finish(ops[i$4]); }
5152 }
5153
5154 function endOperation_R1(op) {
5155 var cm = op.cm, display = cm.display;
5156 maybeClipScrollbars(cm);
5157 if (op.updateMaxLine) { findMaxLine(cm); }
5158
5159 op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
5160 op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
5161 op.scrollToPos.to.line >= display.viewTo) ||
5162 display.maxLineChanged && cm.options.lineWrapping;
5163 op.update = op.mustUpdate &&
5164 new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
5165 }
5166
5167 function endOperation_W1(op) {
5168 op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
5169 }
5170
5171 function endOperation_R2(op) {
5172 var cm = op.cm, display = cm.display;
5173 if (op.updatedDisplay) { updateHeightsInViewport(cm); }
5174
5175 op.barMeasure = measureForScrollbars(cm);
5176
5177 // If the max line changed since it was last measured, measure it,
5178 // and ensure the document's width matches it.
5179 // updateDisplay_W2 will use these properties to do the actual resizing
5180 if (display.maxLineChanged && !cm.options.lineWrapping) {
5181 op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
5182 cm.display.sizerWidth = op.adjustWidthTo;
5183 op.barMeasure.scrollWidth =
5184 Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
5185 op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
5186 }
5187
5188 if (op.updatedDisplay || op.selectionChanged)
5189 { op.preparedSelection = display.input.prepareSelection(); }
5190 }
5191
5192 function endOperation_W2(op) {
5193 var cm = op.cm;
5194
5195 if (op.adjustWidthTo != null) {
5196 cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
5197 if (op.maxScrollLeft < cm.doc.scrollLeft)
5198 { setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); }
5199 cm.display.maxLineChanged = false;
5200 }
5201
5202 var takeFocus = op.focus && op.focus == activeElt();
5203 if (op.preparedSelection)
5204 { cm.display.input.showSelection(op.preparedSelection, takeFocus); }
5205 if (op.updatedDisplay || op.startHeight != cm.doc.height)
5206 { updateScrollbars(cm, op.barMeasure); }
5207 if (op.updatedDisplay)
5208 { setDocumentHeight(cm, op.barMeasure); }
5209
5210 if (op.selectionChanged) { restartBlink(cm); }
5211
5212 if (cm.state.focused && op.updateInput)
5213 { cm.display.input.reset(op.typing); }
5214 if (takeFocus) { ensureFocus(op.cm); }
5215 }
5216
5217 function endOperation_finish(op) {
5218 var cm = op.cm, display = cm.display, doc = cm.doc;
5219
5220 if (op.updatedDisplay) { postUpdateDisplay(cm, op.update); }
5221
5222 // Abort mouse wheel delta measurement, when scrolling explicitly
5223 if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
5224 { display.wheelStartX = display.wheelStartY = null; }
5225
5226 // Propagate the scroll position to the actual DOM scroller
5227 if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll); }
5228
5229 if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true); }
5230 // If we need to scroll a specific position into view, do so.
5231 if (op.scrollToPos) {
5232 var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
5233 clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
5234 maybeScrollWindow(cm, rect);
5235 }
5236
5237 // Fire events for markers that are hidden/unidden by editing or
5238 // undoing
5239 var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
5240 if (hidden) { for (var i = 0; i < hidden.length; ++i)
5241 { if (!hidden[i].lines.length) { signal(hidden[i], "hide"); } } }
5242 if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1)
5243 { if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide"); } } }
5244
5245 if (display.wrapper.offsetHeight)
5246 { doc.scrollTop = cm.display.scroller.scrollTop; }
5247
5248 // Fire change events, and delayed event handlers
5249 if (op.changeObjs)
5250 { signal(cm, "changes", cm, op.changeObjs); }
5251 if (op.update)
5252 { op.update.finish(); }
5253 }
5254
5255 // Run the given function in an operation
5256 function runInOp(cm, f) {
5257 if (cm.curOp) { return f() }
5258 startOperation(cm);
5259 try { return f() }
5260 finally { endOperation(cm); }
5261 }
5262 // Wraps a function in an operation. Returns the wrapped function.
5263 function operation(cm, f) {
5264 return function() {
5265 if (cm.curOp) { return f.apply(cm, arguments) }
5266 startOperation(cm);
5267 try { return f.apply(cm, arguments) }
5268 finally { endOperation(cm); }
5269 }
5270 }
5271 // Used to add methods to editor and doc instances, wrapping them in
5272 // operations.
5273 function methodOp(f) {
5274 return function() {
5275 if (this.curOp) { return f.apply(this, arguments) }
5276 startOperation(this);
5277 try { return f.apply(this, arguments) }
5278 finally { endOperation(this); }
5279 }
5280 }
5281 function docMethodOp(f) {
5282 return function() {
5283 var cm = this.cm;
5284 if (!cm || cm.curOp) { return f.apply(this, arguments) }
5285 startOperation(cm);
5286 try { return f.apply(this, arguments) }
5287 finally { endOperation(cm); }
5288 }
5289 }
5290
5291 // Updates the display.view data structure for a given change to the
5292 // document. From and to are in pre-change coordinates. Lendiff is
5293 // the amount of lines added or subtracted by the change. This is
5294 // used for changes that span multiple lines, or change the way
5295 // lines are divided into visual lines. regLineChange (below)
5296 // registers single-line changes.
5297 function regChange(cm, from, to, lendiff) {
5298 if (from == null) { from = cm.doc.first; }
5299 if (to == null) { to = cm.doc.first + cm.doc.size; }
5300 if (!lendiff) { lendiff = 0; }
5301
5302 var display = cm.display;
5303 if (lendiff && to < display.viewTo &&
5304 (display.updateLineNumbers == null || display.updateLineNumbers > from))
5305 { display.updateLineNumbers = from; }
5306
5307 cm.curOp.viewChanged = true;
5308
5309 if (from >= display.viewTo) { // Change after
5310 if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
5311 { resetView(cm); }
5312 } else if (to <= display.viewFrom) { // Change before
5313 if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
5314 resetView(cm);
5315 } else {
5316 display.viewFrom += lendiff;
5317 display.viewTo += lendiff;
5318 }
5319 } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
5320 resetView(cm);
5321 } else if (from <= display.viewFrom) { // Top overlap
5322 var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
5323 if (cut) {
5324 display.view = display.view.slice(cut.index);
5325 display.viewFrom = cut.lineN;
5326 display.viewTo += lendiff;
5327 } else {
5328 resetView(cm);
5329 }
5330 } else if (to >= display.viewTo) { // Bottom overlap
5331 var cut$1 = viewCuttingPoint(cm, from, from, -1);
5332 if (cut$1) {
5333 display.view = display.view.slice(0, cut$1.index);
5334 display.viewTo = cut$1.lineN;
5335 } else {
5336 resetView(cm);
5337 }
5338 } else { // Gap in the middle
5339 var cutTop = viewCuttingPoint(cm, from, from, -1);
5340 var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
5341 if (cutTop && cutBot) {
5342 display.view = display.view.slice(0, cutTop.index)
5343 .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
5344 .concat(display.view.slice(cutBot.index));
5345 display.viewTo += lendiff;
5346 } else {
5347 resetView(cm);
5348 }
5349 }
5350
5351 var ext = display.externalMeasured;
5352 if (ext) {
5353 if (to < ext.lineN)
5354 { ext.lineN += lendiff; }
5355 else if (from < ext.lineN + ext.size)
5356 { display.externalMeasured = null; }
5357 }
5358 }
5359
5360 // Register a change to a single line. Type must be one of "text",
5361 // "gutter", "class", "widget"
5362 function regLineChange(cm, line, type) {
5363 cm.curOp.viewChanged = true;
5364 var display = cm.display, ext = cm.display.externalMeasured;
5365 if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
5366 { display.externalMeasured = null; }
5367
5368 if (line < display.viewFrom || line >= display.viewTo) { return }
5369 var lineView = display.view[findViewIndex(cm, line)];
5370 if (lineView.node == null) { return }
5371 var arr = lineView.changes || (lineView.changes = []);
5372 if (indexOf(arr, type) == -1) { arr.push(type); }
5373 }
5374
5375 // Clear the view.
5376 function resetView(cm) {
5377 cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
5378 cm.display.view = [];
5379 cm.display.viewOffset = 0;
5380 }
5381
5382 function viewCuttingPoint(cm, oldN, newN, dir) {
5383 var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
5384 if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
5385 { return {index: index, lineN: newN} }
5386 var n = cm.display.viewFrom;
5387 for (var i = 0; i < index; i++)
5388 { n += view[i].size; }
5389 if (n != oldN) {
5390 if (dir > 0) {
5391 if (index == view.length - 1) { return null }
5392 diff = (n + view[index].size) - oldN;
5393 index++;
5394 } else {
5395 diff = n - oldN;
5396 }
5397 oldN += diff; newN += diff;
5398 }
5399 while (visualLineNo(cm.doc, newN) != newN) {
5400 if (index == (dir < 0 ? 0 : view.length - 1)) { return null }
5401 newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
5402 index += dir;
5403 }
5404 return {index: index, lineN: newN}
5405 }
5406
5407 // Force the view to cover a given range, adding empty view element
5408 // or clipping off existing ones as needed.
5409 function adjustView(cm, from, to) {
5410 var display = cm.display, view = display.view;
5411 if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
5412 display.view = buildViewArray(cm, from, to);
5413 display.viewFrom = from;
5414 } else {
5415 if (display.viewFrom > from)
5416 { display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); }
5417 else if (display.viewFrom < from)
5418 { display.view = display.view.slice(findViewIndex(cm, from)); }
5419 display.viewFrom = from;
5420 if (display.viewTo < to)
5421 { display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); }
5422 else if (display.viewTo > to)
5423 { display.view = display.view.slice(0, findViewIndex(cm, to)); }
5424 }
5425 display.viewTo = to;
5426 }
5427
5428 // Count the number of lines in the view whose DOM representation is
5429 // out of date (or nonexistent).
5430 function countDirtyView(cm) {
5431 var view = cm.display.view, dirty = 0;
5432 for (var i = 0; i < view.length; i++) {
5433 var lineView = view[i];
5434 if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }
5435 }
5436 return dirty
5437 }
5438
5439 // HIGHLIGHT WORKER
5440
5441 function startWorker(cm, time) {
5442 if (cm.doc.highlightFrontier < cm.display.viewTo)
5443 { cm.state.highlight.set(time, bind(highlightWorker, cm)); }
5444 }
5445
5446 function highlightWorker(cm) {
5447 var doc = cm.doc;
5448 if (doc.highlightFrontier >= cm.display.viewTo) { return }
5449 var end = +new Date + cm.options.workTime;
5450 var context = getContextBefore(cm, doc.highlightFrontier);
5451 var changedLines = [];
5452
5453 doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {
5454 if (context.line >= cm.display.viewFrom) { // Visible
5455 var oldStyles = line.styles;
5456 var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null;
5457 var highlighted = highlightLine(cm, line, context, true);
5458 if (resetState) { context.state = resetState; }
5459 line.styles = highlighted.styles;
5460 var oldCls = line.styleClasses, newCls = highlighted.classes;
5461 if (newCls) { line.styleClasses = newCls; }
5462 else if (oldCls) { line.styleClasses = null; }
5463 var ischange = !oldStyles || oldStyles.length != line.styles.length ||
5464 oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
5465 for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i]; }
5466 if (ischange) { changedLines.push(context.line); }
5467 line.stateAfter = context.save();
5468 context.nextLine();
5469 } else {
5470 if (line.text.length <= cm.options.maxHighlightLength)
5471 { processLine(cm, line.text, context); }
5472 line.stateAfter = context.line % 5 == 0 ? context.save() : null;
5473 context.nextLine();
5474 }
5475 if (+new Date > end) {
5476 startWorker(cm, cm.options.workDelay);
5477 return true
5478 }
5479 });
5480 doc.highlightFrontier = context.line;
5481 doc.modeFrontier = Math.max(doc.modeFrontier, context.line);
5482 if (changedLines.length) { runInOp(cm, function () {
5483 for (var i = 0; i < changedLines.length; i++)
5484 { regLineChange(cm, changedLines[i], "text"); }
5485 }); }
5486 }
5487
5488 // DISPLAY DRAWING
5489
5490 var DisplayUpdate = function(cm, viewport, force) {
5491 var display = cm.display;
5492
5493 this.viewport = viewport;
5494 // Store some values that we'll need later (but don't want to force a relayout for)
5495 this.visible = visibleLines(display, cm.doc, viewport);
5496 this.editorIsHidden = !display.wrapper.offsetWidth;
5497 this.wrapperHeight = display.wrapper.clientHeight;
5498 this.wrapperWidth = display.wrapper.clientWidth;
5499 this.oldDisplayWidth = displayWidth(cm);
5500 this.force = force;
5501 this.dims = getDimensions(cm);
5502 this.events = [];
5503 };
5504
5505 DisplayUpdate.prototype.signal = function (emitter, type) {
5506 if (hasHandler(emitter, type))
5507 { this.events.push(arguments); }
5508 };
5509 DisplayUpdate.prototype.finish = function () {
5510 var this$1 = this;
5511
5512 for (var i = 0; i < this.events.length; i++)
5513 { signal.apply(null, this$1.events[i]); }
5514 };
5515
5516 function maybeClipScrollbars(cm) {
5517 var display = cm.display;
5518 if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
5519 display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
5520 display.heightForcer.style.height = scrollGap(cm) + "px";
5521 display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
5522 display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
5523 display.scrollbarsClipped = true;
5524 }
5525 }
5526
5527 function selectionSnapshot(cm) {
5528 if (cm.hasFocus()) { return null }
5529 var active = activeElt();
5530 if (!active || !contains(cm.display.lineDiv, active)) { return null }
5531 var result = {activeElt: active};
5532 if (window.getSelection) {
5533 var sel = window.getSelection();
5534 if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) {
5535 result.anchorNode = sel.anchorNode;
5536 result.anchorOffset = sel.anchorOffset;
5537 result.focusNode = sel.focusNode;
5538 result.focusOffset = sel.focusOffset;
5539 }
5540 }
5541 return result
5542 }
5543
5544 function restoreSelection(snapshot) {
5545 if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }
5546 snapshot.activeElt.focus();
5547 if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {
5548 var sel = window.getSelection(), range$$1 = document.createRange();
5549 range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset);
5550 range$$1.collapse(false);
5551 sel.removeAllRanges();
5552 sel.addRange(range$$1);
5553 sel.extend(snapshot.focusNode, snapshot.focusOffset);
5554 }
5555 }
5556
5557 // Does the actual updating of the line display. Bails out
5558 // (returning false) when there is nothing to be done and forced is
5559 // false.
5560 function updateDisplayIfNeeded(cm, update) {
5561 var display = cm.display, doc = cm.doc;
5562
5563 if (update.editorIsHidden) {
5564 resetView(cm);
5565 return false
5566 }
5567
5568 // Bail out if the visible area is already rendered and nothing changed.
5569 if (!update.force &&
5570 update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
5571 (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
5572 display.renderedView == display.view && countDirtyView(cm) == 0)
5573 { return false }
5574
5575 if (maybeUpdateLineNumberWidth(cm)) {
5576 resetView(cm);
5577 update.dims = getDimensions(cm);
5578 }
5579
5580 // Compute a suitable new viewport (from & to)
5581 var end = doc.first + doc.size;
5582 var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
5583 var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
5584 if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom); }
5585 if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo); }
5586 if (sawCollapsedSpans) {
5587 from = visualLineNo(cm.doc, from);
5588 to = visualLineEndNo(cm.doc, to);
5589 }
5590
5591 var different = from != display.viewFrom || to != display.viewTo ||
5592 display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
5593 adjustView(cm, from, to);
5594
5595 display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
5596 // Position the mover div to align with the current scroll position
5597 cm.display.mover.style.top = display.viewOffset + "px";
5598
5599 var toUpdate = countDirtyView(cm);
5600 if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
5601 (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
5602 { return false }
5603
5604 // For big changes, we hide the enclosing element during the
5605 // update, since that speeds up the operations on most browsers.
5606 var selSnapshot = selectionSnapshot(cm);
5607 if (toUpdate > 4) { display.lineDiv.style.display = "none"; }
5608 patchDisplay(cm, display.updateLineNumbers, update.dims);
5609 if (toUpdate > 4) { display.lineDiv.style.display = ""; }
5610 display.renderedView = display.view;
5611 // There might have been a widget with a focused element that got
5612 // hidden or updated, if so re-focus it.
5613 restoreSelection(selSnapshot);
5614
5615 // Prevent selection and cursors from interfering with the scroll
5616 // width and height.
5617 removeChildren(display.cursorDiv);
5618 removeChildren(display.selectionDiv);
5619 display.gutters.style.height = display.sizer.style.minHeight = 0;
5620
5621 if (different) {
5622 display.lastWrapHeight = update.wrapperHeight;
5623 display.lastWrapWidth = update.wrapperWidth;
5624 startWorker(cm, 400);
5625 }
5626
5627 display.updateLineNumbers = null;
5628
5629 return true
5630 }
5631
5632 function postUpdateDisplay(cm, update) {
5633 var viewport = update.viewport;
5634
5635 for (var first = true;; first = false) {
5636 if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
5637 // Clip forced viewport to actual scrollable area.
5638 if (viewport && viewport.top != null)
5639 { viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; }
5640 // Updated line heights might result in the drawn area not
5641 // actually covering the viewport. Keep looping until it does.
5642 update.visible = visibleLines(cm.display, cm.doc, viewport);
5643 if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
5644 { break }
5645 }
5646 if (!updateDisplayIfNeeded(cm, update)) { break }
5647 updateHeightsInViewport(cm);
5648 var barMeasure = measureForScrollbars(cm);
5649 updateSelection(cm);
5650 updateScrollbars(cm, barMeasure);
5651 setDocumentHeight(cm, barMeasure);
5652 update.force = false;
5653 }
5654
5655 update.signal(cm, "update", cm);
5656 if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
5657 update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
5658 cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
5659 }
5660 }
5661
5662 function updateDisplaySimple(cm, viewport) {
5663 var update = new DisplayUpdate(cm, viewport);
5664 if (updateDisplayIfNeeded(cm, update)) {
5665 updateHeightsInViewport(cm);
5666 postUpdateDisplay(cm, update);
5667 var barMeasure = measureForScrollbars(cm);
5668 updateSelection(cm);
5669 updateScrollbars(cm, barMeasure);
5670 setDocumentHeight(cm, barMeasure);
5671 update.finish();
5672 }
5673 }
5674
5675 // Sync the actual display DOM structure with display.view, removing
5676 // nodes for lines that are no longer in view, and creating the ones
5677 // that are not there yet, and updating the ones that are out of
5678 // date.
5679 function patchDisplay(cm, updateNumbersFrom, dims) {
5680 var display = cm.display, lineNumbers = cm.options.lineNumbers;
5681 var container = display.lineDiv, cur = container.firstChild;
5682
5683 function rm(node) {
5684 var next = node.nextSibling;
5685 // Works around a throw-scroll bug in OS X Webkit
5686 if (webkit && mac && cm.display.currentWheelTarget == node)
5687 { node.style.display = "none"; }
5688 else
5689 { node.parentNode.removeChild(node); }
5690 return next
5691 }
5692
5693 var view = display.view, lineN = display.viewFrom;
5694 // Loop over the elements in the view, syncing cur (the DOM nodes
5695 // in display.lineDiv) with the view as we go.
5696 for (var i = 0; i < view.length; i++) {
5697 var lineView = view[i];
5698 if (lineView.hidden) {
5699 } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
5700 var node = buildLineElement(cm, lineView, lineN, dims);
5701 container.insertBefore(node, cur);
5702 } else { // Already drawn
5703 while (cur != lineView.node) { cur = rm(cur); }
5704 var updateNumber = lineNumbers && updateNumbersFrom != null &&
5705 updateNumbersFrom <= lineN && lineView.lineNumber;
5706 if (lineView.changes) {
5707 if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false; }
5708 updateLineForChanges(cm, lineView, lineN, dims);
5709 }
5710 if (updateNumber) {
5711 removeChildren(lineView.lineNumber);
5712 lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
5713 }
5714 cur = lineView.node.nextSibling;
5715 }
5716 lineN += lineView.size;
5717 }
5718 while (cur) { cur = rm(cur); }
5719 }
5720
5721 function updateGutterSpace(cm) {
5722 var width = cm.display.gutters.offsetWidth;
5723 cm.display.sizer.style.marginLeft = width + "px";
5724 }
5725
5726 function setDocumentHeight(cm, measure) {
5727 cm.display.sizer.style.minHeight = measure.docHeight + "px";
5728 cm.display.heightForcer.style.top = measure.docHeight + "px";
5729 cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
5730 }
5731
5732 // Rebuild the gutter elements, ensure the margin to the left of the
5733 // code matches their width.
5734 function updateGutters(cm) {
5735 var gutters = cm.display.gutters, specs = cm.options.gutters;
5736 removeChildren(gutters);
5737 var i = 0;
5738 for (; i < specs.length; ++i) {
5739 var gutterClass = specs[i];
5740 var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
5741 if (gutterClass == "CodeMirror-linenumbers") {
5742 cm.display.lineGutter = gElt;
5743 gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
5744 }
5745 }
5746 gutters.style.display = i ? "" : "none";
5747 updateGutterSpace(cm);
5748 }
5749
5750 // Make sure the gutters options contains the element
5751 // "CodeMirror-linenumbers" when the lineNumbers option is true.
5752 function setGuttersForLineNumbers(options) {
5753 var found = indexOf(options.gutters, "CodeMirror-linenumbers");
5754 if (found == -1 && options.lineNumbers) {
5755 options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
5756 } else if (found > -1 && !options.lineNumbers) {
5757 options.gutters = options.gutters.slice(0);
5758 options.gutters.splice(found, 1);
5759 }
5760 }
5761
5762 // Since the delta values reported on mouse wheel events are
5763 // unstandardized between browsers and even browser versions, and
5764 // generally horribly unpredictable, this code starts by measuring
5765 // the scroll effect that the first few mouse wheel events have,
5766 // and, from that, detects the way it can convert deltas to pixel
5767 // offsets afterwards.
5768 //
5769 // The reason we want to know the amount a wheel event will scroll
5770 // is that it gives us a chance to update the display before the
5771 // actual scrolling happens, reducing flickering.
5772
5773 var wheelSamples = 0;
5774 var wheelPixelsPerUnit = null;
5775 // Fill in a browser-detected starting value on browsers where we
5776 // know one. These don't have to be accurate -- the result of them
5777 // being wrong would just be a slight flicker on the first wheel
5778 // scroll (if it is large enough).
5779 if (ie) { wheelPixelsPerUnit = -.53; }
5780 else if (gecko) { wheelPixelsPerUnit = 15; }
5781 else if (chrome) { wheelPixelsPerUnit = -.7; }
5782 else if (safari) { wheelPixelsPerUnit = -1/3; }
5783
5784 function wheelEventDelta(e) {
5785 var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
5786 if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail; }
5787 if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail; }
5788 else if (dy == null) { dy = e.wheelDelta; }
5789 return {x: dx, y: dy}
5790 }
5791 function wheelEventPixels(e) {
5792 var delta = wheelEventDelta(e);
5793 delta.x *= wheelPixelsPerUnit;
5794 delta.y *= wheelPixelsPerUnit;
5795 return delta
5796 }
5797
5798 function onScrollWheel(cm, e) {
5799 var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
5800
5801 var display = cm.display, scroll = display.scroller;
5802 // Quit if there's nothing to scroll here
5803 var canScrollX = scroll.scrollWidth > scroll.clientWidth;
5804 var canScrollY = scroll.scrollHeight > scroll.clientHeight;
5805 if (!(dx && canScrollX || dy && canScrollY)) { return }
5806
5807 // Webkit browsers on OS X abort momentum scrolls when the target
5808 // of the scroll event is removed from the scrollable element.
5809 // This hack (see related code in patchDisplay) makes sure the
5810 // element is kept around.
5811 if (dy && mac && webkit) {
5812 outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
5813 for (var i = 0; i < view.length; i++) {
5814 if (view[i].node == cur) {
5815 cm.display.currentWheelTarget = cur;
5816 break outer
5817 }
5818 }
5819 }
5820 }
5821
5822 // On some browsers, horizontal scrolling will cause redraws to
5823 // happen before the gutter has been realigned, causing it to
5824 // wriggle around in a most unseemly way. When we have an
5825 // estimated pixels/delta value, we just handle horizontal
5826 // scrolling entirely here. It'll be slightly off from native, but
5827 // better than glitching out.
5828 if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
5829 if (dy && canScrollY)
5830 { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); }
5831 setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit));
5832 // Only prevent default scrolling if vertical scrolling is
5833 // actually possible. Otherwise, it causes vertical scroll
5834 // jitter on OSX trackpads when deltaX is small and deltaY
5835 // is large (issue #3579)
5836 if (!dy || (dy && canScrollY))
5837 { e_preventDefault(e); }
5838 display.wheelStartX = null; // Abort measurement, if in progress
5839 return
5840 }
5841
5842 // 'Project' the visible viewport to cover the area that is being
5843 // scrolled into view (if we know enough to estimate it).
5844 if (dy && wheelPixelsPerUnit != null) {
5845 var pixels = dy * wheelPixelsPerUnit;
5846 var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
5847 if (pixels < 0) { top = Math.max(0, top + pixels - 50); }
5848 else { bot = Math.min(cm.doc.height, bot + pixels + 50); }
5849 updateDisplaySimple(cm, {top: top, bottom: bot});
5850 }
5851
5852 if (wheelSamples < 20) {
5853 if (display.wheelStartX == null) {
5854 display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
5855 display.wheelDX = dx; display.wheelDY = dy;
5856 setTimeout(function () {
5857 if (display.wheelStartX == null) { return }
5858 var movedX = scroll.scrollLeft - display.wheelStartX;
5859 var movedY = scroll.scrollTop - display.wheelStartY;
5860 var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
5861 (movedX && display.wheelDX && movedX / display.wheelDX);
5862 display.wheelStartX = display.wheelStartY = null;
5863 if (!sample) { return }
5864 wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
5865 ++wheelSamples;
5866 }, 200);
5867 } else {
5868 display.wheelDX += dx; display.wheelDY += dy;
5869 }
5870 }
5871 }
5872
5873 // Selection objects are immutable. A new one is created every time
5874 // the selection changes. A selection is one or more non-overlapping
5875 // (and non-touching) ranges, sorted, and an integer that indicates
5876 // which one is the primary selection (the one that's scrolled into
5877 // view, that getCursor returns, etc).
5878 var Selection = function(ranges, primIndex) {
5879 this.ranges = ranges;
5880 this.primIndex = primIndex;
5881 };
5882
5883 Selection.prototype.primary = function () { return this.ranges[this.primIndex] };
5884
5885 Selection.prototype.equals = function (other) {
5886 var this$1 = this;
5887
5888 if (other == this) { return true }
5889 if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }
5890 for (var i = 0; i < this.ranges.length; i++) {
5891 var here = this$1.ranges[i], there = other.ranges[i];
5892 if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false }
5893 }
5894 return true
5895 };
5896
5897 Selection.prototype.deepCopy = function () {
5898 var this$1 = this;
5899
5900 var out = [];
5901 for (var i = 0; i < this.ranges.length; i++)
5902 { out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)); }
5903 return new Selection(out, this.primIndex)
5904 };
5905
5906 Selection.prototype.somethingSelected = function () {
5907 var this$1 = this;
5908
5909 for (var i = 0; i < this.ranges.length; i++)
5910 { if (!this$1.ranges[i].empty()) { return true } }
5911 return false
5912 };
5913
5914 Selection.prototype.contains = function (pos, end) {
5915 var this$1 = this;
5916
5917 if (!end) { end = pos; }
5918 for (var i = 0; i < this.ranges.length; i++) {
5919 var range = this$1.ranges[i];
5920 if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
5921 { return i }
5922 }
5923 return -1
5924 };
5925
5926 var Range = function(anchor, head) {
5927 this.anchor = anchor; this.head = head;
5928 };
5929
5930 Range.prototype.from = function () { return minPos(this.anchor, this.head) };
5931 Range.prototype.to = function () { return maxPos(this.anchor, this.head) };
5932 Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch };
5933
5934 // Take an unsorted, potentially overlapping set of ranges, and
5935 // build a selection out of it. 'Consumes' ranges array (modifying
5936 // it).
5937 function normalizeSelection(ranges, primIndex) {
5938 var prim = ranges[primIndex];
5939 ranges.sort(function (a, b) { return cmp(a.from(), b.from()); });
5940 primIndex = indexOf(ranges, prim);
5941 for (var i = 1; i < ranges.length; i++) {
5942 var cur = ranges[i], prev = ranges[i - 1];
5943 if (cmp(prev.to(), cur.from()) >= 0) {
5944 var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
5945 var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
5946 if (i <= primIndex) { --primIndex; }
5947 ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
5948 }
5949 }
5950 return new Selection(ranges, primIndex)
5951 }
5952
5953 function simpleSelection(anchor, head) {
5954 return new Selection([new Range(anchor, head || anchor)], 0)
5955 }
5956
5957 // Compute the position of the end of a change (its 'to' property
5958 // refers to the pre-change end).
5959 function changeEnd(change) {
5960 if (!change.text) { return change.to }
5961 return Pos(change.from.line + change.text.length - 1,
5962 lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0))
5963 }
5964
5965 // Adjust a position to refer to the post-change position of the
5966 // same text, or the end of the change if the change covers it.
5967 function adjustForChange(pos, change) {
5968 if (cmp(pos, change.from) < 0) { return pos }
5969 if (cmp(pos, change.to) <= 0) { return changeEnd(change) }
5970
5971 var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
5972 if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch; }
5973 return Pos(line, ch)
5974 }
5975
5976 function computeSelAfterChange(doc, change) {
5977 var out = [];
5978 for (var i = 0; i < doc.sel.ranges.length; i++) {
5979 var range = doc.sel.ranges[i];
5980 out.push(new Range(adjustForChange(range.anchor, change),
5981 adjustForChange(range.head, change)));
5982 }
5983 return normalizeSelection(out, doc.sel.primIndex)
5984 }
5985
5986 function offsetPos(pos, old, nw) {
5987 if (pos.line == old.line)
5988 { return Pos(nw.line, pos.ch - old.ch + nw.ch) }
5989 else
5990 { return Pos(nw.line + (pos.line - old.line), pos.ch) }
5991 }
5992
5993 // Used by replaceSelections to allow moving the selection to the
5994 // start or around the replaced test. Hint may be "start" or "around".
5995 function computeReplacedSel(doc, changes, hint) {
5996 var out = [];
5997 var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
5998 for (var i = 0; i < changes.length; i++) {
5999 var change = changes[i];
6000 var from = offsetPos(change.from, oldPrev, newPrev);
6001 var to = offsetPos(changeEnd(change), oldPrev, newPrev);
6002 oldPrev = change.to;
6003 newPrev = to;
6004 if (hint == "around") {
6005 var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
6006 out[i] = new Range(inv ? to : from, inv ? from : to);
6007 } else {
6008 out[i] = new Range(from, from);
6009 }
6010 }
6011 return new Selection(out, doc.sel.primIndex)
6012 }
6013
6014 // Used to get the editor into a consistent state again when options change.
6015
6016 function loadMode(cm) {
6017 cm.doc.mode = getMode(cm.options, cm.doc.modeOption);
6018 resetModeState(cm);
6019 }
6020
6021 function resetModeState(cm) {
6022 cm.doc.iter(function (line) {
6023 if (line.stateAfter) { line.stateAfter = null; }
6024 if (line.styles) { line.styles = null; }
6025 });
6026 cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first;
6027 startWorker(cm, 100);
6028 cm.state.modeGen++;
6029 if (cm.curOp) { regChange(cm); }
6030 }
6031
6032 // DOCUMENT DATA STRUCTURE
6033
6034 // By default, updates that start and end at the beginning of a line
6035 // are treated specially, in order to make the association of line
6036 // widgets and marker elements with the text behave more intuitive.
6037 function isWholeLineUpdate(doc, change) {
6038 return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
6039 (!doc.cm || doc.cm.options.wholeLineUpdateBefore)
6040 }
6041
6042 // Perform a change on the document data structure.
6043 function updateDoc(doc, change, markedSpans, estimateHeight$$1) {
6044 function spansFor(n) {return markedSpans ? markedSpans[n] : null}
6045 function update(line, text, spans) {
6046 updateLine(line, text, spans, estimateHeight$$1);
6047 signalLater(line, "change", line, change);
6048 }
6049 function linesFor(start, end) {
6050 var result = [];
6051 for (var i = start; i < end; ++i)
6052 { result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); }
6053 return result
6054 }
6055
6056 var from = change.from, to = change.to, text = change.text;
6057 var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
6058 var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
6059
6060 // Adjust the line structure
6061 if (change.full) {
6062 doc.insert(0, linesFor(0, text.length));
6063 doc.remove(text.length, doc.size - text.length);
6064 } else if (isWholeLineUpdate(doc, change)) {
6065 // This is a whole-line replace. Treated specially to make
6066 // sure line objects move the way they are supposed to.
6067 var added = linesFor(0, text.length - 1);
6068 update(lastLine, lastLine.text, lastSpans);
6069 if (nlines) { doc.remove(from.line, nlines); }
6070 if (added.length) { doc.insert(from.line, added); }
6071 } else if (firstLine == lastLine) {
6072 if (text.length == 1) {
6073 update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
6074 } else {
6075 var added$1 = linesFor(1, text.length - 1);
6076 added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1));
6077 update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
6078 doc.insert(from.line + 1, added$1);
6079 }
6080 } else if (text.length == 1) {
6081 update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
6082 doc.remove(from.line + 1, nlines);
6083 } else {
6084 update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
6085 update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
6086 var added$2 = linesFor(1, text.length - 1);
6087 if (nlines > 1) { doc.remove(from.line + 1, nlines - 1); }
6088 doc.insert(from.line + 1, added$2);
6089 }
6090
6091 signalLater(doc, "change", doc, change);
6092 }
6093
6094 // Call f for all linked documents.
6095 function linkedDocs(doc, f, sharedHistOnly) {
6096 function propagate(doc, skip, sharedHist) {
6097 if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) {
6098 var rel = doc.linked[i];
6099 if (rel.doc == skip) { continue }
6100 var shared = sharedHist && rel.sharedHist;
6101 if (sharedHistOnly && !shared) { continue }
6102 f(rel.doc, shared);
6103 propagate(rel.doc, doc, shared);
6104 } }
6105 }
6106 propagate(doc, null, true);
6107 }
6108
6109 // Attach a document to an editor.
6110 function attachDoc(cm, doc) {
6111 if (doc.cm) { throw new Error("This document is already in use.") }
6112 cm.doc = doc;
6113 doc.cm = cm;
6114 estimateLineHeights(cm);
6115 loadMode(cm);
6116 setDirectionClass(cm);
6117 if (!cm.options.lineWrapping) { findMaxLine(cm); }
6118 cm.options.mode = doc.modeOption;
6119 regChange(cm);
6120 }
6121
6122 function setDirectionClass(cm) {
6123 (cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl");
6124 }
6125
6126 function directionChanged(cm) {
6127 runInOp(cm, function () {
6128 setDirectionClass(cm);
6129 regChange(cm);
6130 });
6131 }
6132
6133 function History(startGen) {
6134 // Arrays of change events and selections. Doing something adds an
6135 // event to done and clears undo. Undoing moves events from done
6136 // to undone, redoing moves them in the other direction.
6137 this.done = []; this.undone = [];
6138 this.undoDepth = Infinity;
6139 // Used to track when changes can be merged into a single undo
6140 // event
6141 this.lastModTime = this.lastSelTime = 0;
6142 this.lastOp = this.lastSelOp = null;
6143 this.lastOrigin = this.lastSelOrigin = null;
6144 // Used by the isClean() method
6145 this.generation = this.maxGeneration = startGen || 1;
6146 }
6147
6148 // Create a history change event from an updateDoc-style change
6149 // object.
6150 function historyChangeFromChange(doc, change) {
6151 var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
6152 attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
6153 linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true);
6154 return histChange
6155 }
6156
6157 // Pop all selection events off the end of a history array. Stop at
6158 // a change event.
6159 function clearSelectionEvents(array) {
6160 while (array.length) {
6161 var last = lst(array);
6162 if (last.ranges) { array.pop(); }
6163 else { break }
6164 }
6165 }
6166
6167 // Find the top change event in the history. Pop off selection
6168 // events that are in the way.
6169 function lastChangeEvent(hist, force) {
6170 if (force) {
6171 clearSelectionEvents(hist.done);
6172 return lst(hist.done)
6173 } else if (hist.done.length && !lst(hist.done).ranges) {
6174 return lst(hist.done)
6175 } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
6176 hist.done.pop();
6177 return lst(hist.done)
6178 }
6179 }
6180
6181 // Register a change in the history. Merges changes that are within
6182 // a single operation, or are close together with an origin that
6183 // allows merging (starting with "+") into a single event.
6184 function addChangeToHistory(doc, change, selAfter, opId) {
6185 var hist = doc.history;
6186 hist.undone.length = 0;
6187 var time = +new Date, cur;
6188 var last;
6189
6190 if ((hist.lastOp == opId ||
6191 hist.lastOrigin == change.origin && change.origin &&
6192 ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
6193 change.origin.charAt(0) == "*")) &&
6194 (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
6195 // Merge this change into the last event
6196 last = lst(cur.changes);
6197 if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
6198 // Optimized case for simple insertion -- don't want to add
6199 // new changesets for every character typed
6200 last.to = changeEnd(change);
6201 } else {
6202 // Add new sub-event
6203 cur.changes.push(historyChangeFromChange(doc, change));
6204 }
6205 } else {
6206 // Can not be merged, start a new event.
6207 var before = lst(hist.done);
6208 if (!before || !before.ranges)
6209 { pushSelectionToHistory(doc.sel, hist.done); }
6210 cur = {changes: [historyChangeFromChange(doc, change)],
6211 generation: hist.generation};
6212 hist.done.push(cur);
6213 while (hist.done.length > hist.undoDepth) {
6214 hist.done.shift();
6215 if (!hist.done[0].ranges) { hist.done.shift(); }
6216 }
6217 }
6218 hist.done.push(selAfter);
6219 hist.generation = ++hist.maxGeneration;
6220 hist.lastModTime = hist.lastSelTime = time;
6221 hist.lastOp = hist.lastSelOp = opId;
6222 hist.lastOrigin = hist.lastSelOrigin = change.origin;
6223
6224 if (!last) { signal(doc, "historyAdded"); }
6225 }
6226
6227 function selectionEventCanBeMerged(doc, origin, prev, sel) {
6228 var ch = origin.charAt(0);
6229 return ch == "*" ||
6230 ch == "+" &&
6231 prev.ranges.length == sel.ranges.length &&
6232 prev.somethingSelected() == sel.somethingSelected() &&
6233 new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500)
6234 }
6235
6236 // Called whenever the selection changes, sets the new selection as
6237 // the pending selection in the history, and pushes the old pending
6238 // selection into the 'done' array when it was significantly
6239 // different (in number of selected ranges, emptiness, or time).
6240 function addSelectionToHistory(doc, sel, opId, options) {
6241 var hist = doc.history, origin = options && options.origin;
6242
6243 // A new event is started when the previous origin does not match
6244 // the current, or the origins don't allow matching. Origins
6245 // starting with * are always merged, those starting with + are
6246 // merged when similar and close together in time.
6247 if (opId == hist.lastSelOp ||
6248 (origin && hist.lastSelOrigin == origin &&
6249 (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
6250 selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
6251 { hist.done[hist.done.length - 1] = sel; }
6252 else
6253 { pushSelectionToHistory(sel, hist.done); }
6254
6255 hist.lastSelTime = +new Date;
6256 hist.lastSelOrigin = origin;
6257 hist.lastSelOp = opId;
6258 if (options && options.clearRedo !== false)
6259 { clearSelectionEvents(hist.undone); }
6260 }
6261
6262 function pushSelectionToHistory(sel, dest) {
6263 var top = lst(dest);
6264 if (!(top && top.ranges && top.equals(sel)))
6265 { dest.push(sel); }
6266 }
6267
6268 // Used to store marked span information in the history.
6269 function attachLocalSpans(doc, change, from, to) {
6270 var existing = change["spans_" + doc.id], n = 0;
6271 doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) {
6272 if (line.markedSpans)
6273 { (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; }
6274 ++n;
6275 });
6276 }
6277
6278 // When un/re-doing restores text containing marked spans, those
6279 // that have been explicitly cleared should not be restored.
6280 function removeClearedSpans(spans) {
6281 if (!spans) { return null }
6282 var out;
6283 for (var i = 0; i < spans.length; ++i) {
6284 if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i); } }
6285 else if (out) { out.push(spans[i]); }
6286 }
6287 return !out ? spans : out.length ? out : null
6288 }
6289
6290 // Retrieve and filter the old marked spans stored in a change event.
6291 function getOldSpans(doc, change) {
6292 var found = change["spans_" + doc.id];
6293 if (!found) { return null }
6294 var nw = [];
6295 for (var i = 0; i < change.text.length; ++i)
6296 { nw.push(removeClearedSpans(found[i])); }
6297 return nw
6298 }
6299
6300 // Used for un/re-doing changes from the history. Combines the
6301 // result of computing the existing spans with the set of spans that
6302 // existed in the history (so that deleting around a span and then
6303 // undoing brings back the span).
6304 function mergeOldSpans(doc, change) {
6305 var old = getOldSpans(doc, change);
6306 var stretched = stretchSpansOverChange(doc, change);
6307 if (!old) { return stretched }
6308 if (!stretched) { return old }
6309
6310 for (var i = 0; i < old.length; ++i) {
6311 var oldCur = old[i], stretchCur = stretched[i];
6312 if (oldCur && stretchCur) {
6313 spans: for (var j = 0; j < stretchCur.length; ++j) {
6314 var span = stretchCur[j];
6315 for (var k = 0; k < oldCur.length; ++k)
6316 { if (oldCur[k].marker == span.marker) { continue spans } }
6317 oldCur.push(span);
6318 }
6319 } else if (stretchCur) {
6320 old[i] = stretchCur;
6321 }
6322 }
6323 return old
6324 }
6325
6326 // Used both to provide a JSON-safe object in .getHistory, and, when
6327 // detaching a document, to split the history in two
6328 function copyHistoryArray(events, newGroup, instantiateSel) {
6329 var copy = [];
6330 for (var i = 0; i < events.length; ++i) {
6331 var event = events[i];
6332 if (event.ranges) {
6333 copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
6334 continue
6335 }
6336 var changes = event.changes, newChanges = [];
6337 copy.push({changes: newChanges});
6338 for (var j = 0; j < changes.length; ++j) {
6339 var change = changes[j], m = (void 0);
6340 newChanges.push({from: change.from, to: change.to, text: change.text});
6341 if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) {
6342 if (indexOf(newGroup, Number(m[1])) > -1) {
6343 lst(newChanges)[prop] = change[prop];
6344 delete change[prop];
6345 }
6346 } } }
6347 }
6348 }
6349 return copy
6350 }
6351
6352 // The 'scroll' parameter given to many of these indicated whether
6353 // the new cursor position should be scrolled into view after
6354 // modifying the selection.
6355
6356 // If shift is held or the extend flag is set, extends a range to
6357 // include a given position (and optionally a second position).
6358 // Otherwise, simply returns the range between the given positions.
6359 // Used for cursor motion and such.
6360 function extendRange(range, head, other, extend) {
6361 if (extend) {
6362 var anchor = range.anchor;
6363 if (other) {
6364 var posBefore = cmp(head, anchor) < 0;
6365 if (posBefore != (cmp(other, anchor) < 0)) {
6366 anchor = head;
6367 head = other;
6368 } else if (posBefore != (cmp(head, other) < 0)) {
6369 head = other;
6370 }
6371 }
6372 return new Range(anchor, head)
6373 } else {
6374 return new Range(other || head, head)
6375 }
6376 }
6377
6378 // Extend the primary selection range, discard the rest.
6379 function extendSelection(doc, head, other, options, extend) {
6380 if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend); }
6381 setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options);
6382 }
6383
6384 // Extend all selections (pos is an array of selections with length
6385 // equal the number of selections)
6386 function extendSelections(doc, heads, options) {
6387 var out = [];
6388 var extend = doc.cm && (doc.cm.display.shift || doc.extend);
6389 for (var i = 0; i < doc.sel.ranges.length; i++)
6390 { out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend); }
6391 var newSel = normalizeSelection(out, doc.sel.primIndex);
6392 setSelection(doc, newSel, options);
6393 }
6394
6395 // Updates a single range in the selection.
6396 function replaceOneSelection(doc, i, range, options) {
6397 var ranges = doc.sel.ranges.slice(0);
6398 ranges[i] = range;
6399 setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
6400 }
6401
6402 // Reset the selection to a single range.
6403 function setSimpleSelection(doc, anchor, head, options) {
6404 setSelection(doc, simpleSelection(anchor, head), options);
6405 }
6406
6407 // Give beforeSelectionChange handlers a change to influence a
6408 // selection update.
6409 function filterSelectionChange(doc, sel, options) {
6410 var obj = {
6411 ranges: sel.ranges,
6412 update: function(ranges) {
6413 var this$1 = this;
6414
6415 this.ranges = [];
6416 for (var i = 0; i < ranges.length; i++)
6417 { this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
6418 clipPos(doc, ranges[i].head)); }
6419 },
6420 origin: options && options.origin
6421 };
6422 signal(doc, "beforeSelectionChange", doc, obj);
6423 if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj); }
6424 if (obj.ranges != sel.ranges) { return normalizeSelection(obj.ranges, obj.ranges.length - 1) }
6425 else { return sel }
6426 }
6427
6428 function setSelectionReplaceHistory(doc, sel, options) {
6429 var done = doc.history.done, last = lst(done);
6430 if (last && last.ranges) {
6431 done[done.length - 1] = sel;
6432 setSelectionNoUndo(doc, sel, options);
6433 } else {
6434 setSelection(doc, sel, options);
6435 }
6436 }
6437
6438 // Set a new selection.
6439 function setSelection(doc, sel, options) {
6440 setSelectionNoUndo(doc, sel, options);
6441 addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
6442 }
6443
6444 function setSelectionNoUndo(doc, sel, options) {
6445 if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
6446 { sel = filterSelectionChange(doc, sel, options); }
6447
6448 var bias = options && options.bias ||
6449 (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
6450 setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
6451
6452 if (!(options && options.scroll === false) && doc.cm)
6453 { ensureCursorVisible(doc.cm); }
6454 }
6455
6456 function setSelectionInner(doc, sel) {
6457 if (sel.equals(doc.sel)) { return }
6458
6459 doc.sel = sel;
6460
6461 if (doc.cm) {
6462 doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
6463 signalCursorActivity(doc.cm);
6464 }
6465 signalLater(doc, "cursorActivity", doc);
6466 }
6467
6468 // Verify that the selection does not partially select any atomic
6469 // marked ranges.
6470 function reCheckSelection(doc) {
6471 setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false));
6472 }
6473
6474 // Return a selection that does not partially select any atomic
6475 // ranges.
6476 function skipAtomicInSelection(doc, sel, bias, mayClear) {
6477 var out;
6478 for (var i = 0; i < sel.ranges.length; i++) {
6479 var range = sel.ranges[i];
6480 var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
6481 var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
6482 var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
6483 if (out || newAnchor != range.anchor || newHead != range.head) {
6484 if (!out) { out = sel.ranges.slice(0, i); }
6485 out[i] = new Range(newAnchor, newHead);
6486 }
6487 }
6488 return out ? normalizeSelection(out, sel.primIndex) : sel
6489 }
6490
6491 function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
6492 var line = getLine(doc, pos.line);
6493 if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
6494 var sp = line.markedSpans[i], m = sp.marker;
6495 if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
6496 (sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
6497 if (mayClear) {
6498 signal(m, "beforeCursorEnter");
6499 if (m.explicitlyCleared) {
6500 if (!line.markedSpans) { break }
6501 else {--i; continue}
6502 }
6503 }
6504 if (!m.atomic) { continue }
6505
6506 if (oldPos) {
6507 var near = m.find(dir < 0 ? 1 : -1), diff = (void 0);
6508 if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)
6509 { near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); }
6510 if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
6511 { return skipAtomicInner(doc, near, pos, dir, mayClear) }
6512 }
6513
6514 var far = m.find(dir < 0 ? -1 : 1);
6515 if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)
6516 { far = movePos(doc, far, dir, far.line == pos.line ? line : null); }
6517 return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null
6518 }
6519 } }
6520 return pos
6521 }
6522
6523 // Ensure a given position is not inside an atomic range.
6524 function skipAtomic(doc, pos, oldPos, bias, mayClear) {
6525 var dir = bias || 1;
6526 var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
6527 (!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
6528 skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
6529 (!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
6530 if (!found) {
6531 doc.cantEdit = true;
6532 return Pos(doc.first, 0)
6533 }
6534 return found
6535 }
6536
6537 function movePos(doc, pos, dir, line) {
6538 if (dir < 0 && pos.ch == 0) {
6539 if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) }
6540 else { return null }
6541 } else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
6542 if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) }
6543 else { return null }
6544 } else {
6545 return new Pos(pos.line, pos.ch + dir)
6546 }
6547 }
6548
6549 function selectAll(cm) {
6550 cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);
6551 }
6552
6553 // UPDATING
6554
6555 // Allow "beforeChange" event handlers to influence a change
6556 function filterChange(doc, change, update) {
6557 var obj = {
6558 canceled: false,
6559 from: change.from,
6560 to: change.to,
6561 text: change.text,
6562 origin: change.origin,
6563 cancel: function () { return obj.canceled = true; }
6564 };
6565 if (update) { obj.update = function (from, to, text, origin) {
6566 if (from) { obj.from = clipPos(doc, from); }
6567 if (to) { obj.to = clipPos(doc, to); }
6568 if (text) { obj.text = text; }
6569 if (origin !== undefined) { obj.origin = origin; }
6570 }; }
6571 signal(doc, "beforeChange", doc, obj);
6572 if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj); }
6573
6574 if (obj.canceled) { return null }
6575 return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}
6576 }
6577
6578 // Apply a change to a document, and add it to the document's
6579 // history, and propagating it to all linked documents.
6580 function makeChange(doc, change, ignoreReadOnly) {
6581 if (doc.cm) {
6582 if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) }
6583 if (doc.cm.state.suppressEdits) { return }
6584 }
6585
6586 if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
6587 change = filterChange(doc, change, true);
6588 if (!change) { return }
6589 }
6590
6591 // Possibly split or suppress the update based on the presence
6592 // of read-only spans in its range.
6593 var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
6594 if (split) {
6595 for (var i = split.length - 1; i >= 0; --i)
6596 { makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}); }
6597 } else {
6598 makeChangeInner(doc, change);
6599 }
6600 }
6601
6602 function makeChangeInner(doc, change) {
6603 if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return }
6604 var selAfter = computeSelAfterChange(doc, change);
6605 addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
6606
6607 makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
6608 var rebased = [];
6609
6610 linkedDocs(doc, function (doc, sharedHist) {
6611 if (!sharedHist && indexOf(rebased, doc.history) == -1) {
6612 rebaseHist(doc.history, change);
6613 rebased.push(doc.history);
6614 }
6615 makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
6616 });
6617 }
6618
6619 // Revert a change stored in a document's history.
6620 function makeChangeFromHistory(doc, type, allowSelectionOnly) {
6621 if (doc.cm && doc.cm.state.suppressEdits && !allowSelectionOnly) { return }
6622
6623 var hist = doc.history, event, selAfter = doc.sel;
6624 var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
6625
6626 // Verify that there is a useable event (so that ctrl-z won't
6627 // needlessly clear selection events)
6628 var i = 0;
6629 for (; i < source.length; i++) {
6630 event = source[i];
6631 if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
6632 { break }
6633 }
6634 if (i == source.length) { return }
6635 hist.lastOrigin = hist.lastSelOrigin = null;
6636
6637 for (;;) {
6638 event = source.pop();
6639 if (event.ranges) {
6640 pushSelectionToHistory(event, dest);
6641 if (allowSelectionOnly && !event.equals(doc.sel)) {
6642 setSelection(doc, event, {clearRedo: false});
6643 return
6644 }
6645 selAfter = event;
6646 }
6647 else { break }
6648 }
6649
6650 // Build up a reverse change object to add to the opposite history
6651 // stack (redo when undoing, and vice versa).
6652 var antiChanges = [];
6653 pushSelectionToHistory(selAfter, dest);
6654 dest.push({changes: antiChanges, generation: hist.generation});
6655 hist.generation = event.generation || ++hist.maxGeneration;
6656
6657 var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
6658
6659 var loop = function ( i ) {
6660 var change = event.changes[i];
6661 change.origin = type;
6662 if (filter && !filterChange(doc, change, false)) {
6663 source.length = 0;
6664 return {}
6665 }
6666
6667 antiChanges.push(historyChangeFromChange(doc, change));
6668
6669 var after = i ? computeSelAfterChange(doc, change) : lst(source);
6670 makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
6671 if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); }
6672 var rebased = [];
6673
6674 // Propagate to the linked documents
6675 linkedDocs(doc, function (doc, sharedHist) {
6676 if (!sharedHist && indexOf(rebased, doc.history) == -1) {
6677 rebaseHist(doc.history, change);
6678 rebased.push(doc.history);
6679 }
6680 makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
6681 });
6682 };
6683
6684 for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) {
6685 var returned = loop( i$1 );
6686
6687 if ( returned ) return returned.v;
6688 }
6689 }
6690
6691 // Sub-views need their line numbers shifted when text is added
6692 // above or below them in the parent document.
6693 function shiftDoc(doc, distance) {
6694 if (distance == 0) { return }
6695 doc.first += distance;
6696 doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range(
6697 Pos(range.anchor.line + distance, range.anchor.ch),
6698 Pos(range.head.line + distance, range.head.ch)
6699 ); }), doc.sel.primIndex);
6700 if (doc.cm) {
6701 regChange(doc.cm, doc.first, doc.first - distance, distance);
6702 for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
6703 { regLineChange(doc.cm, l, "gutter"); }
6704 }
6705 }
6706
6707 // More lower-level change function, handling only a single document
6708 // (not linked ones).
6709 function makeChangeSingleDoc(doc, change, selAfter, spans) {
6710 if (doc.cm && !doc.cm.curOp)
6711 { return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) }
6712
6713 if (change.to.line < doc.first) {
6714 shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
6715 return
6716 }
6717 if (change.from.line > doc.lastLine()) { return }
6718
6719 // Clip the change to the size of this doc
6720 if (change.from.line < doc.first) {
6721 var shift = change.text.length - 1 - (doc.first - change.from.line);
6722 shiftDoc(doc, shift);
6723 change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
6724 text: [lst(change.text)], origin: change.origin};
6725 }
6726 var last = doc.lastLine();
6727 if (change.to.line > last) {
6728 change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
6729 text: [change.text[0]], origin: change.origin};
6730 }
6731
6732 change.removed = getBetween(doc, change.from, change.to);
6733
6734 if (!selAfter) { selAfter = computeSelAfterChange(doc, change); }
6735 if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); }
6736 else { updateDoc(doc, change, spans); }
6737 setSelectionNoUndo(doc, selAfter, sel_dontScroll);
6738 }
6739
6740 // Handle the interaction of a change to a document with the editor
6741 // that this document is part of.
6742 function makeChangeSingleDocInEditor(cm, change, spans) {
6743 var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
6744
6745 var recomputeMaxLength = false, checkWidthStart = from.line;
6746 if (!cm.options.lineWrapping) {
6747 checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
6748 doc.iter(checkWidthStart, to.line + 1, function (line) {
6749 if (line == display.maxLine) {
6750 recomputeMaxLength = true;
6751 return true
6752 }
6753 });
6754 }
6755
6756 if (doc.sel.contains(change.from, change.to) > -1)
6757 { signalCursorActivity(cm); }
6758
6759 updateDoc(doc, change, spans, estimateHeight(cm));
6760
6761 if (!cm.options.lineWrapping) {
6762 doc.iter(checkWidthStart, from.line + change.text.length, function (line) {
6763 var len = lineLength(line);
6764 if (len > display.maxLineLength) {
6765 display.maxLine = line;
6766 display.maxLineLength = len;
6767 display.maxLineChanged = true;
6768 recomputeMaxLength = false;
6769 }
6770 });
6771 if (recomputeMaxLength) { cm.curOp.updateMaxLine = true; }
6772 }
6773
6774 retreatFrontier(doc, from.line);
6775 startWorker(cm, 400);
6776
6777 var lendiff = change.text.length - (to.line - from.line) - 1;
6778 // Remember that these lines changed, for updating the display
6779 if (change.full)
6780 { regChange(cm); }
6781 else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
6782 { regLineChange(cm, from.line, "text"); }
6783 else
6784 { regChange(cm, from.line, to.line + 1, lendiff); }
6785
6786 var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
6787 if (changeHandler || changesHandler) {
6788 var obj = {
6789 from: from, to: to,
6790 text: change.text,
6791 removed: change.removed,
6792 origin: change.origin
6793 };
6794 if (changeHandler) { signalLater(cm, "change", cm, obj); }
6795 if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); }
6796 }
6797 cm.display.selForContextMenu = null;
6798 }
6799
6800 function replaceRange(doc, code, from, to, origin) {
6801 if (!to) { to = from; }
6802 if (cmp(to, from) < 0) { var assign;
6803 (assign = [to, from], from = assign[0], to = assign[1], assign); }
6804 if (typeof code == "string") { code = doc.splitLines(code); }
6805 makeChange(doc, {from: from, to: to, text: code, origin: origin});
6806 }
6807
6808 // Rebasing/resetting history to deal with externally-sourced changes
6809
6810 function rebaseHistSelSingle(pos, from, to, diff) {
6811 if (to < pos.line) {
6812 pos.line += diff;
6813 } else if (from < pos.line) {
6814 pos.line = from;
6815 pos.ch = 0;
6816 }
6817 }
6818
6819 // Tries to rebase an array of history events given a change in the
6820 // document. If the change touches the same lines as the event, the
6821 // event, and everything 'behind' it, is discarded. If the change is
6822 // before the event, the event's positions are updated. Uses a
6823 // copy-on-write scheme for the positions, to avoid having to
6824 // reallocate them all on every rebase, but also avoid problems with
6825 // shared position objects being unsafely updated.
6826 function rebaseHistArray(array, from, to, diff) {
6827 for (var i = 0; i < array.length; ++i) {
6828 var sub = array[i], ok = true;
6829 if (sub.ranges) {
6830 if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
6831 for (var j = 0; j < sub.ranges.length; j++) {
6832 rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
6833 rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
6834 }
6835 continue
6836 }
6837 for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) {
6838 var cur = sub.changes[j$1];
6839 if (to < cur.from.line) {
6840 cur.from = Pos(cur.from.line + diff, cur.from.ch);
6841 cur.to = Pos(cur.to.line + diff, cur.to.ch);
6842 } else if (from <= cur.to.line) {
6843 ok = false;
6844 break
6845 }
6846 }
6847 if (!ok) {
6848 array.splice(0, i + 1);
6849 i = 0;
6850 }
6851 }
6852 }
6853
6854 function rebaseHist(hist, change) {
6855 var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
6856 rebaseHistArray(hist.done, from, to, diff);
6857 rebaseHistArray(hist.undone, from, to, diff);
6858 }
6859
6860 // Utility for applying a change to a line by handle or number,
6861 // returning the number and optionally registering the line as
6862 // changed.
6863 function changeLine(doc, handle, changeType, op) {
6864 var no = handle, line = handle;
6865 if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)); }
6866 else { no = lineNo(handle); }
6867 if (no == null) { return null }
6868 if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType); }
6869 return line
6870 }
6871
6872 // The document is represented as a BTree consisting of leaves, with
6873 // chunk of lines in them, and branches, with up to ten leaves or
6874 // other branch nodes below them. The top node is always a branch
6875 // node, and is the document object itself (meaning it has
6876 // additional methods and properties).
6877 //
6878 // All nodes have parent links. The tree is used both to go from
6879 // line numbers to line objects, and to go from objects to numbers.
6880 // It also indexes by height, and is used to convert between height
6881 // and line object, and to find the total height of the document.
6882 //
6883 // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
6884
6885 function LeafChunk(lines) {
6886 var this$1 = this;
6887
6888 this.lines = lines;
6889 this.parent = null;
6890 var height = 0;
6891 for (var i = 0; i < lines.length; ++i) {
6892 lines[i].parent = this$1;
6893 height += lines[i].height;
6894 }
6895 this.height = height;
6896 }
6897
6898 LeafChunk.prototype = {
6899 chunkSize: function chunkSize() { return this.lines.length },
6900
6901 // Remove the n lines at offset 'at'.
6902 removeInner: function removeInner(at, n) {
6903 var this$1 = this;
6904
6905 for (var i = at, e = at + n; i < e; ++i) {
6906 var line = this$1.lines[i];
6907 this$1.height -= line.height;
6908 cleanUpLine(line);
6909 signalLater(line, "delete");
6910 }
6911 this.lines.splice(at, n);
6912 },
6913
6914 // Helper used to collapse a small branch into a single leaf.
6915 collapse: function collapse(lines) {
6916 lines.push.apply(lines, this.lines);
6917 },
6918
6919 // Insert the given array of lines at offset 'at', count them as
6920 // having the given height.
6921 insertInner: function insertInner(at, lines, height) {
6922 var this$1 = this;
6923
6924 this.height += height;
6925 this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
6926 for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1; }
6927 },
6928
6929 // Used to iterate over a part of the tree.
6930 iterN: function iterN(at, n, op) {
6931 var this$1 = this;
6932
6933 for (var e = at + n; at < e; ++at)
6934 { if (op(this$1.lines[at])) { return true } }
6935 }
6936 };
6937
6938 function BranchChunk(children) {
6939 var this$1 = this;
6940
6941 this.children = children;
6942 var size = 0, height = 0;
6943 for (var i = 0; i < children.length; ++i) {
6944 var ch = children[i];
6945 size += ch.chunkSize(); height += ch.height;
6946 ch.parent = this$1;
6947 }
6948 this.size = size;
6949 this.height = height;
6950 this.parent = null;
6951 }
6952
6953 BranchChunk.prototype = {
6954 chunkSize: function chunkSize() { return this.size },
6955
6956 removeInner: function removeInner(at, n) {
6957 var this$1 = this;
6958
6959 this.size -= n;
6960 for (var i = 0; i < this.children.length; ++i) {
6961 var child = this$1.children[i], sz = child.chunkSize();
6962 if (at < sz) {
6963 var rm = Math.min(n, sz - at), oldHeight = child.height;
6964 child.removeInner(at, rm);
6965 this$1.height -= oldHeight - child.height;
6966 if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null; }
6967 if ((n -= rm) == 0) { break }
6968 at = 0;
6969 } else { at -= sz; }
6970 }
6971 // If the result is smaller than 25 lines, ensure that it is a
6972 // single leaf node.
6973 if (this.size - n < 25 &&
6974 (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
6975 var lines = [];
6976 this.collapse(lines);
6977 this.children = [new LeafChunk(lines)];
6978 this.children[0].parent = this;
6979 }
6980 },
6981
6982 collapse: function collapse(lines) {
6983 var this$1 = this;
6984
6985 for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines); }
6986 },
6987
6988 insertInner: function insertInner(at, lines, height) {
6989 var this$1 = this;
6990
6991 this.size += lines.length;
6992 this.height += height;
6993 for (var i = 0; i < this.children.length; ++i) {
6994 var child = this$1.children[i], sz = child.chunkSize();
6995 if (at <= sz) {
6996 child.insertInner(at, lines, height);
6997 if (child.lines && child.lines.length > 50) {
6998 // To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.
6999 // Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.
7000 var remaining = child.lines.length % 25 + 25;
7001 for (var pos = remaining; pos < child.lines.length;) {
7002 var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));
7003 child.height -= leaf.height;
7004 this$1.children.splice(++i, 0, leaf);
7005 leaf.parent = this$1;
7006 }
7007 child.lines = child.lines.slice(0, remaining);
7008 this$1.maybeSpill();
7009 }
7010 break
7011 }
7012 at -= sz;
7013 }
7014 },
7015
7016 // When a node has grown, check whether it should be split.
7017 maybeSpill: function maybeSpill() {
7018 if (this.children.length <= 10) { return }
7019 var me = this;
7020 do {
7021 var spilled = me.children.splice(me.children.length - 5, 5);
7022 var sibling = new BranchChunk(spilled);
7023 if (!me.parent) { // Become the parent node
7024 var copy = new BranchChunk(me.children);
7025 copy.parent = me;
7026 me.children = [copy, sibling];
7027 me = copy;
7028 } else {
7029 me.size -= sibling.size;
7030 me.height -= sibling.height;
7031 var myIndex = indexOf(me.parent.children, me);
7032 me.parent.children.splice(myIndex + 1, 0, sibling);
7033 }
7034 sibling.parent = me.parent;
7035 } while (me.children.length > 10)
7036 me.parent.maybeSpill();
7037 },
7038
7039 iterN: function iterN(at, n, op) {
7040 var this$1 = this;
7041
7042 for (var i = 0; i < this.children.length; ++i) {
7043 var child = this$1.children[i], sz = child.chunkSize();
7044 if (at < sz) {
7045 var used = Math.min(n, sz - at);
7046 if (child.iterN(at, used, op)) { return true }
7047 if ((n -= used) == 0) { break }
7048 at = 0;
7049 } else { at -= sz; }
7050 }
7051 }
7052 };
7053
7054 // Line widgets are block elements displayed above or below a line.
7055
7056 var LineWidget = function(doc, node, options) {
7057 var this$1 = this;
7058
7059 if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))
7060 { this$1[opt] = options[opt]; } } }
7061 this.doc = doc;
7062 this.node = node;
7063 };
7064
7065 LineWidget.prototype.clear = function () {
7066 var this$1 = this;
7067
7068 var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
7069 if (no == null || !ws) { return }
7070 for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1); } }
7071 if (!ws.length) { line.widgets = null; }
7072 var height = widgetHeight(this);
7073 updateLineHeight(line, Math.max(0, line.height - height));
7074 if (cm) {
7075 runInOp(cm, function () {
7076 adjustScrollWhenAboveVisible(cm, line, -height);
7077 regLineChange(cm, no, "widget");
7078 });
7079 signalLater(cm, "lineWidgetCleared", cm, this, no);
7080 }
7081 };
7082
7083 LineWidget.prototype.changed = function () {
7084 var this$1 = this;
7085
7086 var oldH = this.height, cm = this.doc.cm, line = this.line;
7087 this.height = null;
7088 var diff = widgetHeight(this) - oldH;
7089 if (!diff) { return }
7090 updateLineHeight(line, line.height + diff);
7091 if (cm) {
7092 runInOp(cm, function () {
7093 cm.curOp.forceUpdate = true;
7094 adjustScrollWhenAboveVisible(cm, line, diff);
7095 signalLater(cm, "lineWidgetChanged", cm, this$1, lineNo(line));
7096 });
7097 }
7098 };
7099 eventMixin(LineWidget);
7100
7101 function adjustScrollWhenAboveVisible(cm, line, diff) {
7102 if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
7103 { addToScrollTop(cm, diff); }
7104 }
7105
7106 function addLineWidget(doc, handle, node, options) {
7107 var widget = new LineWidget(doc, node, options);
7108 var cm = doc.cm;
7109 if (cm && widget.noHScroll) { cm.display.alignWidgets = true; }
7110 changeLine(doc, handle, "widget", function (line) {
7111 var widgets = line.widgets || (line.widgets = []);
7112 if (widget.insertAt == null) { widgets.push(widget); }
7113 else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); }
7114 widget.line = line;
7115 if (cm && !lineIsHidden(doc, line)) {
7116 var aboveVisible = heightAtLine(line) < doc.scrollTop;
7117 updateLineHeight(line, line.height + widgetHeight(widget));
7118 if (aboveVisible) { addToScrollTop(cm, widget.height); }
7119 cm.curOp.forceUpdate = true;
7120 }
7121 return true
7122 });
7123 signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle));
7124 return widget
7125 }
7126
7127 // TEXTMARKERS
7128
7129 // Created with markText and setBookmark methods. A TextMarker is a
7130 // handle that can be used to clear or find a marked position in the
7131 // document. Line objects hold arrays (markedSpans) containing
7132 // {from, to, marker} object pointing to such marker objects, and
7133 // indicating that such a marker is present on that line. Multiple
7134 // lines may point to the same marker when it spans across lines.
7135 // The spans will have null for their from/to properties when the
7136 // marker continues beyond the start/end of the line. Markers have
7137 // links back to the lines they currently touch.
7138
7139 // Collapsed markers have unique ids, in order to be able to order
7140 // them, which is needed for uniquely determining an outer marker
7141 // when they overlap (they may nest, but not partially overlap).
7142 var nextMarkerId = 0;
7143
7144 var TextMarker = function(doc, type) {
7145 this.lines = [];
7146 this.type = type;
7147 this.doc = doc;
7148 this.id = ++nextMarkerId;
7149 };
7150
7151 // Clear the marker.
7152 TextMarker.prototype.clear = function () {
7153 var this$1 = this;
7154
7155 if (this.explicitlyCleared) { return }
7156 var cm = this.doc.cm, withOp = cm && !cm.curOp;
7157 if (withOp) { startOperation(cm); }
7158 if (hasHandler(this, "clear")) {
7159 var found = this.find();
7160 if (found) { signalLater(this, "clear", found.from, found.to); }
7161 }
7162 var min = null, max = null;
7163 for (var i = 0; i < this.lines.length; ++i) {
7164 var line = this$1.lines[i];
7165 var span = getMarkedSpanFor(line.markedSpans, this$1);
7166 if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text"); }
7167 else if (cm) {
7168 if (span.to != null) { max = lineNo(line); }
7169 if (span.from != null) { min = lineNo(line); }
7170 }
7171 line.markedSpans = removeMarkedSpan(line.markedSpans, span);
7172 if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm)
7173 { updateLineHeight(line, textHeight(cm.display)); }
7174 }
7175 if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {
7176 var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual);
7177 if (len > cm.display.maxLineLength) {
7178 cm.display.maxLine = visual;
7179 cm.display.maxLineLength = len;
7180 cm.display.maxLineChanged = true;
7181 }
7182 } }
7183
7184 if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1); }
7185 this.lines.length = 0;
7186 this.explicitlyCleared = true;
7187 if (this.atomic && this.doc.cantEdit) {
7188 this.doc.cantEdit = false;
7189 if (cm) { reCheckSelection(cm.doc); }
7190 }
7191 if (cm) { signalLater(cm, "markerCleared", cm, this, min, max); }
7192 if (withOp) { endOperation(cm); }
7193 if (this.parent) { this.parent.clear(); }
7194 };
7195
7196 // Find the position of the marker in the document. Returns a {from,
7197 // to} object by default. Side can be passed to get a specific side
7198 // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
7199 // Pos objects returned contain a line object, rather than a line
7200 // number (used to prevent looking up the same line twice).
7201 TextMarker.prototype.find = function (side, lineObj) {
7202 var this$1 = this;
7203
7204 if (side == null && this.type == "bookmark") { side = 1; }
7205 var from, to;
7206 for (var i = 0; i < this.lines.length; ++i) {
7207 var line = this$1.lines[i];
7208 var span = getMarkedSpanFor(line.markedSpans, this$1);
7209 if (span.from != null) {
7210 from = Pos(lineObj ? line : lineNo(line), span.from);
7211 if (side == -1) { return from }
7212 }
7213 if (span.to != null) {
7214 to = Pos(lineObj ? line : lineNo(line), span.to);
7215 if (side == 1) { return to }
7216 }
7217 }
7218 return from && {from: from, to: to}
7219 };
7220
7221 // Signals that the marker's widget changed, and surrounding layout
7222 // should be recomputed.
7223 TextMarker.prototype.changed = function () {
7224 var this$1 = this;
7225
7226 var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
7227 if (!pos || !cm) { return }
7228 runInOp(cm, function () {
7229 var line = pos.line, lineN = lineNo(pos.line);
7230 var view = findViewForLine(cm, lineN);
7231 if (view) {
7232 clearLineMeasurementCacheFor(view);
7233 cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
7234 }
7235 cm.curOp.updateMaxLine = true;
7236 if (!lineIsHidden(widget.doc, line) && widget.height != null) {
7237 var oldHeight = widget.height;
7238 widget.height = null;
7239 var dHeight = widgetHeight(widget) - oldHeight;
7240 if (dHeight)
7241 { updateLineHeight(line, line.height + dHeight); }
7242 }
7243 signalLater(cm, "markerChanged", cm, this$1);
7244 });
7245 };
7246
7247 TextMarker.prototype.attachLine = function (line) {
7248 if (!this.lines.length && this.doc.cm) {
7249 var op = this.doc.cm.curOp;
7250 if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
7251 { (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); }
7252 }
7253 this.lines.push(line);
7254 };
7255
7256 TextMarker.prototype.detachLine = function (line) {
7257 this.lines.splice(indexOf(this.lines, line), 1);
7258 if (!this.lines.length && this.doc.cm) {
7259 var op = this.doc.cm.curOp;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
7260 }
7261 };
7262 eventMixin(TextMarker);
7263
7264 // Create a marker, wire it up to the right lines, and
7265 function markText(doc, from, to, options, type) {
7266 // Shared markers (across linked documents) are handled separately
7267 // (markTextShared will call out to this again, once per
7268 // document).
7269 if (options && options.shared) { return markTextShared(doc, from, to, options, type) }
7270 // Ensure we are in an operation.
7271 if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) }
7272
7273 var marker = new TextMarker(doc, type), diff = cmp(from, to);
7274 if (options) { copyObj(options, marker, false); }
7275 // Don't connect empty markers unless clearWhenEmpty is false
7276 if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
7277 { return marker }
7278 if (marker.replacedWith) {
7279 // Showing up as a widget implies collapsed (widget replaces text)
7280 marker.collapsed = true;
7281 marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget");
7282 if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true"); }
7283 if (options.insertLeft) { marker.widgetNode.insertLeft = true; }
7284 }
7285 if (marker.collapsed) {
7286 if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
7287 from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
7288 { throw new Error("Inserting collapsed marker partially overlapping an existing one") }
7289 seeCollapsedSpans();
7290 }
7291
7292 if (marker.addToHistory)
7293 { addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); }
7294
7295 var curLine = from.line, cm = doc.cm, updateMaxLine;
7296 doc.iter(curLine, to.line + 1, function (line) {
7297 if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
7298 { updateMaxLine = true; }
7299 if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); }
7300 addMarkedSpan(line, new MarkedSpan(marker,
7301 curLine == from.line ? from.ch : null,
7302 curLine == to.line ? to.ch : null));
7303 ++curLine;
7304 });
7305 // lineIsHidden depends on the presence of the spans, so needs a second pass
7306 if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) {
7307 if (lineIsHidden(doc, line)) { updateLineHeight(line, 0); }
7308 }); }
7309
7310 if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }); }
7311
7312 if (marker.readOnly) {
7313 seeReadOnlySpans();
7314 if (doc.history.done.length || doc.history.undone.length)
7315 { doc.clearHistory(); }
7316 }
7317 if (marker.collapsed) {
7318 marker.id = ++nextMarkerId;
7319 marker.atomic = true;
7320 }
7321 if (cm) {
7322 // Sync editor state
7323 if (updateMaxLine) { cm.curOp.updateMaxLine = true; }
7324 if (marker.collapsed)
7325 { regChange(cm, from.line, to.line + 1); }
7326 else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
7327 { for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text"); } }
7328 if (marker.atomic) { reCheckSelection(cm.doc); }
7329 signalLater(cm, "markerAdded", cm, marker);
7330 }
7331 return marker
7332 }
7333
7334 // SHARED TEXTMARKERS
7335
7336 // A shared marker spans multiple linked documents. It is
7337 // implemented as a meta-marker-object controlling multiple normal
7338 // markers.
7339 var SharedTextMarker = function(markers, primary) {
7340 var this$1 = this;
7341
7342 this.markers = markers;
7343 this.primary = primary;
7344 for (var i = 0; i < markers.length; ++i)
7345 { markers[i].parent = this$1; }
7346 };
7347
7348 SharedTextMarker.prototype.clear = function () {
7349 var this$1 = this;
7350
7351 if (this.explicitlyCleared) { return }
7352 this.explicitlyCleared = true;
7353 for (var i = 0; i < this.markers.length; ++i)
7354 { this$1.markers[i].clear(); }
7355 signalLater(this, "clear");
7356 };
7357
7358 SharedTextMarker.prototype.find = function (side, lineObj) {
7359 return this.primary.find(side, lineObj)
7360 };
7361 eventMixin(SharedTextMarker);
7362
7363 function markTextShared(doc, from, to, options, type) {
7364 options = copyObj(options);
7365 options.shared = false;
7366 var markers = [markText(doc, from, to, options, type)], primary = markers[0];
7367 var widget = options.widgetNode;
7368 linkedDocs(doc, function (doc) {
7369 if (widget) { options.widgetNode = widget.cloneNode(true); }
7370 markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
7371 for (var i = 0; i < doc.linked.length; ++i)
7372 { if (doc.linked[i].isParent) { return } }
7373 primary = lst(markers);
7374 });
7375 return new SharedTextMarker(markers, primary)
7376 }
7377
7378 function findSharedMarkers(doc) {
7379 return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; })
7380 }
7381
7382 function copySharedMarkers(doc, markers) {
7383 for (var i = 0; i < markers.length; i++) {
7384 var marker = markers[i], pos = marker.find();
7385 var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
7386 if (cmp(mFrom, mTo)) {
7387 var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
7388 marker.markers.push(subMark);
7389 subMark.parent = marker;
7390 }
7391 }
7392 }
7393
7394 function detachSharedMarkers(markers) {
7395 var loop = function ( i ) {
7396 var marker = markers[i], linked = [marker.primary.doc];
7397 linkedDocs(marker.primary.doc, function (d) { return linked.push(d); });
7398 for (var j = 0; j < marker.markers.length; j++) {
7399 var subMarker = marker.markers[j];
7400 if (indexOf(linked, subMarker.doc) == -1) {
7401 subMarker.parent = null;
7402 marker.markers.splice(j--, 1);
7403 }
7404 }
7405 };
7406
7407 for (var i = 0; i < markers.length; i++) loop( i );
7408 }
7409
7410 var nextDocId = 0;
7411 var Doc = function(text, mode, firstLine, lineSep, direction) {
7412 if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) }
7413 if (firstLine == null) { firstLine = 0; }
7414
7415 BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
7416 this.first = firstLine;
7417 this.scrollTop = this.scrollLeft = 0;
7418 this.cantEdit = false;
7419 this.cleanGeneration = 1;
7420 this.modeFrontier = this.highlightFrontier = firstLine;
7421 var start = Pos(firstLine, 0);
7422 this.sel = simpleSelection(start);
7423 this.history = new History(null);
7424 this.id = ++nextDocId;
7425 this.modeOption = mode;
7426 this.lineSep = lineSep;
7427 this.direction = (direction == "rtl") ? "rtl" : "ltr";
7428 this.extend = false;
7429
7430 if (typeof text == "string") { text = this.splitLines(text); }
7431 updateDoc(this, {from: start, to: start, text: text});
7432 setSelection(this, simpleSelection(start), sel_dontScroll);
7433 };
7434
7435 Doc.prototype = createObj(BranchChunk.prototype, {
7436 constructor: Doc,
7437 // Iterate over the document. Supports two forms -- with only one
7438 // argument, it calls that for each line in the document. With
7439 // three, it iterates over the range given by the first two (with
7440 // the second being non-inclusive).
7441 iter: function(from, to, op) {
7442 if (op) { this.iterN(from - this.first, to - from, op); }
7443 else { this.iterN(this.first, this.first + this.size, from); }
7444 },
7445
7446 // Non-public interface for adding and removing lines.
7447 insert: function(at, lines) {
7448 var height = 0;
7449 for (var i = 0; i < lines.length; ++i) { height += lines[i].height; }
7450 this.insertInner(at - this.first, lines, height);
7451 },
7452 remove: function(at, n) { this.removeInner(at - this.first, n); },
7453
7454 // From here, the methods are part of the public interface. Most
7455 // are also available from CodeMirror (editor) instances.
7456
7457 getValue: function(lineSep) {
7458 var lines = getLines(this, this.first, this.first + this.size);
7459 if (lineSep === false) { return lines }
7460 return lines.join(lineSep || this.lineSeparator())
7461 },
7462 setValue: docMethodOp(function(code) {
7463 var top = Pos(this.first, 0), last = this.first + this.size - 1;
7464 makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
7465 text: this.splitLines(code), origin: "setValue", full: true}, true);
7466 if (this.cm) { scrollToCoords(this.cm, 0, 0); }
7467 setSelection(this, simpleSelection(top), sel_dontScroll);
7468 }),
7469 replaceRange: function(code, from, to, origin) {
7470 from = clipPos(this, from);
7471 to = to ? clipPos(this, to) : from;
7472 replaceRange(this, code, from, to, origin);
7473 },
7474 getRange: function(from, to, lineSep) {
7475 var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
7476 if (lineSep === false) { return lines }
7477 return lines.join(lineSep || this.lineSeparator())
7478 },
7479
7480 getLine: function(line) {var l = this.getLineHandle(line); return l && l.text},
7481
7482 getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }},
7483 getLineNumber: function(line) {return lineNo(line)},
7484
7485 getLineHandleVisualStart: function(line) {
7486 if (typeof line == "number") { line = getLine(this, line); }
7487 return visualLine(line)
7488 },
7489
7490 lineCount: function() {return this.size},
7491 firstLine: function() {return this.first},
7492 lastLine: function() {return this.first + this.size - 1},
7493
7494 clipPos: function(pos) {return clipPos(this, pos)},
7495
7496 getCursor: function(start) {
7497 var range$$1 = this.sel.primary(), pos;
7498 if (start == null || start == "head") { pos = range$$1.head; }
7499 else if (start == "anchor") { pos = range$$1.anchor; }
7500 else if (start == "end" || start == "to" || start === false) { pos = range$$1.to(); }
7501 else { pos = range$$1.from(); }
7502 return pos
7503 },
7504 listSelections: function() { return this.sel.ranges },
7505 somethingSelected: function() {return this.sel.somethingSelected()},
7506
7507 setCursor: docMethodOp(function(line, ch, options) {
7508 setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
7509 }),
7510 setSelection: docMethodOp(function(anchor, head, options) {
7511 setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
7512 }),
7513 extendSelection: docMethodOp(function(head, other, options) {
7514 extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
7515 }),
7516 extendSelections: docMethodOp(function(heads, options) {
7517 extendSelections(this, clipPosArray(this, heads), options);
7518 }),
7519 extendSelectionsBy: docMethodOp(function(f, options) {
7520 var heads = map(this.sel.ranges, f);
7521 extendSelections(this, clipPosArray(this, heads), options);
7522 }),
7523 setSelections: docMethodOp(function(ranges, primary, options) {
7524 var this$1 = this;
7525
7526 if (!ranges.length) { return }
7527 var out = [];
7528 for (var i = 0; i < ranges.length; i++)
7529 { out[i] = new Range(clipPos(this$1, ranges[i].anchor),
7530 clipPos(this$1, ranges[i].head)); }
7531 if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); }
7532 setSelection(this, normalizeSelection(out, primary), options);
7533 }),
7534 addSelection: docMethodOp(function(anchor, head, options) {
7535 var ranges = this.sel.ranges.slice(0);
7536 ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
7537 setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
7538 }),
7539
7540 getSelection: function(lineSep) {
7541 var this$1 = this;
7542
7543 var ranges = this.sel.ranges, lines;
7544 for (var i = 0; i < ranges.length; i++) {
7545 var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
7546 lines = lines ? lines.concat(sel) : sel;
7547 }
7548 if (lineSep === false) { return lines }
7549 else { return lines.join(lineSep || this.lineSeparator()) }
7550 },
7551 getSelections: function(lineSep) {
7552 var this$1 = this;
7553
7554 var parts = [], ranges = this.sel.ranges;
7555 for (var i = 0; i < ranges.length; i++) {
7556 var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
7557 if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()); }
7558 parts[i] = sel;
7559 }
7560 return parts
7561 },
7562 replaceSelection: function(code, collapse, origin) {
7563 var dup = [];
7564 for (var i = 0; i < this.sel.ranges.length; i++)
7565 { dup[i] = code; }
7566 this.replaceSelections(dup, collapse, origin || "+input");
7567 },
7568 replaceSelections: docMethodOp(function(code, collapse, origin) {
7569 var this$1 = this;
7570
7571 var changes = [], sel = this.sel;
7572 for (var i = 0; i < sel.ranges.length; i++) {
7573 var range$$1 = sel.ranges[i];
7574 changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this$1.splitLines(code[i]), origin: origin};
7575 }
7576 var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
7577 for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)
7578 { makeChange(this$1, changes[i$1]); }
7579 if (newSel) { setSelectionReplaceHistory(this, newSel); }
7580 else if (this.cm) { ensureCursorVisible(this.cm); }
7581 }),
7582 undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
7583 redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
7584 undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
7585 redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
7586
7587 setExtending: function(val) {this.extend = val;},
7588 getExtending: function() {return this.extend},
7589
7590 historySize: function() {
7591 var hist = this.history, done = 0, undone = 0;
7592 for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done; } }
7593 for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }
7594 return {undo: done, redo: undone}
7595 },
7596 clearHistory: function() {this.history = new History(this.history.maxGeneration);},
7597
7598 markClean: function() {
7599 this.cleanGeneration = this.changeGeneration(true);
7600 },
7601 changeGeneration: function(forceSplit) {
7602 if (forceSplit)
7603 { this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; }
7604 return this.history.generation
7605 },
7606 isClean: function (gen) {
7607 return this.history.generation == (gen || this.cleanGeneration)
7608 },
7609
7610 getHistory: function() {
7611 return {done: copyHistoryArray(this.history.done),
7612 undone: copyHistoryArray(this.history.undone)}
7613 },
7614 setHistory: function(histData) {
7615 var hist = this.history = new History(this.history.maxGeneration);
7616 hist.done = copyHistoryArray(histData.done.slice(0), null, true);
7617 hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
7618 },
7619
7620 setGutterMarker: docMethodOp(function(line, gutterID, value) {
7621 return changeLine(this, line, "gutter", function (line) {
7622 var markers = line.gutterMarkers || (line.gutterMarkers = {});
7623 markers[gutterID] = value;
7624 if (!value && isEmpty(markers)) { line.gutterMarkers = null; }
7625 return true
7626 })
7627 }),
7628
7629 clearGutter: docMethodOp(function(gutterID) {
7630 var this$1 = this;
7631
7632 this.iter(function (line) {
7633 if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
7634 changeLine(this$1, line, "gutter", function () {
7635 line.gutterMarkers[gutterID] = null;
7636 if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null; }
7637 return true
7638 });
7639 }
7640 });
7641 }),
7642
7643 lineInfo: function(line) {
7644 var n;
7645 if (typeof line == "number") {
7646 if (!isLine(this, line)) { return null }
7647 n = line;
7648 line = getLine(this, line);
7649 if (!line) { return null }
7650 } else {
7651 n = lineNo(line);
7652 if (n == null) { return null }
7653 }
7654 return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
7655 textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
7656 widgets: line.widgets}
7657 },
7658
7659 addLineClass: docMethodOp(function(handle, where, cls) {
7660 return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
7661 var prop = where == "text" ? "textClass"
7662 : where == "background" ? "bgClass"
7663 : where == "gutter" ? "gutterClass" : "wrapClass";
7664 if (!line[prop]) { line[prop] = cls; }
7665 else if (classTest(cls).test(line[prop])) { return false }
7666 else { line[prop] += " " + cls; }
7667 return true
7668 })
7669 }),
7670 removeLineClass: docMethodOp(function(handle, where, cls) {
7671 return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
7672 var prop = where == "text" ? "textClass"
7673 : where == "background" ? "bgClass"
7674 : where == "gutter" ? "gutterClass" : "wrapClass";
7675 var cur = line[prop];
7676 if (!cur) { return false }
7677 else if (cls == null) { line[prop] = null; }
7678 else {
7679 var found = cur.match(classTest(cls));
7680 if (!found) { return false }
7681 var end = found.index + found[0].length;
7682 line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
7683 }
7684 return true
7685 })
7686 }),
7687
7688 addLineWidget: docMethodOp(function(handle, node, options) {
7689 return addLineWidget(this, handle, node, options)
7690 }),
7691 removeLineWidget: function(widget) { widget.clear(); },
7692
7693 markText: function(from, to, options) {
7694 return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range")
7695 },
7696 setBookmark: function(pos, options) {
7697 var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
7698 insertLeft: options && options.insertLeft,
7699 clearWhenEmpty: false, shared: options && options.shared,
7700 handleMouseEvents: options && options.handleMouseEvents};
7701 pos = clipPos(this, pos);
7702 return markText(this, pos, pos, realOpts, "bookmark")
7703 },
7704 findMarksAt: function(pos) {
7705 pos = clipPos(this, pos);
7706 var markers = [], spans = getLine(this, pos.line).markedSpans;
7707 if (spans) { for (var i = 0; i < spans.length; ++i) {
7708 var span = spans[i];
7709 if ((span.from == null || span.from <= pos.ch) &&
7710 (span.to == null || span.to >= pos.ch))
7711 { markers.push(span.marker.parent || span.marker); }
7712 } }
7713 return markers
7714 },
7715 findMarks: function(from, to, filter) {
7716 from = clipPos(this, from); to = clipPos(this, to);
7717 var found = [], lineNo$$1 = from.line;
7718 this.iter(from.line, to.line + 1, function (line) {
7719 var spans = line.markedSpans;
7720 if (spans) { for (var i = 0; i < spans.length; i++) {
7721 var span = spans[i];
7722 if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to ||
7723 span.from == null && lineNo$$1 != from.line ||
7724 span.from != null && lineNo$$1 == to.line && span.from >= to.ch) &&
7725 (!filter || filter(span.marker)))
7726 { found.push(span.marker.parent || span.marker); }
7727 } }
7728 ++lineNo$$1;
7729 });
7730 return found
7731 },
7732 getAllMarks: function() {
7733 var markers = [];
7734 this.iter(function (line) {
7735 var sps = line.markedSpans;
7736 if (sps) { for (var i = 0; i < sps.length; ++i)
7737 { if (sps[i].from != null) { markers.push(sps[i].marker); } } }
7738 });
7739 return markers
7740 },
7741
7742 posFromIndex: function(off) {
7743 var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length;
7744 this.iter(function (line) {
7745 var sz = line.text.length + sepSize;
7746 if (sz > off) { ch = off; return true }
7747 off -= sz;
7748 ++lineNo$$1;
7749 });
7750 return clipPos(this, Pos(lineNo$$1, ch))
7751 },
7752 indexFromPos: function (coords) {
7753 coords = clipPos(this, coords);
7754 var index = coords.ch;
7755 if (coords.line < this.first || coords.ch < 0) { return 0 }
7756 var sepSize = this.lineSeparator().length;
7757 this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value
7758 index += line.text.length + sepSize;
7759 });
7760 return index
7761 },
7762
7763 copy: function(copyHistory) {
7764 var doc = new Doc(getLines(this, this.first, this.first + this.size),
7765 this.modeOption, this.first, this.lineSep, this.direction);
7766 doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
7767 doc.sel = this.sel;
7768 doc.extend = false;
7769 if (copyHistory) {
7770 doc.history.undoDepth = this.history.undoDepth;
7771 doc.setHistory(this.getHistory());
7772 }
7773 return doc
7774 },
7775
7776 linkedDoc: function(options) {
7777 if (!options) { options = {}; }
7778 var from = this.first, to = this.first + this.size;
7779 if (options.from != null && options.from > from) { from = options.from; }
7780 if (options.to != null && options.to < to) { to = options.to; }
7781 var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction);
7782 if (options.sharedHist) { copy.history = this.history
7783 ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
7784 copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
7785 copySharedMarkers(copy, findSharedMarkers(this));
7786 return copy
7787 },
7788 unlinkDoc: function(other) {
7789 var this$1 = this;
7790
7791 if (other instanceof CodeMirror$1) { other = other.doc; }
7792 if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {
7793 var link = this$1.linked[i];
7794 if (link.doc != other) { continue }
7795 this$1.linked.splice(i, 1);
7796 other.unlinkDoc(this$1);
7797 detachSharedMarkers(findSharedMarkers(this$1));
7798 break
7799 } }
7800 // If the histories were shared, split them again
7801 if (other.history == this.history) {
7802 var splitIds = [other.id];
7803 linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true);
7804 other.history = new History(null);
7805 other.history.done = copyHistoryArray(this.history.done, splitIds);
7806 other.history.undone = copyHistoryArray(this.history.undone, splitIds);
7807 }
7808 },
7809 iterLinkedDocs: function(f) {linkedDocs(this, f);},
7810
7811 getMode: function() {return this.mode},
7812 getEditor: function() {return this.cm},
7813
7814 splitLines: function(str) {
7815 if (this.lineSep) { return str.split(this.lineSep) }
7816 return splitLinesAuto(str)
7817 },
7818 lineSeparator: function() { return this.lineSep || "\n" },
7819
7820 setDirection: docMethodOp(function (dir) {
7821 if (dir != "rtl") { dir = "ltr"; }
7822 if (dir == this.direction) { return }
7823 this.direction = dir;
7824 this.iter(function (line) { return line.order = null; });
7825 if (this.cm) { directionChanged(this.cm); }
7826 })
7827 });
7828
7829 // Public alias.
7830 Doc.prototype.eachLine = Doc.prototype.iter;
7831
7832 // Kludge to work around strange IE behavior where it'll sometimes
7833 // re-fire a series of drag-related events right after the drop (#1551)
7834 var lastDrop = 0;
7835
7836 function onDrop(e) {
7837 var cm = this;
7838 clearDragCursor(cm);
7839 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
7840 { return }
7841 e_preventDefault(e);
7842 if (ie) { lastDrop = +new Date; }
7843 var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
7844 if (!pos || cm.isReadOnly()) { return }
7845 // Might be a file drop, in which case we simply extract the text
7846 // and insert it.
7847 if (files && files.length && window.FileReader && window.File) {
7848 var n = files.length, text = Array(n), read = 0;
7849 var loadFile = function (file, i) {
7850 if (cm.options.allowDropFileTypes &&
7851 indexOf(cm.options.allowDropFileTypes, file.type) == -1)
7852 { return }
7853
7854 var reader = new FileReader;
7855 reader.onload = operation(cm, function () {
7856 var content = reader.result;
7857 if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = ""; }
7858 text[i] = content;
7859 if (++read == n) {
7860 pos = clipPos(cm.doc, pos);
7861 var change = {from: pos, to: pos,
7862 text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
7863 origin: "paste"};
7864 makeChange(cm.doc, change);
7865 setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
7866 }
7867 });
7868 reader.readAsText(file);
7869 };
7870 for (var i = 0; i < n; ++i) { loadFile(files[i], i); }
7871 } else { // Normal drop
7872 // Don't do a replace if the drop happened inside of the selected text.
7873 if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
7874 cm.state.draggingText(e);
7875 // Ensure the editor is re-focused
7876 setTimeout(function () { return cm.display.input.focus(); }, 20);
7877 return
7878 }
7879 try {
7880 var text$1 = e.dataTransfer.getData("Text");
7881 if (text$1) {
7882 var selected;
7883 if (cm.state.draggingText && !cm.state.draggingText.copy)
7884 { selected = cm.listSelections(); }
7885 setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
7886 if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1)
7887 { replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag"); } }
7888 cm.replaceSelection(text$1, "around", "paste");
7889 cm.display.input.focus();
7890 }
7891 }
7892 catch(e){}
7893 }
7894 }
7895
7896 function onDragStart(cm, e) {
7897 if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return }
7898 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return }
7899
7900 e.dataTransfer.setData("Text", cm.getSelection());
7901 e.dataTransfer.effectAllowed = "copyMove";
7902
7903 // Use dummy image instead of default browsers image.
7904 // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
7905 if (e.dataTransfer.setDragImage && !safari) {
7906 var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
7907 img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
7908 if (presto) {
7909 img.width = img.height = 1;
7910 cm.display.wrapper.appendChild(img);
7911 // Force a relayout, or Opera won't use our image for some obscure reason
7912 img._top = img.offsetTop;
7913 }
7914 e.dataTransfer.setDragImage(img, 0, 0);
7915 if (presto) { img.parentNode.removeChild(img); }
7916 }
7917 }
7918
7919 function onDragOver(cm, e) {
7920 var pos = posFromMouse(cm, e);
7921 if (!pos) { return }
7922 var frag = document.createDocumentFragment();
7923 drawSelectionCursor(cm, pos, frag);
7924 if (!cm.display.dragCursor) {
7925 cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
7926 cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
7927 }
7928 removeChildrenAndAdd(cm.display.dragCursor, frag);
7929 }
7930
7931 function clearDragCursor(cm) {
7932 if (cm.display.dragCursor) {
7933 cm.display.lineSpace.removeChild(cm.display.dragCursor);
7934 cm.display.dragCursor = null;
7935 }
7936 }
7937
7938 // These must be handled carefully, because naively registering a
7939 // handler for each editor will cause the editors to never be
7940 // garbage collected.
7941
7942 function forEachCodeMirror(f) {
7943 if (!document.getElementsByClassName) { return }
7944 var byClass = document.getElementsByClassName("CodeMirror");
7945 for (var i = 0; i < byClass.length; i++) {
7946 var cm = byClass[i].CodeMirror;
7947 if (cm) { f(cm); }
7948 }
7949 }
7950
7951 var globalsRegistered = false;
7952 function ensureGlobalHandlers() {
7953 if (globalsRegistered) { return }
7954 registerGlobalHandlers();
7955 globalsRegistered = true;
7956 }
7957 function registerGlobalHandlers() {
7958 // When the window resizes, we need to refresh active editors.
7959 var resizeTimer;
7960 on(window, "resize", function () {
7961 if (resizeTimer == null) { resizeTimer = setTimeout(function () {
7962 resizeTimer = null;
7963 forEachCodeMirror(onResize);
7964 }, 100); }
7965 });
7966 // When the window loses focus, we want to show the editor as blurred
7967 on(window, "blur", function () { return forEachCodeMirror(onBlur); });
7968 }
7969 // Called when the window resizes
7970 function onResize(cm) {
7971 var d = cm.display;
7972 if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)
7973 { return }
7974 // Might be a text scaling operation, clear size caches.
7975 d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
7976 d.scrollbarsClipped = false;
7977 cm.setSize();
7978 }
7979
7980 var keyNames = {
7981 3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
7982 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
7983 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
7984 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
7985 106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete",
7986 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
7987 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
7988 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
7989 };
7990
7991 // Number keys
7992 for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); }
7993 // Alphabetic keys
7994 for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); }
7995 // Function keys
7996 for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2; }
7997
7998 var keyMap = {};
7999
8000 keyMap.basic = {
8001 "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
8002 "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
8003 "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
8004 "Tab": "defaultTab", "Shift-Tab": "indentAuto",
8005 "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
8006 "Esc": "singleSelection"
8007 };
8008 // Note that the save and find-related commands aren't defined by
8009 // default. User code or addons can define them. Unknown commands
8010 // are simply ignored.
8011 keyMap.pcDefault = {
8012 "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
8013 "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
8014 "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
8015 "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
8016 "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
8017 "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
8018 "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
8019 fallthrough: "basic"
8020 };
8021 // Very basic readline/emacs-style bindings, which are standard on Mac.
8022 keyMap.emacsy = {
8023 "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
8024 "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
8025 "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
8026 "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars",
8027 "Ctrl-O": "openLine"
8028 };
8029 keyMap.macDefault = {
8030 "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
8031 "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
8032 "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
8033 "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
8034 "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
8035 "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
8036 "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
8037 fallthrough: ["basic", "emacsy"]
8038 };
8039 keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
8040
8041 // KEYMAP DISPATCH
8042
8043 function normalizeKeyName(name) {
8044 var parts = name.split(/-(?!$)/);
8045 name = parts[parts.length - 1];
8046 var alt, ctrl, shift, cmd;
8047 for (var i = 0; i < parts.length - 1; i++) {
8048 var mod = parts[i];
8049 if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true; }
8050 else if (/^a(lt)?$/i.test(mod)) { alt = true; }
8051 else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; }
8052 else if (/^s(hift)?$/i.test(mod)) { shift = true; }
8053 else { throw new Error("Unrecognized modifier name: " + mod) }
8054 }
8055 if (alt) { name = "Alt-" + name; }
8056 if (ctrl) { name = "Ctrl-" + name; }
8057 if (cmd) { name = "Cmd-" + name; }
8058 if (shift) { name = "Shift-" + name; }
8059 return name
8060 }
8061
8062 // This is a kludge to keep keymaps mostly working as raw objects
8063 // (backwards compatibility) while at the same time support features
8064 // like normalization and multi-stroke key bindings. It compiles a
8065 // new normalized keymap, and then updates the old object to reflect
8066 // this.
8067 function normalizeKeyMap(keymap) {
8068 var copy = {};
8069 for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) {
8070 var value = keymap[keyname];
8071 if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue }
8072 if (value == "...") { delete keymap[keyname]; continue }
8073
8074 var keys = map(keyname.split(" "), normalizeKeyName);
8075 for (var i = 0; i < keys.length; i++) {
8076 var val = (void 0), name = (void 0);
8077 if (i == keys.length - 1) {
8078 name = keys.join(" ");
8079 val = value;
8080 } else {
8081 name = keys.slice(0, i + 1).join(" ");
8082 val = "...";
8083 }
8084 var prev = copy[name];
8085 if (!prev) { copy[name] = val; }
8086 else if (prev != val) { throw new Error("Inconsistent bindings for " + name) }
8087 }
8088 delete keymap[keyname];
8089 } }
8090 for (var prop in copy) { keymap[prop] = copy[prop]; }
8091 return keymap
8092 }
8093
8094 function lookupKey(key, map$$1, handle, context) {
8095 map$$1 = getKeyMap(map$$1);
8096 var found = map$$1.call ? map$$1.call(key, context) : map$$1[key];
8097 if (found === false) { return "nothing" }
8098 if (found === "...") { return "multi" }
8099 if (found != null && handle(found)) { return "handled" }
8100
8101 if (map$$1.fallthrough) {
8102 if (Object.prototype.toString.call(map$$1.fallthrough) != "[object Array]")
8103 { return lookupKey(key, map$$1.fallthrough, handle, context) }
8104 for (var i = 0; i < map$$1.fallthrough.length; i++) {
8105 var result = lookupKey(key, map$$1.fallthrough[i], handle, context);
8106 if (result) { return result }
8107 }
8108 }
8109 }
8110
8111 // Modifier key presses don't count as 'real' key presses for the
8112 // purpose of keymap fallthrough.
8113 function isModifierKey(value) {
8114 var name = typeof value == "string" ? value : keyNames[value.keyCode];
8115 return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"
8116 }
8117
8118 function addModifierNames(name, event, noShift) {
8119 var base = name;
8120 if (event.altKey && base != "Alt") { name = "Alt-" + name; }
8121 if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; }
8122 if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name; }
8123 if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; }
8124 return name
8125 }
8126
8127 // Look up the name of a key as indicated by an event object.
8128 function keyName(event, noShift) {
8129 if (presto && event.keyCode == 34 && event["char"]) { return false }
8130 var name = keyNames[event.keyCode];
8131 if (name == null || event.altGraphKey) { return false }
8132 return addModifierNames(name, event, noShift)
8133 }
8134
8135 function getKeyMap(val) {
8136 return typeof val == "string" ? keyMap[val] : val
8137 }
8138
8139 // Helper for deleting text near the selection(s), used to implement
8140 // backspace, delete, and similar functionality.
8141 function deleteNearSelection(cm, compute) {
8142 var ranges = cm.doc.sel.ranges, kill = [];
8143 // Build up a set of ranges to kill first, merging overlapping
8144 // ranges.
8145 for (var i = 0; i < ranges.length; i++) {
8146 var toKill = compute(ranges[i]);
8147 while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
8148 var replaced = kill.pop();
8149 if (cmp(replaced.from, toKill.from) < 0) {
8150 toKill.from = replaced.from;
8151 break
8152 }
8153 }
8154 kill.push(toKill);
8155 }
8156 // Next, remove those actual ranges.
8157 runInOp(cm, function () {
8158 for (var i = kill.length - 1; i >= 0; i--)
8159 { replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); }
8160 ensureCursorVisible(cm);
8161 });
8162 }
8163
8164 function moveCharLogically(line, ch, dir) {
8165 var target = skipExtendingChars(line.text, ch + dir, dir);
8166 return target < 0 || target > line.text.length ? null : target
8167 }
8168
8169 function moveLogically(line, start, dir) {
8170 var ch = moveCharLogically(line, start.ch, dir);
8171 return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
8172 }
8173
8174 function endOfLine(visually, cm, lineObj, lineNo, dir) {
8175 if (visually) {
8176 var order = getOrder(lineObj, cm.doc.direction);
8177 if (order) {
8178 var part = dir < 0 ? lst(order) : order[0];
8179 var moveInStorageOrder = (dir < 0) == (part.level == 1);
8180 var sticky = moveInStorageOrder ? "after" : "before";
8181 var ch;
8182 // With a wrapped rtl chunk (possibly spanning multiple bidi parts),
8183 // it could be that the last bidi part is not on the last visual line,
8184 // since visual lines contain content order-consecutive chunks.
8185 // Thus, in rtl, we are looking for the first (content-order) character
8186 // in the rtl chunk that is on the last line (that is, the same line
8187 // as the last (content-order) character).
8188 if (part.level > 0 || cm.doc.direction == "rtl") {
8189 var prep = prepareMeasureForLine(cm, lineObj);
8190 ch = dir < 0 ? lineObj.text.length - 1 : 0;
8191 var targetTop = measureCharPrepared(cm, prep, ch).top;
8192 ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch);
8193 if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1); }
8194 } else { ch = dir < 0 ? part.to : part.from; }
8195 return new Pos(lineNo, ch, sticky)
8196 }
8197 }
8198 return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
8199 }
8200
8201 function moveVisually(cm, line, start, dir) {
8202 var bidi = getOrder(line, cm.doc.direction);
8203 if (!bidi) { return moveLogically(line, start, dir) }
8204 if (start.ch >= line.text.length) {
8205 start.ch = line.text.length;
8206 start.sticky = "before";
8207 } else if (start.ch <= 0) {
8208 start.ch = 0;
8209 start.sticky = "after";
8210 }
8211 var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos];
8212 if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
8213 // Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
8214 // nothing interesting happens.
8215 return moveLogically(line, start, dir)
8216 }
8217
8218 var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); };
8219 var prep;
8220 var getWrappedLineExtent = function (ch) {
8221 if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
8222 prep = prep || prepareMeasureForLine(cm, line);
8223 return wrappedLineExtentChar(cm, line, prep, ch)
8224 };
8225 var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch);
8226
8227 if (cm.doc.direction == "rtl" || part.level == 1) {
8228 var moveInStorageOrder = (part.level == 1) == (dir < 0);
8229 var ch = mv(start, moveInStorageOrder ? 1 : -1);
8230 if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
8231 // Case 2: We move within an rtl part or in an rtl editor on the same visual line
8232 var sticky = moveInStorageOrder ? "before" : "after";
8233 return new Pos(start.line, ch, sticky)
8234 }
8235 }
8236
8237 // Case 3: Could not move within this bidi part in this visual line, so leave
8238 // the current bidi part
8239
8240 var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
8241 var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
8242 ? new Pos(start.line, mv(ch, 1), "before")
8243 : new Pos(start.line, ch, "after"); };
8244
8245 for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
8246 var part = bidi[partPos];
8247 var moveInStorageOrder = (dir > 0) == (part.level != 1);
8248 var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1);
8249 if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
8250 ch = moveInStorageOrder ? part.from : mv(part.to, -1);
8251 if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
8252 }
8253 };
8254
8255 // Case 3a: Look for other bidi parts on the same visual line
8256 var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent);
8257 if (res) { return res }
8258
8259 // Case 3b: Look for other bidi parts on the next visual line
8260 var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1);
8261 if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
8262 res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh));
8263 if (res) { return res }
8264 }
8265
8266 // Case 4: Nowhere to move
8267 return null
8268 }
8269
8270 // Commands are parameter-less actions that can be performed on an
8271 // editor, mostly used for keybindings.
8272 var commands = {
8273 selectAll: selectAll,
8274 singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); },
8275 killLine: function (cm) { return deleteNearSelection(cm, function (range) {
8276 if (range.empty()) {
8277 var len = getLine(cm.doc, range.head.line).text.length;
8278 if (range.head.ch == len && range.head.line < cm.lastLine())
8279 { return {from: range.head, to: Pos(range.head.line + 1, 0)} }
8280 else
8281 { return {from: range.head, to: Pos(range.head.line, len)} }
8282 } else {
8283 return {from: range.from(), to: range.to()}
8284 }
8285 }); },
8286 deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({
8287 from: Pos(range.from().line, 0),
8288 to: clipPos(cm.doc, Pos(range.to().line + 1, 0))
8289 }); }); },
8290 delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({
8291 from: Pos(range.from().line, 0), to: range.from()
8292 }); }); },
8293 delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) {
8294 var top = cm.charCoords(range.head, "div").top + 5;
8295 var leftPos = cm.coordsChar({left: 0, top: top}, "div");
8296 return {from: leftPos, to: range.from()}
8297 }); },
8298 delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) {
8299 var top = cm.charCoords(range.head, "div").top + 5;
8300 var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
8301 return {from: range.from(), to: rightPos }
8302 }); },
8303 undo: function (cm) { return cm.undo(); },
8304 redo: function (cm) { return cm.redo(); },
8305 undoSelection: function (cm) { return cm.undoSelection(); },
8306 redoSelection: function (cm) { return cm.redoSelection(); },
8307 goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); },
8308 goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); },
8309 goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); },
8310 {origin: "+move", bias: 1}
8311 ); },
8312 goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); },
8313 {origin: "+move", bias: 1}
8314 ); },
8315 goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); },
8316 {origin: "+move", bias: -1}
8317 ); },
8318 goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) {
8319 var top = cm.cursorCoords(range.head, "div").top + 5;
8320 return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")
8321 }, sel_move); },
8322 goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) {
8323 var top = cm.cursorCoords(range.head, "div").top + 5;
8324 return cm.coordsChar({left: 0, top: top}, "div")
8325 }, sel_move); },
8326 goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) {
8327 var top = cm.cursorCoords(range.head, "div").top + 5;
8328 var pos = cm.coordsChar({left: 0, top: top}, "div");
8329 if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) }
8330 return pos
8331 }, sel_move); },
8332 goLineUp: function (cm) { return cm.moveV(-1, "line"); },
8333 goLineDown: function (cm) { return cm.moveV(1, "line"); },
8334 goPageUp: function (cm) { return cm.moveV(-1, "page"); },
8335 goPageDown: function (cm) { return cm.moveV(1, "page"); },
8336 goCharLeft: function (cm) { return cm.moveH(-1, "char"); },
8337 goCharRight: function (cm) { return cm.moveH(1, "char"); },
8338 goColumnLeft: function (cm) { return cm.moveH(-1, "column"); },
8339 goColumnRight: function (cm) { return cm.moveH(1, "column"); },
8340 goWordLeft: function (cm) { return cm.moveH(-1, "word"); },
8341 goGroupRight: function (cm) { return cm.moveH(1, "group"); },
8342 goGroupLeft: function (cm) { return cm.moveH(-1, "group"); },
8343 goWordRight: function (cm) { return cm.moveH(1, "word"); },
8344 delCharBefore: function (cm) { return cm.deleteH(-1, "char"); },
8345 delCharAfter: function (cm) { return cm.deleteH(1, "char"); },
8346 delWordBefore: function (cm) { return cm.deleteH(-1, "word"); },
8347 delWordAfter: function (cm) { return cm.deleteH(1, "word"); },
8348 delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); },
8349 delGroupAfter: function (cm) { return cm.deleteH(1, "group"); },
8350 indentAuto: function (cm) { return cm.indentSelection("smart"); },
8351 indentMore: function (cm) { return cm.indentSelection("add"); },
8352 indentLess: function (cm) { return cm.indentSelection("subtract"); },
8353 insertTab: function (cm) { return cm.replaceSelection("\t"); },
8354 insertSoftTab: function (cm) {
8355 var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
8356 for (var i = 0; i < ranges.length; i++) {
8357 var pos = ranges[i].from();
8358 var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
8359 spaces.push(spaceStr(tabSize - col % tabSize));
8360 }
8361 cm.replaceSelections(spaces);
8362 },
8363 defaultTab: function (cm) {
8364 if (cm.somethingSelected()) { cm.indentSelection("add"); }
8365 else { cm.execCommand("insertTab"); }
8366 },
8367 // Swap the two chars left and right of each selection's head.
8368 // Move cursor behind the two swapped characters afterwards.
8369 //
8370 // Doesn't consider line feeds a character.
8371 // Doesn't scan more than one line above to find a character.
8372 // Doesn't do anything on an empty line.
8373 // Doesn't do anything with non-empty selections.
8374 transposeChars: function (cm) { return runInOp(cm, function () {
8375 var ranges = cm.listSelections(), newSel = [];
8376 for (var i = 0; i < ranges.length; i++) {
8377 if (!ranges[i].empty()) { continue }
8378 var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
8379 if (line) {
8380 if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); }
8381 if (cur.ch > 0) {
8382 cur = new Pos(cur.line, cur.ch + 1);
8383 cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
8384 Pos(cur.line, cur.ch - 2), cur, "+transpose");
8385 } else if (cur.line > cm.doc.first) {
8386 var prev = getLine(cm.doc, cur.line - 1).text;
8387 if (prev) {
8388 cur = new Pos(cur.line, 1);
8389 cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
8390 prev.charAt(prev.length - 1),
8391 Pos(cur.line - 1, prev.length - 1), cur, "+transpose");
8392 }
8393 }
8394 }
8395 newSel.push(new Range(cur, cur));
8396 }
8397 cm.setSelections(newSel);
8398 }); },
8399 newlineAndIndent: function (cm) { return runInOp(cm, function () {
8400 var sels = cm.listSelections();
8401 for (var i = sels.length - 1; i >= 0; i--)
8402 { cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input"); }
8403 sels = cm.listSelections();
8404 for (var i$1 = 0; i$1 < sels.length; i$1++)
8405 { cm.indentLine(sels[i$1].from().line, null, true); }
8406 ensureCursorVisible(cm);
8407 }); },
8408 openLine: function (cm) { return cm.replaceSelection("\n", "start"); },
8409 toggleOverwrite: function (cm) { return cm.toggleOverwrite(); }
8410 };
8411
8412
8413 function lineStart(cm, lineN) {
8414 var line = getLine(cm.doc, lineN);
8415 var visual = visualLine(line);
8416 if (visual != line) { lineN = lineNo(visual); }
8417 return endOfLine(true, cm, visual, lineN, 1)
8418 }
8419 function lineEnd(cm, lineN) {
8420 var line = getLine(cm.doc, lineN);
8421 var visual = visualLineEnd(line);
8422 if (visual != line) { lineN = lineNo(visual); }
8423 return endOfLine(true, cm, line, lineN, -1)
8424 }
8425 function lineStartSmart(cm, pos) {
8426 var start = lineStart(cm, pos.line);
8427 var line = getLine(cm.doc, start.line);
8428 var order = getOrder(line, cm.doc.direction);
8429 if (!order || order[0].level == 0) {
8430 var firstNonWS = Math.max(0, line.text.search(/\S/));
8431 var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
8432 return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)
8433 }
8434 return start
8435 }
8436
8437 // Run a handler that was bound to a key.
8438 function doHandleBinding(cm, bound, dropShift) {
8439 if (typeof bound == "string") {
8440 bound = commands[bound];
8441 if (!bound) { return false }
8442 }
8443 // Ensure previous input has been read, so that the handler sees a
8444 // consistent view of the document
8445 cm.display.input.ensurePolled();
8446 var prevShift = cm.display.shift, done = false;
8447 try {
8448 if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
8449 if (dropShift) { cm.display.shift = false; }
8450 done = bound(cm) != Pass;
8451 } finally {
8452 cm.display.shift = prevShift;
8453 cm.state.suppressEdits = false;
8454 }
8455 return done
8456 }
8457
8458 function lookupKeyForEditor(cm, name, handle) {
8459 for (var i = 0; i < cm.state.keyMaps.length; i++) {
8460 var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
8461 if (result) { return result }
8462 }
8463 return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
8464 || lookupKey(name, cm.options.keyMap, handle, cm)
8465 }
8466
8467 // Note that, despite the name, this function is also used to check
8468 // for bound mouse clicks.
8469
8470 var stopSeq = new Delayed;
8471 function dispatchKey(cm, name, e, handle) {
8472 var seq = cm.state.keySeq;
8473 if (seq) {
8474 if (isModifierKey(name)) { return "handled" }
8475 stopSeq.set(50, function () {
8476 if (cm.state.keySeq == seq) {
8477 cm.state.keySeq = null;
8478 cm.display.input.reset();
8479 }
8480 });
8481 name = seq + " " + name;
8482 }
8483 var result = lookupKeyForEditor(cm, name, handle);
8484
8485 if (result == "multi")
8486 { cm.state.keySeq = name; }
8487 if (result == "handled")
8488 { signalLater(cm, "keyHandled", cm, name, e); }
8489
8490 if (result == "handled" || result == "multi") {
8491 e_preventDefault(e);
8492 restartBlink(cm);
8493 }
8494
8495 if (seq && !result && /\'$/.test(name)) {
8496 e_preventDefault(e);
8497 return true
8498 }
8499 return !!result
8500 }
8501
8502 // Handle a key from the keydown event.
8503 function handleKeyBinding(cm, e) {
8504 var name = keyName(e, true);
8505 if (!name) { return false }
8506
8507 if (e.shiftKey && !cm.state.keySeq) {
8508 // First try to resolve full name (including 'Shift-'). Failing
8509 // that, see if there is a cursor-motion command (starting with
8510 // 'go') bound to the keyname without 'Shift-'.
8511 return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); })
8512 || dispatchKey(cm, name, e, function (b) {
8513 if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
8514 { return doHandleBinding(cm, b) }
8515 })
8516 } else {
8517 return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); })
8518 }
8519 }
8520
8521 // Handle a key from the keypress event
8522 function handleCharBinding(cm, e, ch) {
8523 return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); })
8524 }
8525
8526 var lastStoppedKey = null;
8527 function onKeyDown(e) {
8528 var cm = this;
8529 cm.curOp.focus = activeElt();
8530 if (signalDOMEvent(cm, e)) { return }
8531 // IE does strange things with escape.
8532 if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; }
8533 var code = e.keyCode;
8534 cm.display.shift = code == 16 || e.shiftKey;
8535 var handled = handleKeyBinding(cm, e);
8536 if (presto) {
8537 lastStoppedKey = handled ? code : null;
8538 // Opera has no cut event... we try to at least catch the key combo
8539 if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
8540 { cm.replaceSelection("", null, "cut"); }
8541 }
8542
8543 // Turn mouse into crosshair when Alt is held on Mac.
8544 if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
8545 { showCrossHair(cm); }
8546 }
8547
8548 function showCrossHair(cm) {
8549 var lineDiv = cm.display.lineDiv;
8550 addClass(lineDiv, "CodeMirror-crosshair");
8551
8552 function up(e) {
8553 if (e.keyCode == 18 || !e.altKey) {
8554 rmClass(lineDiv, "CodeMirror-crosshair");
8555 off(document, "keyup", up);
8556 off(document, "mouseover", up);
8557 }
8558 }
8559 on(document, "keyup", up);
8560 on(document, "mouseover", up);
8561 }
8562
8563 function onKeyUp(e) {
8564 if (e.keyCode == 16) { this.doc.sel.shift = false; }
8565 signalDOMEvent(this, e);
8566 }
8567
8568 function onKeyPress(e) {
8569 var cm = this;
8570 if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }
8571 var keyCode = e.keyCode, charCode = e.charCode;
8572 if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}
8573 if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return }
8574 var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
8575 // Some browsers fire keypress events for backspace
8576 if (ch == "\x08") { return }
8577 if (handleCharBinding(cm, e, ch)) { return }
8578 cm.display.input.onKeyPress(e);
8579 }
8580
8581 var DOUBLECLICK_DELAY = 400;
8582
8583 var PastClick = function(time, pos, button) {
8584 this.time = time;
8585 this.pos = pos;
8586 this.button = button;
8587 };
8588
8589 PastClick.prototype.compare = function (time, pos, button) {
8590 return this.time + DOUBLECLICK_DELAY > time &&
8591 cmp(pos, this.pos) == 0 && button == this.button
8592 };
8593
8594 var lastClick;
8595 var lastDoubleClick;
8596 function clickRepeat(pos, button) {
8597 var now = +new Date;
8598 if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) {
8599 lastClick = lastDoubleClick = null;
8600 return "triple"
8601 } else if (lastClick && lastClick.compare(now, pos, button)) {
8602 lastDoubleClick = new PastClick(now, pos, button);
8603 lastClick = null;
8604 return "double"
8605 } else {
8606 lastClick = new PastClick(now, pos, button);
8607 lastDoubleClick = null;
8608 return "single"
8609 }
8610 }
8611
8612 // A mouse down can be a single click, double click, triple click,
8613 // start of selection drag, start of text drag, new cursor
8614 // (ctrl-click), rectangle drag (alt-drag), or xwin
8615 // middle-click-paste. Or it might be a click on something we should
8616 // not interfere with, such as a scrollbar or widget.
8617 function onMouseDown(e) {
8618 var cm = this, display = cm.display;
8619 if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return }
8620 display.input.ensurePolled();
8621 display.shift = e.shiftKey;
8622
8623 if (eventInWidget(display, e)) {
8624 if (!webkit) {
8625 // Briefly turn off draggability, to allow widgets to do
8626 // normal dragging things.
8627 display.scroller.draggable = false;
8628 setTimeout(function () { return display.scroller.draggable = true; }, 100);
8629 }
8630 return
8631 }
8632 if (clickInGutter(cm, e)) { return }
8633 var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single";
8634 window.focus();
8635
8636 // #3261: make sure, that we're not starting a second selection
8637 if (button == 1 && cm.state.selectingText)
8638 { cm.state.selectingText(e); }
8639
8640 if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return }
8641
8642 if (button == 1) {
8643 if (pos) { leftButtonDown(cm, pos, repeat, e); }
8644 else if (e_target(e) == display.scroller) { e_preventDefault(e); }
8645 } else if (button == 2) {
8646 if (pos) { extendSelection(cm.doc, pos); }
8647 setTimeout(function () { return display.input.focus(); }, 20);
8648 } else if (button == 3) {
8649 if (captureRightClick) { onContextMenu(cm, e); }
8650 else { delayBlurEvent(cm); }
8651 }
8652 }
8653
8654 function handleMappedButton(cm, button, pos, repeat, event) {
8655 var name = "Click";
8656 if (repeat == "double") { name = "Double" + name; }
8657 else if (repeat == "triple") { name = "Triple" + name; }
8658 name = (button == 1 ? "Left" : button == 2 ? "Middle" : "Right") + name;
8659
8660 return dispatchKey(cm, addModifierNames(name, event), event, function (bound) {
8661 if (typeof bound == "string") { bound = commands[bound]; }
8662 if (!bound) { return false }
8663 var done = false;
8664 try {
8665 if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
8666 done = bound(cm, pos) != Pass;
8667 } finally {
8668 cm.state.suppressEdits = false;
8669 }
8670 return done
8671 })
8672 }
8673
8674 function configureMouse(cm, repeat, event) {
8675 var option = cm.getOption("configureMouse");
8676 var value = option ? option(cm, repeat, event) : {};
8677 if (value.unit == null) {
8678 var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey;
8679 value.unit = rect ? "rectangle" : repeat == "single" ? "char" : repeat == "double" ? "word" : "line";
8680 }
8681 if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey; }
8682 if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey; }
8683 if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey); }
8684 return value
8685 }
8686
8687 function leftButtonDown(cm, pos, repeat, event) {
8688 if (ie) { setTimeout(bind(ensureFocus, cm), 0); }
8689 else { cm.curOp.focus = activeElt(); }
8690
8691 var behavior = configureMouse(cm, repeat, event);
8692
8693 var sel = cm.doc.sel, contained;
8694 if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
8695 repeat == "single" && (contained = sel.contains(pos)) > -1 &&
8696 (cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) &&
8697 (cmp(contained.to(), pos) > 0 || pos.xRel < 0))
8698 { leftButtonStartDrag(cm, event, pos, behavior); }
8699 else
8700 { leftButtonSelect(cm, event, pos, behavior); }
8701 }
8702
8703 // Start a text drag. When it ends, see if any dragging actually
8704 // happen, and treat as a click if it didn't.
8705 function leftButtonStartDrag(cm, event, pos, behavior) {
8706 var display = cm.display, moved = false;
8707 var dragEnd = operation(cm, function (e) {
8708 if (webkit) { display.scroller.draggable = false; }
8709 cm.state.draggingText = false;
8710 off(document, "mouseup", dragEnd);
8711 off(document, "mousemove", mouseMove);
8712 off(display.scroller, "dragstart", dragStart);
8713 off(display.scroller, "drop", dragEnd);
8714 if (!moved) {
8715 e_preventDefault(e);
8716 if (!behavior.addNew)
8717 { extendSelection(cm.doc, pos, null, null, behavior.extend); }
8718 // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
8719 if (webkit || ie && ie_version == 9)
8720 { setTimeout(function () {document.body.focus(); display.input.focus();}, 20); }
8721 else
8722 { display.input.focus(); }
8723 }
8724 });
8725 var mouseMove = function(e2) {
8726 moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10;
8727 };
8728 var dragStart = function () { return moved = true; };
8729 // Let the drag handler handle this.
8730 if (webkit) { display.scroller.draggable = true; }
8731 cm.state.draggingText = dragEnd;
8732 dragEnd.copy = !behavior.moveOnDrag;
8733 // IE's approach to draggable
8734 if (display.scroller.dragDrop) { display.scroller.dragDrop(); }
8735 on(document, "mouseup", dragEnd);
8736 on(document, "mousemove", mouseMove);
8737 on(display.scroller, "dragstart", dragStart);
8738 on(display.scroller, "drop", dragEnd);
8739
8740 delayBlurEvent(cm);
8741 setTimeout(function () { return display.input.focus(); }, 20);
8742 }
8743
8744 function rangeForUnit(cm, pos, unit) {
8745 if (unit == "char") { return new Range(pos, pos) }
8746 if (unit == "word") { return cm.findWordAt(pos) }
8747 if (unit == "line") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) }
8748 var result = unit(cm, pos);
8749 return new Range(result.from, result.to)
8750 }
8751
8752 // Normal selection, as opposed to text dragging.
8753 function leftButtonSelect(cm, event, start, behavior) {
8754 var display = cm.display, doc = cm.doc;
8755 e_preventDefault(event);
8756
8757 var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
8758 if (behavior.addNew && !behavior.extend) {
8759 ourIndex = doc.sel.contains(start);
8760 if (ourIndex > -1)
8761 { ourRange = ranges[ourIndex]; }
8762 else
8763 { ourRange = new Range(start, start); }
8764 } else {
8765 ourRange = doc.sel.primary();
8766 ourIndex = doc.sel.primIndex;
8767 }
8768
8769 if (behavior.unit == "rectangle") {
8770 if (!behavior.addNew) { ourRange = new Range(start, start); }
8771 start = posFromMouse(cm, event, true, true);
8772 ourIndex = -1;
8773 } else {
8774 var range$$1 = rangeForUnit(cm, start, behavior.unit);
8775 if (behavior.extend)
8776 { ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); }
8777 else
8778 { ourRange = range$$1; }
8779 }
8780
8781 if (!behavior.addNew) {
8782 ourIndex = 0;
8783 setSelection(doc, new Selection([ourRange], 0), sel_mouse);
8784 startSel = doc.sel;
8785 } else if (ourIndex == -1) {
8786 ourIndex = ranges.length;
8787 setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
8788 {scroll: false, origin: "*mouse"});
8789 } else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) {
8790 setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
8791 {scroll: false, origin: "*mouse"});
8792 startSel = doc.sel;
8793 } else {
8794 replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
8795 }
8796
8797 var lastPos = start;
8798 function extendTo(pos) {
8799 if (cmp(lastPos, pos) == 0) { return }
8800 lastPos = pos;
8801
8802 if (behavior.unit == "rectangle") {
8803 var ranges = [], tabSize = cm.options.tabSize;
8804 var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
8805 var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
8806 var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
8807 for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
8808 line <= end; line++) {
8809 var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
8810 if (left == right)
8811 { ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); }
8812 else if (text.length > leftPos)
8813 { ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); }
8814 }
8815 if (!ranges.length) { ranges.push(new Range(start, start)); }
8816 setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
8817 {origin: "*mouse", scroll: false});
8818 cm.scrollIntoView(pos);
8819 } else {
8820 var oldRange = ourRange;
8821 var range$$1 = rangeForUnit(cm, pos, behavior.unit);
8822 var anchor = oldRange.anchor, head;
8823 if (cmp(range$$1.anchor, anchor) > 0) {
8824 head = range$$1.head;
8825 anchor = minPos(oldRange.from(), range$$1.anchor);
8826 } else {
8827 head = range$$1.anchor;
8828 anchor = maxPos(oldRange.to(), range$$1.head);
8829 }
8830 var ranges$1 = startSel.ranges.slice(0);
8831 ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head));
8832 setSelection(doc, normalizeSelection(ranges$1, ourIndex), sel_mouse);
8833 }
8834 }
8835
8836 var editorSize = display.wrapper.getBoundingClientRect();
8837 // Used to ensure timeout re-tries don't fire when another extend
8838 // happened in the meantime (clearTimeout isn't reliable -- at
8839 // least on Chrome, the timeouts still happen even when cleared,
8840 // if the clear happens after their scheduled firing time).
8841 var counter = 0;
8842
8843 function extend(e) {
8844 var curCount = ++counter;
8845 var cur = posFromMouse(cm, e, true, behavior.unit == "rectangle");
8846 if (!cur) { return }
8847 if (cmp(cur, lastPos) != 0) {
8848 cm.curOp.focus = activeElt();
8849 extendTo(cur);
8850 var visible = visibleLines(display, doc);
8851 if (cur.line >= visible.to || cur.line < visible.from)
8852 { setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); }
8853 } else {
8854 var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
8855 if (outside) { setTimeout(operation(cm, function () {
8856 if (counter != curCount) { return }
8857 display.scroller.scrollTop += outside;
8858 extend(e);
8859 }), 50); }
8860 }
8861 }
8862
8863 function done(e) {
8864 cm.state.selectingText = false;
8865 counter = Infinity;
8866 e_preventDefault(e);
8867 display.input.focus();
8868 off(document, "mousemove", move);
8869 off(document, "mouseup", up);
8870 doc.history.lastSelOrigin = null;
8871 }
8872
8873 var move = operation(cm, function (e) {
8874 if (!e_button(e)) { done(e); }
8875 else { extend(e); }
8876 });
8877 var up = operation(cm, done);
8878 cm.state.selectingText = up;
8879 on(document, "mousemove", move);
8880 on(document, "mouseup", up);
8881 }
8882
8883 // Used when mouse-selecting to adjust the anchor to the proper side
8884 // of a bidi jump depending on the visual position of the head.
8885 function bidiSimplify(cm, range$$1) {
8886 var anchor = range$$1.anchor;
8887 var head = range$$1.head;
8888 var anchorLine = getLine(cm.doc, anchor.line);
8889 if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range$$1 }
8890 var order = getOrder(anchorLine);
8891 if (!order) { return range$$1 }
8892 var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index];
8893 if (part.from != anchor.ch && part.to != anchor.ch) { return range$$1 }
8894 var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1);
8895 if (boundary == 0 || boundary == order.length) { return range$$1 }
8896
8897 // Compute the relative visual position of the head compared to the
8898 // anchor (<0 is to the left, >0 to the right)
8899 var leftSide;
8900 if (head.line != anchor.line) {
8901 leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0;
8902 } else {
8903 var headIndex = getBidiPartAt(order, head.ch, head.sticky);
8904 var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1);
8905 if (headIndex == boundary - 1 || headIndex == boundary)
8906 { leftSide = dir < 0; }
8907 else
8908 { leftSide = dir > 0; }
8909 }
8910
8911 var usePart = order[boundary + (leftSide ? -1 : 0)];
8912 var from = leftSide == (usePart.level == 1);
8913 var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before";
8914 return anchor.ch == ch && anchor.sticky == sticky ? range$$1 : new Range(new Pos(anchor.line, ch, sticky), head)
8915 }
8916
8917
8918 // Determines whether an event happened in the gutter, and fires the
8919 // handlers for the corresponding event.
8920 function gutterEvent(cm, e, type, prevent) {
8921 var mX, mY;
8922 if (e.touches) {
8923 mX = e.touches[0].clientX;
8924 mY = e.touches[0].clientY;
8925 } else {
8926 try { mX = e.clientX; mY = e.clientY; }
8927 catch(e) { return false }
8928 }
8929 if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
8930 if (prevent) { e_preventDefault(e); }
8931
8932 var display = cm.display;
8933 var lineBox = display.lineDiv.getBoundingClientRect();
8934
8935 if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }
8936 mY -= lineBox.top - display.viewOffset;
8937
8938 for (var i = 0; i < cm.options.gutters.length; ++i) {
8939 var g = display.gutters.childNodes[i];
8940 if (g && g.getBoundingClientRect().right >= mX) {
8941 var line = lineAtHeight(cm.doc, mY);
8942 var gutter = cm.options.gutters[i];
8943 signal(cm, type, cm, line, gutter, e);
8944 return e_defaultPrevented(e)
8945 }
8946 }
8947 }
8948
8949 function clickInGutter(cm, e) {
8950 return gutterEvent(cm, e, "gutterClick", true)
8951 }
8952
8953 // CONTEXT MENU HANDLING
8954
8955 // To make the context menu work, we need to briefly unhide the
8956 // textarea (making it as unobtrusive as possible) to let the
8957 // right-click take effect on it.
8958 function onContextMenu(cm, e) {
8959 if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return }
8960 if (signalDOMEvent(cm, e, "contextmenu")) { return }
8961 cm.display.input.onContextMenu(e);
8962 }
8963
8964 function contextMenuInGutter(cm, e) {
8965 if (!hasHandler(cm, "gutterContextMenu")) { return false }
8966 return gutterEvent(cm, e, "gutterContextMenu", false)
8967 }
8968
8969 function themeChanged(cm) {
8970 cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
8971 cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
8972 clearCaches(cm);
8973 }
8974
8975 var Init = {toString: function(){return "CodeMirror.Init"}};
8976
8977 var defaults = {};
8978 var optionHandlers = {};
8979
8980 function defineOptions(CodeMirror) {
8981 var optionHandlers = CodeMirror.optionHandlers;
8982
8983 function option(name, deflt, handle, notOnInit) {
8984 CodeMirror.defaults[name] = deflt;
8985 if (handle) { optionHandlers[name] =
8986 notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old); }} : handle; }
8987 }
8988
8989 CodeMirror.defineOption = option;
8990
8991 // Passed to option handlers when there is no old value.
8992 CodeMirror.Init = Init;
8993
8994 // These two are, on init, called from the constructor because they
8995 // have to be initialized before the editor can start at all.
8996 option("value", "", function (cm, val) { return cm.setValue(val); }, true);
8997 option("mode", null, function (cm, val) {
8998 cm.doc.modeOption = val;
8999 loadMode(cm);
9000 }, true);
9001
9002 option("indentUnit", 2, loadMode, true);
9003 option("indentWithTabs", false);
9004 option("smartIndent", true);
9005 option("tabSize", 4, function (cm) {
9006 resetModeState(cm);
9007 clearCaches(cm);
9008 regChange(cm);
9009 }, true);
9010 option("lineSeparator", null, function (cm, val) {
9011 cm.doc.lineSep = val;
9012 if (!val) { return }
9013 var newBreaks = [], lineNo = cm.doc.first;
9014 cm.doc.iter(function (line) {
9015 for (var pos = 0;;) {
9016 var found = line.text.indexOf(val, pos);
9017 if (found == -1) { break }
9018 pos = found + val.length;
9019 newBreaks.push(Pos(lineNo, found));
9020 }
9021 lineNo++;
9022 });
9023 for (var i = newBreaks.length - 1; i >= 0; i--)
9024 { replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }
9025 });
9026 option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) {
9027 cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
9028 if (old != Init) { cm.refresh(); }
9029 });
9030 option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true);
9031 option("electricChars", true);
9032 option("inputStyle", mobile ? "contenteditable" : "textarea", function () {
9033 throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME
9034 }, true);
9035 option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true);
9036 option("rtlMoveVisually", !windows);
9037 option("wholeLineUpdateBefore", true);
9038
9039 option("theme", "default", function (cm) {
9040 themeChanged(cm);
9041 guttersChanged(cm);
9042 }, true);
9043 option("keyMap", "default", function (cm, val, old) {
9044 var next = getKeyMap(val);
9045 var prev = old != Init && getKeyMap(old);
9046 if (prev && prev.detach) { prev.detach(cm, next); }
9047 if (next.attach) { next.attach(cm, prev || null); }
9048 });
9049 option("extraKeys", null);
9050 option("configureMouse", null);
9051
9052 option("lineWrapping", false, wrappingChanged, true);
9053 option("gutters", [], function (cm) {
9054 setGuttersForLineNumbers(cm.options);
9055 guttersChanged(cm);
9056 }, true);
9057 option("fixedGutter", true, function (cm, val) {
9058 cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
9059 cm.refresh();
9060 }, true);
9061 option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true);
9062 option("scrollbarStyle", "native", function (cm) {
9063 initScrollbars(cm);
9064 updateScrollbars(cm);
9065 cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
9066 cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
9067 }, true);
9068 option("lineNumbers", false, function (cm) {
9069 setGuttersForLineNumbers(cm.options);
9070 guttersChanged(cm);
9071 }, true);
9072 option("firstLineNumber", 1, guttersChanged, true);
9073 option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true);
9074 option("showCursorWhenSelecting", false, updateSelection, true);
9075
9076 option("resetSelectionOnContextMenu", true);
9077 option("lineWiseCopyCut", true);
9078 option("pasteLinesPerSelection", true);
9079
9080 option("readOnly", false, function (cm, val) {
9081 if (val == "nocursor") {
9082 onBlur(cm);
9083 cm.display.input.blur();
9084 }
9085 cm.display.input.readOnlyChanged(val);
9086 });
9087 option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);
9088 option("dragDrop", true, dragDropChanged);
9089 option("allowDropFileTypes", null);
9090
9091 option("cursorBlinkRate", 530);
9092 option("cursorScrollMargin", 0);
9093 option("cursorHeight", 1, updateSelection, true);
9094 option("singleCursorHeightPerLine", true, updateSelection, true);
9095 option("workTime", 100);
9096 option("workDelay", 100);
9097 option("flattenSpans", true, resetModeState, true);
9098 option("addModeClass", false, resetModeState, true);
9099 option("pollInterval", 100);
9100 option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; });
9101 option("historyEventDelay", 1250);
9102 option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true);
9103 option("maxHighlightLength", 10000, resetModeState, true);
9104 option("moveInputWithCursor", true, function (cm, val) {
9105 if (!val) { cm.display.input.resetPosition(); }
9106 });
9107
9108 option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; });
9109 option("autofocus", null);
9110 option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true);
9111 }
9112
9113 function guttersChanged(cm) {
9114 updateGutters(cm);
9115 regChange(cm);
9116 alignHorizontally(cm);
9117 }
9118
9119 function dragDropChanged(cm, value, old) {
9120 var wasOn = old && old != Init;
9121 if (!value != !wasOn) {
9122 var funcs = cm.display.dragFunctions;
9123 var toggle = value ? on : off;
9124 toggle(cm.display.scroller, "dragstart", funcs.start);
9125 toggle(cm.display.scroller, "dragenter", funcs.enter);
9126 toggle(cm.display.scroller, "dragover", funcs.over);
9127 toggle(cm.display.scroller, "dragleave", funcs.leave);
9128 toggle(cm.display.scroller, "drop", funcs.drop);
9129 }
9130 }
9131
9132 function wrappingChanged(cm) {
9133 if (cm.options.lineWrapping) {
9134 addClass(cm.display.wrapper, "CodeMirror-wrap");
9135 cm.display.sizer.style.minWidth = "";
9136 cm.display.sizerWidth = null;
9137 } else {
9138 rmClass(cm.display.wrapper, "CodeMirror-wrap");
9139 findMaxLine(cm);
9140 }
9141 estimateLineHeights(cm);
9142 regChange(cm);
9143 clearCaches(cm);
9144 setTimeout(function () { return updateScrollbars(cm); }, 100);
9145 }
9146
9147 // A CodeMirror instance represents an editor. This is the object
9148 // that user code is usually dealing with.
9149
9150 function CodeMirror$1(place, options) {
9151 var this$1 = this;
9152
9153 if (!(this instanceof CodeMirror$1)) { return new CodeMirror$1(place, options) }
9154
9155 this.options = options = options ? copyObj(options) : {};
9156 // Determine effective options based on given values and defaults.
9157 copyObj(defaults, options, false);
9158 setGuttersForLineNumbers(options);
9159
9160 var doc = options.value;
9161 if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); }
9162 this.doc = doc;
9163
9164 var input = new CodeMirror$1.inputStyles[options.inputStyle](this);
9165 var display = this.display = new Display(place, doc, input);
9166 display.wrapper.CodeMirror = this;
9167 updateGutters(this);
9168 themeChanged(this);
9169 if (options.lineWrapping)
9170 { this.display.wrapper.className += " CodeMirror-wrap"; }
9171 initScrollbars(this);
9172
9173 this.state = {
9174 keyMaps: [], // stores maps added by addKeyMap
9175 overlays: [], // highlighting overlays, as added by addOverlay
9176 modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
9177 overwrite: false,
9178 delayingBlurEvent: false,
9179 focused: false,
9180 suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
9181 pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
9182 selectingText: false,
9183 draggingText: false,
9184 highlight: new Delayed(), // stores highlight worker timeout
9185 keySeq: null, // Unfinished key sequence
9186 specialChars: null
9187 };
9188
9189 if (options.autofocus && !mobile) { display.input.focus(); }
9190
9191 // Override magic textarea content restore that IE sometimes does
9192 // on our hidden textarea on reload
9193 if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); }
9194
9195 registerEventHandlers(this);
9196 ensureGlobalHandlers();
9197
9198 startOperation(this);
9199 this.curOp.forceUpdate = true;
9200 attachDoc(this, doc);
9201
9202 if ((options.autofocus && !mobile) || this.hasFocus())
9203 { setTimeout(bind(onFocus, this), 20); }
9204 else
9205 { onBlur(this); }
9206
9207 for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))
9208 { optionHandlers[opt](this$1, options[opt], Init); } }
9209 maybeUpdateLineNumberWidth(this);
9210 if (options.finishInit) { options.finishInit(this); }
9211 for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1); }
9212 endOperation(this);
9213 // Suppress optimizelegibility in Webkit, since it breaks text
9214 // measuring on line wrapping boundaries.
9215 if (webkit && options.lineWrapping &&
9216 getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
9217 { display.lineDiv.style.textRendering = "auto"; }
9218 }
9219
9220 // The default configuration options.
9221 CodeMirror$1.defaults = defaults;
9222 // Functions to run when options are changed.
9223 CodeMirror$1.optionHandlers = optionHandlers;
9224
9225 // Attach the necessary event handlers when initializing the editor
9226 function registerEventHandlers(cm) {
9227 var d = cm.display;
9228 on(d.scroller, "mousedown", operation(cm, onMouseDown));
9229 // Older IE's will not fire a second mousedown for a double click
9230 if (ie && ie_version < 11)
9231 { on(d.scroller, "dblclick", operation(cm, function (e) {
9232 if (signalDOMEvent(cm, e)) { return }
9233 var pos = posFromMouse(cm, e);
9234 if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return }
9235 e_preventDefault(e);
9236 var word = cm.findWordAt(pos);
9237 extendSelection(cm.doc, word.anchor, word.head);
9238 })); }
9239 else
9240 { on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }); }
9241 // Some browsers fire contextmenu *after* opening the menu, at
9242 // which point we can't mess with it anymore. Context menu is
9243 // handled in onMouseDown for these browsers.
9244 if (!captureRightClick) { on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); }); }
9245
9246 // Used to suppress mouse event handling when a touch happens
9247 var touchFinished, prevTouch = {end: 0};
9248 function finishTouch() {
9249 if (d.activeTouch) {
9250 touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000);
9251 prevTouch = d.activeTouch;
9252 prevTouch.end = +new Date;
9253 }
9254 }
9255 function isMouseLikeTouchEvent(e) {
9256 if (e.touches.length != 1) { return false }
9257 var touch = e.touches[0];
9258 return touch.radiusX <= 1 && touch.radiusY <= 1
9259 }
9260 function farAway(touch, other) {
9261 if (other.left == null) { return true }
9262 var dx = other.left - touch.left, dy = other.top - touch.top;
9263 return dx * dx + dy * dy > 20 * 20
9264 }
9265 on(d.scroller, "touchstart", function (e) {
9266 if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {
9267 d.input.ensurePolled();
9268 clearTimeout(touchFinished);
9269 var now = +new Date;
9270 d.activeTouch = {start: now, moved: false,
9271 prev: now - prevTouch.end <= 300 ? prevTouch : null};
9272 if (e.touches.length == 1) {
9273 d.activeTouch.left = e.touches[0].pageX;
9274 d.activeTouch.top = e.touches[0].pageY;
9275 }
9276 }
9277 });
9278 on(d.scroller, "touchmove", function () {
9279 if (d.activeTouch) { d.activeTouch.moved = true; }
9280 });
9281 on(d.scroller, "touchend", function (e) {
9282 var touch = d.activeTouch;
9283 if (touch && !eventInWidget(d, e) && touch.left != null &&
9284 !touch.moved && new Date - touch.start < 300) {
9285 var pos = cm.coordsChar(d.activeTouch, "page"), range;
9286 if (!touch.prev || farAway(touch, touch.prev)) // Single tap
9287 { range = new Range(pos, pos); }
9288 else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
9289 { range = cm.findWordAt(pos); }
9290 else // Triple tap
9291 { range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); }
9292 cm.setSelection(range.anchor, range.head);
9293 cm.focus();
9294 e_preventDefault(e);
9295 }
9296 finishTouch();
9297 });
9298 on(d.scroller, "touchcancel", finishTouch);
9299
9300 // Sync scrolling between fake scrollbars and real scrollable
9301 // area, ensure viewport is updated when scrolling.
9302 on(d.scroller, "scroll", function () {
9303 if (d.scroller.clientHeight) {
9304 updateScrollTop(cm, d.scroller.scrollTop);
9305 setScrollLeft(cm, d.scroller.scrollLeft, true);
9306 signal(cm, "scroll", cm);
9307 }
9308 });
9309
9310 // Listen to wheel events in order to try and update the viewport on time.
9311 on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); });
9312 on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); });
9313
9314 // Prevent wrapper from ever scrolling
9315 on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
9316
9317 d.dragFunctions = {
9318 enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e); }},
9319 over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
9320 start: function (e) { return onDragStart(cm, e); },
9321 drop: operation(cm, onDrop),
9322 leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}
9323 };
9324
9325 var inp = d.input.getField();
9326 on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); });
9327 on(inp, "keydown", operation(cm, onKeyDown));
9328 on(inp, "keypress", operation(cm, onKeyPress));
9329 on(inp, "focus", function (e) { return onFocus(cm, e); });
9330 on(inp, "blur", function (e) { return onBlur(cm, e); });
9331 }
9332
9333 var initHooks = [];
9334 CodeMirror$1.defineInitHook = function (f) { return initHooks.push(f); };
9335
9336 // Indent the given line. The how parameter can be "smart",
9337 // "add"/null, "subtract", or "prev". When aggressive is false
9338 // (typically set to true for forced single-line indents), empty
9339 // lines are not indented, and places where the mode returns Pass
9340 // are left alone.
9341 function indentLine(cm, n, how, aggressive) {
9342 var doc = cm.doc, state;
9343 if (how == null) { how = "add"; }
9344 if (how == "smart") {
9345 // Fall back to "prev" when the mode doesn't have an indentation
9346 // method.
9347 if (!doc.mode.indent) { how = "prev"; }
9348 else { state = getContextBefore(cm, n).state; }
9349 }
9350
9351 var tabSize = cm.options.tabSize;
9352 var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
9353 if (line.stateAfter) { line.stateAfter = null; }
9354 var curSpaceString = line.text.match(/^\s*/)[0], indentation;
9355 if (!aggressive && !/\S/.test(line.text)) {
9356 indentation = 0;
9357 how = "not";
9358 } else if (how == "smart") {
9359 indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
9360 if (indentation == Pass || indentation > 150) {
9361 if (!aggressive) { return }
9362 how = "prev";
9363 }
9364 }
9365 if (how == "prev") {
9366 if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize); }
9367 else { indentation = 0; }
9368 } else if (how == "add") {
9369 indentation = curSpace + cm.options.indentUnit;
9370 } else if (how == "subtract") {
9371 indentation = curSpace - cm.options.indentUnit;
9372 } else if (typeof how == "number") {
9373 indentation = curSpace + how;
9374 }
9375 indentation = Math.max(0, indentation);
9376
9377 var indentString = "", pos = 0;
9378 if (cm.options.indentWithTabs)
9379 { for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} }
9380 if (pos < indentation) { indentString += spaceStr(indentation - pos); }
9381
9382 if (indentString != curSpaceString) {
9383 replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
9384 line.stateAfter = null;
9385 return true
9386 } else {
9387 // Ensure that, if the cursor was in the whitespace at the start
9388 // of the line, it is moved to the end of that space.
9389 for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) {
9390 var range = doc.sel.ranges[i$1];
9391 if (range.head.line == n && range.head.ch < curSpaceString.length) {
9392 var pos$1 = Pos(n, curSpaceString.length);
9393 replaceOneSelection(doc, i$1, new Range(pos$1, pos$1));
9394 break
9395 }
9396 }
9397 }
9398 }
9399
9400 // This will be set to a {lineWise: bool, text: [string]} object, so
9401 // that, when pasting, we know what kind of selections the copied
9402 // text was made out of.
9403 var lastCopied = null;
9404
9405 function setLastCopied(newLastCopied) {
9406 lastCopied = newLastCopied;
9407 }
9408
9409 function applyTextInput(cm, inserted, deleted, sel, origin) {
9410 var doc = cm.doc;
9411 cm.display.shift = false;
9412 if (!sel) { sel = doc.sel; }
9413
9414 var paste = cm.state.pasteIncoming || origin == "paste";
9415 var textLines = splitLinesAuto(inserted), multiPaste = null;
9416 // When pasing N lines into N selections, insert one line per selection
9417 if (paste && sel.ranges.length > 1) {
9418 if (lastCopied && lastCopied.text.join("\n") == inserted) {
9419 if (sel.ranges.length % lastCopied.text.length == 0) {
9420 multiPaste = [];
9421 for (var i = 0; i < lastCopied.text.length; i++)
9422 { multiPaste.push(doc.splitLines(lastCopied.text[i])); }
9423 }
9424 } else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) {
9425 multiPaste = map(textLines, function (l) { return [l]; });
9426 }
9427 }
9428
9429 var updateInput;
9430 // Normal behavior is to insert the new text into every selection
9431 for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {
9432 var range$$1 = sel.ranges[i$1];
9433 var from = range$$1.from(), to = range$$1.to();
9434 if (range$$1.empty()) {
9435 if (deleted && deleted > 0) // Handle deletion
9436 { from = Pos(from.line, from.ch - deleted); }
9437 else if (cm.state.overwrite && !paste) // Handle overwrite
9438 { to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }
9439 else if (lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted)
9440 { from = to = Pos(from.line, 0); }
9441 }
9442 updateInput = cm.curOp.updateInput;
9443 var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,
9444 origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")};
9445 makeChange(cm.doc, changeEvent);
9446 signalLater(cm, "inputRead", cm, changeEvent);
9447 }
9448 if (inserted && !paste)
9449 { triggerElectric(cm, inserted); }
9450
9451 ensureCursorVisible(cm);
9452 cm.curOp.updateInput = updateInput;
9453 cm.curOp.typing = true;
9454 cm.state.pasteIncoming = cm.state.cutIncoming = false;
9455 }
9456
9457 function handlePaste(e, cm) {
9458 var pasted = e.clipboardData && e.clipboardData.getData("Text");
9459 if (pasted) {
9460 e.preventDefault();
9461 if (!cm.isReadOnly() && !cm.options.disableInput)
9462 { runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }); }
9463 return true
9464 }
9465 }
9466
9467 function triggerElectric(cm, inserted) {
9468 // When an 'electric' character is inserted, immediately trigger a reindent
9469 if (!cm.options.electricChars || !cm.options.smartIndent) { return }
9470 var sel = cm.doc.sel;
9471
9472 for (var i = sel.ranges.length - 1; i >= 0; i--) {
9473 var range$$1 = sel.ranges[i];
9474 if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue }
9475 var mode = cm.getModeAt(range$$1.head);
9476 var indented = false;
9477 if (mode.electricChars) {
9478 for (var j = 0; j < mode.electricChars.length; j++)
9479 { if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
9480 indented = indentLine(cm, range$$1.head.line, "smart");
9481 break
9482 } }
9483 } else if (mode.electricInput) {
9484 if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch)))
9485 { indented = indentLine(cm, range$$1.head.line, "smart"); }
9486 }
9487 if (indented) { signalLater(cm, "electricInput", cm, range$$1.head.line); }
9488 }
9489 }
9490
9491 function copyableRanges(cm) {
9492 var text = [], ranges = [];
9493 for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
9494 var line = cm.doc.sel.ranges[i].head.line;
9495 var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
9496 ranges.push(lineRange);
9497 text.push(cm.getRange(lineRange.anchor, lineRange.head));
9498 }
9499 return {text: text, ranges: ranges}
9500 }
9501
9502 function disableBrowserMagic(field, spellcheck) {
9503 field.setAttribute("autocorrect", "off");
9504 field.setAttribute("autocapitalize", "off");
9505 field.setAttribute("spellcheck", !!spellcheck);
9506 }
9507
9508 function hiddenTextarea() {
9509 var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none");
9510 var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
9511 // The textarea is kept positioned near the cursor to prevent the
9512 // fact that it'll be scrolled into view on input from scrolling
9513 // our fake cursor out of view. On webkit, when wrap=off, paste is
9514 // very slow. So make the area wide instead.
9515 if (webkit) { te.style.width = "1000px"; }
9516 else { te.setAttribute("wrap", "off"); }
9517 // If border: 0; -- iOS fails to open keyboard (issue #1287)
9518 if (ios) { te.style.border = "1px solid black"; }
9519 disableBrowserMagic(te);
9520 return div
9521 }
9522
9523 // The publicly visible API. Note that methodOp(f) means
9524 // 'wrap f in an operation, performed on its `this` parameter'.
9525
9526 // This is not the complete set of editor methods. Most of the
9527 // methods defined on the Doc type are also injected into
9528 // CodeMirror.prototype, for backwards compatibility and
9529 // convenience.
9530
9531 var addEditorMethods = function(CodeMirror) {
9532 var optionHandlers = CodeMirror.optionHandlers;
9533
9534 var helpers = CodeMirror.helpers = {};
9535
9536 CodeMirror.prototype = {
9537 constructor: CodeMirror,
9538 focus: function(){window.focus(); this.display.input.focus();},
9539
9540 setOption: function(option, value) {
9541 var options = this.options, old = options[option];
9542 if (options[option] == value && option != "mode") { return }
9543 options[option] = value;
9544 if (optionHandlers.hasOwnProperty(option))
9545 { operation(this, optionHandlers[option])(this, value, old); }
9546 signal(this, "optionChange", this, option);
9547 },
9548
9549 getOption: function(option) {return this.options[option]},
9550 getDoc: function() {return this.doc},
9551
9552 addKeyMap: function(map$$1, bottom) {
9553 this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map$$1));
9554 },
9555 removeKeyMap: function(map$$1) {
9556 var maps = this.state.keyMaps;
9557 for (var i = 0; i < maps.length; ++i)
9558 { if (maps[i] == map$$1 || maps[i].name == map$$1) {
9559 maps.splice(i, 1);
9560 return true
9561 } }
9562 },
9563
9564 addOverlay: methodOp(function(spec, options) {
9565 var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
9566 if (mode.startState) { throw new Error("Overlays may not be stateful.") }
9567 insertSorted(this.state.overlays,
9568 {mode: mode, modeSpec: spec, opaque: options && options.opaque,
9569 priority: (options && options.priority) || 0},
9570 function (overlay) { return overlay.priority; });
9571 this.state.modeGen++;
9572 regChange(this);
9573 }),
9574 removeOverlay: methodOp(function(spec) {
9575 var this$1 = this;
9576
9577 var overlays = this.state.overlays;
9578 for (var i = 0; i < overlays.length; ++i) {
9579 var cur = overlays[i].modeSpec;
9580 if (cur == spec || typeof spec == "string" && cur.name == spec) {
9581 overlays.splice(i, 1);
9582 this$1.state.modeGen++;
9583 regChange(this$1);
9584 return
9585 }
9586 }
9587 }),
9588
9589 indentLine: methodOp(function(n, dir, aggressive) {
9590 if (typeof dir != "string" && typeof dir != "number") {
9591 if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev"; }
9592 else { dir = dir ? "add" : "subtract"; }
9593 }
9594 if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); }
9595 }),
9596 indentSelection: methodOp(function(how) {
9597 var this$1 = this;
9598
9599 var ranges = this.doc.sel.ranges, end = -1;
9600 for (var i = 0; i < ranges.length; i++) {
9601 var range$$1 = ranges[i];
9602 if (!range$$1.empty()) {
9603 var from = range$$1.from(), to = range$$1.to();
9604 var start = Math.max(end, from.line);
9605 end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
9606 for (var j = start; j < end; ++j)
9607 { indentLine(this$1, j, how); }
9608 var newRanges = this$1.doc.sel.ranges;
9609 if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
9610 { replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); }
9611 } else if (range$$1.head.line > end) {
9612 indentLine(this$1, range$$1.head.line, how, true);
9613 end = range$$1.head.line;
9614 if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1); }
9615 }
9616 }
9617 }),
9618
9619 // Fetch the parser token for a given character. Useful for hacks
9620 // that want to inspect the mode state (say, for completion).
9621 getTokenAt: function(pos, precise) {
9622 return takeToken(this, pos, precise)
9623 },
9624
9625 getLineTokens: function(line, precise) {
9626 return takeToken(this, Pos(line), precise, true)
9627 },
9628
9629 getTokenTypeAt: function(pos) {
9630 pos = clipPos(this.doc, pos);
9631 var styles = getLineStyles(this, getLine(this.doc, pos.line));
9632 var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
9633 var type;
9634 if (ch == 0) { type = styles[2]; }
9635 else { for (;;) {
9636 var mid = (before + after) >> 1;
9637 if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid; }
9638 else if (styles[mid * 2 + 1] < ch) { before = mid + 1; }
9639 else { type = styles[mid * 2 + 2]; break }
9640 } }
9641 var cut = type ? type.indexOf("overlay ") : -1;
9642 return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1)
9643 },
9644
9645 getModeAt: function(pos) {
9646 var mode = this.doc.mode;
9647 if (!mode.innerMode) { return mode }
9648 return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode
9649 },
9650
9651 getHelper: function(pos, type) {
9652 return this.getHelpers(pos, type)[0]
9653 },
9654
9655 getHelpers: function(pos, type) {
9656 var this$1 = this;
9657
9658 var found = [];
9659 if (!helpers.hasOwnProperty(type)) { return found }
9660 var help = helpers[type], mode = this.getModeAt(pos);
9661 if (typeof mode[type] == "string") {
9662 if (help[mode[type]]) { found.push(help[mode[type]]); }
9663 } else if (mode[type]) {
9664 for (var i = 0; i < mode[type].length; i++) {
9665 var val = help[mode[type][i]];
9666 if (val) { found.push(val); }
9667 }
9668 } else if (mode.helperType && help[mode.helperType]) {
9669 found.push(help[mode.helperType]);
9670 } else if (help[mode.name]) {
9671 found.push(help[mode.name]);
9672 }
9673 for (var i$1 = 0; i$1 < help._global.length; i$1++) {
9674 var cur = help._global[i$1];
9675 if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1)
9676 { found.push(cur.val); }
9677 }
9678 return found
9679 },
9680
9681 getStateAfter: function(line, precise) {
9682 var doc = this.doc;
9683 line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
9684 return getContextBefore(this, line + 1, precise).state
9685 },
9686
9687 cursorCoords: function(start, mode) {
9688 var pos, range$$1 = this.doc.sel.primary();
9689 if (start == null) { pos = range$$1.head; }
9690 else if (typeof start == "object") { pos = clipPos(this.doc, start); }
9691 else { pos = start ? range$$1.from() : range$$1.to(); }
9692 return cursorCoords(this, pos, mode || "page")
9693 },
9694
9695 charCoords: function(pos, mode) {
9696 return charCoords(this, clipPos(this.doc, pos), mode || "page")
9697 },
9698
9699 coordsChar: function(coords, mode) {
9700 coords = fromCoordSystem(this, coords, mode || "page");
9701 return coordsChar(this, coords.left, coords.top)
9702 },
9703
9704 lineAtHeight: function(height, mode) {
9705 height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
9706 return lineAtHeight(this.doc, height + this.display.viewOffset)
9707 },
9708 heightAtLine: function(line, mode, includeWidgets) {
9709 var end = false, lineObj;
9710 if (typeof line == "number") {
9711 var last = this.doc.first + this.doc.size - 1;
9712 if (line < this.doc.first) { line = this.doc.first; }
9713 else if (line > last) { line = last; end = true; }
9714 lineObj = getLine(this.doc, line);
9715 } else {
9716 lineObj = line;
9717 }
9718 return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets || end).top +
9719 (end ? this.doc.height - heightAtLine(lineObj) : 0)
9720 },
9721
9722 defaultTextHeight: function() { return textHeight(this.display) },
9723 defaultCharWidth: function() { return charWidth(this.display) },
9724
9725 getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}},
9726
9727 addWidget: function(pos, node, scroll, vert, horiz) {
9728 var display = this.display;
9729 pos = cursorCoords(this, clipPos(this.doc, pos));
9730 var top = pos.bottom, left = pos.left;
9731 node.style.position = "absolute";
9732 node.setAttribute("cm-ignore-events", "true");
9733 this.display.input.setUneditable(node);
9734 display.sizer.appendChild(node);
9735 if (vert == "over") {
9736 top = pos.top;
9737 } else if (vert == "above" || vert == "near") {
9738 var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
9739 hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
9740 // Default to positioning above (if specified and possible); otherwise default to positioning below
9741 if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
9742 { top = pos.top - node.offsetHeight; }
9743 else if (pos.bottom + node.offsetHeight <= vspace)
9744 { top = pos.bottom; }
9745 if (left + node.offsetWidth > hspace)
9746 { left = hspace - node.offsetWidth; }
9747 }
9748 node.style.top = top + "px";
9749 node.style.left = node.style.right = "";
9750 if (horiz == "right") {
9751 left = display.sizer.clientWidth - node.offsetWidth;
9752 node.style.right = "0px";
9753 } else {
9754 if (horiz == "left") { left = 0; }
9755 else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2; }
9756 node.style.left = left + "px";
9757 }
9758 if (scroll)
9759 { scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}); }
9760 },
9761
9762 triggerOnKeyDown: methodOp(onKeyDown),
9763 triggerOnKeyPress: methodOp(onKeyPress),
9764 triggerOnKeyUp: onKeyUp,
9765 triggerOnMouseDown: methodOp(onMouseDown),
9766
9767 execCommand: function(cmd) {
9768 if (commands.hasOwnProperty(cmd))
9769 { return commands[cmd].call(null, this) }
9770 },
9771
9772 triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
9773
9774 findPosH: function(from, amount, unit, visually) {
9775 var this$1 = this;
9776
9777 var dir = 1;
9778 if (amount < 0) { dir = -1; amount = -amount; }
9779 var cur = clipPos(this.doc, from);
9780 for (var i = 0; i < amount; ++i) {
9781 cur = findPosH(this$1.doc, cur, dir, unit, visually);
9782 if (cur.hitSide) { break }
9783 }
9784 return cur
9785 },
9786
9787 moveH: methodOp(function(dir, unit) {
9788 var this$1 = this;
9789
9790 this.extendSelectionsBy(function (range$$1) {
9791 if (this$1.display.shift || this$1.doc.extend || range$$1.empty())
9792 { return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) }
9793 else
9794 { return dir < 0 ? range$$1.from() : range$$1.to() }
9795 }, sel_move);
9796 }),
9797
9798 deleteH: methodOp(function(dir, unit) {
9799 var sel = this.doc.sel, doc = this.doc;
9800 if (sel.somethingSelected())
9801 { doc.replaceSelection("", null, "+delete"); }
9802 else
9803 { deleteNearSelection(this, function (range$$1) {
9804 var other = findPosH(doc, range$$1.head, dir, unit, false);
9805 return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other}
9806 }); }
9807 }),
9808
9809 findPosV: function(from, amount, unit, goalColumn) {
9810 var this$1 = this;
9811
9812 var dir = 1, x = goalColumn;
9813 if (amount < 0) { dir = -1; amount = -amount; }
9814 var cur = clipPos(this.doc, from);
9815 for (var i = 0; i < amount; ++i) {
9816 var coords = cursorCoords(this$1, cur, "div");
9817 if (x == null) { x = coords.left; }
9818 else { coords.left = x; }
9819 cur = findPosV(this$1, coords, dir, unit);
9820 if (cur.hitSide) { break }
9821 }
9822 return cur
9823 },
9824
9825 moveV: methodOp(function(dir, unit) {
9826 var this$1 = this;
9827
9828 var doc = this.doc, goals = [];
9829 var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();
9830 doc.extendSelectionsBy(function (range$$1) {
9831 if (collapse)
9832 { return dir < 0 ? range$$1.from() : range$$1.to() }
9833 var headPos = cursorCoords(this$1, range$$1.head, "div");
9834 if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; }
9835 goals.push(headPos.left);
9836 var pos = findPosV(this$1, headPos, dir, unit);
9837 if (unit == "page" && range$$1 == doc.sel.primary())
9838 { addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); }
9839 return pos
9840 }, sel_move);
9841 if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++)
9842 { doc.sel.ranges[i].goalColumn = goals[i]; } }
9843 }),
9844
9845 // Find the word at the given position (as returned by coordsChar).
9846 findWordAt: function(pos) {
9847 var doc = this.doc, line = getLine(doc, pos.line).text;
9848 var start = pos.ch, end = pos.ch;
9849 if (line) {
9850 var helper = this.getHelper(pos, "wordChars");
9851 if ((pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end; }
9852 var startChar = line.charAt(start);
9853 var check = isWordChar(startChar, helper)
9854 ? function (ch) { return isWordChar(ch, helper); }
9855 : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); }
9856 : function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); };
9857 while (start > 0 && check(line.charAt(start - 1))) { --start; }
9858 while (end < line.length && check(line.charAt(end))) { ++end; }
9859 }
9860 return new Range(Pos(pos.line, start), Pos(pos.line, end))
9861 },
9862
9863 toggleOverwrite: function(value) {
9864 if (value != null && value == this.state.overwrite) { return }
9865 if (this.state.overwrite = !this.state.overwrite)
9866 { addClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
9867 else
9868 { rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
9869
9870 signal(this, "overwriteToggle", this, this.state.overwrite);
9871 },
9872 hasFocus: function() { return this.display.input.getField() == activeElt() },
9873 isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) },
9874
9875 scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }),
9876 getScrollInfo: function() {
9877 var scroller = this.display.scroller;
9878 return {left: scroller.scrollLeft, top: scroller.scrollTop,
9879 height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
9880 width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
9881 clientHeight: displayHeight(this), clientWidth: displayWidth(this)}
9882 },
9883
9884 scrollIntoView: methodOp(function(range$$1, margin) {
9885 if (range$$1 == null) {
9886 range$$1 = {from: this.doc.sel.primary().head, to: null};
9887 if (margin == null) { margin = this.options.cursorScrollMargin; }
9888 } else if (typeof range$$1 == "number") {
9889 range$$1 = {from: Pos(range$$1, 0), to: null};
9890 } else if (range$$1.from == null) {
9891 range$$1 = {from: range$$1, to: null};
9892 }
9893 if (!range$$1.to) { range$$1.to = range$$1.from; }
9894 range$$1.margin = margin || 0;
9895
9896 if (range$$1.from.line != null) {
9897 scrollToRange(this, range$$1);
9898 } else {
9899 scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin);
9900 }
9901 }),
9902
9903 setSize: methodOp(function(width, height) {
9904 var this$1 = this;
9905
9906 var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; };
9907 if (width != null) { this.display.wrapper.style.width = interpret(width); }
9908 if (height != null) { this.display.wrapper.style.height = interpret(height); }
9909 if (this.options.lineWrapping) { clearLineMeasurementCache(this); }
9910 var lineNo$$1 = this.display.viewFrom;
9911 this.doc.iter(lineNo$$1, this.display.viewTo, function (line) {
9912 if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)
9913 { if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, "widget"); break } } }
9914 ++lineNo$$1;
9915 });
9916 this.curOp.forceUpdate = true;
9917 signal(this, "refresh", this);
9918 }),
9919
9920 operation: function(f){return runInOp(this, f)},
9921 startOperation: function(){return startOperation(this)},
9922 endOperation: function(){return endOperation(this)},
9923
9924 refresh: methodOp(function() {
9925 var oldHeight = this.display.cachedTextHeight;
9926 regChange(this);
9927 this.curOp.forceUpdate = true;
9928 clearCaches(this);
9929 scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);
9930 updateGutterSpace(this);
9931 if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
9932 { estimateLineHeights(this); }
9933 signal(this, "refresh", this);
9934 }),
9935
9936 swapDoc: methodOp(function(doc) {
9937 var old = this.doc;
9938 old.cm = null;
9939 attachDoc(this, doc);
9940 clearCaches(this);
9941 this.display.input.reset();
9942 scrollToCoords(this, doc.scrollLeft, doc.scrollTop);
9943 this.curOp.forceScroll = true;
9944 signalLater(this, "swapDoc", this, old);
9945 return old
9946 }),
9947
9948 getInputField: function(){return this.display.input.getField()},
9949 getWrapperElement: function(){return this.display.wrapper},
9950 getScrollerElement: function(){return this.display.scroller},
9951 getGutterElement: function(){return this.display.gutters}
9952 };
9953 eventMixin(CodeMirror);
9954
9955 CodeMirror.registerHelper = function(type, name, value) {
9956 if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; }
9957 helpers[type][name] = value;
9958 };
9959 CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
9960 CodeMirror.registerHelper(type, name, value);
9961 helpers[type]._global.push({pred: predicate, val: value});
9962 };
9963 };
9964
9965 // Used for horizontal relative motion. Dir is -1 or 1 (left or
9966 // right), unit can be "char", "column" (like char, but doesn't
9967 // cross line boundaries), "word" (across next word), or "group" (to
9968 // the start of next group of word or non-word-non-whitespace
9969 // chars). The visually param controls whether, in right-to-left
9970 // text, direction 1 means to move towards the next index in the
9971 // string, or towards the character to the right of the current
9972 // position. The resulting position will have a hitSide=true
9973 // property if it reached the end of the document.
9974 function findPosH(doc, pos, dir, unit, visually) {
9975 var oldPos = pos;
9976 var origDir = dir;
9977 var lineObj = getLine(doc, pos.line);
9978 function findNextLine() {
9979 var l = pos.line + dir;
9980 if (l < doc.first || l >= doc.first + doc.size) { return false }
9981 pos = new Pos(l, pos.ch, pos.sticky);
9982 return lineObj = getLine(doc, l)
9983 }
9984 function moveOnce(boundToLine) {
9985 var next;
9986 if (visually) {
9987 next = moveVisually(doc.cm, lineObj, pos, dir);
9988 } else {
9989 next = moveLogically(lineObj, pos, dir);
9990 }
9991 if (next == null) {
9992 if (!boundToLine && findNextLine())
9993 { pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir); }
9994 else
9995 { return false }
9996 } else {
9997 pos = next;
9998 }
9999 return true
10000 }
10001
10002 if (unit == "char") {
10003 moveOnce();
10004 } else if (unit == "column") {
10005 moveOnce(true);
10006 } else if (unit == "word" || unit == "group") {
10007 var sawType = null, group = unit == "group";
10008 var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
10009 for (var first = true;; first = false) {
10010 if (dir < 0 && !moveOnce(!first)) { break }
10011 var cur = lineObj.text.charAt(pos.ch) || "\n";
10012 var type = isWordChar(cur, helper) ? "w"
10013 : group && cur == "\n" ? "n"
10014 : !group || /\s/.test(cur) ? null
10015 : "p";
10016 if (group && !first && !type) { type = "s"; }
10017 if (sawType && sawType != type) {
10018 if (dir < 0) {dir = 1; moveOnce(); pos.sticky = "after";}
10019 break
10020 }
10021
10022 if (type) { sawType = type; }
10023 if (dir > 0 && !moveOnce(!first)) { break }
10024 }
10025 }
10026 var result = skipAtomic(doc, pos, oldPos, origDir, true);
10027 if (equalCursorPos(oldPos, result)) { result.hitSide = true; }
10028 return result
10029 }
10030
10031 // For relative vertical movement. Dir may be -1 or 1. Unit can be
10032 // "page" or "line". The resulting position will have a hitSide=true
10033 // property if it reached the end of the document.
10034 function findPosV(cm, pos, dir, unit) {
10035 var doc = cm.doc, x = pos.left, y;
10036 if (unit == "page") {
10037 var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
10038 var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3);
10039 y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount;
10040
10041 } else if (unit == "line") {
10042 y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
10043 }
10044 var target;
10045 for (;;) {
10046 target = coordsChar(cm, x, y);
10047 if (!target.outside) { break }
10048 if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break }
10049 y += dir * 5;
10050 }
10051 return target
10052 }
10053
10054 // CONTENTEDITABLE INPUT STYLE
10055
10056 var ContentEditableInput = function(cm) {
10057 this.cm = cm;
10058 this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
10059 this.polling = new Delayed();
10060 this.composing = null;
10061 this.gracePeriod = false;
10062 this.readDOMTimeout = null;
10063 };
10064
10065 ContentEditableInput.prototype.init = function (display) {
10066 var this$1 = this;
10067
10068 var input = this, cm = input.cm;
10069 var div = input.div = display.lineDiv;
10070 disableBrowserMagic(div, cm.options.spellcheck);
10071
10072 on(div, "paste", function (e) {
10073 if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
10074 // IE doesn't fire input events, so we schedule a read for the pasted content in this way
10075 if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }
10076 });
10077
10078 on(div, "compositionstart", function (e) {
10079 this$1.composing = {data: e.data, done: false};
10080 });
10081 on(div, "compositionupdate", function (e) {
10082 if (!this$1.composing) { this$1.composing = {data: e.data, done: false}; }
10083 });
10084 on(div, "compositionend", function (e) {
10085 if (this$1.composing) {
10086 if (e.data != this$1.composing.data) { this$1.readFromDOMSoon(); }
10087 this$1.composing.done = true;
10088 }
10089 });
10090
10091 on(div, "touchstart", function () { return input.forceCompositionEnd(); });
10092
10093 on(div, "input", function () {
10094 if (!this$1.composing) { this$1.readFromDOMSoon(); }
10095 });
10096
10097 function onCopyCut(e) {
10098 if (signalDOMEvent(cm, e)) { return }
10099 if (cm.somethingSelected()) {
10100 setLastCopied({lineWise: false, text: cm.getSelections()});
10101 if (e.type == "cut") { cm.replaceSelection("", null, "cut"); }
10102 } else if (!cm.options.lineWiseCopyCut) {
10103 return
10104 } else {
10105 var ranges = copyableRanges(cm);
10106 setLastCopied({lineWise: true, text: ranges.text});
10107 if (e.type == "cut") {
10108 cm.operation(function () {
10109 cm.setSelections(ranges.ranges, 0, sel_dontScroll);
10110 cm.replaceSelection("", null, "cut");
10111 });
10112 }
10113 }
10114 if (e.clipboardData) {
10115 e.clipboardData.clearData();
10116 var content = lastCopied.text.join("\n");
10117 // iOS exposes the clipboard API, but seems to discard content inserted into it
10118 e.clipboardData.setData("Text", content);
10119 if (e.clipboardData.getData("Text") == content) {
10120 e.preventDefault();
10121 return
10122 }
10123 }
10124 // Old-fashioned briefly-focus-a-textarea hack
10125 var kludge = hiddenTextarea(), te = kludge.firstChild;
10126 cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
10127 te.value = lastCopied.text.join("\n");
10128 var hadFocus = document.activeElement;
10129 selectInput(te);
10130 setTimeout(function () {
10131 cm.display.lineSpace.removeChild(kludge);
10132 hadFocus.focus();
10133 if (hadFocus == div) { input.showPrimarySelection(); }
10134 }, 50);
10135 }
10136 on(div, "copy", onCopyCut);
10137 on(div, "cut", onCopyCut);
10138 };
10139
10140 ContentEditableInput.prototype.prepareSelection = function () {
10141 var result = prepareSelection(this.cm, false);
10142 result.focus = this.cm.state.focused;
10143 return result
10144 };
10145
10146 ContentEditableInput.prototype.showSelection = function (info, takeFocus) {
10147 if (!info || !this.cm.display.view.length) { return }
10148 if (info.focus || takeFocus) { this.showPrimarySelection(); }
10149 this.showMultipleSelections(info);
10150 };
10151
10152 ContentEditableInput.prototype.showPrimarySelection = function () {
10153 var sel = window.getSelection(), cm = this.cm, prim = cm.doc.sel.primary();
10154 var from = prim.from(), to = prim.to();
10155
10156 if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {
10157 sel.removeAllRanges();
10158 return
10159 }
10160
10161 var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
10162 var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset);
10163 if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
10164 cmp(minPos(curAnchor, curFocus), from) == 0 &&
10165 cmp(maxPos(curAnchor, curFocus), to) == 0)
10166 { return }
10167
10168 var view = cm.display.view;
10169 var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) ||
10170 {node: view[0].measure.map[2], offset: 0};
10171 var end = to.line < cm.display.viewTo && posToDOM(cm, to);
10172 if (!end) {
10173 var measure = view[view.length - 1].measure;
10174 var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
10175 end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]};
10176 }
10177
10178 if (!start || !end) {
10179 sel.removeAllRanges();
10180 return
10181 }
10182
10183 var old = sel.rangeCount && sel.getRangeAt(0), rng;
10184 try { rng = range(start.node, start.offset, end.offset, end.node); }
10185 catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
10186 if (rng) {
10187 if (!gecko && cm.state.focused) {
10188 sel.collapse(start.node, start.offset);
10189 if (!rng.collapsed) {
10190 sel.removeAllRanges();
10191 sel.addRange(rng);
10192 }
10193 } else {
10194 sel.removeAllRanges();
10195 sel.addRange(rng);
10196 }
10197 if (old && sel.anchorNode == null) { sel.addRange(old); }
10198 else if (gecko) { this.startGracePeriod(); }
10199 }
10200 this.rememberSelection();
10201 };
10202
10203 ContentEditableInput.prototype.startGracePeriod = function () {
10204 var this$1 = this;
10205
10206 clearTimeout(this.gracePeriod);
10207 this.gracePeriod = setTimeout(function () {
10208 this$1.gracePeriod = false;
10209 if (this$1.selectionChanged())
10210 { this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }); }
10211 }, 20);
10212 };
10213
10214 ContentEditableInput.prototype.showMultipleSelections = function (info) {
10215 removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
10216 removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
10217 };
10218
10219 ContentEditableInput.prototype.rememberSelection = function () {
10220 var sel = window.getSelection();
10221 this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
10222 this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
10223 };
10224
10225 ContentEditableInput.prototype.selectionInEditor = function () {
10226 var sel = window.getSelection();
10227 if (!sel.rangeCount) { return false }
10228 var node = sel.getRangeAt(0).commonAncestorContainer;
10229 return contains(this.div, node)
10230 };
10231
10232 ContentEditableInput.prototype.focus = function () {
10233 if (this.cm.options.readOnly != "nocursor") {
10234 if (!this.selectionInEditor())
10235 { this.showSelection(this.prepareSelection(), true); }
10236 this.div.focus();
10237 }
10238 };
10239 ContentEditableInput.prototype.blur = function () { this.div.blur(); };
10240 ContentEditableInput.prototype.getField = function () { return this.div };
10241
10242 ContentEditableInput.prototype.supportsTouch = function () { return true };
10243
10244 ContentEditableInput.prototype.receivedFocus = function () {
10245 var input = this;
10246 if (this.selectionInEditor())
10247 { this.pollSelection(); }
10248 else
10249 { runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); }
10250
10251 function poll() {
10252 if (input.cm.state.focused) {
10253 input.pollSelection();
10254 input.polling.set(input.cm.options.pollInterval, poll);
10255 }
10256 }
10257 this.polling.set(this.cm.options.pollInterval, poll);
10258 };
10259
10260 ContentEditableInput.prototype.selectionChanged = function () {
10261 var sel = window.getSelection();
10262 return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
10263 sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
10264 };
10265
10266 ContentEditableInput.prototype.pollSelection = function () {
10267 if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return }
10268 var sel = window.getSelection(), cm = this.cm;
10269 // On Android Chrome (version 56, at least), backspacing into an
10270 // uneditable block element will put the cursor in that element,
10271 // and then, because it's not editable, hide the virtual keyboard.
10272 // Because Android doesn't allow us to actually detect backspace
10273 // presses in a sane way, this code checks for when that happens
10274 // and simulates a backspace press in this case.
10275 if (android && chrome && this.cm.options.gutters.length && isInGutter(sel.anchorNode)) {
10276 this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs});
10277 this.blur();
10278 this.focus();
10279 return
10280 }
10281 if (this.composing) { return }
10282 this.rememberSelection();
10283 var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
10284 var head = domToPos(cm, sel.focusNode, sel.focusOffset);
10285 if (anchor && head) { runInOp(cm, function () {
10286 setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
10287 if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true; }
10288 }); }
10289 };
10290
10291 ContentEditableInput.prototype.pollContent = function () {
10292 if (this.readDOMTimeout != null) {
10293 clearTimeout(this.readDOMTimeout);
10294 this.readDOMTimeout = null;
10295 }
10296
10297 var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
10298 var from = sel.from(), to = sel.to();
10299 if (from.ch == 0 && from.line > cm.firstLine())
10300 { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); }
10301 if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())
10302 { to = Pos(to.line + 1, 0); }
10303 if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }
10304
10305 var fromIndex, fromLine, fromNode;
10306 if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
10307 fromLine = lineNo(display.view[0].line);
10308 fromNode = display.view[0].node;
10309 } else {
10310 fromLine = lineNo(display.view[fromIndex].line);
10311 fromNode = display.view[fromIndex - 1].node.nextSibling;
10312 }
10313 var toIndex = findViewIndex(cm, to.line);
10314 var toLine, toNode;
10315 if (toIndex == display.view.length - 1) {
10316 toLine = display.viewTo - 1;
10317 toNode = display.lineDiv.lastChild;
10318 } else {
10319 toLine = lineNo(display.view[toIndex + 1].line) - 1;
10320 toNode = display.view[toIndex + 1].node.previousSibling;
10321 }
10322
10323 if (!fromNode) { return false }
10324 var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
10325 var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
10326 while (newText.length > 1 && oldText.length > 1) {
10327 if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
10328 else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
10329 else { break }
10330 }
10331
10332 var cutFront = 0, cutEnd = 0;
10333 var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
10334 while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
10335 { ++cutFront; }
10336 var newBot = lst(newText), oldBot = lst(oldText);
10337 var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
10338 oldBot.length - (oldText.length == 1 ? cutFront : 0));
10339 while (cutEnd < maxCutEnd &&
10340 newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
10341 { ++cutEnd; }
10342 // Try to move start of change to start of selection if ambiguous
10343 if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) {
10344 while (cutFront && cutFront > from.ch &&
10345 newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) {
10346 cutFront--;
10347 cutEnd++;
10348 }
10349 }
10350
10351 newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "");
10352 newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "");
10353
10354 var chFrom = Pos(fromLine, cutFront);
10355 var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
10356 if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
10357 replaceRange(cm.doc, newText, chFrom, chTo, "+input");
10358 return true
10359 }
10360 };
10361
10362 ContentEditableInput.prototype.ensurePolled = function () {
10363 this.forceCompositionEnd();
10364 };
10365 ContentEditableInput.prototype.reset = function () {
10366 this.forceCompositionEnd();
10367 };
10368 ContentEditableInput.prototype.forceCompositionEnd = function () {
10369 if (!this.composing) { return }
10370 clearTimeout(this.readDOMTimeout);
10371 this.composing = null;
10372 this.updateFromDOM();
10373 this.div.blur();
10374 this.div.focus();
10375 };
10376 ContentEditableInput.prototype.readFromDOMSoon = function () {
10377 var this$1 = this;
10378
10379 if (this.readDOMTimeout != null) { return }
10380 this.readDOMTimeout = setTimeout(function () {
10381 this$1.readDOMTimeout = null;
10382 if (this$1.composing) {
10383 if (this$1.composing.done) { this$1.composing = null; }
10384 else { return }
10385 }
10386 this$1.updateFromDOM();
10387 }, 80);
10388 };
10389
10390 ContentEditableInput.prototype.updateFromDOM = function () {
10391 var this$1 = this;
10392
10393 if (this.cm.isReadOnly() || !this.pollContent())
10394 { runInOp(this.cm, function () { return regChange(this$1.cm); }); }
10395 };
10396
10397 ContentEditableInput.prototype.setUneditable = function (node) {
10398 node.contentEditable = "false";
10399 };
10400
10401 ContentEditableInput.prototype.onKeyPress = function (e) {
10402 if (e.charCode == 0) { return }
10403 e.preventDefault();
10404 if (!this.cm.isReadOnly())
10405 { operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); }
10406 };
10407
10408 ContentEditableInput.prototype.readOnlyChanged = function (val) {
10409 this.div.contentEditable = String(val != "nocursor");
10410 };
10411
10412 ContentEditableInput.prototype.onContextMenu = function () {};
10413 ContentEditableInput.prototype.resetPosition = function () {};
10414
10415 ContentEditableInput.prototype.needsContentAttribute = true;
10416
10417 function posToDOM(cm, pos) {
10418 var view = findViewForLine(cm, pos.line);
10419 if (!view || view.hidden) { return null }
10420 var line = getLine(cm.doc, pos.line);
10421 var info = mapFromLineView(view, line, pos.line);
10422
10423 var order = getOrder(line, cm.doc.direction), side = "left";
10424 if (order) {
10425 var partPos = getBidiPartAt(order, pos.ch);
10426 side = partPos % 2 ? "right" : "left";
10427 }
10428 var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
10429 result.offset = result.collapse == "right" ? result.end : result.start;
10430 return result
10431 }
10432
10433 function isInGutter(node) {
10434 for (var scan = node; scan; scan = scan.parentNode)
10435 { if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } }
10436 return false
10437 }
10438
10439 function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
10440
10441 function domTextBetween(cm, from, to, fromLine, toLine) {
10442 var text = "", closing = false, lineSep = cm.doc.lineSeparator();
10443 function recognizeMarker(id) { return function (marker) { return marker.id == id; } }
10444 function close() {
10445 if (closing) {
10446 text += lineSep;
10447 closing = false;
10448 }
10449 }
10450 function addText(str) {
10451 if (str) {
10452 close();
10453 text += str;
10454 }
10455 }
10456 function walk(node) {
10457 if (node.nodeType == 1) {
10458 var cmText = node.getAttribute("cm-text");
10459 if (cmText != null) {
10460 addText(cmText || node.textContent.replace(/\u200b/g, ""));
10461 return
10462 }
10463 var markerID = node.getAttribute("cm-marker"), range$$1;
10464 if (markerID) {
10465 var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
10466 if (found.length && (range$$1 = found[0].find(0)))
10467 { addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); }
10468 return
10469 }
10470 if (node.getAttribute("contenteditable") == "false") { return }
10471 var isBlock = /^(pre|div|p)$/i.test(node.nodeName);
10472 if (isBlock) { close(); }
10473 for (var i = 0; i < node.childNodes.length; i++)
10474 { walk(node.childNodes[i]); }
10475 if (isBlock) { closing = true; }
10476 } else if (node.nodeType == 3) {
10477 addText(node.nodeValue);
10478 }
10479 }
10480 for (;;) {
10481 walk(from);
10482 if (from == to) { break }
10483 from = from.nextSibling;
10484 }
10485 return text
10486 }
10487
10488 function domToPos(cm, node, offset) {
10489 var lineNode;
10490 if (node == cm.display.lineDiv) {
10491 lineNode = cm.display.lineDiv.childNodes[offset];
10492 if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) }
10493 node = null; offset = 0;
10494 } else {
10495 for (lineNode = node;; lineNode = lineNode.parentNode) {
10496 if (!lineNode || lineNode == cm.display.lineDiv) { return null }
10497 if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break }
10498 }
10499 }
10500 for (var i = 0; i < cm.display.view.length; i++) {
10501 var lineView = cm.display.view[i];
10502 if (lineView.node == lineNode)
10503 { return locateNodeInLineView(lineView, node, offset) }
10504 }
10505 }
10506
10507 function locateNodeInLineView(lineView, node, offset) {
10508 var wrapper = lineView.text.firstChild, bad = false;
10509 if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) }
10510 if (node == wrapper) {
10511 bad = true;
10512 node = wrapper.childNodes[offset];
10513 offset = 0;
10514 if (!node) {
10515 var line = lineView.rest ? lst(lineView.rest) : lineView.line;
10516 return badPos(Pos(lineNo(line), line.text.length), bad)
10517 }
10518 }
10519
10520 var textNode = node.nodeType == 3 ? node : null, topNode = node;
10521 if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
10522 textNode = node.firstChild;
10523 if (offset) { offset = textNode.nodeValue.length; }
10524 }
10525 while (topNode.parentNode != wrapper) { topNode = topNode.parentNode; }
10526 var measure = lineView.measure, maps = measure.maps;
10527
10528 function find(textNode, topNode, offset) {
10529 for (var i = -1; i < (maps ? maps.length : 0); i++) {
10530 var map$$1 = i < 0 ? measure.map : maps[i];
10531 for (var j = 0; j < map$$1.length; j += 3) {
10532 var curNode = map$$1[j + 2];
10533 if (curNode == textNode || curNode == topNode) {
10534 var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
10535 var ch = map$$1[j] + offset;
10536 if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; }
10537 return Pos(line, ch)
10538 }
10539 }
10540 }
10541 }
10542 var found = find(textNode, topNode, offset);
10543 if (found) { return badPos(found, bad) }
10544
10545 // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
10546 for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
10547 found = find(after, after.firstChild, 0);
10548 if (found)
10549 { return badPos(Pos(found.line, found.ch - dist), bad) }
10550 else
10551 { dist += after.textContent.length; }
10552 }
10553 for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) {
10554 found = find(before, before.firstChild, -1);
10555 if (found)
10556 { return badPos(Pos(found.line, found.ch + dist$1), bad) }
10557 else
10558 { dist$1 += before.textContent.length; }
10559 }
10560 }
10561
10562 // TEXTAREA INPUT STYLE
10563
10564 var TextareaInput = function(cm) {
10565 this.cm = cm;
10566 // See input.poll and input.reset
10567 this.prevInput = "";
10568
10569 // Flag that indicates whether we expect input to appear real soon
10570 // now (after some event like 'keypress' or 'input') and are
10571 // polling intensively.
10572 this.pollingFast = false;
10573 // Self-resetting timeout for the poller
10574 this.polling = new Delayed();
10575 // Used to work around IE issue with selection being forgotten when focus moves away from textarea
10576 this.hasSelection = false;
10577 this.composing = null;
10578 };
10579
10580 TextareaInput.prototype.init = function (display) {
10581 var this$1 = this;
10582
10583 var input = this, cm = this.cm;
10584
10585 // Wraps and hides input textarea
10586 var div = this.wrapper = hiddenTextarea();
10587 // The semihidden textarea that is focused when the editor is
10588 // focused, and receives input.
10589 var te = this.textarea = div.firstChild;
10590 display.wrapper.insertBefore(div, display.wrapper.firstChild);
10591
10592 // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
10593 if (ios) { te.style.width = "0px"; }
10594
10595 on(te, "input", function () {
10596 if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null; }
10597 input.poll();
10598 });
10599
10600 on(te, "paste", function (e) {
10601 if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
10602
10603 cm.state.pasteIncoming = true;
10604 input.fastPoll();
10605 });
10606
10607 function prepareCopyCut(e) {
10608 if (signalDOMEvent(cm, e)) { return }
10609 if (cm.somethingSelected()) {
10610 setLastCopied({lineWise: false, text: cm.getSelections()});
10611 } else if (!cm.options.lineWiseCopyCut) {
10612 return
10613 } else {
10614 var ranges = copyableRanges(cm);
10615 setLastCopied({lineWise: true, text: ranges.text});
10616 if (e.type == "cut") {
10617 cm.setSelections(ranges.ranges, null, sel_dontScroll);
10618 } else {
10619 input.prevInput = "";
10620 te.value = ranges.text.join("\n");
10621 selectInput(te);
10622 }
10623 }
10624 if (e.type == "cut") { cm.state.cutIncoming = true; }
10625 }
10626 on(te, "cut", prepareCopyCut);
10627 on(te, "copy", prepareCopyCut);
10628
10629 on(display.scroller, "paste", function (e) {
10630 if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }
10631 cm.state.pasteIncoming = true;
10632 input.focus();
10633 });
10634
10635 // Prevent normal selection in the editor (we handle our own)
10636 on(display.lineSpace, "selectstart", function (e) {
10637 if (!eventInWidget(display, e)) { e_preventDefault(e); }
10638 });
10639
10640 on(te, "compositionstart", function () {
10641 var start = cm.getCursor("from");
10642 if (input.composing) { input.composing.range.clear(); }
10643 input.composing = {
10644 start: start,
10645 range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
10646 };
10647 });
10648 on(te, "compositionend", function () {
10649 if (input.composing) {
10650 input.poll();
10651 input.composing.range.clear();
10652 input.composing = null;
10653 }
10654 });
10655 };
10656
10657 TextareaInput.prototype.prepareSelection = function () {
10658 // Redraw the selection and/or cursor
10659 var cm = this.cm, display = cm.display, doc = cm.doc;
10660 var result = prepareSelection(cm);
10661
10662 // Move the hidden textarea near the cursor to prevent scrolling artifacts
10663 if (cm.options.moveInputWithCursor) {
10664 var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
10665 var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
10666 result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
10667 headPos.top + lineOff.top - wrapOff.top));
10668 result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
10669 headPos.left + lineOff.left - wrapOff.left));
10670 }
10671
10672 return result
10673 };
10674
10675 TextareaInput.prototype.showSelection = function (drawn) {
10676 var cm = this.cm, display = cm.display;
10677 removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
10678 removeChildrenAndAdd(display.selectionDiv, drawn.selection);
10679 if (drawn.teTop != null) {
10680 this.wrapper.style.top = drawn.teTop + "px";
10681 this.wrapper.style.left = drawn.teLeft + "px";
10682 }
10683 };
10684
10685 // Reset the input to correspond to the selection (or to be empty,
10686 // when not typing and nothing is selected)
10687 TextareaInput.prototype.reset = function (typing) {
10688 if (this.contextMenuPending || this.composing) { return }
10689 var cm = this.cm;
10690 if (cm.somethingSelected()) {
10691 this.prevInput = "";
10692 var content = cm.getSelection();
10693 this.textarea.value = content;
10694 if (cm.state.focused) { selectInput(this.textarea); }
10695 if (ie && ie_version >= 9) { this.hasSelection = content; }
10696 } else if (!typing) {
10697 this.prevInput = this.textarea.value = "";
10698 if (ie && ie_version >= 9) { this.hasSelection = null; }
10699 }
10700 };
10701
10702 TextareaInput.prototype.getField = function () { return this.textarea };
10703
10704 TextareaInput.prototype.supportsTouch = function () { return false };
10705
10706 TextareaInput.prototype.focus = function () {
10707 if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
10708 try { this.textarea.focus(); }
10709 catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
10710 }
10711 };
10712
10713 TextareaInput.prototype.blur = function () { this.textarea.blur(); };
10714
10715 TextareaInput.prototype.resetPosition = function () {
10716 this.wrapper.style.top = this.wrapper.style.left = 0;
10717 };
10718
10719 TextareaInput.prototype.receivedFocus = function () { this.slowPoll(); };
10720
10721 // Poll for input changes, using the normal rate of polling. This
10722 // runs as long as the editor is focused.
10723 TextareaInput.prototype.slowPoll = function () {
10724 var this$1 = this;
10725
10726 if (this.pollingFast) { return }
10727 this.polling.set(this.cm.options.pollInterval, function () {
10728 this$1.poll();
10729 if (this$1.cm.state.focused) { this$1.slowPoll(); }
10730 });
10731 };
10732
10733 // When an event has just come in that is likely to add or change
10734 // something in the input textarea, we poll faster, to ensure that
10735 // the change appears on the screen quickly.
10736 TextareaInput.prototype.fastPoll = function () {
10737 var missed = false, input = this;
10738 input.pollingFast = true;
10739 function p() {
10740 var changed = input.poll();
10741 if (!changed && !missed) {missed = true; input.polling.set(60, p);}
10742 else {input.pollingFast = false; input.slowPoll();}
10743 }
10744 input.polling.set(20, p);
10745 };
10746
10747 // Read input from the textarea, and update the document to match.
10748 // When something is selected, it is present in the textarea, and
10749 // selected (unless it is huge, in which case a placeholder is
10750 // used). When nothing is selected, the cursor sits after previously
10751 // seen text (can be empty), which is stored in prevInput (we must
10752 // not reset the textarea when typing, because that breaks IME).
10753 TextareaInput.prototype.poll = function () {
10754 var this$1 = this;
10755
10756 var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
10757 // Since this is called a *lot*, try to bail out as cheaply as
10758 // possible when it is clear that nothing happened. hasSelection
10759 // will be the case when there is a lot of text in the textarea,
10760 // in which case reading its value would be expensive.
10761 if (this.contextMenuPending || !cm.state.focused ||
10762 (hasSelection(input) && !prevInput && !this.composing) ||
10763 cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
10764 { return false }
10765
10766 var text = input.value;
10767 // If nothing changed, bail.
10768 if (text == prevInput && !cm.somethingSelected()) { return false }
10769 // Work around nonsensical selection resetting in IE9/10, and
10770 // inexplicable appearance of private area unicode characters on
10771 // some key combos in Mac (#2689).
10772 if (ie && ie_version >= 9 && this.hasSelection === text ||
10773 mac && /[\uf700-\uf7ff]/.test(text)) {
10774 cm.display.input.reset();
10775 return false
10776 }
10777
10778 if (cm.doc.sel == cm.display.selForContextMenu) {
10779 var first = text.charCodeAt(0);
10780 if (first == 0x200b && !prevInput) { prevInput = "\u200b"; }
10781 if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") }
10782 }
10783 // Find the part of the input that is actually new
10784 var same = 0, l = Math.min(prevInput.length, text.length);
10785 while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; }
10786
10787 runInOp(cm, function () {
10788 applyTextInput(cm, text.slice(same), prevInput.length - same,
10789 null, this$1.composing ? "*compose" : null);
10790
10791 // Don't leave long text in the textarea, since it makes further polling slow
10792 if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = ""; }
10793 else { this$1.prevInput = text; }
10794
10795 if (this$1.composing) {
10796 this$1.composing.range.clear();
10797 this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"),
10798 {className: "CodeMirror-composing"});
10799 }
10800 });
10801 return true
10802 };
10803
10804 TextareaInput.prototype.ensurePolled = function () {
10805 if (this.pollingFast && this.poll()) { this.pollingFast = false; }
10806 };
10807
10808 TextareaInput.prototype.onKeyPress = function () {
10809 if (ie && ie_version >= 9) { this.hasSelection = null; }
10810 this.fastPoll();
10811 };
10812
10813 TextareaInput.prototype.onContextMenu = function (e) {
10814 var input = this, cm = input.cm, display = cm.display, te = input.textarea;
10815 var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
10816 if (!pos || presto) { return } // Opera is difficult.
10817
10818 // Reset the current text selection only if the click is done outside of the selection
10819 // and 'resetSelectionOnContextMenu' option is true.
10820 var reset = cm.options.resetSelectionOnContextMenu;
10821 if (reset && cm.doc.sel.contains(pos) == -1)
10822 { operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); }
10823
10824 var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;
10825 input.wrapper.style.cssText = "position: absolute";
10826 var wrapperBox = input.wrapper.getBoundingClientRect();
10827 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);";
10828 var oldScrollY;
10829 if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712)
10830 display.input.focus();
10831 if (webkit) { window.scrollTo(null, oldScrollY); }
10832 display.input.reset();
10833 // Adds "Select all" to context menu in FF
10834 if (!cm.somethingSelected()) { te.value = input.prevInput = " "; }
10835 input.contextMenuPending = true;
10836 display.selForContextMenu = cm.doc.sel;
10837 clearTimeout(display.detectingSelectAll);
10838
10839 // Select-all will be greyed out if there's nothing to select, so
10840 // this adds a zero-width space so that we can later check whether
10841 // it got selected.
10842 function prepareSelectAllHack() {
10843 if (te.selectionStart != null) {
10844 var selected = cm.somethingSelected();
10845 var extval = "\u200b" + (selected ? te.value : "");
10846 te.value = "\u21da"; // Used to catch context-menu undo
10847 te.value = extval;
10848 input.prevInput = selected ? "" : "\u200b";
10849 te.selectionStart = 1; te.selectionEnd = extval.length;
10850 // Re-set this, in case some other handler touched the
10851 // selection in the meantime.
10852 display.selForContextMenu = cm.doc.sel;
10853 }
10854 }
10855 function rehide() {
10856 input.contextMenuPending = false;
10857 input.wrapper.style.cssText = oldWrapperCSS;
10858 te.style.cssText = oldCSS;
10859 if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); }
10860
10861 // Try to detect the user choosing select-all
10862 if (te.selectionStart != null) {
10863 if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack(); }
10864 var i = 0, poll = function () {
10865 if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
10866 te.selectionEnd > 0 && input.prevInput == "\u200b") {
10867 operation(cm, selectAll)(cm);
10868 } else if (i++ < 10) {
10869 display.detectingSelectAll = setTimeout(poll, 500);
10870 } else {
10871 display.selForContextMenu = null;
10872 display.input.reset();
10873 }
10874 };
10875 display.detectingSelectAll = setTimeout(poll, 200);
10876 }
10877 }
10878
10879 if (ie && ie_version >= 9) { prepareSelectAllHack(); }
10880 if (captureRightClick) {
10881 e_stop(e);
10882 var mouseup = function () {
10883 off(window, "mouseup", mouseup);
10884 setTimeout(rehide, 20);
10885 };
10886 on(window, "mouseup", mouseup);
10887 } else {
10888 setTimeout(rehide, 50);
10889 }
10890 };
10891
10892 TextareaInput.prototype.readOnlyChanged = function (val) {
10893 if (!val) { this.reset(); }
10894 this.textarea.disabled = val == "nocursor";
10895 };
10896
10897 TextareaInput.prototype.setUneditable = function () {};
10898
10899 TextareaInput.prototype.needsContentAttribute = false;
10900
10901 function fromTextArea(textarea, options) {
10902 options = options ? copyObj(options) : {};
10903 options.value = textarea.value;
10904 if (!options.tabindex && textarea.tabIndex)
10905 { options.tabindex = textarea.tabIndex; }
10906 if (!options.placeholder && textarea.placeholder)
10907 { options.placeholder = textarea.placeholder; }
10908 // Set autofocus to true if this textarea is focused, or if it has
10909 // autofocus and no other element is focused.
10910 if (options.autofocus == null) {
10911 var hasFocus = activeElt();
10912 options.autofocus = hasFocus == textarea ||
10913 textarea.getAttribute("autofocus") != null && hasFocus == document.body;
10914 }
10915
10916 function save() {textarea.value = cm.getValue();}
10917
10918 var realSubmit;
10919 if (textarea.form) {
10920 on(textarea.form, "submit", save);
10921 // Deplorable hack to make the submit method do the right thing.
10922 if (!options.leaveSubmitMethodAlone) {
10923 var form = textarea.form;
10924 realSubmit = form.submit;
10925 try {
10926 var wrappedSubmit = form.submit = function () {
10927 save();
10928 form.submit = realSubmit;
10929 form.submit();
10930 form.submit = wrappedSubmit;
10931 };
10932 } catch(e) {}
10933 }
10934 }
10935
10936 options.finishInit = function (cm) {
10937 cm.save = save;
10938 cm.getTextArea = function () { return textarea; };
10939 cm.toTextArea = function () {
10940 cm.toTextArea = isNaN; // Prevent this from being ran twice
10941 save();
10942 textarea.parentNode.removeChild(cm.getWrapperElement());
10943 textarea.style.display = "";
10944 if (textarea.form) {
10945 off(textarea.form, "submit", save);
10946 if (typeof textarea.form.submit == "function")
10947 { textarea.form.submit = realSubmit; }
10948 }
10949 };
10950 };
10951
10952 textarea.style.display = "none";
10953 var cm = CodeMirror$1(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); },
10954 options);
10955 return cm
10956 }
10957
10958 function addLegacyProps(CodeMirror) {
10959 CodeMirror.off = off;
10960 CodeMirror.on = on;
10961 CodeMirror.wheelEventPixels = wheelEventPixels;
10962 CodeMirror.Doc = Doc;
10963 CodeMirror.splitLines = splitLinesAuto;
10964 CodeMirror.countColumn = countColumn;
10965 CodeMirror.findColumn = findColumn;
10966 CodeMirror.isWordChar = isWordCharBasic;
10967 CodeMirror.Pass = Pass;
10968 CodeMirror.signal = signal;
10969 CodeMirror.Line = Line;
10970 CodeMirror.changeEnd = changeEnd;
10971 CodeMirror.scrollbarModel = scrollbarModel;
10972 CodeMirror.Pos = Pos;
10973 CodeMirror.cmpPos = cmp;
10974 CodeMirror.modes = modes;
10975 CodeMirror.mimeModes = mimeModes;
10976 CodeMirror.resolveMode = resolveMode;
10977 CodeMirror.getMode = getMode;
10978 CodeMirror.modeExtensions = modeExtensions;
10979 CodeMirror.extendMode = extendMode;
10980 CodeMirror.copyState = copyState;
10981 CodeMirror.startState = startState;
10982 CodeMirror.innerMode = innerMode;
10983 CodeMirror.commands = commands;
10984 CodeMirror.keyMap = keyMap;
10985 CodeMirror.keyName = keyName;
10986 CodeMirror.isModifierKey = isModifierKey;
10987 CodeMirror.lookupKey = lookupKey;
10988 CodeMirror.normalizeKeyMap = normalizeKeyMap;
10989 CodeMirror.StringStream = StringStream;
10990 CodeMirror.SharedTextMarker = SharedTextMarker;
10991 CodeMirror.TextMarker = TextMarker;
10992 CodeMirror.LineWidget = LineWidget;
10993 CodeMirror.e_preventDefault = e_preventDefault;
10994 CodeMirror.e_stopPropagation = e_stopPropagation;
10995 CodeMirror.e_stop = e_stop;
10996 CodeMirror.addClass = addClass;
10997 CodeMirror.contains = contains;
10998 CodeMirror.rmClass = rmClass;
10999 CodeMirror.keyNames = keyNames;
11000 }
11001
11002 // EDITOR CONSTRUCTOR
11003
11004 defineOptions(CodeMirror$1);
11005
11006 addEditorMethods(CodeMirror$1);
11007
11008 // Set up methods on CodeMirror's prototype to redirect to the editor's document.
11009 var dontDelegate = "iter insert remove copy getEditor constructor".split(" ");
11010 for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
11011 { CodeMirror$1.prototype[prop] = (function(method) {
11012 return function() {return method.apply(this.doc, arguments)}
11013 })(Doc.prototype[prop]); } }
11014
11015 eventMixin(Doc);
11016
11017 // INPUT HANDLING
11018
11019 CodeMirror$1.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
11020
11021 // MODE DEFINITION AND QUERYING
11022
11023 // Extra arguments are stored as the mode's dependencies, which is
11024 // used by (legacy) mechanisms like loadmode.js to automatically
11025 // load a mode. (Preferred mechanism is the require/define calls.)
11026 CodeMirror$1.defineMode = function(name/*, mode, …*/) {
11027 if (!CodeMirror$1.defaults.mode && name != "null") { CodeMirror$1.defaults.mode = name; }
11028 defineMode.apply(this, arguments);
11029 };
11030
11031 CodeMirror$1.defineMIME = defineMIME;
11032
11033 // Minimal default mode.
11034 CodeMirror$1.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });
11035 CodeMirror$1.defineMIME("text/plain", "null");
11036
11037 // EXTENSIONS
11038
11039 CodeMirror$1.defineExtension = function (name, func) {
11040 CodeMirror$1.prototype[name] = func;
11041 };
11042 CodeMirror$1.defineDocExtension = function (name, func) {
11043 Doc.prototype[name] = func;
11044 };
11045
11046 CodeMirror$1.fromTextArea = fromTextArea;
11047
11048 addLegacyProps(CodeMirror$1);
11049
11050 CodeMirror$1.version = "5.31.0";
11051
11052 return CodeMirror$1;
11053
11054 })));
11055
11056 },{}],13:[function(require,module,exports){
11057 // CodeMirror, copyright (c) by Marijn Haverbeke and others
11058 // Distributed under an MIT license: http://codemirror.net/LICENSE
11059
11060 (function(mod) {
11061 if (typeof exports == "object" && typeof module == "object") // CommonJS
11062 mod(require("../../lib/codemirror"));
11063 else if (typeof define == "function" && define.amd) // AMD
11064 define(["../../lib/codemirror"], mod);
11065 else // Plain browser env
11066 mod(CodeMirror);
11067 })(function(CodeMirror) {
11068 "use strict";
11069
11070 CodeMirror.defineMode("css", function(config, parserConfig) {
11071 var inline = parserConfig.inline
11072 if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
11073
11074 var indentUnit = config.indentUnit,
11075 tokenHooks = parserConfig.tokenHooks,
11076 documentTypes = parserConfig.documentTypes || {},
11077 mediaTypes = parserConfig.mediaTypes || {},
11078 mediaFeatures = parserConfig.mediaFeatures || {},
11079 mediaValueKeywords = parserConfig.mediaValueKeywords || {},
11080 propertyKeywords = parserConfig.propertyKeywords || {},
11081 nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
11082 fontProperties = parserConfig.fontProperties || {},
11083 counterDescriptors = parserConfig.counterDescriptors || {},
11084 colorKeywords = parserConfig.colorKeywords || {},
11085 valueKeywords = parserConfig.valueKeywords || {},
11086 allowNested = parserConfig.allowNested,
11087 lineComment = parserConfig.lineComment,
11088 supportsAtComponent = parserConfig.supportsAtComponent === true;
11089
11090 var type, override;
11091 function ret(style, tp) { type = tp; return style; }
11092
11093 // Tokenizers
11094
11095 function tokenBase(stream, state) {
11096 var ch = stream.next();
11097 if (tokenHooks[ch]) {
11098 var result = tokenHooks[ch](stream, state);
11099 if (result !== false) return result;
11100 }
11101 if (ch == "@") {
11102 stream.eatWhile(/[\w\\\-]/);
11103 return ret("def", stream.current());
11104 } else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
11105 return ret(null, "compare");
11106 } else if (ch == "\"" || ch == "'") {
11107 state.tokenize = tokenString(ch);
11108 return state.tokenize(stream, state);
11109 } else if (ch == "#") {
11110 stream.eatWhile(/[\w\\\-]/);
11111 return ret("atom", "hash");
11112 } else if (ch == "!") {
11113 stream.match(/^\s*\w*/);
11114 return ret("keyword", "important");
11115 } else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
11116 stream.eatWhile(/[\w.%]/);
11117 return ret("number", "unit");
11118 } else if (ch === "-") {
11119 if (/[\d.]/.test(stream.peek())) {
11120 stream.eatWhile(/[\w.%]/);
11121 return ret("number", "unit");
11122 } else if (stream.match(/^-[\w\\\-]+/)) {
11123 stream.eatWhile(/[\w\\\-]/);
11124 if (stream.match(/^\s*:/, false))
11125 return ret("variable-2", "variable-definition");
11126 return ret("variable-2", "variable");
11127 } else if (stream.match(/^\w+-/)) {
11128 return ret("meta", "meta");
11129 }
11130 } else if (/[,+>*\/]/.test(ch)) {
11131 return ret(null, "select-op");
11132 } else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
11133 return ret("qualifier", "qualifier");
11134 } else if (/[:;{}\[\]\(\)]/.test(ch)) {
11135 return ret(null, ch);
11136 } else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) ||
11137 (ch == "d" && stream.match("omain(")) ||
11138 (ch == "r" && stream.match("egexp("))) {
11139 stream.backUp(1);
11140 state.tokenize = tokenParenthesized;
11141 return ret("property", "word");
11142 } else if (/[\w\\\-]/.test(ch)) {
11143 stream.eatWhile(/[\w\\\-]/);
11144 return ret("property", "word");
11145 } else {
11146 return ret(null, null);
11147 }
11148 }
11149
11150 function tokenString(quote) {
11151 return function(stream, state) {
11152 var escaped = false, ch;
11153 while ((ch = stream.next()) != null) {
11154 if (ch == quote && !escaped) {
11155 if (quote == ")") stream.backUp(1);
11156 break;
11157 }
11158 escaped = !escaped && ch == "\\";
11159 }
11160 if (ch == quote || !escaped && quote != ")") state.tokenize = null;
11161 return ret("string", "string");
11162 };
11163 }
11164
11165 function tokenParenthesized(stream, state) {
11166 stream.next(); // Must be '('
11167 if (!stream.match(/\s*[\"\')]/, false))
11168 state.tokenize = tokenString(")");
11169 else
11170 state.tokenize = null;
11171 return ret(null, "(");
11172 }
11173
11174 // Context management
11175
11176 function Context(type, indent, prev) {
11177 this.type = type;
11178 this.indent = indent;
11179 this.prev = prev;
11180 }
11181
11182 function pushContext(state, stream, type, indent) {
11183 state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context);
11184 return type;
11185 }
11186
11187 function popContext(state) {
11188 if (state.context.prev)
11189 state.context = state.context.prev;
11190 return state.context.type;
11191 }
11192
11193 function pass(type, stream, state) {
11194 return states[state.context.type](type, stream, state);
11195 }
11196 function popAndPass(type, stream, state, n) {
11197 for (var i = n || 1; i > 0; i--)
11198 state.context = state.context.prev;
11199 return pass(type, stream, state);
11200 }
11201
11202 // Parser
11203
11204 function wordAsValue(stream) {
11205 var word = stream.current().toLowerCase();
11206 if (valueKeywords.hasOwnProperty(word))
11207 override = "atom";
11208 else if (colorKeywords.hasOwnProperty(word))
11209 override = "keyword";
11210 else
11211 override = "variable";
11212 }
11213
11214 var states = {};
11215
11216 states.top = function(type, stream, state) {
11217 if (type == "{") {
11218 return pushContext(state, stream, "block");
11219 } else if (type == "}" && state.context.prev) {
11220 return popContext(state);
11221 } else if (supportsAtComponent && /@component/.test(type)) {
11222 return pushContext(state, stream, "atComponentBlock");
11223 } else if (/^@(-moz-)?document$/.test(type)) {
11224 return pushContext(state, stream, "documentTypes");
11225 } else if (/^@(media|supports|(-moz-)?document|import)$/.test(type)) {
11226 return pushContext(state, stream, "atBlock");
11227 } else if (/^@(font-face|counter-style)/.test(type)) {
11228 state.stateArg = type;
11229 return "restricted_atBlock_before";
11230 } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) {
11231 return "keyframes";
11232 } else if (type && type.charAt(0) == "@") {
11233 return pushContext(state, stream, "at");
11234 } else if (type == "hash") {
11235 override = "builtin";
11236 } else if (type == "word") {
11237 override = "tag";
11238 } else if (type == "variable-definition") {
11239 return "maybeprop";
11240 } else if (type == "interpolation") {
11241 return pushContext(state, stream, "interpolation");
11242 } else if (type == ":") {
11243 return "pseudo";
11244 } else if (allowNested && type == "(") {
11245 return pushContext(state, stream, "parens");
11246 }
11247 return state.context.type;
11248 };
11249
11250 states.block = function(type, stream, state) {
11251 if (type == "word") {
11252 var word = stream.current().toLowerCase();
11253 if (propertyKeywords.hasOwnProperty(word)) {
11254 override = "property";
11255 return "maybeprop";
11256 } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
11257 override = "string-2";
11258 return "maybeprop";
11259 } else if (allowNested) {
11260 override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag";
11261 return "block";
11262 } else {
11263 override += " error";
11264 return "maybeprop";
11265 }
11266 } else if (type == "meta") {
11267 return "block";
11268 } else if (!allowNested && (type == "hash" || type == "qualifier")) {
11269 override = "error";
11270 return "block";
11271 } else {
11272 return states.top(type, stream, state);
11273 }
11274 };
11275
11276 states.maybeprop = function(type, stream, state) {
11277 if (type == ":") return pushContext(state, stream, "prop");
11278 return pass(type, stream, state);
11279 };
11280
11281 states.prop = function(type, stream, state) {
11282 if (type == ";") return popContext(state);
11283 if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
11284 if (type == "}" || type == "{") return popAndPass(type, stream, state);
11285 if (type == "(") return pushContext(state, stream, "parens");
11286
11287 if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) {
11288 override += " error";
11289 } else if (type == "word") {
11290 wordAsValue(stream);
11291 } else if (type == "interpolation") {
11292 return pushContext(state, stream, "interpolation");
11293 }
11294 return "prop";
11295 };
11296
11297 states.propBlock = function(type, _stream, state) {
11298 if (type == "}") return popContext(state);
11299 if (type == "word") { override = "property"; return "maybeprop"; }
11300 return state.context.type;
11301 };
11302
11303 states.parens = function(type, stream, state) {
11304 if (type == "{" || type == "}") return popAndPass(type, stream, state);
11305 if (type == ")") return popContext(state);
11306 if (type == "(") return pushContext(state, stream, "parens");
11307 if (type == "interpolation") return pushContext(state, stream, "interpolation");
11308 if (type == "word") wordAsValue(stream);
11309 return "parens";
11310 };
11311
11312 states.pseudo = function(type, stream, state) {
11313 if (type == "meta") return "pseudo";
11314
11315 if (type == "word") {
11316 override = "variable-3";
11317 return state.context.type;
11318 }
11319 return pass(type, stream, state);
11320 };
11321
11322 states.documentTypes = function(type, stream, state) {
11323 if (type == "word" && documentTypes.hasOwnProperty(stream.current())) {
11324 override = "tag";
11325 return state.context.type;
11326 } else {
11327 return states.atBlock(type, stream, state);
11328 }
11329 };
11330
11331 states.atBlock = function(type, stream, state) {
11332 if (type == "(") return pushContext(state, stream, "atBlock_parens");
11333 if (type == "}" || type == ";") return popAndPass(type, stream, state);
11334 if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
11335
11336 if (type == "interpolation") return pushContext(state, stream, "interpolation");
11337
11338 if (type == "word") {
11339 var word = stream.current().toLowerCase();
11340 if (word == "only" || word == "not" || word == "and" || word == "or")
11341 override = "keyword";
11342 else if (mediaTypes.hasOwnProperty(word))
11343 override = "attribute";
11344 else if (mediaFeatures.hasOwnProperty(word))
11345 override = "property";
11346 else if (mediaValueKeywords.hasOwnProperty(word))
11347 override = "keyword";
11348 else if (propertyKeywords.hasOwnProperty(word))
11349 override = "property";
11350 else if (nonStandardPropertyKeywords.hasOwnProperty(word))
11351 override = "string-2";
11352 else if (valueKeywords.hasOwnProperty(word))
11353 override = "atom";
11354 else if (colorKeywords.hasOwnProperty(word))
11355 override = "keyword";
11356 else
11357 override = "error";
11358 }
11359 return state.context.type;
11360 };
11361
11362 states.atComponentBlock = function(type, stream, state) {
11363 if (type == "}")
11364 return popAndPass(type, stream, state);
11365 if (type == "{")
11366 return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false);
11367 if (type == "word")
11368 override = "error";
11369 return state.context.type;
11370 };
11371
11372 states.atBlock_parens = function(type, stream, state) {
11373 if (type == ")") return popContext(state);
11374 if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
11375 return states.atBlock(type, stream, state);
11376 };
11377
11378 states.restricted_atBlock_before = function(type, stream, state) {
11379 if (type == "{")
11380 return pushContext(state, stream, "restricted_atBlock");
11381 if (type == "word" && state.stateArg == "@counter-style") {
11382 override = "variable";
11383 return "restricted_atBlock_before";
11384 }
11385 return pass(type, stream, state);
11386 };
11387
11388 states.restricted_atBlock = function(type, stream, state) {
11389 if (type == "}") {
11390 state.stateArg = null;
11391 return popContext(state);
11392 }
11393 if (type == "word") {
11394 if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) ||
11395 (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase())))
11396 override = "error";
11397 else
11398 override = "property";
11399 return "maybeprop";
11400 }
11401 return "restricted_atBlock";
11402 };
11403
11404 states.keyframes = function(type, stream, state) {
11405 if (type == "word") { override = "variable"; return "keyframes"; }
11406 if (type == "{") return pushContext(state, stream, "top");
11407 return pass(type, stream, state);
11408 };
11409
11410 states.at = function(type, stream, state) {
11411 if (type == ";") return popContext(state);
11412 if (type == "{" || type == "}") return popAndPass(type, stream, state);
11413 if (type == "word") override = "tag";
11414 else if (type == "hash") override = "builtin";
11415 return "at";
11416 };
11417
11418 states.interpolation = function(type, stream, state) {
11419 if (type == "}") return popContext(state);
11420 if (type == "{" || type == ";") return popAndPass(type, stream, state);
11421 if (type == "word") override = "variable";
11422 else if (type != "variable" && type != "(" && type != ")") override = "error";
11423 return "interpolation";
11424 };
11425
11426 return {
11427 startState: function(base) {
11428 return {tokenize: null,
11429 state: inline ? "block" : "top",
11430 stateArg: null,
11431 context: new Context(inline ? "block" : "top", base || 0, null)};
11432 },
11433
11434 token: function(stream, state) {
11435 if (!state.tokenize && stream.eatSpace()) return null;
11436 var style = (state.tokenize || tokenBase)(stream, state);
11437 if (style && typeof style == "object") {
11438 type = style[1];
11439 style = style[0];
11440 }
11441 override = style;
11442 if (type != "comment")
11443 state.state = states[state.state](type, stream, state);
11444 return override;
11445 },
11446
11447 indent: function(state, textAfter) {
11448 var cx = state.context, ch = textAfter && textAfter.charAt(0);
11449 var indent = cx.indent;
11450 if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev;
11451 if (cx.prev) {
11452 if (ch == "}" && (cx.type == "block" || cx.type == "top" ||
11453 cx.type == "interpolation" || cx.type == "restricted_atBlock")) {
11454 // Resume indentation from parent context.
11455 cx = cx.prev;
11456 indent = cx.indent;
11457 } else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") ||
11458 ch == "{" && (cx.type == "at" || cx.type == "atBlock")) {
11459 // Dedent relative to current context.
11460 indent = Math.max(0, cx.indent - indentUnit);
11461 }
11462 }
11463 return indent;
11464 },
11465
11466 electricChars: "}",
11467 blockCommentStart: "/*",
11468 blockCommentEnd: "*/",
11469 blockCommentContinue: " * ",
11470 lineComment: lineComment,
11471 fold: "brace"
11472 };
11473 });
11474
11475 function keySet(array) {
11476 var keys = {};
11477 for (var i = 0; i < array.length; ++i) {
11478 keys[array[i].toLowerCase()] = true;
11479 }
11480 return keys;
11481 }
11482
11483 var documentTypes_ = [
11484 "domain", "regexp", "url", "url-prefix"
11485 ], documentTypes = keySet(documentTypes_);
11486
11487 var mediaTypes_ = [
11488 "all", "aural", "braille", "handheld", "print", "projection", "screen",
11489 "tty", "tv", "embossed"
11490 ], mediaTypes = keySet(mediaTypes_);
11491
11492 var mediaFeatures_ = [
11493 "width", "min-width", "max-width", "height", "min-height", "max-height",
11494 "device-width", "min-device-width", "max-device-width", "device-height",
11495 "min-device-height", "max-device-height", "aspect-ratio",
11496 "min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
11497 "min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
11498 "max-color", "color-index", "min-color-index", "max-color-index",
11499 "monochrome", "min-monochrome", "max-monochrome", "resolution",
11500 "min-resolution", "max-resolution", "scan", "grid", "orientation",
11501 "device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio",
11502 "pointer", "any-pointer", "hover", "any-hover"
11503 ], mediaFeatures = keySet(mediaFeatures_);
11504
11505 var mediaValueKeywords_ = [
11506 "landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover",
11507 "interlace", "progressive"
11508 ], mediaValueKeywords = keySet(mediaValueKeywords_);
11509
11510 var propertyKeywords_ = [
11511 "align-content", "align-items", "align-self", "alignment-adjust",
11512 "alignment-baseline", "anchor-point", "animation", "animation-delay",
11513 "animation-direction", "animation-duration", "animation-fill-mode",
11514 "animation-iteration-count", "animation-name", "animation-play-state",
11515 "animation-timing-function", "appearance", "azimuth", "backface-visibility",
11516 "background", "background-attachment", "background-blend-mode", "background-clip",
11517 "background-color", "background-image", "background-origin", "background-position",
11518 "background-repeat", "background-size", "baseline-shift", "binding",
11519 "bleed", "bookmark-label", "bookmark-level", "bookmark-state",
11520 "bookmark-target", "border", "border-bottom", "border-bottom-color",
11521 "border-bottom-left-radius", "border-bottom-right-radius",
11522 "border-bottom-style", "border-bottom-width", "border-collapse",
11523 "border-color", "border-image", "border-image-outset",
11524 "border-image-repeat", "border-image-slice", "border-image-source",
11525 "border-image-width", "border-left", "border-left-color",
11526 "border-left-style", "border-left-width", "border-radius", "border-right",
11527 "border-right-color", "border-right-style", "border-right-width",
11528 "border-spacing", "border-style", "border-top", "border-top-color",
11529 "border-top-left-radius", "border-top-right-radius", "border-top-style",
11530 "border-top-width", "border-width", "bottom", "box-decoration-break",
11531 "box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
11532 "caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count",
11533 "column-fill", "column-gap", "column-rule", "column-rule-color",
11534 "column-rule-style", "column-rule-width", "column-span", "column-width",
11535 "columns", "content", "counter-increment", "counter-reset", "crop", "cue",
11536 "cue-after", "cue-before", "cursor", "direction", "display",
11537 "dominant-baseline", "drop-initial-after-adjust",
11538 "drop-initial-after-align", "drop-initial-before-adjust",
11539 "drop-initial-before-align", "drop-initial-size", "drop-initial-value",
11540 "elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
11541 "flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
11542 "float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
11543 "font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
11544 "font-stretch", "font-style", "font-synthesis", "font-variant",
11545 "font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
11546 "font-variant-ligatures", "font-variant-numeric", "font-variant-position",
11547 "font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
11548 "grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
11549 "grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap",
11550 "grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns",
11551 "grid-template-rows", "hanging-punctuation", "height", "hyphens",
11552 "icon", "image-orientation", "image-rendering", "image-resolution",
11553 "inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing",
11554 "line-break", "line-height", "line-stacking", "line-stacking-ruby",
11555 "line-stacking-shift", "line-stacking-strategy", "list-style",
11556 "list-style-image", "list-style-position", "list-style-type", "margin",
11557 "margin-bottom", "margin-left", "margin-right", "margin-top",
11558 "marks", "marquee-direction", "marquee-loop",
11559 "marquee-play-count", "marquee-speed", "marquee-style", "max-height",
11560 "max-width", "min-height", "min-width", "move-to", "nav-down", "nav-index",
11561 "nav-left", "nav-right", "nav-up", "object-fit", "object-position",
11562 "opacity", "order", "orphans", "outline",
11563 "outline-color", "outline-offset", "outline-style", "outline-width",
11564 "overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
11565 "padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
11566 "page", "page-break-after", "page-break-before", "page-break-inside",
11567 "page-policy", "pause", "pause-after", "pause-before", "perspective",
11568 "perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position",
11569 "presentation-level", "punctuation-trim", "quotes", "region-break-after",
11570 "region-break-before", "region-break-inside", "region-fragment",
11571 "rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
11572 "right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
11573 "ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
11574 "shape-outside", "size", "speak", "speak-as", "speak-header",
11575 "speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
11576 "tab-size", "table-layout", "target", "target-name", "target-new",
11577 "target-position", "text-align", "text-align-last", "text-decoration",
11578 "text-decoration-color", "text-decoration-line", "text-decoration-skip",
11579 "text-decoration-style", "text-emphasis", "text-emphasis-color",
11580 "text-emphasis-position", "text-emphasis-style", "text-height",
11581 "text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
11582 "text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
11583 "text-wrap", "top", "transform", "transform-origin", "transform-style",
11584 "transition", "transition-delay", "transition-duration",
11585 "transition-property", "transition-timing-function", "unicode-bidi",
11586 "user-select", "vertical-align", "visibility", "voice-balance", "voice-duration",
11587 "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
11588 "voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break",
11589 "word-spacing", "word-wrap", "z-index",
11590 // SVG-specific
11591 "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
11592 "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
11593 "color-interpolation", "color-interpolation-filters",
11594 "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
11595 "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
11596 "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
11597 "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
11598 "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
11599 "glyph-orientation-vertical", "text-anchor", "writing-mode"
11600 ], propertyKeywords = keySet(propertyKeywords_);
11601
11602 var nonStandardPropertyKeywords_ = [
11603 "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
11604 "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
11605 "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
11606 "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
11607 "searchfield-results-decoration", "zoom"
11608 ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
11609
11610 var fontProperties_ = [
11611 "font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
11612 "font-stretch", "font-weight", "font-style"
11613 ], fontProperties = keySet(fontProperties_);
11614
11615 var counterDescriptors_ = [
11616 "additive-symbols", "fallback", "negative", "pad", "prefix", "range",
11617 "speak-as", "suffix", "symbols", "system"
11618 ], counterDescriptors = keySet(counterDescriptors_);
11619
11620 var colorKeywords_ = [
11621 "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
11622 "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
11623 "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
11624 "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
11625 "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
11626 "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
11627 "darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
11628 "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
11629 "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
11630 "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
11631 "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
11632 "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
11633 "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
11634 "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
11635 "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
11636 "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
11637 "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
11638 "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
11639 "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
11640 "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
11641 "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
11642 "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown",
11643 "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
11644 "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
11645 "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
11646 "whitesmoke", "yellow", "yellowgreen"
11647 ], colorKeywords = keySet(colorKeywords_);
11648
11649 var valueKeywords_ = [
11650 "above", "absolute", "activeborder", "additive", "activecaption", "afar",
11651 "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
11652 "always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
11653 "arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page",
11654 "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
11655 "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
11656 "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
11657 "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian",
11658 "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
11659 "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
11660 "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
11661 "col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
11662 "compact", "condensed", "contain", "content", "contents",
11663 "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
11664 "cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
11665 "decimal-leading-zero", "default", "default-button", "dense", "destination-atop",
11666 "destination-in", "destination-out", "destination-over", "devanagari", "difference",
11667 "disc", "discard", "disclosure-closed", "disclosure-open", "document",
11668 "dot-dash", "dot-dot-dash",
11669 "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
11670 "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
11671 "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
11672 "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
11673 "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
11674 "ethiopic-halehame-gez", "ethiopic-halehame-om-et",
11675 "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
11676 "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
11677 "ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
11678 "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
11679 "forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove",
11680 "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
11681 "help", "hidden", "hide", "higher", "highlight", "highlighttext",
11682 "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore",
11683 "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
11684 "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
11685 "inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert",
11686 "italic", "japanese-formal", "japanese-informal", "justify", "kannada",
11687 "katakana", "katakana-iroha", "keep-all", "khmer",
11688 "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal",
11689 "landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten",
11690 "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem",
11691 "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
11692 "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
11693 "lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d",
11694 "media-controls-background", "media-current-time-display",
11695 "media-fullscreen-button", "media-mute-button", "media-play-button",
11696 "media-return-to-realtime-button", "media-rewind-button",
11697 "media-seek-back-button", "media-seek-forward-button", "media-slider",
11698 "media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
11699 "media-volume-slider-container", "media-volume-sliderthumb", "medium",
11700 "menu", "menulist", "menulist-button", "menulist-text",
11701 "menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
11702 "mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
11703 "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
11704 "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
11705 "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote",
11706 "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
11707 "outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
11708 "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
11709 "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d",
11710 "progress", "push-button", "radial-gradient", "radio", "read-only",
11711 "read-write", "read-write-plaintext-only", "rectangle", "region",
11712 "relative", "repeat", "repeating-linear-gradient",
11713 "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse",
11714 "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
11715 "rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
11716 "s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
11717 "scroll", "scrollbar", "scroll-position", "se-resize", "searchfield",
11718 "searchfield-cancel-button", "searchfield-decoration",
11719 "searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end",
11720 "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
11721 "simp-chinese-formal", "simp-chinese-informal", "single",
11722 "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal",
11723 "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
11724 "small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
11725 "source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square",
11726 "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
11727 "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table",
11728 "table-caption", "table-cell", "table-column", "table-column-group",
11729 "table-footer-group", "table-header-group", "table-row", "table-row-group",
11730 "tamil",
11731 "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
11732 "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
11733 "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
11734 "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
11735 "trad-chinese-formal", "trad-chinese-informal", "transform",
11736 "translate", "translate3d", "translateX", "translateY", "translateZ",
11737 "transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up",
11738 "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
11739 "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
11740 "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
11741 "visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
11742 "window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor",
11743 "xx-large", "xx-small"
11744 ], valueKeywords = keySet(valueKeywords_);
11745
11746 var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_)
11747 .concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_)
11748 .concat(valueKeywords_);
11749 CodeMirror.registerHelper("hintWords", "css", allWords);
11750
11751 function tokenCComment(stream, state) {
11752 var maybeEnd = false, ch;
11753 while ((ch = stream.next()) != null) {
11754 if (maybeEnd && ch == "/") {
11755 state.tokenize = null;
11756 break;
11757 }
11758 maybeEnd = (ch == "*");
11759 }
11760 return ["comment", "comment"];
11761 }
11762
11763 CodeMirror.defineMIME("text/css", {
11764 documentTypes: documentTypes,
11765 mediaTypes: mediaTypes,
11766 mediaFeatures: mediaFeatures,
11767 mediaValueKeywords: mediaValueKeywords,
11768 propertyKeywords: propertyKeywords,
11769 nonStandardPropertyKeywords: nonStandardPropertyKeywords,
11770 fontProperties: fontProperties,
11771 counterDescriptors: counterDescriptors,
11772 colorKeywords: colorKeywords,
11773 valueKeywords: valueKeywords,
11774 tokenHooks: {
11775 "/": function(stream, state) {
11776 if (!stream.eat("*")) return false;
11777 state.tokenize = tokenCComment;
11778 return tokenCComment(stream, state);
11779 }
11780 },
11781 name: "css"
11782 });
11783
11784 CodeMirror.defineMIME("text/x-scss", {
11785 mediaTypes: mediaTypes,
11786 mediaFeatures: mediaFeatures,
11787 mediaValueKeywords: mediaValueKeywords,
11788 propertyKeywords: propertyKeywords,
11789 nonStandardPropertyKeywords: nonStandardPropertyKeywords,
11790 colorKeywords: colorKeywords,
11791 valueKeywords: valueKeywords,
11792 fontProperties: fontProperties,
11793 allowNested: true,
11794 lineComment: "//",
11795 tokenHooks: {
11796 "/": function(stream, state) {
11797 if (stream.eat("/")) {
11798 stream.skipToEnd();
11799 return ["comment", "comment"];
11800 } else if (stream.eat("*")) {
11801 state.tokenize = tokenCComment;
11802 return tokenCComment(stream, state);
11803 } else {
11804 return ["operator", "operator"];
11805 }
11806 },
11807 ":": function(stream) {
11808 if (stream.match(/\s*\{/, false))
11809 return [null, null]
11810 return false;
11811 },
11812 "$": function(stream) {
11813 stream.match(/^[\w-]+/);
11814 if (stream.match(/^\s*:/, false))
11815 return ["variable-2", "variable-definition"];
11816 return ["variable-2", "variable"];
11817 },
11818 "#": function(stream) {
11819 if (!stream.eat("{")) return false;
11820 return [null, "interpolation"];
11821 }
11822 },
11823 name: "css",
11824 helperType: "scss"
11825 });
11826
11827 CodeMirror.defineMIME("text/x-less", {
11828 mediaTypes: mediaTypes,
11829 mediaFeatures: mediaFeatures,
11830 mediaValueKeywords: mediaValueKeywords,
11831 propertyKeywords: propertyKeywords,
11832 nonStandardPropertyKeywords: nonStandardPropertyKeywords,
11833 colorKeywords: colorKeywords,
11834 valueKeywords: valueKeywords,
11835 fontProperties: fontProperties,
11836 allowNested: true,
11837 lineComment: "//",
11838 tokenHooks: {
11839 "/": function(stream, state) {
11840 if (stream.eat("/")) {
11841 stream.skipToEnd();
11842 return ["comment", "comment"];
11843 } else if (stream.eat("*")) {
11844 state.tokenize = tokenCComment;
11845 return tokenCComment(stream, state);
11846 } else {
11847 return ["operator", "operator"];
11848 }
11849 },
11850 "@": function(stream) {
11851 if (stream.eat("{")) return [null, "interpolation"];
11852 if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/, false)) return false;
11853 stream.eatWhile(/[\w\\\-]/);
11854 if (stream.match(/^\s*:/, false))
11855 return ["variable-2", "variable-definition"];
11856 return ["variable-2", "variable"];
11857 },
11858 "&": function() {
11859 return ["atom", "atom"];
11860 }
11861 },
11862 name: "css",
11863 helperType: "less"
11864 });
11865
11866 CodeMirror.defineMIME("text/x-gss", {
11867 documentTypes: documentTypes,
11868 mediaTypes: mediaTypes,
11869 mediaFeatures: mediaFeatures,
11870 propertyKeywords: propertyKeywords,
11871 nonStandardPropertyKeywords: nonStandardPropertyKeywords,
11872 fontProperties: fontProperties,
11873 counterDescriptors: counterDescriptors,
11874 colorKeywords: colorKeywords,
11875 valueKeywords: valueKeywords,
11876 supportsAtComponent: true,
11877 tokenHooks: {
11878 "/": function(stream, state) {
11879 if (!stream.eat("*")) return false;
11880 state.tokenize = tokenCComment;
11881 return tokenCComment(stream, state);
11882 }
11883 },
11884 name: "css",
11885 helperType: "gss"
11886 });
11887
11888 });
11889
11890 },{"../../lib/codemirror":12}],14:[function(require,module,exports){
11891 // CodeMirror, copyright (c) by Marijn Haverbeke and others
11892 // Distributed under an MIT license: http://codemirror.net/LICENSE
11893
11894 (function(mod) {
11895 if (typeof exports == "object" && typeof module == "object") // CommonJS
11896 mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"), require("../css/css"));
11897 else if (typeof define == "function" && define.amd) // AMD
11898 define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript", "../css/css"], mod);
11899 else // Plain browser env
11900 mod(CodeMirror);
11901 })(function(CodeMirror) {
11902 "use strict";
11903
11904 var defaultTags = {
11905 script: [
11906 ["lang", /(javascript|babel)/i, "javascript"],
11907 ["type", /^(?:text|application)\/(?:x-)?(?:java|ecma)script$|^module$|^$/i, "javascript"],
11908 ["type", /./, "text/plain"],
11909 [null, null, "javascript"]
11910 ],
11911 style: [
11912 ["lang", /^css$/i, "css"],
11913 ["type", /^(text\/)?(x-)?(stylesheet|css)$/i, "css"],
11914 ["type", /./, "text/plain"],
11915 [null, null, "css"]
11916 ]
11917 };
11918
11919 function maybeBackup(stream, pat, style) {
11920 var cur = stream.current(), close = cur.search(pat);
11921 if (close > -1) {
11922 stream.backUp(cur.length - close);
11923 } else if (cur.match(/<\/?$/)) {
11924 stream.backUp(cur.length);
11925 if (!stream.match(pat, false)) stream.match(cur);
11926 }
11927 return style;
11928 }
11929
11930 var attrRegexpCache = {};
11931 function getAttrRegexp(attr) {
11932 var regexp = attrRegexpCache[attr];
11933 if (regexp) return regexp;
11934 return attrRegexpCache[attr] = new RegExp("\\s+" + attr + "\\s*=\\s*('|\")?([^'\"]+)('|\")?\\s*");
11935 }
11936
11937 function getAttrValue(text, attr) {
11938 var match = text.match(getAttrRegexp(attr))
11939 return match ? /^\s*(.*?)\s*$/.exec(match[2])[1] : ""
11940 }
11941
11942 function getTagRegexp(tagName, anchored) {
11943 return new RegExp((anchored ? "^" : "") + "<\/\s*" + tagName + "\s*>", "i");
11944 }
11945
11946 function addTags(from, to) {
11947 for (var tag in from) {
11948 var dest = to[tag] || (to[tag] = []);
11949 var source = from[tag];
11950 for (var i = source.length - 1; i >= 0; i--)
11951 dest.unshift(source[i])
11952 }
11953 }
11954
11955 function findMatchingMode(tagInfo, tagText) {
11956 for (var i = 0; i < tagInfo.length; i++) {
11957 var spec = tagInfo[i];
11958 if (!spec[0] || spec[1].test(getAttrValue(tagText, spec[0]))) return spec[2];
11959 }
11960 }
11961
11962 CodeMirror.defineMode("htmlmixed", function (config, parserConfig) {
11963 var htmlMode = CodeMirror.getMode(config, {
11964 name: "xml",
11965 htmlMode: true,
11966 multilineTagIndentFactor: parserConfig.multilineTagIndentFactor,
11967 multilineTagIndentPastTag: parserConfig.multilineTagIndentPastTag
11968 });
11969
11970 var tags = {};
11971 var configTags = parserConfig && parserConfig.tags, configScript = parserConfig && parserConfig.scriptTypes;
11972 addTags(defaultTags, tags);
11973 if (configTags) addTags(configTags, tags);
11974 if (configScript) for (var i = configScript.length - 1; i >= 0; i--)
11975 tags.script.unshift(["type", configScript[i].matches, configScript[i].mode])
11976
11977 function html(stream, state) {
11978 var style = htmlMode.token(stream, state.htmlState), tag = /\btag\b/.test(style), tagName
11979 if (tag && !/[<>\s\/]/.test(stream.current()) &&
11980 (tagName = state.htmlState.tagName && state.htmlState.tagName.toLowerCase()) &&
11981 tags.hasOwnProperty(tagName)) {
11982 state.inTag = tagName + " "
11983 } else if (state.inTag && tag && />$/.test(stream.current())) {
11984 var inTag = /^([\S]+) (.*)/.exec(state.inTag)
11985 state.inTag = null
11986 var modeSpec = stream.current() == ">" && findMatchingMode(tags[inTag[1]], inTag[2])
11987 var mode = CodeMirror.getMode(config, modeSpec)
11988 var endTagA = getTagRegexp(inTag[1], true), endTag = getTagRegexp(inTag[1], false);
11989 state.token = function (stream, state) {
11990 if (stream.match(endTagA, false)) {
11991 state.token = html;
11992 state.localState = state.localMode = null;
11993 return null;
11994 }
11995 return maybeBackup(stream, endTag, state.localMode.token(stream, state.localState));
11996 };
11997 state.localMode = mode;
11998 state.localState = CodeMirror.startState(mode, htmlMode.indent(state.htmlState, ""));
11999 } else if (state.inTag) {
12000 state.inTag += stream.current()
12001 if (stream.eol()) state.inTag += " "
12002 }
12003 return style;
12004 };
12005
12006 return {
12007 startState: function () {
12008 var state = CodeMirror.startState(htmlMode);
12009 return {token: html, inTag: null, localMode: null, localState: null, htmlState: state};
12010 },
12011
12012 copyState: function (state) {
12013 var local;
12014 if (state.localState) {
12015 local = CodeMirror.copyState(state.localMode, state.localState);
12016 }
12017 return {token: state.token, inTag: state.inTag,
12018 localMode: state.localMode, localState: local,
12019 htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
12020 },
12021
12022 token: function (stream, state) {
12023 return state.token(stream, state);
12024 },
12025
12026 indent: function (state, textAfter, line) {
12027 if (!state.localMode || /^\s*<\//.test(textAfter))
12028 return htmlMode.indent(state.htmlState, textAfter);
12029 else if (state.localMode.indent)
12030 return state.localMode.indent(state.localState, textAfter, line);
12031 else
12032 return CodeMirror.Pass;
12033 },
12034
12035 innerMode: function (state) {
12036 return {state: state.localState || state.htmlState, mode: state.localMode || htmlMode};
12037 }
12038 };
12039 }, "xml", "javascript", "css");
12040
12041 CodeMirror.defineMIME("text/html", "htmlmixed");
12042 });
12043
12044 },{"../../lib/codemirror":12,"../css/css":13,"../javascript/javascript":15,"../xml/xml":16}],15:[function(require,module,exports){
12045 // CodeMirror, copyright (c) by Marijn Haverbeke and others
12046 // Distributed under an MIT license: http://codemirror.net/LICENSE
12047
12048 (function(mod) {
12049 if (typeof exports == "object" && typeof module == "object") // CommonJS
12050 mod(require("../../lib/codemirror"));
12051 else if (typeof define == "function" && define.amd) // AMD
12052 define(["../../lib/codemirror"], mod);
12053 else // Plain browser env
12054 mod(CodeMirror);
12055 })(function(CodeMirror) {
12056 "use strict";
12057
12058 CodeMirror.defineMode("javascript", function(config, parserConfig) {
12059 var indentUnit = config.indentUnit;
12060 var statementIndent = parserConfig.statementIndent;
12061 var jsonldMode = parserConfig.jsonld;
12062 var jsonMode = parserConfig.json || jsonldMode;
12063 var isTS = parserConfig.typescript;
12064 var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
12065
12066 // Tokenizer
12067
12068 var keywords = function(){
12069 function kw(type) {return {type: type, style: "keyword"};}
12070 var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c"), D = kw("keyword d");
12071 var operator = kw("operator"), atom = {type: "atom", style: "atom"};
12072
12073 var jsKeywords = {
12074 "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
12075 "return": D, "break": D, "continue": D, "new": kw("new"), "delete": C, "void": C, "throw": C,
12076 "debugger": kw("debugger"), "var": kw("var"), "const": kw("var"), "let": kw("var"),
12077 "function": kw("function"), "catch": kw("catch"),
12078 "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
12079 "in": operator, "typeof": operator, "instanceof": operator,
12080 "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
12081 "this": kw("this"), "class": kw("class"), "super": kw("atom"),
12082 "yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
12083 "await": C
12084 };
12085
12086 // Extend the 'normal' keywords with the TypeScript language extensions
12087 if (isTS) {
12088 var type = {type: "variable", style: "type"};
12089 var tsKeywords = {
12090 // object-like things
12091 "interface": kw("class"),
12092 "implements": C,
12093 "namespace": C,
12094 "module": kw("module"),
12095 "enum": kw("module"),
12096
12097 // scope modifiers
12098 "public": kw("modifier"),
12099 "private": kw("modifier"),
12100 "protected": kw("modifier"),
12101 "abstract": kw("modifier"),
12102 "readonly": kw("modifier"),
12103
12104 // types
12105 "string": type, "number": type, "boolean": type, "any": type
12106 };
12107
12108 for (var attr in tsKeywords) {
12109 jsKeywords[attr] = tsKeywords[attr];
12110 }
12111 }
12112
12113 return jsKeywords;
12114 }();
12115
12116 var isOperatorChar = /[+\-*&%=<>!?|~^@]/;
12117 var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
12118
12119 function readRegexp(stream) {
12120 var escaped = false, next, inSet = false;
12121 while ((next = stream.next()) != null) {
12122 if (!escaped) {
12123 if (next == "/" && !inSet) return;
12124 if (next == "[") inSet = true;
12125 else if (inSet && next == "]") inSet = false;
12126 }
12127 escaped = !escaped && next == "\\";
12128 }
12129 }
12130
12131 // Used as scratch variables to communicate multiple values without
12132 // consing up tons of objects.
12133 var type, content;
12134 function ret(tp, style, cont) {
12135 type = tp; content = cont;
12136 return style;
12137 }
12138 function tokenBase(stream, state) {
12139 var ch = stream.next();
12140 if (ch == '"' || ch == "'") {
12141 state.tokenize = tokenString(ch);
12142 return state.tokenize(stream, state);
12143 } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
12144 return ret("number", "number");
12145 } else if (ch == "." && stream.match("..")) {
12146 return ret("spread", "meta");
12147 } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
12148 return ret(ch);
12149 } else if (ch == "=" && stream.eat(">")) {
12150 return ret("=>", "operator");
12151 } else if (ch == "0" && stream.eat(/x/i)) {
12152 stream.eatWhile(/[\da-f]/i);
12153 return ret("number", "number");
12154 } else if (ch == "0" && stream.eat(/o/i)) {
12155 stream.eatWhile(/[0-7]/i);
12156 return ret("number", "number");
12157 } else if (ch == "0" && stream.eat(/b/i)) {
12158 stream.eatWhile(/[01]/i);
12159 return ret("number", "number");
12160 } else if (/\d/.test(ch)) {
12161 stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
12162 return ret("number", "number");
12163 } else if (ch == "/") {
12164 if (stream.eat("*")) {
12165 state.tokenize = tokenComment;
12166 return tokenComment(stream, state);
12167 } else if (stream.eat("/")) {
12168 stream.skipToEnd();
12169 return ret("comment", "comment");
12170 } else if (expressionAllowed(stream, state, 1)) {
12171 readRegexp(stream);
12172 stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
12173 return ret("regexp", "string-2");
12174 } else {
12175 stream.eat("=");
12176 return ret("operator", "operator", stream.current());
12177 }
12178 } else if (ch == "`") {
12179 state.tokenize = tokenQuasi;
12180 return tokenQuasi(stream, state);
12181 } else if (ch == "#") {
12182 stream.skipToEnd();
12183 return ret("error", "error");
12184 } else if (isOperatorChar.test(ch)) {
12185 if (ch != ">" || !state.lexical || state.lexical.type != ">") {
12186 if (stream.eat("=")) {
12187 if (ch == "!" || ch == "=") stream.eat("=")
12188 } else if (/[<>*+\-]/.test(ch)) {
12189 stream.eat(ch)
12190 if (ch == ">") stream.eat(ch)
12191 }
12192 }
12193 return ret("operator", "operator", stream.current());
12194 } else if (wordRE.test(ch)) {
12195 stream.eatWhile(wordRE);
12196 var word = stream.current()
12197 if (state.lastType != ".") {
12198 if (keywords.propertyIsEnumerable(word)) {
12199 var kw = keywords[word]
12200 return ret(kw.type, kw.style, word)
12201 }
12202 if (word == "async" && stream.match(/^\s*[\(\w]/, false))
12203 return ret("async", "keyword", word)
12204 }
12205 return ret("variable", "variable", word)
12206 }
12207 }
12208
12209 function tokenString(quote) {
12210 return function(stream, state) {
12211 var escaped = false, next;
12212 if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
12213 state.tokenize = tokenBase;
12214 return ret("jsonld-keyword", "meta");
12215 }
12216 while ((next = stream.next()) != null) {
12217 if (next == quote && !escaped) break;
12218 escaped = !escaped && next == "\\";
12219 }
12220 if (!escaped) state.tokenize = tokenBase;
12221 return ret("string", "string");
12222 };
12223 }
12224
12225 function tokenComment(stream, state) {
12226 var maybeEnd = false, ch;
12227 while (ch = stream.next()) {
12228 if (ch == "/" && maybeEnd) {
12229 state.tokenize = tokenBase;
12230 break;
12231 }
12232 maybeEnd = (ch == "*");
12233 }
12234 return ret("comment", "comment");
12235 }
12236
12237 function tokenQuasi(stream, state) {
12238 var escaped = false, next;
12239 while ((next = stream.next()) != null) {
12240 if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
12241 state.tokenize = tokenBase;
12242 break;
12243 }
12244 escaped = !escaped && next == "\\";
12245 }
12246 return ret("quasi", "string-2", stream.current());
12247 }
12248
12249 var brackets = "([{}])";
12250 // This is a crude lookahead trick to try and notice that we're
12251 // parsing the argument patterns for a fat-arrow function before we
12252 // actually hit the arrow token. It only works if the arrow is on
12253 // the same line as the arguments and there's no strange noise
12254 // (comments) in between. Fallback is to only notice when we hit the
12255 // arrow, and not declare the arguments as locals for the arrow
12256 // body.
12257 function findFatArrow(stream, state) {
12258 if (state.fatArrowAt) state.fatArrowAt = null;
12259 var arrow = stream.string.indexOf("=>", stream.start);
12260 if (arrow < 0) return;
12261
12262 if (isTS) { // Try to skip TypeScript return type declarations after the arguments
12263 var m = /:\s*(?:\w+(?:<[^>]*>|\[\])?|\{[^}]*\})\s*$/.exec(stream.string.slice(stream.start, arrow))
12264 if (m) arrow = m.index
12265 }
12266
12267 var depth = 0, sawSomething = false;
12268 for (var pos = arrow - 1; pos >= 0; --pos) {
12269 var ch = stream.string.charAt(pos);
12270 var bracket = brackets.indexOf(ch);
12271 if (bracket >= 0 && bracket < 3) {
12272 if (!depth) { ++pos; break; }
12273 if (--depth == 0) { if (ch == "(") sawSomething = true; break; }
12274 } else if (bracket >= 3 && bracket < 6) {
12275 ++depth;
12276 } else if (wordRE.test(ch)) {
12277 sawSomething = true;
12278 } else if (/["'\/]/.test(ch)) {
12279 return;
12280 } else if (sawSomething && !depth) {
12281 ++pos;
12282 break;
12283 }
12284 }
12285 if (sawSomething && !depth) state.fatArrowAt = pos;
12286 }
12287
12288 // Parser
12289
12290 var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
12291
12292 function JSLexical(indented, column, type, align, prev, info) {
12293 this.indented = indented;
12294 this.column = column;
12295 this.type = type;
12296 this.prev = prev;
12297 this.info = info;
12298 if (align != null) this.align = align;
12299 }
12300
12301 function inScope(state, varname) {
12302 for (var v = state.localVars; v; v = v.next)
12303 if (v.name == varname) return true;
12304 for (var cx = state.context; cx; cx = cx.prev) {
12305 for (var v = cx.vars; v; v = v.next)
12306 if (v.name == varname) return true;
12307 }
12308 }
12309
12310 function parseJS(state, style, type, content, stream) {
12311 var cc = state.cc;
12312 // Communicate our context to the combinators.
12313 // (Less wasteful than consing up a hundred closures on every call.)
12314 cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
12315
12316 if (!state.lexical.hasOwnProperty("align"))
12317 state.lexical.align = true;
12318
12319 while(true) {
12320 var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
12321 if (combinator(type, content)) {
12322 while(cc.length && cc[cc.length - 1].lex)
12323 cc.pop()();
12324 if (cx.marked) return cx.marked;
12325 if (type == "variable" && inScope(state, content)) return "variable-2";
12326 return style;
12327 }
12328 }
12329 }
12330
12331 // Combinator utils
12332
12333 var cx = {state: null, column: null, marked: null, cc: null};
12334 function pass() {
12335 for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
12336 }
12337 function cont() {
12338 pass.apply(null, arguments);
12339 return true;
12340 }
12341 function register(varname) {
12342 function inList(list) {
12343 for (var v = list; v; v = v.next)
12344 if (v.name == varname) return true;
12345 return false;
12346 }
12347 var state = cx.state;
12348 cx.marked = "def";
12349 if (state.context) {
12350 if (inList(state.localVars)) return;
12351 state.localVars = {name: varname, next: state.localVars};
12352 } else {
12353 if (inList(state.globalVars)) return;
12354 if (parserConfig.globalVars)
12355 state.globalVars = {name: varname, next: state.globalVars};
12356 }
12357 }
12358
12359 // Combinators
12360
12361 var defaultVars = {name: "this", next: {name: "arguments"}};
12362 function pushcontext() {
12363 cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
12364 cx.state.localVars = defaultVars;
12365 }
12366 function popcontext() {
12367 cx.state.localVars = cx.state.context.vars;
12368 cx.state.context = cx.state.context.prev;
12369 }
12370 function pushlex(type, info) {
12371 var result = function() {
12372 var state = cx.state, indent = state.indented;
12373 if (state.lexical.type == "stat") indent = state.lexical.indented;
12374 else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
12375 indent = outer.indented;
12376 state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
12377 };
12378 result.lex = true;
12379 return result;
12380 }
12381 function poplex() {
12382 var state = cx.state;
12383 if (state.lexical.prev) {
12384 if (state.lexical.type == ")")
12385 state.indented = state.lexical.indented;
12386 state.lexical = state.lexical.prev;
12387 }
12388 }
12389 poplex.lex = true;
12390
12391 function expect(wanted) {
12392 function exp(type) {
12393 if (type == wanted) return cont();
12394 else if (wanted == ";") return pass();
12395 else return cont(exp);
12396 };
12397 return exp;
12398 }
12399
12400 function statement(type, value) {
12401 if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
12402 if (type == "keyword a") return cont(pushlex("form"), parenExpr, statement, poplex);
12403 if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
12404 if (type == "keyword d") return cx.stream.match(/^\s*$/, false) ? cont() : cont(pushlex("stat"), maybeexpression, expect(";"), poplex);
12405 if (type == "debugger") return cont(expect(";"));
12406 if (type == "{") return cont(pushlex("}"), block, poplex);
12407 if (type == ";") return cont();
12408 if (type == "if") {
12409 if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
12410 cx.state.cc.pop()();
12411 return cont(pushlex("form"), parenExpr, statement, poplex, maybeelse);
12412 }
12413 if (type == "function") return cont(functiondef);
12414 if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
12415 if (type == "variable") {
12416 if (isTS && value == "type") {
12417 cx.marked = "keyword"
12418 return cont(typeexpr, expect("operator"), typeexpr, expect(";"));
12419 } if (isTS && value == "declare") {
12420 cx.marked = "keyword"
12421 return cont(statement)
12422 } else {
12423 return cont(pushlex("stat"), maybelabel);
12424 }
12425 }
12426 if (type == "switch") return cont(pushlex("form"), parenExpr, expect("{"), pushlex("}", "switch"),
12427 block, poplex, poplex);
12428 if (type == "case") return cont(expression, expect(":"));
12429 if (type == "default") return cont(expect(":"));
12430 if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
12431 statement, poplex, popcontext);
12432 if (type == "class") return cont(pushlex("form"), className, poplex);
12433 if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
12434 if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
12435 if (type == "module") return cont(pushlex("form"), pattern, expect("{"), pushlex("}"), block, poplex, poplex)
12436 if (type == "async") return cont(statement)
12437 if (value == "@") return cont(expression, statement)
12438 return pass(pushlex("stat"), expression, expect(";"), poplex);
12439 }
12440 function expression(type) {
12441 return expressionInner(type, false);
12442 }
12443 function expressionNoComma(type) {
12444 return expressionInner(type, true);
12445 }
12446 function parenExpr(type) {
12447 if (type != "(") return pass()
12448 return cont(pushlex(")"), expression, expect(")"), poplex)
12449 }
12450 function expressionInner(type, noComma) {
12451 if (cx.state.fatArrowAt == cx.stream.start) {
12452 var body = noComma ? arrowBodyNoComma : arrowBody;
12453 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, expect("=>"), body, popcontext);
12454 else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
12455 }
12456
12457 var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
12458 if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
12459 if (type == "function") return cont(functiondef, maybeop);
12460 if (type == "class") return cont(pushlex("form"), classExpression, poplex);
12461 if (type == "keyword c" || type == "async") return cont(noComma ? expressionNoComma : expression);
12462 if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeop);
12463 if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
12464 if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
12465 if (type == "{") return contCommasep(objprop, "}", null, maybeop);
12466 if (type == "quasi") return pass(quasi, maybeop);
12467 if (type == "new") return cont(maybeTarget(noComma));
12468 return cont();
12469 }
12470 function maybeexpression(type) {
12471 if (type.match(/[;\}\)\],]/)) return pass();
12472 return pass(expression);
12473 }
12474
12475 function maybeoperatorComma(type, value) {
12476 if (type == ",") return cont(expression);
12477 return maybeoperatorNoComma(type, value, false);
12478 }
12479 function maybeoperatorNoComma(type, value, noComma) {
12480 var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
12481 var expr = noComma == false ? expression : expressionNoComma;
12482 if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
12483 if (type == "operator") {
12484 if (/\+\+|--/.test(value) || isTS && value == "!") return cont(me);
12485 if (value == "?") return cont(expression, expect(":"), expr);
12486 return cont(expr);
12487 }
12488 if (type == "quasi") { return pass(quasi, me); }
12489 if (type == ";") return;
12490 if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
12491 if (type == ".") return cont(property, me);
12492 if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
12493 if (isTS && value == "as") { cx.marked = "keyword"; return cont(typeexpr, me) }
12494 if (type == "regexp") {
12495 cx.state.lastType = cx.marked = "operator"
12496 cx.stream.backUp(cx.stream.pos - cx.stream.start - 1)
12497 return cont(expr)
12498 }
12499 }
12500 function quasi(type, value) {
12501 if (type != "quasi") return pass();
12502 if (value.slice(value.length - 2) != "${") return cont(quasi);
12503 return cont(expression, continueQuasi);
12504 }
12505 function continueQuasi(type) {
12506 if (type == "}") {
12507 cx.marked = "string-2";
12508 cx.state.tokenize = tokenQuasi;
12509 return cont(quasi);
12510 }
12511 }
12512 function arrowBody(type) {
12513 findFatArrow(cx.stream, cx.state);
12514 return pass(type == "{" ? statement : expression);
12515 }
12516 function arrowBodyNoComma(type) {
12517 findFatArrow(cx.stream, cx.state);
12518 return pass(type == "{" ? statement : expressionNoComma);
12519 }
12520 function maybeTarget(noComma) {
12521 return function(type) {
12522 if (type == ".") return cont(noComma ? targetNoComma : target);
12523 else if (type == "variable" && isTS) return cont(maybeTypeArgs, noComma ? maybeoperatorNoComma : maybeoperatorComma)
12524 else return pass(noComma ? expressionNoComma : expression);
12525 };
12526 }
12527 function target(_, value) {
12528 if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
12529 }
12530 function targetNoComma(_, value) {
12531 if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
12532 }
12533 function maybelabel(type) {
12534 if (type == ":") return cont(poplex, statement);
12535 return pass(maybeoperatorComma, expect(";"), poplex);
12536 }
12537 function property(type) {
12538 if (type == "variable") {cx.marked = "property"; return cont();}
12539 }
12540 function objprop(type, value) {
12541 if (type == "async") {
12542 cx.marked = "property";
12543 return cont(objprop);
12544 } else if (type == "variable" || cx.style == "keyword") {
12545 cx.marked = "property";
12546 if (value == "get" || value == "set") return cont(getterSetter);
12547 var m // Work around fat-arrow-detection complication for detecting typescript typed arrow params
12548 if (isTS && cx.state.fatArrowAt == cx.stream.start && (m = cx.stream.match(/^\s*:\s*/, false)))
12549 cx.state.fatArrowAt = cx.stream.pos + m[0].length
12550 return cont(afterprop);
12551 } else if (type == "number" || type == "string") {
12552 cx.marked = jsonldMode ? "property" : (cx.style + " property");
12553 return cont(afterprop);
12554 } else if (type == "jsonld-keyword") {
12555 return cont(afterprop);
12556 } else if (type == "modifier") {
12557 return cont(objprop)
12558 } else if (type == "[") {
12559 return cont(expression, expect("]"), afterprop);
12560 } else if (type == "spread") {
12561 return cont(expressionNoComma, afterprop);
12562 } else if (value == "*") {
12563 cx.marked = "keyword";
12564 return cont(objprop);
12565 } else if (type == ":") {
12566 return pass(afterprop)
12567 }
12568 }
12569 function getterSetter(type) {
12570 if (type != "variable") return pass(afterprop);
12571 cx.marked = "property";
12572 return cont(functiondef);
12573 }
12574 function afterprop(type) {
12575 if (type == ":") return cont(expressionNoComma);
12576 if (type == "(") return pass(functiondef);
12577 }
12578 function commasep(what, end, sep) {
12579 function proceed(type, value) {
12580 if (sep ? sep.indexOf(type) > -1 : type == ",") {
12581 var lex = cx.state.lexical;
12582 if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
12583 return cont(function(type, value) {
12584 if (type == end || value == end) return pass()
12585 return pass(what)
12586 }, proceed);
12587 }
12588 if (type == end || value == end) return cont();
12589 return cont(expect(end));
12590 }
12591 return function(type, value) {
12592 if (type == end || value == end) return cont();
12593 return pass(what, proceed);
12594 };
12595 }
12596 function contCommasep(what, end, info) {
12597 for (var i = 3; i < arguments.length; i++)
12598 cx.cc.push(arguments[i]);
12599 return cont(pushlex(end, info), commasep(what, end), poplex);
12600 }
12601 function block(type) {
12602 if (type == "}") return cont();
12603 return pass(statement, block);
12604 }
12605 function maybetype(type, value) {
12606 if (isTS) {
12607 if (type == ":") return cont(typeexpr);
12608 if (value == "?") return cont(maybetype);
12609 }
12610 }
12611 function typeexpr(type, value) {
12612 if (type == "variable" || value == "void") {
12613 if (value == "keyof") {
12614 cx.marked = "keyword"
12615 return cont(typeexpr)
12616 } else {
12617 cx.marked = "type"
12618 return cont(afterType)
12619 }
12620 }
12621 if (type == "string" || type == "number" || type == "atom") return cont(afterType);
12622 if (type == "[") return cont(pushlex("]"), commasep(typeexpr, "]", ","), poplex, afterType)
12623 if (type == "{") return cont(pushlex("}"), commasep(typeprop, "}", ",;"), poplex, afterType)
12624 if (type == "(") return cont(commasep(typearg, ")"), maybeReturnType)
12625 }
12626 function maybeReturnType(type) {
12627 if (type == "=>") return cont(typeexpr)
12628 }
12629 function typeprop(type, value) {
12630 if (type == "variable" || cx.style == "keyword") {
12631 cx.marked = "property"
12632 return cont(typeprop)
12633 } else if (value == "?") {
12634 return cont(typeprop)
12635 } else if (type == ":") {
12636 return cont(typeexpr)
12637 } else if (type == "[") {
12638 return cont(expression, maybetype, expect("]"), typeprop)
12639 }
12640 }
12641 function typearg(type) {
12642 if (type == "variable") return cont(typearg)
12643 else if (type == ":") return cont(typeexpr)
12644 }
12645 function afterType(type, value) {
12646 if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
12647 if (value == "|" || type == ".") return cont(typeexpr)
12648 if (type == "[") return cont(expect("]"), afterType)
12649 if (value == "extends") return cont(typeexpr)
12650 }
12651 function maybeTypeArgs(_, value) {
12652 if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, afterType)
12653 }
12654 function vardef() {
12655 return pass(pattern, maybetype, maybeAssign, vardefCont);
12656 }
12657 function pattern(type, value) {
12658 if (type == "modifier") return cont(pattern)
12659 if (type == "variable") { register(value); return cont(); }
12660 if (type == "spread") return cont(pattern);
12661 if (type == "[") return contCommasep(pattern, "]");
12662 if (type == "{") return contCommasep(proppattern, "}");
12663 }
12664 function proppattern(type, value) {
12665 if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
12666 register(value);
12667 return cont(maybeAssign);
12668 }
12669 if (type == "variable") cx.marked = "property";
12670 if (type == "spread") return cont(pattern);
12671 if (type == "}") return pass();
12672 return cont(expect(":"), pattern, maybeAssign);
12673 }
12674 function maybeAssign(_type, value) {
12675 if (value == "=") return cont(expressionNoComma);
12676 }
12677 function vardefCont(type) {
12678 if (type == ",") return cont(vardef);
12679 }
12680 function maybeelse(type, value) {
12681 if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
12682 }
12683 function forspec(type) {
12684 if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
12685 }
12686 function forspec1(type) {
12687 if (type == "var") return cont(vardef, expect(";"), forspec2);
12688 if (type == ";") return cont(forspec2);
12689 if (type == "variable") return cont(formaybeinof);
12690 return pass(expression, expect(";"), forspec2);
12691 }
12692 function formaybeinof(_type, value) {
12693 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
12694 return cont(maybeoperatorComma, forspec2);
12695 }
12696 function forspec2(type, value) {
12697 if (type == ";") return cont(forspec3);
12698 if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
12699 return pass(expression, expect(";"), forspec3);
12700 }
12701 function forspec3(type) {
12702 if (type != ")") cont(expression);
12703 }
12704 function functiondef(type, value) {
12705 if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
12706 if (type == "variable") {register(value); return cont(functiondef);}
12707 if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
12708 if (isTS && value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, functiondef)
12709 }
12710 function funarg(type, value) {
12711 if (value == "@") cont(expression, funarg)
12712 if (type == "spread" || type == "modifier") return cont(funarg);
12713 return pass(pattern, maybetype, maybeAssign);
12714 }
12715 function classExpression(type, value) {
12716 // Class expressions may have an optional name.
12717 if (type == "variable") return className(type, value);
12718 return classNameAfter(type, value);
12719 }
12720 function className(type, value) {
12721 if (type == "variable") {register(value); return cont(classNameAfter);}
12722 }
12723 function classNameAfter(type, value) {
12724 if (value == "<") return cont(pushlex(">"), commasep(typeexpr, ">"), poplex, classNameAfter)
12725 if (value == "extends" || value == "implements" || (isTS && type == ","))
12726 return cont(isTS ? typeexpr : expression, classNameAfter);
12727 if (type == "{") return cont(pushlex("}"), classBody, poplex);
12728 }
12729 function classBody(type, value) {
12730 if (type == "modifier" || type == "async" ||
12731 (type == "variable" &&
12732 (value == "static" || value == "get" || value == "set") &&
12733 cx.stream.match(/^\s+[\w$\xa1-\uffff]/, false))) {
12734 cx.marked = "keyword";
12735 return cont(classBody);
12736 }
12737 if (type == "variable" || cx.style == "keyword") {
12738 cx.marked = "property";
12739 return cont(isTS ? classfield : functiondef, classBody);
12740 }
12741 if (type == "[")
12742 return cont(expression, expect("]"), isTS ? classfield : functiondef, classBody)
12743 if (value == "*") {
12744 cx.marked = "keyword";
12745 return cont(classBody);
12746 }
12747 if (type == ";") return cont(classBody);
12748 if (type == "}") return cont();
12749 if (value == "@") return cont(expression, classBody)
12750 }
12751 function classfield(type, value) {
12752 if (value == "?") return cont(classfield)
12753 if (type == ":") return cont(typeexpr, maybeAssign)
12754 if (value == "=") return cont(expressionNoComma)
12755 return pass(functiondef)
12756 }
12757 function afterExport(type, value) {
12758 if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
12759 if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
12760 if (type == "{") return cont(commasep(exportField, "}"), maybeFrom, expect(";"));
12761 return pass(statement);
12762 }
12763 function exportField(type, value) {
12764 if (value == "as") { cx.marked = "keyword"; return cont(expect("variable")); }
12765 if (type == "variable") return pass(expressionNoComma, exportField);
12766 }
12767 function afterImport(type) {
12768 if (type == "string") return cont();
12769 return pass(importSpec, maybeMoreImports, maybeFrom);
12770 }
12771 function importSpec(type, value) {
12772 if (type == "{") return contCommasep(importSpec, "}");
12773 if (type == "variable") register(value);
12774 if (value == "*") cx.marked = "keyword";
12775 return cont(maybeAs);
12776 }
12777 function maybeMoreImports(type) {
12778 if (type == ",") return cont(importSpec, maybeMoreImports)
12779 }
12780 function maybeAs(_type, value) {
12781 if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
12782 }
12783 function maybeFrom(_type, value) {
12784 if (value == "from") { cx.marked = "keyword"; return cont(expression); }
12785 }
12786 function arrayLiteral(type) {
12787 if (type == "]") return cont();
12788 return pass(commasep(expressionNoComma, "]"));
12789 }
12790
12791 function isContinuedStatement(state, textAfter) {
12792 return state.lastType == "operator" || state.lastType == "," ||
12793 isOperatorChar.test(textAfter.charAt(0)) ||
12794 /[,.]/.test(textAfter.charAt(0));
12795 }
12796
12797 function expressionAllowed(stream, state, backUp) {
12798 return state.tokenize == tokenBase &&
12799 /^(?:operator|sof|keyword [bcd]|case|new|export|default|spread|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
12800 (state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
12801 }
12802
12803 // Interface
12804
12805 return {
12806 startState: function(basecolumn) {
12807 var state = {
12808 tokenize: tokenBase,
12809 lastType: "sof",
12810 cc: [],
12811 lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
12812 localVars: parserConfig.localVars,
12813 context: parserConfig.localVars && {vars: parserConfig.localVars},
12814 indented: basecolumn || 0
12815 };
12816 if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
12817 state.globalVars = parserConfig.globalVars;
12818 return state;
12819 },
12820
12821 token: function(stream, state) {
12822 if (stream.sol()) {
12823 if (!state.lexical.hasOwnProperty("align"))
12824 state.lexical.align = false;
12825 state.indented = stream.indentation();
12826 findFatArrow(stream, state);
12827 }
12828 if (state.tokenize != tokenComment && stream.eatSpace()) return null;
12829 var style = state.tokenize(stream, state);
12830 if (type == "comment") return style;
12831 state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
12832 return parseJS(state, style, type, content, stream);
12833 },
12834
12835 indent: function(state, textAfter) {
12836 if (state.tokenize == tokenComment) return CodeMirror.Pass;
12837 if (state.tokenize != tokenBase) return 0;
12838 var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical, top
12839 // Kludge to prevent 'maybelse' from blocking lexical scope pops
12840 if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
12841 var c = state.cc[i];
12842 if (c == poplex) lexical = lexical.prev;
12843 else if (c != maybeelse) break;
12844 }
12845 while ((lexical.type == "stat" || lexical.type == "form") &&
12846 (firstChar == "}" || ((top = state.cc[state.cc.length - 1]) &&
12847 (top == maybeoperatorComma || top == maybeoperatorNoComma) &&
12848 !/^[,\.=+\-*:?[\(]/.test(textAfter))))
12849 lexical = lexical.prev;
12850 if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
12851 lexical = lexical.prev;
12852 var type = lexical.type, closing = firstChar == type;
12853
12854 if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
12855 else if (type == "form" && firstChar == "{") return lexical.indented;
12856 else if (type == "form") return lexical.indented + indentUnit;
12857 else if (type == "stat")
12858 return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
12859 else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
12860 return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
12861 else if (lexical.align) return lexical.column + (closing ? 0 : 1);
12862 else return lexical.indented + (closing ? 0 : indentUnit);
12863 },
12864
12865 electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
12866 blockCommentStart: jsonMode ? null : "/*",
12867 blockCommentEnd: jsonMode ? null : "*/",
12868 blockCommentContinue: jsonMode ? null : " * ",
12869 lineComment: jsonMode ? null : "//",
12870 fold: "brace",
12871 closeBrackets: "()[]{}''\"\"``",
12872
12873 helperType: jsonMode ? "json" : "javascript",
12874 jsonldMode: jsonldMode,
12875 jsonMode: jsonMode,
12876
12877 expressionAllowed: expressionAllowed,
12878
12879 skipExpression: function(state) {
12880 var top = state.cc[state.cc.length - 1]
12881 if (top == expression || top == expressionNoComma) state.cc.pop()
12882 }
12883 };
12884 });
12885
12886 CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
12887
12888 CodeMirror.defineMIME("text/javascript", "javascript");
12889 CodeMirror.defineMIME("text/ecmascript", "javascript");
12890 CodeMirror.defineMIME("application/javascript", "javascript");
12891 CodeMirror.defineMIME("application/x-javascript", "javascript");
12892 CodeMirror.defineMIME("application/ecmascript", "javascript");
12893 CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
12894 CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
12895 CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
12896 CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
12897 CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
12898
12899 });
12900
12901 },{"../../lib/codemirror":12}],16:[function(require,module,exports){
12902 // CodeMirror, copyright (c) by Marijn Haverbeke and others
12903 // Distributed under an MIT license: http://codemirror.net/LICENSE
12904
12905 (function(mod) {
12906 if (typeof exports == "object" && typeof module == "object") // CommonJS
12907 mod(require("../../lib/codemirror"));
12908 else if (typeof define == "function" && define.amd) // AMD
12909 define(["../../lib/codemirror"], mod);
12910 else // Plain browser env
12911 mod(CodeMirror);
12912 })(function(CodeMirror) {
12913 "use strict";
12914
12915 var htmlConfig = {
12916 autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
12917 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
12918 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
12919 'track': true, 'wbr': true, 'menuitem': true},
12920 implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
12921 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
12922 'th': true, 'tr': true},
12923 contextGrabbers: {
12924 'dd': {'dd': true, 'dt': true},
12925 'dt': {'dd': true, 'dt': true},
12926 'li': {'li': true},
12927 'option': {'option': true, 'optgroup': true},
12928 'optgroup': {'optgroup': true},
12929 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
12930 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
12931 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
12932 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
12933 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
12934 'rp': {'rp': true, 'rt': true},
12935 'rt': {'rp': true, 'rt': true},
12936 'tbody': {'tbody': true, 'tfoot': true},
12937 'td': {'td': true, 'th': true},
12938 'tfoot': {'tbody': true},
12939 'th': {'td': true, 'th': true},
12940 'thead': {'tbody': true, 'tfoot': true},
12941 'tr': {'tr': true}
12942 },
12943 doNotIndent: {"pre": true},
12944 allowUnquoted: true,
12945 allowMissing: true,
12946 caseFold: true
12947 }
12948
12949 var xmlConfig = {
12950 autoSelfClosers: {},
12951 implicitlyClosed: {},
12952 contextGrabbers: {},
12953 doNotIndent: {},
12954 allowUnquoted: false,
12955 allowMissing: false,
12956 caseFold: false
12957 }
12958
12959 CodeMirror.defineMode("xml", function(editorConf, config_) {
12960 var indentUnit = editorConf.indentUnit
12961 var config = {}
12962 var defaults = config_.htmlMode ? htmlConfig : xmlConfig
12963 for (var prop in defaults) config[prop] = defaults[prop]
12964 for (var prop in config_) config[prop] = config_[prop]
12965
12966 // Return variables for tokenizers
12967 var type, setStyle;
12968
12969 function inText(stream, state) {
12970 function chain(parser) {
12971 state.tokenize = parser;
12972 return parser(stream, state);
12973 }
12974
12975 var ch = stream.next();
12976 if (ch == "<") {
12977 if (stream.eat("!")) {
12978 if (stream.eat("[")) {
12979 if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
12980 else return null;
12981 } else if (stream.match("--")) {
12982 return chain(inBlock("comment", "-->"));
12983 } else if (stream.match("DOCTYPE", true, true)) {
12984 stream.eatWhile(/[\w\._\-]/);
12985 return chain(doctype(1));
12986 } else {
12987 return null;
12988 }
12989 } else if (stream.eat("?")) {
12990 stream.eatWhile(/[\w\._\-]/);
12991 state.tokenize = inBlock("meta", "?>");
12992 return "meta";
12993 } else {
12994 type = stream.eat("/") ? "closeTag" : "openTag";
12995 state.tokenize = inTag;
12996 return "tag bracket";
12997 }
12998 } else if (ch == "&") {
12999 var ok;
13000 if (stream.eat("#")) {
13001 if (stream.eat("x")) {
13002 ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
13003 } else {
13004 ok = stream.eatWhile(/[\d]/) && stream.eat(";");
13005 }
13006 } else {
13007 ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
13008 }
13009 return ok ? "atom" : "error";
13010 } else {
13011 stream.eatWhile(/[^&<]/);
13012 return null;
13013 }
13014 }
13015 inText.isInText = true;
13016
13017 function inTag(stream, state) {
13018 var ch = stream.next();
13019 if (ch == ">" || (ch == "/" && stream.eat(">"))) {
13020 state.tokenize = inText;
13021 type = ch == ">" ? "endTag" : "selfcloseTag";
13022 return "tag bracket";
13023 } else if (ch == "=") {
13024 type = "equals";
13025 return null;
13026 } else if (ch == "<") {
13027 state.tokenize = inText;
13028 state.state = baseState;
13029 state.tagName = state.tagStart = null;
13030 var next = state.tokenize(stream, state);
13031 return next ? next + " tag error" : "tag error";
13032 } else if (/[\'\"]/.test(ch)) {
13033 state.tokenize = inAttribute(ch);
13034 state.stringStartCol = stream.column();
13035 return state.tokenize(stream, state);
13036 } else {
13037 stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
13038 return "word";
13039 }
13040 }
13041
13042 function inAttribute(quote) {
13043 var closure = function(stream, state) {
13044 while (!stream.eol()) {
13045 if (stream.next() == quote) {
13046 state.tokenize = inTag;
13047 break;
13048 }
13049 }
13050 return "string";
13051 };
13052 closure.isInAttribute = true;
13053 return closure;
13054 }
13055
13056 function inBlock(style, terminator) {
13057 return function(stream, state) {
13058 while (!stream.eol()) {
13059 if (stream.match(terminator)) {
13060 state.tokenize = inText;
13061 break;
13062 }
13063 stream.next();
13064 }
13065 return style;
13066 };
13067 }
13068 function doctype(depth) {
13069 return function(stream, state) {
13070 var ch;
13071 while ((ch = stream.next()) != null) {
13072 if (ch == "<") {
13073 state.tokenize = doctype(depth + 1);
13074 return state.tokenize(stream, state);
13075 } else if (ch == ">") {
13076 if (depth == 1) {
13077 state.tokenize = inText;
13078 break;
13079 } else {
13080 state.tokenize = doctype(depth - 1);
13081 return state.tokenize(stream, state);
13082 }
13083 }
13084 }
13085 return "meta";
13086 };
13087 }
13088
13089 function Context(state, tagName, startOfLine) {
13090 this.prev = state.context;
13091 this.tagName = tagName;
13092 this.indent = state.indented;
13093 this.startOfLine = startOfLine;
13094 if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
13095 this.noIndent = true;
13096 }
13097 function popContext(state) {
13098 if (state.context) state.context = state.context.prev;
13099 }
13100 function maybePopContext(state, nextTagName) {
13101 var parentTagName;
13102 while (true) {
13103 if (!state.context) {
13104 return;
13105 }
13106 parentTagName = state.context.tagName;
13107 if (!config.contextGrabbers.hasOwnProperty(parentTagName) ||
13108 !config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
13109 return;
13110 }
13111 popContext(state);
13112 }
13113 }
13114
13115 function baseState(type, stream, state) {
13116 if (type == "openTag") {
13117 state.tagStart = stream.column();
13118 return tagNameState;
13119 } else if (type == "closeTag") {
13120 return closeTagNameState;
13121 } else {
13122 return baseState;
13123 }
13124 }
13125 function tagNameState(type, stream, state) {
13126 if (type == "word") {
13127 state.tagName = stream.current();
13128 setStyle = "tag";
13129 return attrState;
13130 } else {
13131 setStyle = "error";
13132 return tagNameState;
13133 }
13134 }
13135 function closeTagNameState(type, stream, state) {
13136 if (type == "word") {
13137 var tagName = stream.current();
13138 if (state.context && state.context.tagName != tagName &&
13139 config.implicitlyClosed.hasOwnProperty(state.context.tagName))
13140 popContext(state);
13141 if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {
13142 setStyle = "tag";
13143 return closeState;
13144 } else {
13145 setStyle = "tag error";
13146 return closeStateErr;
13147 }
13148 } else {
13149 setStyle = "error";
13150 return closeStateErr;
13151 }
13152 }
13153
13154 function closeState(type, _stream, state) {
13155 if (type != "endTag") {
13156 setStyle = "error";
13157 return closeState;
13158 }
13159 popContext(state);
13160 return baseState;
13161 }
13162 function closeStateErr(type, stream, state) {
13163 setStyle = "error";
13164 return closeState(type, stream, state);
13165 }
13166
13167 function attrState(type, _stream, state) {
13168 if (type == "word") {
13169 setStyle = "attribute";
13170 return attrEqState;
13171 } else if (type == "endTag" || type == "selfcloseTag") {
13172 var tagName = state.tagName, tagStart = state.tagStart;
13173 state.tagName = state.tagStart = null;
13174 if (type == "selfcloseTag" ||
13175 config.autoSelfClosers.hasOwnProperty(tagName)) {
13176 maybePopContext(state, tagName);
13177 } else {
13178 maybePopContext(state, tagName);
13179 state.context = new Context(state, tagName, tagStart == state.indented);
13180 }
13181 return baseState;
13182 }
13183 setStyle = "error";
13184 return attrState;
13185 }
13186 function attrEqState(type, stream, state) {
13187 if (type == "equals") return attrValueState;
13188 if (!config.allowMissing) setStyle = "error";
13189 return attrState(type, stream, state);
13190 }
13191 function attrValueState(type, stream, state) {
13192 if (type == "string") return attrContinuedState;
13193 if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;}
13194 setStyle = "error";
13195 return attrState(type, stream, state);
13196 }
13197 function attrContinuedState(type, stream, state) {
13198 if (type == "string") return attrContinuedState;
13199 return attrState(type, stream, state);
13200 }
13201
13202 return {
13203 startState: function(baseIndent) {
13204 var state = {tokenize: inText,
13205 state: baseState,
13206 indented: baseIndent || 0,
13207 tagName: null, tagStart: null,
13208 context: null}
13209 if (baseIndent != null) state.baseIndent = baseIndent
13210 return state
13211 },
13212
13213 token: function(stream, state) {
13214 if (!state.tagName && stream.sol())
13215 state.indented = stream.indentation();
13216
13217 if (stream.eatSpace()) return null;
13218 type = null;
13219 var style = state.tokenize(stream, state);
13220 if ((style || type) && style != "comment") {
13221 setStyle = null;
13222 state.state = state.state(type || style, stream, state);
13223 if (setStyle)
13224 style = setStyle == "error" ? style + " error" : setStyle;
13225 }
13226 return style;
13227 },
13228
13229 indent: function(state, textAfter, fullLine) {
13230 var context = state.context;
13231 // Indent multi-line strings (e.g. css).
13232 if (state.tokenize.isInAttribute) {
13233 if (state.tagStart == state.indented)
13234 return state.stringStartCol + 1;
13235 else
13236 return state.indented + indentUnit;
13237 }
13238 if (context && context.noIndent) return CodeMirror.Pass;
13239 if (state.tokenize != inTag && state.tokenize != inText)
13240 return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
13241 // Indent the starts of attribute names.
13242 if (state.tagName) {
13243 if (config.multilineTagIndentPastTag !== false)
13244 return state.tagStart + state.tagName.length + 2;
13245 else
13246 return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1);
13247 }
13248 if (config.alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
13249 var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
13250 if (tagAfter && tagAfter[1]) { // Closing tag spotted
13251 while (context) {
13252 if (context.tagName == tagAfter[2]) {
13253 context = context.prev;
13254 break;
13255 } else if (config.implicitlyClosed.hasOwnProperty(context.tagName)) {
13256 context = context.prev;
13257 } else {
13258 break;
13259 }
13260 }
13261 } else if (tagAfter) { // Opening tag spotted
13262 while (context) {
13263 var grabbers = config.contextGrabbers[context.tagName];
13264 if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
13265 context = context.prev;
13266 else
13267 break;
13268 }
13269 }
13270 while (context && context.prev && !context.startOfLine)
13271 context = context.prev;
13272 if (context) return context.indent + indentUnit;
13273 else return state.baseIndent || 0;
13274 },
13275
13276 electricInput: /<\/[\s\w:]+>$/,
13277 blockCommentStart: "<!--",
13278 blockCommentEnd: "-->",
13279
13280 configuration: config.htmlMode ? "html" : "xml",
13281 helperType: config.htmlMode ? "html" : "xml",
13282
13283 skipAttribute: function(state) {
13284 if (state.state == attrValueState)
13285 state.state = attrState
13286 }
13287 };
13288 });
13289
13290 CodeMirror.defineMIME("text/xml", "xml");
13291 CodeMirror.defineMIME("application/xml", "xml");
13292 if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
13293 CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
13294
13295 });
13296
13297 },{"../../lib/codemirror":12}],17:[function(require,module,exports){
13298 (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);};};}});
13299
13300
13301 },{}],18:[function(require,module,exports){
13302 /*
13303
13304 Style HTML
13305 ---------------
13306
13307 Written by Nochum Sossonko, (nsossonko@hotmail.com)
13308
13309 Based on code initially developed by: Einar Lielmanis, <elfz@laacz.lv>
13310 http://jsbeautifier.org/
13311
13312
13313 You are free to use this in any way you want, in case you find this useful or working for you.
13314
13315 Usage:
13316 style_html(html_source);
13317
13318 style_html(html_source, options);
13319
13320 The options are:
13321 indent_size (default 4) — indentation size,
13322 indent_char (default space) — character to indent with,
13323 max_char (default 70) - maximum amount of characters per line,
13324 brace_style (default "collapse") - "collapse" | "expand" | "end-expand"
13325 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.
13326 unformatted (defaults to inline tags) - list of tags, that shouldn't be reformatted
13327 indent_scripts (default normal) - "keep"|"separate"|"normal"
13328
13329 e.g.
13330
13331 style_html(html_source, {
13332 'indent_size': 2,
13333 'indent_char': ' ',
13334 'max_char': 78,
13335 'brace_style': 'expand',
13336 'unformatted': ['a', 'sub', 'sup', 'b', 'i', 'u']
13337 });
13338 */
13339
13340 function style_html(html_source, options) {
13341 //Wrapper function to invoke all the necessary constructors and deal with the output.
13342
13343 var multi_parser,
13344 indent_size,
13345 indent_character,
13346 max_char,
13347 brace_style,
13348 unformatted;
13349
13350 options = options || {};
13351 indent_size = options.indent_size || 4;
13352 indent_character = options.indent_char || ' ';
13353 brace_style = options.brace_style || 'collapse';
13354 max_char = options.max_char == 0 ? Infinity : options.max_char || 70;
13355 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'];
13356
13357 function Parser() {
13358
13359 this.pos = 0; //Parser position
13360 this.token = '';
13361 this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT
13362 this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values
13363 parent: 'parent1',
13364 parentcount: 1,
13365 parent1: ''
13366 };
13367 this.tag_type = '';
13368 this.token_text = this.last_token = this.last_text = this.token_type = '';
13369
13370 this.Utils = { //Uilities made available to the various functions
13371 whitespace: "\n\r\t ".split(''),
13372 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
13373 extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them
13374 in_array: function (what, arr) {
13375 for (var i=0; i<arr.length; i++) {
13376 if (what === arr[i]) {
13377 return true;
13378 }
13379 }
13380 return false;
13381 }
13382 }
13383
13384 this.get_content = function () { //function to capture regular content between tags
13385
13386 var input_char = '',
13387 content = [],
13388 space = false; //if a space is needed
13389
13390 while (this.input.charAt(this.pos) !== '<') {
13391 if (this.pos >= this.input.length) {
13392 return content.length?content.join(''):['', 'TK_EOF'];
13393 }
13394
13395 input_char = this.input.charAt(this.pos);
13396 this.pos++;
13397 this.line_char_count++;
13398
13399 if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
13400 if (content.length) {
13401 space = true;
13402 }
13403 this.line_char_count--;
13404 continue; //don't want to insert unnecessary space
13405 }
13406 else if (space) {
13407 if (this.line_char_count >= this.max_char) { //insert a line when the max_char is reached
13408 content.push('\n');
13409 for (var i=0; i<this.indent_level; i++) {
13410 content.push(this.indent_string);
13411 }
13412 this.line_char_count = 0;
13413 }
13414 else{
13415 content.push(' ');
13416 this.line_char_count++;
13417 }
13418 space = false;
13419 }
13420 content.push(input_char); //letter at-a-time (or string) inserted to an array
13421 }
13422 return content.length?content.join(''):'';
13423 }
13424
13425 this.get_contents_to = function (name) { //get the full content of a script or style to pass to js_beautify
13426 if (this.pos == this.input.length) {
13427 return ['', 'TK_EOF'];
13428 }
13429 var input_char = '';
13430 var content = '';
13431 var reg_match = new RegExp('\<\/' + name + '\\s*\>', 'igm');
13432 reg_match.lastIndex = this.pos;
13433 var reg_array = reg_match.exec(this.input);
13434 var end_script = reg_array?reg_array.index:this.input.length; //absolute end of script
13435 if(this.pos < end_script) { //get everything in between the script tags
13436 content = this.input.substring(this.pos, end_script);
13437 this.pos = end_script;
13438 }
13439 return content;
13440 }
13441
13442 this.record_tag = function (tag){ //function to record a tag and its parent in this.tags Object
13443 if (this.tags[tag + 'count']) { //check for the existence of this tag type
13444 this.tags[tag + 'count']++;
13445 this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
13446 }
13447 else { //otherwise initialize this tag type
13448 this.tags[tag + 'count'] = 1;
13449 this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level
13450 }
13451 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)
13452 this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1')
13453 }
13454
13455 this.retrieve_tag = function (tag) { //function to retrieve the opening tag to the corresponding closer
13456 if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it
13457 var temp_parent = this.tags.parent; //check to see if it's a closable tag.
13458 while (temp_parent) { //till we reach '' (the initial value);
13459 if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it
13460 break;
13461 }
13462 temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree
13463 }
13464 if (temp_parent) { //if we caught something
13465 this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly
13466 this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent
13467 }
13468 delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference...
13469 delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself
13470 if (this.tags[tag + 'count'] == 1) {
13471 delete this.tags[tag + 'count'];
13472 }
13473 else {
13474 this.tags[tag + 'count']--;
13475 }
13476 }
13477 }
13478
13479 this.get_tag = function () { //function to get a full tag and parse its type
13480 var input_char = '',
13481 content = [],
13482 space = false,
13483 tag_start, tag_end;
13484
13485 do {
13486 if (this.pos >= this.input.length) {
13487 return content.length?content.join(''):['', 'TK_EOF'];
13488 }
13489
13490 input_char = this.input.charAt(this.pos);
13491 this.pos++;
13492 this.line_char_count++;
13493
13494 if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space
13495 space = true;
13496 this.line_char_count--;
13497 continue;
13498 }
13499
13500 if (input_char === "'" || input_char === '"') {
13501 if (!content[1] || content[1] !== '!') { //if we're in a comment strings don't get treated specially
13502 input_char += this.get_unformatted(input_char);
13503 space = true;
13504 }
13505 }
13506
13507 if (input_char === '=') { //no space before =
13508 space = false;
13509 }
13510
13511 if (content.length && content[content.length-1] !== '=' && input_char !== '>'
13512 && space) { //no space after = or before >
13513 if (this.line_char_count >= this.max_char) {
13514 this.print_newline(false, content);
13515 this.line_char_count = 0;
13516 }
13517 else {
13518 content.push(' ');
13519 this.line_char_count++;
13520 }
13521 space = false;
13522 }
13523 if (input_char === '<') {
13524 tag_start = this.pos - 1;
13525 }
13526 content.push(input_char); //inserts character at-a-time (or string)
13527 } while (input_char !== '>');
13528
13529 var tag_complete = content.join('');
13530 var tag_index;
13531 if (tag_complete.indexOf(' ') != -1) { //if there's whitespace, thats where the tag name ends
13532 tag_index = tag_complete.indexOf(' ');
13533 }
13534 else { //otherwise go with the tag ending
13535 tag_index = tag_complete.indexOf('>');
13536 }
13537 var tag_check = tag_complete.substring(1, tag_index).toLowerCase();
13538 if (tag_complete.charAt(tag_complete.length-2) === '/' ||
13539 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 /)
13540 this.tag_type = 'SINGLE';
13541 }
13542 else if (tag_check === 'script') { //for later script handling
13543 this.record_tag(tag_check);
13544 this.tag_type = 'SCRIPT';
13545 }
13546 else if (tag_check === 'style') { //for future style handling (for now it justs uses get_content)
13547 this.record_tag(tag_check);
13548 this.tag_type = 'STYLE';
13549 }
13550 else if (this.Utils.in_array(tag_check, unformatted)) { // do not reformat the "unformatted" tags
13551 var comment = this.get_unformatted('</'+tag_check+'>', tag_complete); //...delegate to get_unformatted function
13552 content.push(comment);
13553 // Preserve collapsed whitespace either before or after this tag.
13554 if (tag_start > 0 && this.Utils.in_array(this.input.charAt(tag_start - 1), this.Utils.whitespace)){
13555 content.splice(0, 0, this.input.charAt(tag_start - 1));
13556 }
13557 tag_end = this.pos - 1;
13558 if (this.Utils.in_array(this.input.charAt(tag_end + 1), this.Utils.whitespace)){
13559 content.push(this.input.charAt(tag_end + 1));
13560 }
13561 this.tag_type = 'SINGLE';
13562 }
13563 else if (tag_check.charAt(0) === '!') { //peek for <!-- comment
13564 if (tag_check.indexOf('[if') != -1) { //peek for <!--[if conditional comment
13565 if (tag_complete.indexOf('!IE') != -1) { //this type needs a closing --> so...
13566 var comment = this.get_unformatted('-->', tag_complete); //...delegate to get_unformatted
13567 content.push(comment);
13568 }
13569 this.tag_type = 'START';
13570 }
13571 else if (tag_check.indexOf('[endif') != -1) {//peek for <!--[endif end conditional comment
13572 this.tag_type = 'END';
13573 this.unindent();
13574 }
13575 else if (tag_check.indexOf('[cdata[') != -1) { //if it's a <[cdata[ comment...
13576 var comment = this.get_unformatted(']]>', tag_complete); //...delegate to get_unformatted function
13577 content.push(comment);
13578 this.tag_type = 'SINGLE'; //<![CDATA[ comments are treated like single tags
13579 }
13580 else {
13581 var comment = this.get_unformatted('-->', tag_complete);
13582 content.push(comment);
13583 this.tag_type = 'SINGLE';
13584 }
13585 }
13586 else {
13587 if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending
13588 this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors
13589 this.tag_type = 'END';
13590 }
13591 else { //otherwise it's a start-tag
13592 this.record_tag(tag_check); //push it on the tag stack
13593 this.tag_type = 'START';
13594 }
13595 if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line
13596 this.print_newline(true, this.output);
13597 }
13598 }
13599 return content.join(''); //returns fully formatted tag
13600 }
13601
13602 this.get_unformatted = function (delimiter, orig_tag) { //function to return unformatted content in its entirety
13603
13604 if (orig_tag && orig_tag.toLowerCase().indexOf(delimiter) != -1) {
13605 return '';
13606 }
13607 var input_char = '';
13608 var content = '';
13609 var space = true;
13610 do {
13611
13612 if (this.pos >= this.input.length) {
13613 return content;
13614 }
13615
13616 input_char = this.input.charAt(this.pos);
13617 this.pos++
13618
13619 if (this.Utils.in_array(input_char, this.Utils.whitespace)) {
13620 if (!space) {
13621 this.line_char_count--;
13622 continue;
13623 }
13624 if (input_char === '\n' || input_char === '\r') {
13625 content += '\n';
13626 /* 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'
13627 for (var i=0; i<this.indent_level; i++) {
13628 content += this.indent_string;
13629 }
13630 space = false; //...and make sure other indentation is erased
13631 */
13632 this.line_char_count = 0;
13633 continue;
13634 }
13635 }
13636 content += input_char;
13637 this.line_char_count++;
13638 space = true;
13639
13640
13641 } while (content.toLowerCase().indexOf(delimiter) == -1);
13642 return content;
13643 }
13644
13645 this.get_token = function () { //initial handler for token-retrieval
13646 var token;
13647
13648 if (this.last_token === 'TK_TAG_SCRIPT' || this.last_token === 'TK_TAG_STYLE') { //check if we need to format javascript
13649 var type = this.last_token.substr(7)
13650 token = this.get_contents_to(type);
13651 if (typeof token !== 'string') {
13652 return token;
13653 }
13654 return [token, 'TK_' + type];
13655 }
13656 if (this.current_mode === 'CONTENT') {
13657 token = this.get_content();
13658 if (typeof token !== 'string') {
13659 return token;
13660 }
13661 else {
13662 return [token, 'TK_CONTENT'];
13663 }
13664 }
13665
13666 if (this.current_mode === 'TAG') {
13667 token = this.get_tag();
13668 if (typeof token !== 'string') {
13669 return token;
13670 }
13671 else {
13672 var tag_name_type = 'TK_TAG_' + this.tag_type;
13673 return [token, tag_name_type];
13674 }
13675 }
13676 }
13677
13678 this.get_full_indent = function (level) {
13679 level = this.indent_level + level || 0;
13680 if (level < 1)
13681 return '';
13682
13683 return Array(level + 1).join(this.indent_string);
13684 }
13685
13686
13687 this.printer = function (js_source, indent_character, indent_size, max_char, brace_style) { //handles input/output and some other printing functions
13688
13689 this.input = js_source || ''; //gets the input for the Parser
13690 this.output = [];
13691 this.indent_character = indent_character;
13692 this.indent_string = '';
13693 this.indent_size = indent_size;
13694 this.brace_style = brace_style;
13695 this.indent_level = 0;
13696 this.max_char = max_char;
13697 this.line_char_count = 0; //count to see if max_char was exceeded
13698
13699 for (var i=0; i<this.indent_size; i++) {
13700 this.indent_string += this.indent_character;
13701 }
13702
13703 this.print_newline = function (ignore, arr) {
13704 this.line_char_count = 0;
13705 if (!arr || !arr.length) {
13706 return;
13707 }
13708 if (!ignore) { //we might want the extra line
13709 while (this.Utils.in_array(arr[arr.length-1], this.Utils.whitespace)) {
13710 arr.pop();
13711 }
13712 }
13713 arr.push('\n');
13714 for (var i=0; i<this.indent_level; i++) {
13715 arr.push(this.indent_string);
13716 }
13717 }
13718
13719 this.print_token = function (text) {
13720 this.output.push(text);
13721 }
13722
13723 this.indent = function () {
13724 this.indent_level++;
13725 }
13726
13727 this.unindent = function () {
13728 if (this.indent_level > 0) {
13729 this.indent_level--;
13730 }
13731 }
13732 }
13733 return this;
13734 }
13735
13736 /*_____________________--------------------_____________________*/
13737
13738 multi_parser = new Parser(); //wrapping functions Parser
13739 multi_parser.printer(html_source, indent_character, indent_size, max_char, brace_style); //initialize starting values
13740
13741 while (true) {
13742 var t = multi_parser.get_token();
13743 multi_parser.token_text = t[0];
13744 multi_parser.token_type = t[1];
13745
13746 if (multi_parser.token_type === 'TK_EOF') {
13747 break;
13748 }
13749
13750 switch (multi_parser.token_type) {
13751 case 'TK_TAG_START':
13752 multi_parser.print_newline(false, multi_parser.output);
13753 multi_parser.print_token(multi_parser.token_text);
13754 multi_parser.indent();
13755 multi_parser.current_mode = 'CONTENT';
13756 break;
13757 case 'TK_TAG_STYLE':
13758 case 'TK_TAG_SCRIPT':
13759 multi_parser.print_newline(false, multi_parser.output);
13760 multi_parser.print_token(multi_parser.token_text);
13761 multi_parser.current_mode = 'CONTENT';
13762 break;
13763 case 'TK_TAG_END':
13764 //Print new line only if the tag has no content and has child
13765 if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') {
13766 var tag_name = multi_parser.token_text.match(/\w+/)[0];
13767 var tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length -1].match(/<\s*(\w+)/);
13768 if (tag_extracted_from_last_output === null || tag_extracted_from_last_output[1] !== tag_name)
13769 multi_parser.print_newline(true, multi_parser.output);
13770 }
13771 multi_parser.print_token(multi_parser.token_text);
13772 multi_parser.current_mode = 'CONTENT';
13773 break;
13774 case 'TK_TAG_SINGLE':
13775 // Don't add a newline before elements that should remain unformatted.
13776 var tag_check = multi_parser.token_text.match(/^\s*<([a-z]+)/i);
13777 if (!tag_check || !multi_parser.Utils.in_array(tag_check[1], unformatted)){
13778 multi_parser.print_newline(false, multi_parser.output);
13779 }
13780 multi_parser.print_token(multi_parser.token_text);
13781 multi_parser.current_mode = 'CONTENT';
13782 break;
13783 case 'TK_CONTENT':
13784 if (multi_parser.token_text !== '') {
13785 multi_parser.print_token(multi_parser.token_text);
13786 }
13787 multi_parser.current_mode = 'TAG';
13788 break;
13789 case 'TK_STYLE':
13790 case 'TK_SCRIPT':
13791 if (multi_parser.token_text !== '') {
13792 multi_parser.output.push('\n');
13793 var text = multi_parser.token_text;
13794 if (multi_parser.token_type == 'TK_SCRIPT') {
13795 var _beautifier = typeof js_beautify == 'function' && js_beautify;
13796 } else if (multi_parser.token_type == 'TK_STYLE') {
13797 var _beautifier = typeof css_beautify == 'function' && css_beautify;
13798 }
13799
13800 if (options.indent_scripts == "keep") {
13801 var script_indent_level = 0;
13802 } else if (options.indent_scripts == "separate") {
13803 var script_indent_level = -multi_parser.indent_level;
13804 } else {
13805 var script_indent_level = 1;
13806 }
13807
13808 var indentation = multi_parser.get_full_indent(script_indent_level);
13809 if (_beautifier) {
13810 // call the Beautifier if avaliable
13811 text = _beautifier(text.replace(/^\s*/, indentation), options);
13812 } else {
13813 // simply indent the string otherwise
13814 var white = text.match(/^\s*/)[0];
13815 var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1;
13816 var reindent = multi_parser.get_full_indent(script_indent_level -_level);
13817 text = text.replace(/^\s*/, indentation)
13818 .replace(/\r\n|\r|\n/g, '\n' + reindent)
13819 .replace(/\s*$/, '');
13820 }
13821 if (text) {
13822 multi_parser.print_token(text);
13823 multi_parser.print_newline(true, multi_parser.output);
13824 }
13825 }
13826 multi_parser.current_mode = 'TAG';
13827 break;
13828 }
13829 multi_parser.last_token = multi_parser.token_type;
13830 multi_parser.last_text = multi_parser.token_text;
13831 }
13832 return multi_parser.output.join('');
13833 }
13834
13835 module.exports = {
13836 prettyPrint: style_html
13837 };
13838 },{}],19:[function(require,module,exports){
13839 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;
13840
13841
13842 },{}],20:[function(require,module,exports){
13843 (function (global, factory) {
13844 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
13845 typeof define === 'function' && define.amd ? define(factory) :
13846 (global.preactRenderToString = factory());
13847 }(this, (function () {
13848
13849 var NON_DIMENSION_PROPS = {
13850 boxFlex: 1, boxFlexGroup: 1, columnCount: 1, fillOpacity: 1, flex: 1, flexGrow: 1,
13851 flexPositive: 1, flexShrink: 1, flexNegative: 1, fontWeight: 1, lineClamp: 1, lineHeight: 1,
13852 opacity: 1, order: 1, orphans: 1, strokeOpacity: 1, widows: 1, zIndex: 1, zoom: 1
13853 };
13854
13855 var ESC = {
13856 '<': '&lt;',
13857 '>': '&gt;',
13858 '"': '&quot;',
13859 '&': '&amp;'
13860 };
13861
13862 var objectKeys = Object.keys || function (obj) {
13863 var keys = [];
13864 for (var i in obj) {
13865 if (obj.hasOwnProperty(i)) keys.push(i);
13866 }return keys;
13867 };
13868
13869 var encodeEntities = function encodeEntities(s) {
13870 return String(s).replace(/[<>"&]/g, escapeChar);
13871 };
13872
13873 var escapeChar = function escapeChar(a) {
13874 return ESC[a] || a;
13875 };
13876
13877 var falsey = function falsey(v) {
13878 return v == null || v === false;
13879 };
13880
13881 var memoize = function memoize(fn) {
13882 var mem = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
13883 return function (v) {
13884 return mem[v] || (mem[v] = fn(v));
13885 };
13886 };
13887
13888 var indent = function indent(s, char) {
13889 return String(s).replace(/(\n+)/g, '$1' + (char || '\t'));
13890 };
13891
13892 var isLargeString = function isLargeString(s, length, ignoreLines) {
13893 return String(s).length > (length || 40) || !ignoreLines && String(s).indexOf('\n') !== -1 || String(s).indexOf('<') !== -1;
13894 };
13895
13896 function styleObjToCss(s) {
13897 var str = '';
13898 for (var prop in s) {
13899 var val = s[prop];
13900 if (val != null) {
13901 if (str) str += ' ';
13902 str += jsToCss(prop);
13903 str += ': ';
13904 str += val;
13905 if (typeof val === 'number' && !NON_DIMENSION_PROPS[prop]) {
13906 str += 'px';
13907 }
13908 str += ';';
13909 }
13910 }
13911 return str || undefined;
13912 }
13913
13914 function hashToClassName(c) {
13915 var str = '';
13916 for (var prop in c) {
13917 if (c[prop]) {
13918 if (str) str += ' ';
13919 str += prop;
13920 }
13921 }
13922 return str;
13923 }
13924
13925 var jsToCss = memoize(function (s) {
13926 return s.replace(/([A-Z])/g, '-$1').toLowerCase();
13927 });
13928
13929 function assign(obj, props) {
13930 for (var i in props) {
13931 obj[i] = props[i];
13932 }return obj;
13933 }
13934
13935 function getNodeProps(vnode) {
13936 var defaultProps = vnode.nodeName.defaultProps,
13937 props = assign({}, defaultProps || vnode.attributes);
13938 if (defaultProps) assign(props, vnode.attributes);
13939 if (vnode.children) props.children = vnode.children;
13940 return props;
13941 }
13942
13943 var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
13944
13945 var SHALLOW = { shallow: true };
13946
13947 var UNNAMED = [];
13948
13949 var EMPTY = {};
13950
13951 var VOID_ELEMENTS = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
13952
13953 renderToString.render = renderToString;
13954
13955 var shallowRender = function shallowRender(vnode, context) {
13956 return renderToString(vnode, context, SHALLOW);
13957 };
13958
13959 function renderToString(vnode, context, opts, inner, isSvgMode) {
13960 var _ref = vnode || EMPTY,
13961 nodeName = _ref.nodeName,
13962 attributes = _ref.attributes,
13963 children = _ref.children,
13964 isComponent = false;
13965
13966 context = context || {};
13967 opts = opts || {};
13968
13969 var pretty = opts.pretty,
13970 indentChar = typeof pretty === 'string' ? pretty : '\t';
13971
13972 if (vnode == null || typeof vnode === 'boolean') {
13973 return '';
13974 }
13975
13976 if ((typeof vnode === 'undefined' ? 'undefined' : _typeof(vnode)) !== 'object' && !nodeName) {
13977 return encodeEntities(vnode);
13978 }
13979
13980 if (typeof nodeName === 'function') {
13981 isComponent = true;
13982 if (opts.shallow && (inner || opts.renderRootComponent === false)) {
13983 nodeName = getComponentName(nodeName);
13984 } else {
13985 var props = getNodeProps(vnode),
13986 rendered = void 0;
13987
13988 if (!nodeName.prototype || typeof nodeName.prototype.render !== 'function') {
13989 rendered = nodeName(props, context);
13990 } else {
13991 var c = new nodeName(props, context);
13992
13993 c._disable = c.__x = true;
13994 c.props = props;
13995 c.context = context;
13996 if (c.componentWillMount) c.componentWillMount();
13997 rendered = c.render(c.props, c.state, c.context);
13998
13999 if (c.getChildContext) {
14000 context = assign(assign({}, context), c.getChildContext());
14001 }
14002 }
14003
14004 return renderToString(rendered, context, opts, opts.shallowHighOrder !== false);
14005 }
14006 }
14007
14008 var s = '',
14009 html = void 0;
14010
14011 if (attributes) {
14012 var attrs = objectKeys(attributes);
14013
14014 if (opts && opts.sortAttributes === true) attrs.sort();
14015
14016 for (var i = 0; i < attrs.length; i++) {
14017 var name = attrs[i],
14018 v = attributes[name];
14019 if (name === 'children') continue;
14020 if (!(opts && opts.allAttributes) && (name === 'key' || name === 'ref')) continue;
14021
14022 if (name === 'className') {
14023 if (attributes['class']) continue;
14024 name = 'class';
14025 } else if (isSvgMode && name.match(/^xlink\:?(.+)/)) {
14026 name = name.toLowerCase().replace(/^xlink\:?(.+)/, 'xlink:$1');
14027 }
14028
14029 if (name === 'class' && v && (typeof v === 'undefined' ? 'undefined' : _typeof(v)) === 'object') {
14030 v = hashToClassName(v);
14031 } else if (name === 'style' && v && (typeof v === 'undefined' ? 'undefined' : _typeof(v)) === 'object') {
14032 v = styleObjToCss(v);
14033 }
14034
14035 var hooked = opts.attributeHook && opts.attributeHook(name, v, context, opts, isComponent);
14036 if (hooked || hooked === '') {
14037 s += hooked;
14038 continue;
14039 }
14040
14041 if (name === 'dangerouslySetInnerHTML') {
14042 html = v && v.__html;
14043 } else if ((v || v === 0 || v === '') && typeof v !== 'function') {
14044 if (v === true || v === '') {
14045 v = name;
14046
14047 if (!opts || !opts.xml) {
14048 s += ' ' + name;
14049 continue;
14050 }
14051 }
14052 s += ' ' + name + '="' + encodeEntities(v) + '"';
14053 }
14054 }
14055 }
14056
14057 var sub = s.replace(/^\n\s*/, ' ');
14058 if (sub !== s && !~sub.indexOf('\n')) s = sub;else if (pretty && ~s.indexOf('\n')) s += '\n';
14059
14060 s = '<' + nodeName + s + '>';
14061
14062 if (VOID_ELEMENTS.indexOf(nodeName) > -1) {
14063 s = s.replace(/>$/, ' />');
14064 }
14065
14066 if (html) {
14067 if (pretty && isLargeString(html)) {
14068 html = '\n' + indentChar + indent(html, indentChar);
14069 }
14070 s += html;
14071 } else {
14072 var len = children && children.length,
14073 pieces = [],
14074 hasLarge = ~s.indexOf('\n');
14075 for (var _i = 0; _i < len; _i++) {
14076 var child = children[_i];
14077 if (!falsey(child)) {
14078 var childSvgMode = nodeName === 'svg' ? true : nodeName === 'foreignObject' ? false : isSvgMode,
14079 ret = renderToString(child, context, opts, true, childSvgMode);
14080 if (!hasLarge && pretty && isLargeString(ret)) hasLarge = true;
14081 if (ret) pieces.push(ret);
14082 }
14083 }
14084 if (pretty && hasLarge) {
14085 for (var _i2 = pieces.length; _i2--;) {
14086 pieces[_i2] = '\n' + indentChar + indent(pieces[_i2], indentChar);
14087 }
14088 }
14089 if (pieces.length) {
14090 s += pieces.join('');
14091 } else if (opts && opts.xml) {
14092 return s.substring(0, s.length - 1) + ' />';
14093 }
14094 }
14095
14096 if (VOID_ELEMENTS.indexOf(nodeName) === -1) {
14097 if (pretty && ~s.indexOf('\n')) s += '\n';
14098 s += '</' + nodeName + '>';
14099 }
14100
14101 return s;
14102 }
14103
14104 function getComponentName(component) {
14105 return component.displayName || component !== Function && component.name || getFallbackComponentName(component);
14106 }
14107
14108 function getFallbackComponentName(component) {
14109 var str = Function.prototype.toString.call(component),
14110 name = (str.match(/^\s*function\s+([^\( ]+)/) || EMPTY)[1];
14111 if (!name) {
14112 var index = -1;
14113 for (var i = UNNAMED.length; i--;) {
14114 if (UNNAMED[i] === component) {
14115 index = i;
14116 break;
14117 }
14118 }
14119
14120 if (index < 0) {
14121 index = UNNAMED.push(component) - 1;
14122 }
14123 name = 'UnnamedComponent' + index;
14124 }
14125 return name;
14126 }
14127 renderToString.shallowRender = shallowRender;
14128
14129 return renderToString;
14130
14131 })));
14132
14133
14134 },{}],21:[function(require,module,exports){
14135 !function() {
14136 'use strict';
14137 function VNode() {}
14138 function h(nodeName, attributes) {
14139 var lastSimple, child, simple, i, children = EMPTY_CHILDREN;
14140 for (i = arguments.length; i-- > 2; ) stack.push(arguments[i]);
14141 if (attributes && null != attributes.children) {
14142 if (!stack.length) stack.push(attributes.children);
14143 delete attributes.children;
14144 }
14145 while (stack.length) if ((child = stack.pop()) && void 0 !== child.pop) for (i = child.length; i--; ) stack.push(child[i]); else {
14146 if ('boolean' == typeof child) child = null;
14147 if (simple = 'function' != typeof nodeName) if (null == child) child = ''; else if ('number' == typeof child) child = String(child); else if ('string' != typeof child) simple = !1;
14148 if (simple && lastSimple) children[children.length - 1] += child; else if (children === EMPTY_CHILDREN) children = [ child ]; else children.push(child);
14149 lastSimple = simple;
14150 }
14151 var p = new VNode();
14152 p.nodeName = nodeName;
14153 p.children = children;
14154 p.attributes = null == attributes ? void 0 : attributes;
14155 p.key = null == attributes ? void 0 : attributes.key;
14156 if (void 0 !== options.vnode) options.vnode(p);
14157 return p;
14158 }
14159 function extend(obj, props) {
14160 for (var i in props) obj[i] = props[i];
14161 return obj;
14162 }
14163 function cloneElement(vnode, props) {
14164 return h(vnode.nodeName, extend(extend({}, vnode.attributes), props), arguments.length > 2 ? [].slice.call(arguments, 2) : vnode.children);
14165 }
14166 function enqueueRender(component) {
14167 if (!component.__d && (component.__d = !0) && 1 == items.push(component)) (options.debounceRendering || defer)(rerender);
14168 }
14169 function rerender() {
14170 var p, list = items;
14171 items = [];
14172 while (p = list.pop()) if (p.__d) renderComponent(p);
14173 }
14174 function isSameNodeType(node, vnode, hydrating) {
14175 if ('string' == typeof vnode || 'number' == typeof vnode) return void 0 !== node.splitText;
14176 if ('string' == typeof vnode.nodeName) return !node._componentConstructor && isNamedNode(node, vnode.nodeName); else return hydrating || node._componentConstructor === vnode.nodeName;
14177 }
14178 function isNamedNode(node, nodeName) {
14179 return node.__n === nodeName || node.nodeName.toLowerCase() === nodeName.toLowerCase();
14180 }
14181 function getNodeProps(vnode) {
14182 var props = extend({}, vnode.attributes);
14183 props.children = vnode.children;
14184 var defaultProps = vnode.nodeName.defaultProps;
14185 if (void 0 !== defaultProps) for (var i in defaultProps) if (void 0 === props[i]) props[i] = defaultProps[i];
14186 return props;
14187 }
14188 function createNode(nodeName, isSvg) {
14189 var node = isSvg ? document.createElementNS('http://www.w3.org/2000/svg', nodeName) : document.createElement(nodeName);
14190 node.__n = nodeName;
14191 return node;
14192 }
14193 function removeNode(node) {
14194 var parentNode = node.parentNode;
14195 if (parentNode) parentNode.removeChild(node);
14196 }
14197 function setAccessor(node, name, old, value, isSvg) {
14198 if ('className' === name) name = 'class';
14199 if ('key' === name) ; else if ('ref' === name) {
14200 if (old) old(null);
14201 if (value) value(node);
14202 } else if ('class' === name && !isSvg) node.className = value || ''; else if ('style' === name) {
14203 if (!value || 'string' == typeof value || 'string' == typeof old) node.style.cssText = value || '';
14204 if (value && 'object' == typeof value) {
14205 if ('string' != typeof old) for (var i in old) if (!(i in value)) node.style[i] = '';
14206 for (var i in value) node.style[i] = 'number' == typeof value[i] && !1 === IS_NON_DIMENSIONAL.test(i) ? value[i] + 'px' : value[i];
14207 }
14208 } else if ('dangerouslySetInnerHTML' === name) {
14209 if (value) node.innerHTML = value.__html || '';
14210 } else if ('o' == name[0] && 'n' == name[1]) {
14211 var useCapture = name !== (name = name.replace(/Capture$/, ''));
14212 name = name.toLowerCase().substring(2);
14213 if (value) {
14214 if (!old) node.addEventListener(name, eventProxy, useCapture);
14215 } else node.removeEventListener(name, eventProxy, useCapture);
14216 (node.__l || (node.__l = {}))[name] = value;
14217 } else if ('list' !== name && 'type' !== name && !isSvg && name in node) {
14218 setProperty(node, name, null == value ? '' : value);
14219 if (null == value || !1 === value) node.removeAttribute(name);
14220 } else {
14221 var ns = isSvg && name !== (name = name.replace(/^xlink\:?/, ''));
14222 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);
14223 }
14224 }
14225 function setProperty(node, name, value) {
14226 try {
14227 node[name] = value;
14228 } catch (e) {}
14229 }
14230 function eventProxy(e) {
14231 return this.__l[e.type](options.event && options.event(e) || e);
14232 }
14233 function flushMounts() {
14234 var c;
14235 while (c = mounts.pop()) {
14236 if (options.afterMount) options.afterMount(c);
14237 if (c.componentDidMount) c.componentDidMount();
14238 }
14239 }
14240 function diff(dom, vnode, context, mountAll, parent, componentRoot) {
14241 if (!diffLevel++) {
14242 isSvgMode = null != parent && void 0 !== parent.ownerSVGElement;
14243 hydrating = null != dom && !('__preactattr_' in dom);
14244 }
14245 var ret = idiff(dom, vnode, context, mountAll, componentRoot);
14246 if (parent && ret.parentNode !== parent) parent.appendChild(ret);
14247 if (!--diffLevel) {
14248 hydrating = !1;
14249 if (!componentRoot) flushMounts();
14250 }
14251 return ret;
14252 }
14253 function idiff(dom, vnode, context, mountAll, componentRoot) {
14254 var out = dom, prevSvgMode = isSvgMode;
14255 if (null == vnode || 'boolean' == typeof vnode) vnode = '';
14256 if ('string' == typeof vnode || 'number' == typeof vnode) {
14257 if (dom && void 0 !== dom.splitText && dom.parentNode && (!dom._component || componentRoot)) {
14258 if (dom.nodeValue != vnode) dom.nodeValue = vnode;
14259 } else {
14260 out = document.createTextNode(vnode);
14261 if (dom) {
14262 if (dom.parentNode) dom.parentNode.replaceChild(out, dom);
14263 recollectNodeTree(dom, !0);
14264 }
14265 }
14266 out.__preactattr_ = !0;
14267 return out;
14268 }
14269 var vnodeName = vnode.nodeName;
14270 if ('function' == typeof vnodeName) return buildComponentFromVNode(dom, vnode, context, mountAll);
14271 isSvgMode = 'svg' === vnodeName ? !0 : 'foreignObject' === vnodeName ? !1 : isSvgMode;
14272 vnodeName = String(vnodeName);
14273 if (!dom || !isNamedNode(dom, vnodeName)) {
14274 out = createNode(vnodeName, isSvgMode);
14275 if (dom) {
14276 while (dom.firstChild) out.appendChild(dom.firstChild);
14277 if (dom.parentNode) dom.parentNode.replaceChild(out, dom);
14278 recollectNodeTree(dom, !0);
14279 }
14280 }
14281 var fc = out.firstChild, props = out.__preactattr_, vchildren = vnode.children;
14282 if (null == props) {
14283 props = out.__preactattr_ = {};
14284 for (var a = out.attributes, i = a.length; i--; ) props[a[i].name] = a[i].value;
14285 }
14286 if (!hydrating && vchildren && 1 === vchildren.length && 'string' == typeof vchildren[0] && null != fc && void 0 !== fc.splitText && null == fc.nextSibling) {
14287 if (fc.nodeValue != vchildren[0]) fc.nodeValue = vchildren[0];
14288 } else if (vchildren && vchildren.length || null != fc) innerDiffNode(out, vchildren, context, mountAll, hydrating || null != props.dangerouslySetInnerHTML);
14289 diffAttributes(out, vnode.attributes, props);
14290 isSvgMode = prevSvgMode;
14291 return out;
14292 }
14293 function innerDiffNode(dom, vchildren, context, mountAll, isHydrating) {
14294 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;
14295 if (0 !== len) for (var i = 0; i < len; i++) {
14296 var _child = originalChildren[i], props = _child.__preactattr_, key = vlen && props ? _child._component ? _child._component.__k : props.key : null;
14297 if (null != key) {
14298 keyedLen++;
14299 keyed[key] = _child;
14300 } else if (props || (void 0 !== _child.splitText ? isHydrating ? _child.nodeValue.trim() : !0 : isHydrating)) children[childrenLen++] = _child;
14301 }
14302 if (0 !== vlen) for (var i = 0; i < vlen; i++) {
14303 vchild = vchildren[i];
14304 child = null;
14305 var key = vchild.key;
14306 if (null != key) {
14307 if (keyedLen && void 0 !== keyed[key]) {
14308 child = keyed[key];
14309 keyed[key] = void 0;
14310 keyedLen--;
14311 }
14312 } else if (!child && min < childrenLen) for (j = min; j < childrenLen; j++) if (void 0 !== children[j] && isSameNodeType(c = children[j], vchild, isHydrating)) {
14313 child = c;
14314 children[j] = void 0;
14315 if (j === childrenLen - 1) childrenLen--;
14316 if (j === min) min++;
14317 break;
14318 }
14319 child = idiff(child, vchild, context, mountAll);
14320 f = originalChildren[i];
14321 if (child && child !== dom && child !== f) if (null == f) dom.appendChild(child); else if (child === f.nextSibling) removeNode(f); else dom.insertBefore(child, f);
14322 }
14323 if (keyedLen) for (var i in keyed) if (void 0 !== keyed[i]) recollectNodeTree(keyed[i], !1);
14324 while (min <= childrenLen) if (void 0 !== (child = children[childrenLen--])) recollectNodeTree(child, !1);
14325 }
14326 function recollectNodeTree(node, unmountOnly) {
14327 var component = node._component;
14328 if (component) unmountComponent(component); else {
14329 if (null != node.__preactattr_ && node.__preactattr_.ref) node.__preactattr_.ref(null);
14330 if (!1 === unmountOnly || null == node.__preactattr_) removeNode(node);
14331 removeChildren(node);
14332 }
14333 }
14334 function removeChildren(node) {
14335 node = node.lastChild;
14336 while (node) {
14337 var next = node.previousSibling;
14338 recollectNodeTree(node, !0);
14339 node = next;
14340 }
14341 }
14342 function diffAttributes(dom, attrs, old) {
14343 var name;
14344 for (name in old) if ((!attrs || null == attrs[name]) && null != old[name]) setAccessor(dom, name, old[name], old[name] = void 0, isSvgMode);
14345 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);
14346 }
14347 function collectComponent(component) {
14348 var name = component.constructor.name;
14349 (components[name] || (components[name] = [])).push(component);
14350 }
14351 function createComponent(Ctor, props, context) {
14352 var inst, list = components[Ctor.name];
14353 if (Ctor.prototype && Ctor.prototype.render) {
14354 inst = new Ctor(props, context);
14355 Component.call(inst, props, context);
14356 } else {
14357 inst = new Component(props, context);
14358 inst.constructor = Ctor;
14359 inst.render = doRender;
14360 }
14361 if (list) for (var i = list.length; i--; ) if (list[i].constructor === Ctor) {
14362 inst.__b = list[i].__b;
14363 list.splice(i, 1);
14364 break;
14365 }
14366 return inst;
14367 }
14368 function doRender(props, state, context) {
14369 return this.constructor(props, context);
14370 }
14371 function setComponentProps(component, props, opts, context, mountAll) {
14372 if (!component.__x) {
14373 component.__x = !0;
14374 if (component.__r = props.ref) delete props.ref;
14375 if (component.__k = props.key) delete props.key;
14376 if (!component.base || mountAll) {
14377 if (component.componentWillMount) component.componentWillMount();
14378 } else if (component.componentWillReceiveProps) component.componentWillReceiveProps(props, context);
14379 if (context && context !== component.context) {
14380 if (!component.__c) component.__c = component.context;
14381 component.context = context;
14382 }
14383 if (!component.__p) component.__p = component.props;
14384 component.props = props;
14385 component.__x = !1;
14386 if (0 !== opts) if (1 === opts || !1 !== options.syncComponentUpdates || !component.base) renderComponent(component, 1, mountAll); else enqueueRender(component);
14387 if (component.__r) component.__r(component);
14388 }
14389 }
14390 function renderComponent(component, opts, mountAll, isChild) {
14391 if (!component.__x) {
14392 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;
14393 if (isUpdate) {
14394 component.props = previousProps;
14395 component.state = previousState;
14396 component.context = previousContext;
14397 if (2 !== opts && component.shouldComponentUpdate && !1 === component.shouldComponentUpdate(props, state, context)) skip = !0; else if (component.componentWillUpdate) component.componentWillUpdate(props, state, context);
14398 component.props = props;
14399 component.state = state;
14400 component.context = context;
14401 }
14402 component.__p = component.__s = component.__c = component.__b = null;
14403 component.__d = !1;
14404 if (!skip) {
14405 rendered = component.render(props, state, context);
14406 if (component.getChildContext) context = extend(extend({}, context), component.getChildContext());
14407 var toUnmount, base, childComponent = rendered && rendered.nodeName;
14408 if ('function' == typeof childComponent) {
14409 var childProps = getNodeProps(rendered);
14410 inst = initialChildComponent;
14411 if (inst && inst.constructor === childComponent && childProps.key == inst.__k) setComponentProps(inst, childProps, 1, context, !1); else {
14412 toUnmount = inst;
14413 component._component = inst = createComponent(childComponent, childProps, context);
14414 inst.__b = inst.__b || nextBase;
14415 inst.__u = component;
14416 setComponentProps(inst, childProps, 0, context, !1);
14417 renderComponent(inst, 1, mountAll, !0);
14418 }
14419 base = inst.base;
14420 } else {
14421 cbase = initialBase;
14422 toUnmount = initialChildComponent;
14423 if (toUnmount) cbase = component._component = null;
14424 if (initialBase || 1 === opts) {
14425 if (cbase) cbase._component = null;
14426 base = diff(cbase, rendered, context, mountAll || !isUpdate, initialBase && initialBase.parentNode, !0);
14427 }
14428 }
14429 if (initialBase && base !== initialBase && inst !== initialChildComponent) {
14430 var baseParent = initialBase.parentNode;
14431 if (baseParent && base !== baseParent) {
14432 baseParent.replaceChild(base, initialBase);
14433 if (!toUnmount) {
14434 initialBase._component = null;
14435 recollectNodeTree(initialBase, !1);
14436 }
14437 }
14438 }
14439 if (toUnmount) unmountComponent(toUnmount);
14440 component.base = base;
14441 if (base && !isChild) {
14442 var componentRef = component, t = component;
14443 while (t = t.__u) (componentRef = t).base = base;
14444 base._component = componentRef;
14445 base._componentConstructor = componentRef.constructor;
14446 }
14447 }
14448 if (!isUpdate || mountAll) mounts.unshift(component); else if (!skip) {
14449 if (component.componentDidUpdate) component.componentDidUpdate(previousProps, previousState, previousContext);
14450 if (options.afterUpdate) options.afterUpdate(component);
14451 }
14452 if (null != component.__h) while (component.__h.length) component.__h.pop().call(component);
14453 if (!diffLevel && !isChild) flushMounts();
14454 }
14455 }
14456 function buildComponentFromVNode(dom, vnode, context, mountAll) {
14457 var c = dom && dom._component, originalComponent = c, oldDom = dom, isDirectOwner = c && dom._componentConstructor === vnode.nodeName, isOwner = isDirectOwner, props = getNodeProps(vnode);
14458 while (c && !isOwner && (c = c.__u)) isOwner = c.constructor === vnode.nodeName;
14459 if (c && isOwner && (!mountAll || c._component)) {
14460 setComponentProps(c, props, 3, context, mountAll);
14461 dom = c.base;
14462 } else {
14463 if (originalComponent && !isDirectOwner) {
14464 unmountComponent(originalComponent);
14465 dom = oldDom = null;
14466 }
14467 c = createComponent(vnode.nodeName, props, context);
14468 if (dom && !c.__b) {
14469 c.__b = dom;
14470 oldDom = null;
14471 }
14472 setComponentProps(c, props, 1, context, mountAll);
14473 dom = c.base;
14474 if (oldDom && dom !== oldDom) {
14475 oldDom._component = null;
14476 recollectNodeTree(oldDom, !1);
14477 }
14478 }
14479 return dom;
14480 }
14481 function unmountComponent(component) {
14482 if (options.beforeUnmount) options.beforeUnmount(component);
14483 var base = component.base;
14484 component.__x = !0;
14485 if (component.componentWillUnmount) component.componentWillUnmount();
14486 component.base = null;
14487 var inner = component._component;
14488 if (inner) unmountComponent(inner); else if (base) {
14489 if (base.__preactattr_ && base.__preactattr_.ref) base.__preactattr_.ref(null);
14490 component.__b = base;
14491 removeNode(base);
14492 collectComponent(component);
14493 removeChildren(base);
14494 }
14495 if (component.__r) component.__r(null);
14496 }
14497 function Component(props, context) {
14498 this.__d = !0;
14499 this.context = context;
14500 this.props = props;
14501 this.state = this.state || {};
14502 }
14503 function render(vnode, parent, merge) {
14504 return diff(merge, vnode, {}, !1, parent, !1);
14505 }
14506 var options = {};
14507 var stack = [];
14508 var EMPTY_CHILDREN = [];
14509 var defer = 'function' == typeof Promise ? Promise.resolve().then.bind(Promise.resolve()) : setTimeout;
14510 var IS_NON_DIMENSIONAL = /acit|ex(?:s|g|n|p|$)|rph|ows|mnc|ntw|ine[ch]|zoo|^ord/i;
14511 var items = [];
14512 var mounts = [];
14513 var diffLevel = 0;
14514 var isSvgMode = !1;
14515 var hydrating = !1;
14516 var components = {};
14517 extend(Component.prototype, {
14518 setState: function(state, callback) {
14519 var s = this.state;
14520 if (!this.__s) this.__s = extend({}, s);
14521 extend(s, 'function' == typeof state ? state(s, this.props) : state);
14522 if (callback) (this.__h = this.__h || []).push(callback);
14523 enqueueRender(this);
14524 },
14525 forceUpdate: function(callback) {
14526 if (callback) (this.__h = this.__h || []).push(callback);
14527 renderComponent(this, 2);
14528 },
14529 render: function() {}
14530 });
14531 var preact = {
14532 h: h,
14533 createElement: h,
14534 cloneElement: cloneElement,
14535 Component: Component,
14536 render: render,
14537 rerender: rerender,
14538 options: options
14539 };
14540 if ('undefined' != typeof module) module.exports = preact; else self.preact = preact;
14541 }();
14542
14543 },{}]},{},[2]);
14544 ; })();