diff --git a/dist/css/field.css b/dist/css/field.css index 610aaa2..89bed5b 100644 --- a/dist/css/field.css +++ b/dist/css/field.css @@ -1,5 +1,5 @@ .form-input.form-input--top { - border-bottom: 0 !important; + border-bottom: 0; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } @@ -19,8 +19,21 @@ } .nova-canvas-header.top-sticky { border-radius: 0; + border-bottom: 4px dashed rgba(var(--colors-gray-200)); box-shadow: none; } +.nova-canvas-header button { + transition: 100ms ease-in-out; +} .nova-canvas.show-source .nova-canvas-content { + cursor: not-allowed; font-family: Consolas, serif; + white-space: pre-wrap; +} +.nova-canvas.show-source .nova-canvas-content p { + margin: 0; +} + +.dark:root .nova-canvas-header.top-sticky { + border-bottom: 4px dashed rgba(var(--colors-gray-700)); } diff --git a/dist/js/field.js b/dist/js/field.js index 9c51d0a..306a1d7 100644 --- a/dist/js/field.js +++ b/dist/js/field.js @@ -6095,6 +6095,11 @@ __webpack_require__.r(__webpack_exports__); // Inject field into each tool. var tool = _modules_tools_index__WEBPACK_IMPORTED_MODULE_0__["default"][item]; tool.field = _this.field; + + // Initialize the tool. + if (tool.init) { + tool.init(_this.editor, _this.refs); + } return tool; }); } @@ -6403,7 +6408,7 @@ __webpack_require__.r(__webpack_exports__); var _hoisted_1 = { ref: "header", - "class": "nova-canvas-header form-control py-3 h-auto form-input form-control-bordered form-input--top" + "class": "nova-canvas-header form-control bg-gray-50 py-3 h-auto form-input form-control-bordered form-input--top" }; var _hoisted_2 = { key: 1 @@ -6628,7 +6633,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) { return (0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("select", { value: $data.currentFormat, disabled: !$data.currentFormat, - "class": "format-dropdown rounded-sm dark:bg-gray-900", + "class": "format-dropdown rounded-sm bg-gray-50 dark:bg-gray-900", onChange: _cache[0] || (_cache[0] = function () { return $options.applyFormat && $options.applyFormat.apply($options, arguments); }) @@ -7221,31 +7226,66 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ }); /* harmony import */ var _heroicons_vue_24_outline__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @heroicons/vue/24/outline */ "./node_modules/@heroicons/vue/24/outline/esm/CommandLineIcon.js"); /* harmony import */ var _components_Tools_Standard_vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../components/Tools/Standard.vue */ "./resources/js/components/Tools/Standard.vue"); -/* harmony import */ var html_format__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! html-format */ "./node_modules/html-format/index.js"); -/* harmony import */ var html_format__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(html_format__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vue */ "vue"); -/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(vue__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vue */ "vue"); +/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(vue__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var simply_beautiful__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! simply-beautiful */ "./node_modules/simply-beautiful/dist/index.js"); +/* harmony import */ var simply_beautiful__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(simply_beautiful__WEBPACK_IMPORTED_MODULE_2__); /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ({ icon: _heroicons_vue_24_outline__WEBPACK_IMPORTED_MODULE_3__["default"], - isActive: (0,vue__WEBPACK_IMPORTED_MODULE_2__.ref)(false), + isActive: (0,vue__WEBPACK_IMPORTED_MODULE_1__.ref)(false), component: _components_Tools_Standard_vue__WEBPACK_IMPORTED_MODULE_0__["default"], + /** + * Toggle show source. + * + * @param {Object} editor + * @param {Object} refs + */ apply: function apply(editor, refs) { - if (this.active(editor)) { - editor.commands.setContent(editor.getText()); - this.isActive.value = false; - refs.container.classList.remove('show-source'); - } else { - editor.commands.setContent("")); - this.isActive.value = true; - refs.container.classList.add('show-source'); - } + this.active() ? this.disable(editor, refs) : this.enable(editor, refs); }, - active: function active(editor) { - return this.isActive.value || false; + /** + * Enable show source + * + * @param {Object} editor + * @param {Object} refs + */ + enable: function enable(editor, refs) { + this.isActive.value = true; + editor.commands.setContent("")); + refs.container.classList.add('show-source'); + editor.setOptions({ + editable: false + }); + }, + /** + * Get pretty HTML from editor content. + * + * @param {Object} editor + * @returns {string} + */ + getPrettyHtml: function getPrettyHtml(editor) { + return simply_beautiful__WEBPACK_IMPORTED_MODULE_2___default().html(editor.getHTML()); + }, + /** + * Disable show source. + * + * @param {Object} editor + * @param {Object} refs + */ + disable: function disable(editor, refs) { + this.isActive.value = false; + editor.commands.setContent(editor.getText()); + refs.container.classList.remove('show-source'); + editor.setOptions({ + editable: true + }); + }, + active: function active() { + return this.isActive.value; } }); @@ -11465,243 +11505,6 @@ function BufferBigIntNotDefined () { module.exports = typeof self == 'object' ? self.FormData : window.FormData; -/***/ }), - -/***/ "./node_modules/html-format/index.js": -/*!*******************************************!*\ - !*** ./node_modules/html-format/index.js ***! - \*******************************************/ -/***/ ((module) => { - -const tagName = String.raw`[A-Za-z][^/\s>]*`; - -// Preserve strings in templates and such -// Avoid apostrophes and unintentional captures -const doubleQuotedString = String.raw`\B"(?:\\[^<>\n]|[^\\"<>\n])*"(?!\w)`; -const singleQuotedString = String.raw`\B'(?:\\[^<>\n]|[^\\'<>\n])*'(?!\w)`; -const quotedString = String.raw`${doubleQuotedString}|${singleQuotedString}`; - -const quotedAttrValue = String.raw`"(?[^"]*)"`; -const singleQuotedAttrValue = String.raw`'(?[^']*)'`; -// https://mothereff.in/unquoted-attributes -const unquotedAttrValue = String.raw`(?[^\s"'\`=<>]+)`; - -const attrName = String.raw`[^=\s>/"']+(?=[=>\s]|$)`; -const attrValue = String.raw`${quotedAttrValue}|${singleQuotedAttrValue}|${unquotedAttrValue}`; -const attrNameValue = String.raw`(?${attrName})(?:\s*=\s*(?:${attrValue}))?`; - -// Make sure not to swallow the closing slash if one exists -const attrText = String.raw`${quotedString}|[^\s>]*[^\s>/]|[^\s>]*/(?!\s*>)`; - -const attr = String.raw`(?\s*)(?:${attrNameValue}|(?${attrText}))`; - -const tokens = { - comment: String.raw``, - dtd: String.raw`]+>`, - startTag: String.raw`<(?${tagName})(?(?:${attr})*)\s*(?/?)\s*>`, - endTag: String.raw`${tagName})\s*>`, - space: String.raw`\s+`, - text: String.raw`[^<\s"']+|${quotedString}|['"]`, - wildcard: String.raw`.`, -}; - -const grammar = Object.entries(tokens) - .map(([k, v]) => `(?<${k}>${v})`) - .join("|"); - -/** - * - * @param {RegExp} lexer - * @param {string} s - */ -function* getTokens(lexer, s) { - let res; - let { lastIndex } = lexer; - while ((res = lexer.exec(s))) { - yield /** @type {RegExpExecArray & { groups: Record }} */ ( - res - ); - ({ lastIndex } = lexer); - } - if (lastIndex != s.length) throw new Error("Failed to parse string"); -} - -const voidTags = new Set([ - "area", - "base", - "basefont", - "bgsound", - "br", - "col", - "command", - "embed", - "frame", - "hr", - "image", - "img", - "input", - "keygen", - "link", - "meta", - "param", - "source", - "track", - "wbr", -]); - -function format(/** @type {string} */ html, indent = " ", width = 80) { - const lexer = new RegExp(grammar, "gys"); - const attrLexer = new RegExp(attr, "gy"); - - /** @type {string[]} */ - const output = []; - - /** @type {string | null} */ - let specialElement = null; - let level = 0; - - let lineLength = 0; - let span = ""; - let spanLevel = 0; - let lastSpace = ""; - - const flushOutput = () => { - if (lastSpace && lastSpace != "\n") { - const newline = span.indexOf("\n"); - const len = newline == -1 ? span.length : newline; - if (lineLength + lastSpace.length + len > width) lastSpace = "\n"; - } - - const ind = lastSpace == "\n" && span ? indent.repeat(spanLevel) : ""; - const out = `${lastSpace}${ind}${span}`; - - if (out) { - const pos = out.lastIndexOf("\n"); - if (pos == -1) lineLength += out.length; - else lineLength = out.length - pos - 1; - output.push(out); - } - - span = lastSpace = ""; - }; - - const addOutput = (/** @type {string[]} */ ...args) => { - for (const s of args) { - if (!specialElement && /^\s+$/.test(s)) { - flushOutput(); - lastSpace = s; - } else { - if (!span) spanLevel = level; - span += s; - } - } - }; - - for (const token of getTokens(lexer, html)) { - // For testing - if (/** @type {any} */ (format).__strict && token.groups.wildcard) - throw new Error("Unexpected wildcard"); - - if (token.groups.endTag) { - const tagName = token.groups.endTagName.toLowerCase(); - if (tagName == specialElement) specialElement = null; - if (!specialElement) { - --level; - addOutput(``); - } - } - - if (!specialElement) { - if (token.groups.space) { - addOutput(...(token[0].match(/\n/g)?.slice(0, 2) ?? [" "])); - } else if ( - token.groups.comment || - token.groups.dtd || - token.groups.text || - token.groups.wildcard - ) { - addOutput(token[0]); - } else if (token.groups.startTag) { - const tagName = token.groups.startTagName.toLowerCase(); - - addOutput(`<${tagName}`); - - ++level; - - if (token.groups.attrs) { - let { lastIndex } = attrLexer; - let attrToken; - let lastToken; - while ( - (attrToken = - /** @type {RegExpExecArray & { groups: Record }} */ ( - attrLexer.exec(token.groups.attrs) - )) - ) { - ({ lastIndex } = attrLexer); - - // For testing - if ( - /** @type {any} */ (format).__strict && - attrToken.groups.attrText - ) - throw new Error("Unexpected attr text"); - - if (attrToken.groups.attrText) { - if (attrToken.groups.attrSpace) - addOutput(/\n/.test(attrToken.groups.attrSpace) ? "\n" : " "); - addOutput(attrToken.groups.attrText); - } else { - if (attrToken.groups.attrSpace || !lastToken?.groups.attrText) - addOutput(/\n/.test(attrToken.groups.attrSpace) ? "\n" : " "); - addOutput( - `${attrToken.groups.attrName}${ - attrToken.groups.quotedAttrValue - ? `="${attrToken.groups.quotedAttrValue}"` - : attrToken.groups.singleQuotedAttrValue - ? `='${attrToken.groups.singleQuotedAttrValue}'` - : attrToken.groups.unquotedAttrValue - ? `=${attrToken.groups.unquotedAttrValue}` - : "" - }` - ); - } - - lastToken = attrToken; - } - if (lastIndex != token.groups.attrs.length) - throw new Error("Failed to parse attributes"); - } - - const hasClosingSlash = Boolean(token.groups.closingSlash); - - addOutput(hasClosingSlash ? " />" : ">"); - - if (hasClosingSlash || voidTags.has(tagName)) --level; - else if (["pre", "textarea", "script", "style"].includes(tagName)) - specialElement = tagName; - } - } else addOutput(token[0]); - } - - // Flush remaining output - flushOutput(); - - let newline = false; - while (/^\s+$/.test(output[output.length - 1])) { - const last = /** @type {string} */ (output.pop()); - if (/\n/.test(last)) newline = true; - } - - if (newline) output.push("\n"); - - return output.join(""); -} - -format.default = format; -module.exports = format; - - /***/ }), /***/ "./node_modules/ieee754/index.js": @@ -13882,6 +13685,2121 @@ process.chdir = function (dir) { process.umask = function() { return 0; }; +/***/ }), + +/***/ "./node_modules/simply-beautiful/dist/index.js": +/*!*****************************************************!*\ + !*** ./node_modules/simply-beautiful/dist/index.js ***! + \*****************************************************/ +/***/ (function(module, exports, __webpack_require__) { + +/* provided dependency */ var process = __webpack_require__(/*! process/browser.js */ "./node_modules/process/browser.js"); +var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (root, factory) { + // https://github.com/umdjs/umd/blob/master/templates/returnExports.js + if (true) { + // AMD. Register as an anonymous module. + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), + __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else {} +}(typeof self !== 'undefined' ? self : this, function () { + + var environment = (Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]') ? 'node' : 'browser'; + + /* + JS + + + Style HTML + --------------- + + Written by Nochum Sossonko, (nsossonko@hotmail.com) + + Based on code initially developed by: Einar Lielmanis, + http://jsbeautifier.org/ + + + You are free to use this in any way you want, in case you find this useful or working for you. + + Usage: + style_html(html_source); + + style_html(html_source, options); + + The options are: + indent_size (default 4) — indentation size, + indent_char (default space) — character to indent with, + max_char (default 70) - maximum amount of characters per line, + brace_style (default "collapse") - "collapse" | "expand" | "end-expand" + 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. + unformatted (defaults to inline tags) - list of tags, that shouldn't be reformatted + indent_scripts (default normal) - "keep"|"separate"|"normal" + + e.g. + + style_html(html_source, { + 'indent_size': 2, + 'indent_char': ' ', + 'max_char': 78, + 'brace_style': 'expand', + 'unformatted': ['a', 'sub', 'sup', 'b', 'i', 'u'] + }); + */ + + function style_html(html_source, options) { + //Wrapper function to invoke all the necessary constructors and deal with the output. + + var multi_parser, + indent_size, + indent_character, + max_char, + brace_style, + unformatted; + + options = options || {}; + indent_size = options.indent_size || 4; + indent_character = options.indent_char || ' '; + brace_style = options.brace_style || 'collapse'; + max_char = options.max_char == 0 ? Infinity : options.max_char || 70; + 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']; + + function Parser() { + + this.pos = 0; //Parser position + this.token = ''; + this.current_mode = 'CONTENT'; //reflects the current Parser mode: TAG/CONTENT + this.tags = { //An object to hold tags, their position, and their parent-tags, initiated with default values + parent: 'parent1', + parentcount: 1, + parent1: '' + }; + this.tag_type = ''; + this.token_text = this.last_token = this.last_text = this.token_type = ''; + + this.Utils = { //Uilities made available to the various functions + whitespace: "\n\r\t ".split(''), + 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 + extra_liners: 'head,body,/html'.split(','), //for tags that need a line of whitespace before them + in_array: function (what, arr) { + for (var i=0; i= this.input.length) { + return content.length?content.join(''):['', 'TK_EOF']; + } + + input_char = this.input.charAt(this.pos); + this.pos++; + this.line_char_count++; + + if (this.Utils.in_array(input_char, this.Utils.whitespace)) { + if (content.length) { + space = true; + } + this.line_char_count--; + continue; //don't want to insert unnecessary space + } + else if (space) { + if (this.line_char_count >= this.max_char) { //insert a line when the max_char is reached + content.push('\n'); + for (var i=0; i', 'igm'); + reg_match.lastIndex = this.pos; + var reg_array = reg_match.exec(this.input); + var end_script = reg_array?reg_array.index:this.input.length; //absolute end of script + if(this.pos < end_script) { //get everything in between the script tags + content = this.input.substring(this.pos, end_script); + this.pos = end_script; + } + return content; + } + + this.record_tag = function (tag){ //function to record a tag and its parent in this.tags Object + if (this.tags[tag + 'count']) { //check for the existence of this tag type + this.tags[tag + 'count']++; + this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level + } + else { //otherwise initialize this tag type + this.tags[tag + 'count'] = 1; + this.tags[tag + this.tags[tag + 'count']] = this.indent_level; //and record the present indent level + } + 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) + this.tags.parent = tag + this.tags[tag + 'count']; //and make this the current parent (i.e. in the case of a div 'div1') + } + + this.retrieve_tag = function (tag) { //function to retrieve the opening tag to the corresponding closer + if (this.tags[tag + 'count']) { //if the openener is not in the Object we ignore it + var temp_parent = this.tags.parent; //check to see if it's a closable tag. + while (temp_parent) { //till we reach '' (the initial value); + if (tag + this.tags[tag + 'count'] === temp_parent) { //if this is it use it + break; + } + temp_parent = this.tags[temp_parent + 'parent']; //otherwise keep on climbing up the DOM Tree + } + if (temp_parent) { //if we caught something + this.indent_level = this.tags[tag + this.tags[tag + 'count']]; //set the indent_level accordingly + this.tags.parent = this.tags[temp_parent + 'parent']; //and set the current parent + } + delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; //delete the closed tags parent reference... + delete this.tags[tag + this.tags[tag + 'count']]; //...and the tag itself + if (this.tags[tag + 'count'] == 1) { + delete this.tags[tag + 'count']; + } + else { + this.tags[tag + 'count']--; + } + } + } + + this.get_tag = function () { //function to get a full tag and parse its type + var input_char = '', + content = [], + space = false, + tag_start, tag_end; + + do { + if (this.pos >= this.input.length) { + return content.length?content.join(''):['', 'TK_EOF']; + } + + input_char = this.input.charAt(this.pos); + this.pos++; + this.line_char_count++; + + if (this.Utils.in_array(input_char, this.Utils.whitespace)) { //don't want to insert unnecessary space + space = true; + this.line_char_count--; + continue; + } + + if (input_char === "'" || input_char === '"') { + if (!content[1] || content[1] !== '!') { //if we're in a comment strings don't get treated specially + input_char += this.get_unformatted(input_char); + space = true; + } + } + + if (input_char === '=') { //no space before = + space = false; + } + + if (content.length && content[content.length-1] !== '=' && input_char !== '>' + && space) { //no space after = or before > + if (this.line_char_count >= this.max_char) { + this.print_newline(false, content); + this.line_char_count = 0; + } + else { + content.push(' '); + this.line_char_count++; + } + space = false; + } + if (input_char === '<') { + tag_start = this.pos - 1; + } + content.push(input_char); //inserts character at-a-time (or string) + } while (input_char !== '>'); + + var tag_complete = content.join(''); + var tag_index; + if (tag_complete.indexOf(' ') != -1) { //if there's whitespace, thats where the tag name ends + tag_index = tag_complete.indexOf(' '); + } + else { //otherwise go with the tag ending + tag_index = tag_complete.indexOf('>'); + } + var tag_check = tag_complete.substring(1, tag_index).toLowerCase(); + if (tag_complete.charAt(tag_complete.length-2) === '/' || + 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 /) + this.tag_type = 'SINGLE'; + } + else if (tag_check === 'script') { //for later script handling + this.record_tag(tag_check); + this.tag_type = 'SCRIPT'; + } + else if (tag_check === 'style') { //for future style handling (for now it justs uses get_content) + this.record_tag(tag_check); + this.tag_type = 'STYLE'; + } + else if (this.Utils.in_array(tag_check, unformatted)) { // do not reformat the "unformatted" tags + var comment = this.get_unformatted('', tag_complete); //...delegate to get_unformatted function + content.push(comment); + // Preserve collapsed whitespace either before or after this tag. + if (tag_start > 0 && this.Utils.in_array(this.input.charAt(tag_start - 1), this.Utils.whitespace)){ + content.splice(0, 0, this.input.charAt(tag_start - 1)); + } + tag_end = this.pos - 1; + if (this.Utils.in_array(this.input.charAt(tag_end + 1), this.Utils.whitespace)){ + content.push(this.input.charAt(tag_end + 1)); + } + this.tag_type = 'SINGLE'; + } + else if (tag_check.charAt(0) === '!') { //peek for so... + var comment = this.get_unformatted('-->', tag_complete); //...delegate to get_unformatted + content.push(comment); + } + this.tag_type = 'START'; + } + else if (tag_check.indexOf('[endif') != -1) {//peek for ', tag_complete); + content.push(comment); + this.tag_type = 'SINGLE'; + } + } + else { + if (tag_check.charAt(0) === '/') { //this tag is a double tag so check for tag-ending + this.retrieve_tag(tag_check.substring(1)); //remove it and all ancestors + this.tag_type = 'END'; + } + else { //otherwise it's a start-tag + this.record_tag(tag_check); //push it on the tag stack + this.tag_type = 'START'; + } + if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { //check if this double needs an extra line + this.print_newline(true, this.output); + } + } + return content.join(''); //returns fully formatted tag + } + + this.get_unformatted = function (delimiter, orig_tag) { //function to return unformatted content in its entirety + + if (orig_tag && orig_tag.indexOf(delimiter) != -1) { + return ''; + } + var input_char = ''; + var content = ''; + var space = true; + do { + + if (this.pos >= this.input.length) { + return content; + } + + input_char = this.input.charAt(this.pos); + this.pos++ + + if (this.Utils.in_array(input_char, this.Utils.whitespace)) { + if (!space) { + this.line_char_count--; + continue; + } + if (input_char === '\n' || input_char === '\r') { + content += '\n'; + /* Don't change tab indention for unformatted blocks. If using code for html editing, this will greatly affect
 tags if they are specified in the 'unformatted array'
+            for (var i=0; i 0) {
+          this.indent_level--;
+        }
+      }
+    }
+    return this;
+  }
+
+  /*_____________________--------------------_____________________*/
+
+  multi_parser = new Parser(); //wrapping functions Parser
+  multi_parser.printer(html_source, indent_character, indent_size, max_char, brace_style); //initialize starting values
+
+  while (true) {
+      var t = multi_parser.get_token();
+      multi_parser.token_text = t[0];
+      multi_parser.token_type = t[1];
+
+    if (multi_parser.token_type === 'TK_EOF') {
+      break;
+    }
+
+    switch (multi_parser.token_type) {
+      case 'TK_TAG_START':
+        multi_parser.print_newline(false, multi_parser.output);
+        multi_parser.print_token(multi_parser.token_text);
+        multi_parser.indent();
+        multi_parser.current_mode = 'CONTENT';
+        break;
+      case 'TK_TAG_STYLE':
+      case 'TK_TAG_SCRIPT':
+        multi_parser.print_newline(false, multi_parser.output);
+        multi_parser.print_token(multi_parser.token_text);
+        multi_parser.current_mode = 'CONTENT';
+        break;
+      case 'TK_TAG_END':
+        //Print new line only if the tag has no content and has child
+        if (multi_parser.last_token === 'TK_CONTENT' && multi_parser.last_text === '') {
+            var tag_name = multi_parser.token_text.match(/\w+/)[0];
+            var tag_extracted_from_last_output = multi_parser.output[multi_parser.output.length -1].match(/<\s*(\w+)/);
+            if (tag_extracted_from_last_output === null || tag_extracted_from_last_output[1] !== tag_name)
+                multi_parser.print_newline(true, multi_parser.output);
+        }
+        multi_parser.print_token(multi_parser.token_text);
+        multi_parser.current_mode = 'CONTENT';
+        break;
+      case 'TK_TAG_SINGLE':
+        // Don't add a newline before elements that should remain unformatted.
+        var tag_check = multi_parser.token_text.match(/^\s*<([a-z]+)/i);
+        if (!tag_check || !multi_parser.Utils.in_array(tag_check[1], unformatted)){
+            multi_parser.print_newline(false, multi_parser.output);
+        }
+        multi_parser.print_token(multi_parser.token_text);
+        multi_parser.current_mode = 'CONTENT';
+        break;
+      case 'TK_CONTENT':
+        if (multi_parser.token_text !== '') {
+          multi_parser.print_token(multi_parser.token_text);
+        }
+        multi_parser.current_mode = 'TAG';
+        break;
+      case 'TK_STYLE':
+      case 'TK_SCRIPT':
+        if (multi_parser.token_text !== '') {
+          multi_parser.output.push('\n');
+          var text = multi_parser.token_text;
+          if (multi_parser.token_type == 'TK_SCRIPT') {
+            var _beautifier = typeof js_beautify == 'function' && js_beautify;
+          } else if (multi_parser.token_type == 'TK_STYLE') {
+            var _beautifier = typeof css_beautify == 'function' && css_beautify;
+          }
+
+          if (options.indent_scripts == "keep") {
+            var script_indent_level = 0;
+          } else if (options.indent_scripts == "separate") {
+            var script_indent_level = -multi_parser.indent_level;
+          } else {
+            var script_indent_level = 1;
+          }
+
+          var indentation = multi_parser.get_full_indent(script_indent_level);
+          if (_beautifier) {
+            // call the Beautifier if avaliable
+            text = _beautifier(text.replace(/^\s*/, indentation), options);
+          } else {
+            // simply indent the string otherwise
+            var white = text.match(/^\s*/)[0];
+            var _level = white.match(/[^\n\r]*$/)[0].split(multi_parser.indent_string).length - 1;
+            var reindent = multi_parser.get_full_indent(script_indent_level -_level);
+            text = text.replace(/^\s*/, indentation)
+                   .replace(/\r\n|\r|\n/g, '\n' + reindent)
+                   .replace(/\s*$/, '');
+          }
+          if (text) {
+            multi_parser.print_token(text);
+            multi_parser.print_newline(true, multi_parser.output);
+          }
+        }
+        multi_parser.current_mode = 'TAG';
+        break;
+    }
+    multi_parser.last_token = multi_parser.token_type;
+    multi_parser.last_text = multi_parser.token_text;
+  }
+  return multi_parser.output.join('');
+  }
+
+  /*
+
+  CSS Beautifier
+  ---------------
+
+    Written by Harutyun Amirjanyan, (amirjanyan@gmail.com)
+
+    Based on code initially developed by: Einar Lielmanis, 
+        http://jsbeautifier.org/
+
+
+    You are free to use this in any way you want, in case you find this useful or working for you.
+
+    Usage:
+        css_beautify(source_text);
+        css_beautify(source_text, options);
+
+    The options are:
+        indent_size (default 4)          — indentation size,
+        indent_char (default space)      — character to indent with,
+
+    e.g
+
+    css_beautify(css_source_text, {
+      'indent_size': 1,
+      'indent_char': '\t'
+    });
+  */
+
+  // http://www.w3.org/TR/CSS21/syndata.html#tokenization
+  // http://www.w3.org/TR/css3-syntax/
+  function css_beautify(source_text, options) {
+    options = options || {};
+    var indentSize = options.indent_size || 4;
+    var indentCharacter = options.indent_char || ' ';
+
+    // compatibility
+    if (typeof indentSize == "string")
+        indentSize = parseInt(indentSize);
+
+
+    // tokenizer
+    var whiteRe = /^\s+$/;
+    var wordRe = /[\w$\-_]/;
+
+    var pos = -1, ch;
+    function next() {
+        return ch = source_text.charAt(++pos)
+    }
+    function peek() {
+        return source_text.charAt(pos+1)
+    }
+    function eatString(comma) {
+        var start = pos;
+        while(next()){
+            if (ch=="\\"){
+                next();
+                next();
+            } else if (ch == comma) {
+                break;
+            } else if (ch == "\n") {
+                break;
+            }
+        }
+        return source_text.substring(start, pos + 1);
+    }
+
+    function eatWhitespace() {
+        var start = pos;
+        while (whiteRe.test(peek()))
+            pos++;
+        return pos != start;
+    }
+
+    function skipWhitespace() {
+        var start = pos;
+        do{
+        }while (whiteRe.test(next()))
+        return pos != start + 1;
+    }
+
+    function eatComment() {
+        var start = pos;
+        next();
+        while (next()) {
+            if (ch == "*" && peek() == "/") {
+                pos ++;
+                break;
+            }
+        }
+
+        return source_text.substring(start, pos + 1);
+    }
+
+
+    function lookBack(str, index) {
+        return output.slice(-str.length + (index||0), index).join("").toLowerCase() == str;
+    }
+
+    // printer
+    var indentString = source_text.match(/^[\r\n]*[\t ]*/)[0];
+    var singleIndent = Array(indentSize + 1).join(indentCharacter);
+    var indentLevel = 0;
+    function indent() {
+        indentLevel++;
+        indentString += singleIndent;
+    }
+    function outdent() {
+        indentLevel--;
+        indentString = indentString.slice(0, -indentSize);
+    }
+
+    var print = {}
+    print["{"] = function(ch) {
+        print.singleSpace();
+        output.push(ch);
+        print.newLine();
+    }
+    print["}"] = function(ch) {
+        print.newLine();
+        output.push(ch);
+        print.newLine();
+    }
+
+    print.newLine = function(keepWhitespace) {
+        if (!keepWhitespace)
+            while (whiteRe.test(output[output.length - 1]))
+                output.pop();
+
+        if (output.length)
+            output.push('\n');
+        if (indentString)
+            output.push(indentString);
+    }
+    print.singleSpace = function() {
+        if (output.length && !whiteRe.test(output[output.length - 1]))
+            output.push(' ');
+    }
+    var output = [];
+    if (indentString)
+        output.push(indentString);
+    /*_____________________--------------------_____________________*/
+
+    while(true) {
+        var isAfterSpace = skipWhitespace();
+
+        if (!ch)
+            break;
+
+        if (ch == '{') {
+            indent();
+            print["{"](ch);
+        } else if (ch == '}') {
+            outdent();
+            print["}"](ch);
+        } else if (ch == '"' || ch == '\'') {
+            output.push(eatString(ch))
+        } else if (ch == ';') {
+            output.push(ch, '\n', indentString);
+        } else if (ch == '/' && peek() == '*') { // comment
+            print.newLine();
+            output.push(eatComment(), "\n", indentString);
+        } else if (ch == '(') { // may be a url
+            if (lookBack("url", -1)) {
+              output.push(ch);
+              eatWhitespace();
+              if (next()) {
+                if (ch != ')' && ch != '"' && ch != '\'')
+                    output.push(eatString(')'));
+                else
+                    pos--;
+              }
+            } else {
+              if (isAfterSpace)
+                  print.singleSpace();
+              output.push(ch);
+              eatWhitespace();
+            }
+        } else if (ch == ')') {
+            output.push(ch);
+        } else if (ch == ',') {
+            eatWhitespace();
+            output.push(ch);
+            print.singleSpace();
+        } else if (ch == ']') {
+            output.push(ch);
+        }  else if (ch == '[' || ch == '=') { // no whitespace before or after
+            eatWhitespace();
+            output.push(ch);
+        } else {
+            if (isAfterSpace)
+                print.singleSpace();
+
+            output.push(ch);
+        }
+    }
+
+
+    var sweetCode = output.join('').replace(/[\n ]+$/, '');
+    return sweetCode;
+  }
+
+
+  if (true)
+    exports.css_beautify = css_beautify;
+
+  /*jslint onevar: false, plusplus: false */
+  /*jshint curly:true, eqeqeq:true, laxbreak:true, noempty:false */
+  /*
+
+  JS Beautifier
+  ---------------
+
+
+  Written by Einar Lielmanis, 
+      http://jsbeautifier.org/
+
+  Originally converted to javascript by Vital, 
+  "End braces on own line" added by Chris J. Shull, 
+
+  You are free to use this in any way you want, in case you find this useful or working for you.
+
+  Usage:
+    js_beautify(js_source_text);
+    js_beautify(js_source_text, options);
+
+  The options are:
+    indent_size (default 4)          - indentation size,
+    indent_char (default space)      - character to indent with,
+    preserve_newlines (default true) - whether existing line breaks should be preserved,
+    max_preserve_newlines (default unlimited) - maximum number of line breaks to be preserved in one chunk,
+
+    jslint_happy (default false) - if true, then jslint-stricter mode is enforced.
+
+            jslint_happy   !jslint_happy
+            ---------------------------------
+             function ()      function()
+
+    brace_style (default "collapse") - "collapse" | "expand" | "end-expand" | "expand-strict"
+            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.
+
+            expand-strict: put brace on own line even in such cases:
+
+                var a =
+                {
+                    a: 5,
+                    b: 6
+                }
+            This mode may break your scripts - e.g "return { a: 1 }" will be broken into two lines, so beware.
+
+    space_before_conditional (default true) - should the space before conditional statement be added, "if(true)" vs "if (true)",
+
+    unescape_strings (default false) - should printable characters in strings encoded in \xNN notation be unescaped, "example" vs "\x65\x78\x61\x6d\x70\x6c\x65"
+
+    e.g
+
+    js_beautify(js_source_text, {
+      'indent_size': 1,
+      'indent_char': '\t'
+    });
+
+
+  */
+
+
+
+  function js_beautify(js_source_text, options) {
+
+    var input, output, token_text, last_type, last_text, last_last_text, last_word, flags, flag_store, indent_string;
+    var whitespace, wordchar, punct, parser_pos, line_starters, digits;
+    var prefix, token_type, do_block_just_closed;
+    var wanted_newline, just_added_newline, n_newlines;
+    var preindent_string = '';
+
+
+    // Some interpreters have unexpected results with foo = baz || bar;
+    options = options ? options : {};
+
+    var opt_brace_style;
+
+    // compatibility
+    if (options.space_after_anon_function !== undefined && options.jslint_happy === undefined) {
+        options.jslint_happy = options.space_after_anon_function;
+    }
+    if (options.braces_on_own_line !== undefined) { //graceful handling of deprecated option
+        opt_brace_style = options.braces_on_own_line ? "expand" : "collapse";
+    }
+    opt_brace_style = options.brace_style ? options.brace_style : (opt_brace_style ? opt_brace_style : "collapse");
+
+
+    var opt_indent_size = options.indent_size ? options.indent_size : 4,
+        opt_indent_char = options.indent_char ? options.indent_char : ' ',
+        opt_preserve_newlines = typeof options.preserve_newlines === 'undefined' ? true : options.preserve_newlines,
+        opt_break_chained_methods = typeof options.break_chained_methods === 'undefined' ? false : options.break_chained_methods,
+        opt_max_preserve_newlines = typeof options.max_preserve_newlines === 'undefined' ? false : options.max_preserve_newlines,
+        opt_jslint_happy = options.jslint_happy === 'undefined' ? false : options.jslint_happy,
+        opt_keep_array_indentation = typeof options.keep_array_indentation === 'undefined' ? false : options.keep_array_indentation,
+        opt_space_before_conditional = typeof options.space_before_conditional === 'undefined' ? true : options.space_before_conditional,
+        opt_unescape_strings = typeof options.unescape_strings === 'undefined' ? false : options.unescape_strings;
+
+    just_added_newline = false;
+
+    // cache the source's length.
+    var input_length = js_source_text.length;
+
+    function trim_output(eat_newlines) {
+        eat_newlines = typeof eat_newlines === 'undefined' ? false : eat_newlines;
+        while (output.length && (output[output.length - 1] === ' '
+            || output[output.length - 1] === indent_string
+            || output[output.length - 1] === preindent_string
+            || (eat_newlines && (output[output.length - 1] === '\n' || output[output.length - 1] === '\r')))) {
+            output.pop();
+        }
+    }
+
+    function trim(s) {
+        return s.replace(/^\s\s*|\s\s*$/, '');
+    }
+
+    // we could use just string.split, but
+    // IE doesn't like returning empty strings
+    function split_newlines(s) {
+        //return s.split(/\x0d\x0a|\x0a/);
+
+        s = s.replace(/\x0d/g, '');
+        var out = [],
+            idx = s.indexOf("\n");
+        while (idx !== -1) {
+            out.push(s.substring(0, idx));
+            s = s.substring(idx + 1);
+            idx = s.indexOf("\n");
+        }
+        if (s.length) {
+            out.push(s);
+        }
+        return out;
+    }
+
+    function force_newline() {
+        var old_keep_array_indentation = opt_keep_array_indentation;
+        opt_keep_array_indentation = false;
+        print_newline();
+        opt_keep_array_indentation = old_keep_array_indentation;
+    }
+
+    function print_newline(ignore_repeated, reset_statement_flags) {
+
+        flags.eat_next_space = false;
+        if (opt_keep_array_indentation && is_array(flags.mode)) {
+            return;
+        }
+
+        ignore_repeated = typeof ignore_repeated === 'undefined' ? true : ignore_repeated;
+        reset_statement_flags = typeof reset_statement_flags === 'undefined' ? true : reset_statement_flags;
+
+        if (reset_statement_flags) {
+            flags.if_line = false;
+            flags.chain_extra_indentation = 0;
+        }
+
+        trim_output();
+
+        if (!output.length) {
+            return; // no newline on start of file
+        }
+
+        if (output[output.length - 1] !== "\n" || !ignore_repeated) {
+            just_added_newline = true;
+            output.push("\n");
+        }
+        if (preindent_string) {
+            output.push(preindent_string);
+        }
+        for (var i = 0; i < flags.indentation_level + flags.chain_extra_indentation; i += 1) {
+            output.push(indent_string);
+        }
+        if (flags.var_line && flags.var_line_reindented) {
+            output.push(indent_string); // skip space-stuffing, if indenting with a tab
+        }
+    }
+
+
+
+    function print_single_space() {
+
+        if (last_type === 'TK_COMMENT') {
+            return print_newline();
+        }
+        if (flags.eat_next_space) {
+            flags.eat_next_space = false;
+            return;
+        }
+        var last_output = ' ';
+        if (output.length) {
+            last_output = output[output.length - 1];
+        }
+        if (last_output !== ' ' && last_output !== '\n' && last_output !== indent_string) { // prevent occassional duplicate space
+            output.push(' ');
+        }
+    }
+
+
+    function print_token() {
+        just_added_newline = false;
+        flags.eat_next_space = false;
+        output.push(token_text);
+    }
+
+    function indent() {
+        flags.indentation_level += 1;
+    }
+
+
+    function remove_indent() {
+        if (output.length && output[output.length - 1] === indent_string) {
+            output.pop();
+        }
+    }
+
+    function set_mode(mode) {
+        if (flags) {
+            flag_store.push(flags);
+        }
+        flags = {
+            previous_mode: flags ? flags.mode : 'BLOCK',
+            mode: mode,
+            var_line: false,
+            var_line_tainted: false,
+            var_line_reindented: false,
+            in_html_comment: false,
+            if_line: false,
+            chain_extra_indentation: 0,
+            in_case_statement: false, // switch(..){ INSIDE HERE }
+            in_case: false, // we're on the exact line with "case 0:"
+            case_body: false, // the indented case-action block
+            eat_next_space: false,
+            indentation_level: (flags ? flags.indentation_level + ((flags.var_line && flags.var_line_reindented) ? 1 : 0) : 0),
+            ternary_depth: 0
+        };
+    }
+
+    function is_array(mode) {
+        return mode === '[EXPRESSION]' || mode === '[INDENTED-EXPRESSION]';
+    }
+
+    function is_expression(mode) {
+        return in_array(mode, ['[EXPRESSION]', '(EXPRESSION)', '(FOR-EXPRESSION)', '(COND-EXPRESSION)']);
+    }
+
+    function restore_mode() {
+        do_block_just_closed = flags.mode === 'DO_BLOCK';
+        if (flag_store.length > 0) {
+            var mode = flags.mode;
+            flags = flag_store.pop();
+            flags.previous_mode = mode;
+        }
+    }
+
+    function all_lines_start_with(lines, c) {
+        for (var i = 0; i < lines.length; i++) {
+            var line = trim(lines[i]);
+            if (line.charAt(0) !== c) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    function is_special_word(word) {
+        return in_array(word, ['case', 'return', 'do', 'if', 'throw', 'else']);
+    }
+
+    function in_array(what, arr) {
+        for (var i = 0; i < arr.length; i += 1) {
+            if (arr[i] === what) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    function look_up(exclude) {
+        var local_pos = parser_pos;
+        var c = input.charAt(local_pos);
+        while (in_array(c, whitespace) && c !== exclude) {
+            local_pos++;
+            if (local_pos >= input_length) {
+                return 0;
+            }
+            c = input.charAt(local_pos);
+        }
+        return c;
+    }
+
+    function get_next_token() {
+        var i;
+        var resulting_string;
+
+        n_newlines = 0;
+
+        if (parser_pos >= input_length) {
+            return ['', 'TK_EOF'];
+        }
+
+        wanted_newline = false;
+
+        var c = input.charAt(parser_pos);
+        parser_pos += 1;
+
+
+        var keep_whitespace = opt_keep_array_indentation && is_array(flags.mode);
+
+        if (keep_whitespace) {
+
+            var whitespace_count = 0;
+
+            while (in_array(c, whitespace)) {
+
+                if (c === "\n") {
+                    trim_output();
+                    output.push("\n");
+                    just_added_newline = true;
+                    whitespace_count = 0;
+                } else {
+                    if (c === '\t') {
+                        whitespace_count += 4;
+                    } else if (c === '\r') {
+                        // nothing
+                    } else {
+                        whitespace_count += 1;
+                    }
+                }
+
+                if (parser_pos >= input_length) {
+                    return ['', 'TK_EOF'];
+                }
+
+                c = input.charAt(parser_pos);
+                parser_pos += 1;
+
+            }
+
+            if (just_added_newline) {
+                for (i = 0; i < whitespace_count; i++) {
+                    output.push(' ');
+                }
+            }
+
+        } else {
+            while (in_array(c, whitespace)) {
+
+                if (c === "\n") {
+                    n_newlines += ((opt_max_preserve_newlines) ? (n_newlines <= opt_max_preserve_newlines) ? 1 : 0 : 1);
+                }
+
+
+                if (parser_pos >= input_length) {
+                    return ['', 'TK_EOF'];
+                }
+
+                c = input.charAt(parser_pos);
+                parser_pos += 1;
+
+            }
+
+            if (opt_preserve_newlines) {
+                if (n_newlines > 1) {
+                    for (i = 0; i < n_newlines; i += 1) {
+                        print_newline(i === 0);
+                        just_added_newline = true;
+                    }
+                }
+            }
+            wanted_newline = n_newlines > 0;
+        }
+
+
+        if (in_array(c, wordchar)) {
+            if (parser_pos < input_length) {
+                while (in_array(input.charAt(parser_pos), wordchar)) {
+                    c += input.charAt(parser_pos);
+                    parser_pos += 1;
+                    if (parser_pos === input_length) {
+                        break;
+                    }
+                }
+            }
+
+            // small and surprisingly unugly hack for 1E-10 representation
+            if (parser_pos !== input_length && c.match(/^[0-9]+[Ee]$/) && (input.charAt(parser_pos) === '-' || input.charAt(parser_pos) === '+')) {
+
+                var sign = input.charAt(parser_pos);
+                parser_pos += 1;
+
+                var t = get_next_token();
+                c += sign + t[0];
+                return [c, 'TK_WORD'];
+            }
+
+            if (c === 'in') { // hack for 'in' operator
+                return [c, 'TK_OPERATOR'];
+            }
+            if (wanted_newline && last_type !== 'TK_OPERATOR'
+                && last_type !== 'TK_EQUALS'
+                && !flags.if_line && (opt_preserve_newlines || last_text !== 'var')) {
+                print_newline();
+            }
+            return [c, 'TK_WORD'];
+        }
+
+        if (c === '(' || c === '[') {
+            return [c, 'TK_START_EXPR'];
+        }
+
+        if (c === ')' || c === ']') {
+            return [c, 'TK_END_EXPR'];
+        }
+
+        if (c === '{') {
+            return [c, 'TK_START_BLOCK'];
+        }
+
+        if (c === '}') {
+            return [c, 'TK_END_BLOCK'];
+        }
+
+        if (c === ';') {
+            return [c, 'TK_SEMICOLON'];
+        }
+
+        if (c === '/') {
+            var comment = '';
+            // peek for comment /* ... */
+            var inline_comment = true;
+            if (input.charAt(parser_pos) === '*') {
+                parser_pos += 1;
+                if (parser_pos < input_length) {
+                    while (parser_pos < input_length &&
+                        ! (input.charAt(parser_pos) === '*' && input.charAt(parser_pos + 1) && input.charAt(parser_pos + 1) === '/')) {
+                        c = input.charAt(parser_pos);
+                        comment += c;
+                        if (c === "\n" || c === "\r") {
+                            inline_comment = false;
+                        }
+                        parser_pos += 1;
+                        if (parser_pos >= input_length) {
+                            break;
+                        }
+                    }
+                }
+                parser_pos += 2;
+                if (inline_comment && n_newlines === 0) {
+                    return ['/*' + comment + '*/', 'TK_INLINE_COMMENT'];
+                } else {
+                    return ['/*' + comment + '*/', 'TK_BLOCK_COMMENT'];
+                }
+            }
+            // peek for comment // ...
+            if (input.charAt(parser_pos) === '/') {
+                comment = c;
+                while (input.charAt(parser_pos) !== '\r' && input.charAt(parser_pos) !== '\n') {
+                    comment += input.charAt(parser_pos);
+                    parser_pos += 1;
+                    if (parser_pos >= input_length) {
+                        break;
+                    }
+                }
+                if (wanted_newline) {
+                    print_newline();
+                }
+                return [comment, 'TK_COMMENT'];
+            }
+
+        }
+
+        if (c === "'" || // string
+        c === '"' || // string
+        (c === '/' &&
+            ((last_type === 'TK_WORD' && is_special_word(last_text)) ||
+                (last_text === ')' && in_array(flags.previous_mode, ['(COND-EXPRESSION)', '(FOR-EXPRESSION)'])) ||
+                (last_type === 'TK_COMMA' || last_type === 'TK_COMMENT' || last_type === 'TK_START_EXPR' || last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK' || last_type === 'TK_OPERATOR' || last_type === 'TK_EQUALS' || last_type === 'TK_EOF' || last_type === 'TK_SEMICOLON')))) { // regexp
+            var sep = c;
+            var esc = false;
+            var esc1 = 0;
+            var esc2 = 0;
+            resulting_string = c;
+
+            if (parser_pos < input_length) {
+                if (sep === '/') {
+                    //
+                    // handle regexp separately...
+                    //
+                    var in_char_class = false;
+                    while (esc || in_char_class || input.charAt(parser_pos) !== sep) {
+                        resulting_string += input.charAt(parser_pos);
+                        if (!esc) {
+                            esc = input.charAt(parser_pos) === '\\';
+                            if (input.charAt(parser_pos) === '[') {
+                                in_char_class = true;
+                            } else if (input.charAt(parser_pos) === ']') {
+                                in_char_class = false;
+                            }
+                        } else {
+                            esc = false;
+                        }
+                        parser_pos += 1;
+                        if (parser_pos >= input_length) {
+                            // incomplete string/rexp when end-of-file reached.
+                            // bail out with what had been received so far.
+                            return [resulting_string, 'TK_STRING'];
+                        }
+                    }
+
+                } else {
+                    //
+                    // and handle string also separately
+                    //
+                    while (esc || input.charAt(parser_pos) !== sep) {
+                        resulting_string += input.charAt(parser_pos);
+                        if (esc1 && esc1 >= esc2) {
+                            esc1 = parseInt(resulting_string.substr(-esc2), 16);
+                            if (esc1 && esc1 >= 0x20 && esc1 <= 0x7e) {
+                                esc1 = String.fromCharCode(esc1);
+                                resulting_string = resulting_string.substr(0, resulting_string.length - esc2 - 2) + (((esc1 === sep) || (esc1 === '\\')) ? '\\' : '') + esc1;
+                            }
+                            esc1 = 0;
+                        }
+                        if (esc1) {
+                            esc1++;
+                        } else if (!esc) {
+                            esc = input.charAt(parser_pos) === '\\';
+                        } else {
+                            esc = false;
+                            if (opt_unescape_strings) {
+                                if (input.charAt(parser_pos) === 'x') {
+                                    esc1++;
+                                    esc2 = 2;
+                                } else if (input.charAt(parser_pos) === 'u') {
+                                    esc1++;
+                                    esc2 = 4;
+                                }
+                            }
+                        }
+                        parser_pos += 1;
+                        if (parser_pos >= input_length) {
+                            // incomplete string/rexp when end-of-file reached.
+                            // bail out with what had been received so far.
+                            return [resulting_string, 'TK_STRING'];
+                        }
+                    }
+                }
+
+
+
+            }
+
+            parser_pos += 1;
+
+            resulting_string += sep;
+
+            if (sep === '/') {
+                // regexps may have modifiers /regexp/MOD , so fetch those, too
+                while (parser_pos < input_length && in_array(input.charAt(parser_pos), wordchar)) {
+                    resulting_string += input.charAt(parser_pos);
+                    parser_pos += 1;
+                }
+            }
+            return [resulting_string, 'TK_STRING'];
+        }
+
+        if (c === '#') {
+
+
+            if (output.length === 0 && input.charAt(parser_pos) === '!') {
+                // shebang
+                resulting_string = c;
+                while (parser_pos < input_length && c !== '\n') {
+                    c = input.charAt(parser_pos);
+                    resulting_string += c;
+                    parser_pos += 1;
+                }
+                output.push(trim(resulting_string) + '\n');
+                print_newline();
+                return get_next_token();
+            }
+
+
+
+            // Spidermonkey-specific sharp variables for circular references
+            // https://developer.mozilla.org/En/Sharp_variables_in_JavaScript
+            // https://mxr.mozilla.org/mozilla-central/source/js/src/jsscan.cpp around line 1935
+            var sharp = '#';
+            if (parser_pos < input_length && in_array(input.charAt(parser_pos), digits)) {
+                do {
+                    c = input.charAt(parser_pos);
+                    sharp += c;
+                    parser_pos += 1;
+                } while (parser_pos < input_length && c !== '#' && c !== '=');
+                if (c === '#') {
+                    //
+                } else if (input.charAt(parser_pos) === '[' && input.charAt(parser_pos + 1) === ']') {
+                    sharp += '[]';
+                    parser_pos += 2;
+                } else if (input.charAt(parser_pos) === '{' && input.charAt(parser_pos + 1) === '}') {
+                    sharp += '{}';
+                    parser_pos += 2;
+                }
+                return [sharp, 'TK_WORD'];
+            }
+        }
+
+        if (c === '<' && input.substring(parser_pos - 1, parser_pos + 3) === '') {
+            flags.in_html_comment = false;
+            parser_pos += 2;
+            if (wanted_newline) {
+                print_newline();
+            }
+            return ['-->', 'TK_COMMENT'];
+        }
+
+        if (c === '.') {
+            return [c, 'TK_DOT'];
+        }
+
+        if (in_array(c, punct)) {
+            while (parser_pos < input_length && in_array(c + input.charAt(parser_pos), punct)) {
+                c += input.charAt(parser_pos);
+                parser_pos += 1;
+                if (parser_pos >= input_length) {
+                    break;
+                }
+            }
+
+            if (c === ',') {
+                return [c, 'TK_COMMA'];
+            } else if (c === '=') {
+                return [c, 'TK_EQUALS'];
+            } else {
+                return [c, 'TK_OPERATOR'];
+            }
+        }
+
+        return [c, 'TK_UNKNOWN'];
+    }
+
+    //----------------------------------
+    indent_string = '';
+    while (opt_indent_size > 0) {
+        indent_string += opt_indent_char;
+        opt_indent_size -= 1;
+    }
+
+    while (js_source_text && (js_source_text.charAt(0) === ' ' || js_source_text.charAt(0) === '\t')) {
+        preindent_string += js_source_text.charAt(0);
+        js_source_text = js_source_text.substring(1);
+    }
+    input = js_source_text;
+
+    last_word = ''; // last 'TK_WORD' passed
+    last_type = 'TK_START_EXPR'; // last token type
+    last_text = ''; // last token text
+    last_last_text = ''; // pre-last token text
+    output = [];
+
+    do_block_just_closed = false;
+
+    whitespace = "\n\r\t ".split('');
+    wordchar = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$'.split('');
+    digits = '0123456789'.split('');
+
+    punct = '+ - * / % & ++ -- = += -= *= /= %= == === != !== > < >= <= >> << >>> >>>= >>= <<= && &= | || ! !! , : ? ^ ^= |= ::';
+    punct += ' <%= <% %> '; // try to be a good boy and try not to break the markup language identifiers
+    punct = punct.split(' ');
+
+    // words which should always start on new line.
+    line_starters = 'continue,try,throw,return,var,if,switch,case,default,for,while,break,function'.split(',');
+
+    // states showing if we are currently in expression (i.e. "if" case) - 'EXPRESSION', or in usual block (like, procedure), 'BLOCK'.
+    // some formatting depends on that.
+    flag_store = [];
+    set_mode('BLOCK');
+
+    parser_pos = 0;
+    while (true) {
+        var t = get_next_token();
+        token_text = t[0];
+        token_type = t[1];
+        if (token_type === 'TK_EOF') {
+            break;
+        }
+
+        switch (token_type) {
+
+        case 'TK_START_EXPR':
+
+            if (token_text === '[') {
+
+                if (last_type === 'TK_WORD' || last_text === ')') {
+                    // this is array index specifier, break immediately
+                    // a[x], fn()[x]
+                    if (in_array(last_text, line_starters)) {
+                        print_single_space();
+                    }
+                    set_mode('(EXPRESSION)');
+                    print_token();
+                    break;
+                }
+
+                if (flags.mode === '[EXPRESSION]' || flags.mode === '[INDENTED-EXPRESSION]') {
+                    if (last_last_text === ']' && last_text === ',') {
+                        // ], [ goes to new line
+                        if (flags.mode === '[EXPRESSION]') {
+                            flags.mode = '[INDENTED-EXPRESSION]';
+                            if (!opt_keep_array_indentation) {
+                                indent();
+                            }
+                        }
+                        set_mode('[EXPRESSION]');
+                        if (!opt_keep_array_indentation) {
+                            print_newline();
+                        }
+                    } else if (last_text === '[') {
+                        if (flags.mode === '[EXPRESSION]') {
+                            flags.mode = '[INDENTED-EXPRESSION]';
+                            if (!opt_keep_array_indentation) {
+                                indent();
+                            }
+                        }
+                        set_mode('[EXPRESSION]');
+
+                        if (!opt_keep_array_indentation) {
+                            print_newline();
+                        }
+                    } else {
+                        set_mode('[EXPRESSION]');
+                    }
+                } else {
+                    set_mode('[EXPRESSION]');
+                }
+
+
+
+            } else {
+                if (last_word === 'for') {
+                    set_mode('(FOR-EXPRESSION)');
+                } else if (in_array(last_word, ['if', 'while'])) {
+                    set_mode('(COND-EXPRESSION)');
+                } else {
+                    set_mode('(EXPRESSION)');
+                }
+            }
+
+            if (last_text === ';' || last_type === 'TK_START_BLOCK') {
+                print_newline();
+            } else if (last_type === 'TK_END_EXPR' || last_type === 'TK_START_EXPR' || last_type === 'TK_END_BLOCK' || last_text === '.') {
+                if (wanted_newline) {
+                    print_newline();
+                }
+                // do nothing on (( and )( and ][ and ]( and .(
+            } else if (last_type !== 'TK_WORD' && last_type !== 'TK_OPERATOR') {
+                print_single_space();
+            } else if (last_word === 'function' || last_word === 'typeof') {
+                // function() vs function ()
+                if (opt_jslint_happy) {
+                    print_single_space();
+                }
+            } else if (in_array(last_text, line_starters) || last_text === 'catch') {
+                if (opt_space_before_conditional) {
+                    print_single_space();
+                }
+            }
+            print_token();
+
+            break;
+
+        case 'TK_DOT':
+
+            if (is_special_word(last_text)) {
+                print_single_space();
+            } else if (last_text === ')') {
+                if (opt_break_chained_methods || wanted_newline) {
+                    flags.chain_extra_indentation = 1;
+                    print_newline(true /* ignore_repeated */, false /* reset_statement_flags */);
+                }
+            }
+
+            print_token();
+            break;
+
+        case 'TK_END_EXPR':
+            if (token_text === ']') {
+                if (opt_keep_array_indentation) {
+                    if (last_text === '}') {
+                        // trim_output();
+                        // print_newline(true);
+                        remove_indent();
+                        print_token();
+                        restore_mode();
+                        break;
+                    }
+                } else {
+                    if (flags.mode === '[INDENTED-EXPRESSION]') {
+                        if (last_text === ']') {
+                            restore_mode();
+                            print_newline();
+                            print_token();
+                            break;
+                        }
+                    }
+                }
+            }
+            restore_mode();
+            print_token();
+            break;
+
+        case 'TK_START_BLOCK':
+
+            if (last_word === 'do') {
+                set_mode('DO_BLOCK');
+            } else {
+                set_mode('BLOCK');
+            }
+            if (opt_brace_style === "expand" || opt_brace_style === "expand-strict") {
+                var empty_braces = false;
+                if (opt_brace_style === "expand-strict") {
+                    empty_braces = (look_up() === '}');
+                    if (!empty_braces) {
+                        print_newline(true);
+                    }
+                } else {
+                    if (last_type !== 'TK_OPERATOR') {
+                        if (last_text === '=' || (is_special_word(last_text) && last_text !== 'else')) {
+                            print_single_space();
+                        } else {
+                            print_newline(true);
+                        }
+                    }
+                }
+                print_token();
+                if (!empty_braces) {
+                    indent();
+                }
+            } else {
+                if (last_type !== 'TK_OPERATOR' && last_type !== 'TK_START_EXPR') {
+                    if (last_type === 'TK_START_BLOCK') {
+                        print_newline();
+                    } else {
+                        print_single_space();
+                    }
+                } else {
+                    // if TK_OPERATOR or TK_START_EXPR
+                    if (is_array(flags.previous_mode) && last_text === ',') {
+                        if (last_last_text === '}') {
+                            // }, { in array context
+                            print_single_space();
+                        } else {
+                            print_newline(); // [a, b, c, {
+                        }
+                    }
+                }
+                indent();
+                print_token();
+            }
+
+            break;
+
+        case 'TK_END_BLOCK':
+            restore_mode();
+            if (opt_brace_style === "expand" || opt_brace_style === "expand-strict") {
+                if (last_text !== '{') {
+                    print_newline();
+                }
+                print_token();
+            } else {
+                if (last_type === 'TK_START_BLOCK') {
+                    // nothing
+                    if (just_added_newline) {
+                        remove_indent();
+                    } else {
+                        // {}
+                        trim_output();
+                    }
+                } else {
+                    if (is_array(flags.mode) && opt_keep_array_indentation) {
+                        // we REALLY need a newline here, but newliner would skip that
+                        opt_keep_array_indentation = false;
+                        print_newline();
+                        opt_keep_array_indentation = true;
+
+                    } else {
+                        print_newline();
+                    }
+                }
+                print_token();
+            }
+            break;
+
+        case 'TK_WORD':
+
+            // no, it's not you. even I have problems understanding how this works
+            // and what does what.
+            if (do_block_just_closed) {
+                // do {} ## while ()
+                print_single_space();
+                print_token();
+                print_single_space();
+                do_block_just_closed = false;
+                break;
+            }
+
+            prefix = 'NONE';
+
+            if (token_text === 'function') {
+                if (flags.var_line && last_type !== 'TK_EQUALS' ) {
+                    flags.var_line_reindented = true;
+                }
+                if ((just_added_newline || last_text === ';') && last_text !== '{'
+                && last_type !== 'TK_BLOCK_COMMENT' && last_type !== 'TK_COMMENT') {
+                    // make sure there is a nice clean space of at least one blank line
+                    // before a new function definition
+                    n_newlines = just_added_newline ? n_newlines : 0;
+                    if (!opt_preserve_newlines) {
+                        n_newlines = 1;
+                    }
+
+                    for (var i = 0; i < 2 - n_newlines; i++) {
+                        print_newline(false);
+                    }
+                }
+                if (last_type === 'TK_WORD') {
+                    if (last_text === 'get' || last_text === 'set' || last_text === 'new' || last_text === 'return') {
+                        print_single_space();
+                    } else {
+                        print_newline();
+                    }
+                } else if (last_type === 'TK_OPERATOR' || last_text === '=') {
+                    // foo = function
+                    print_single_space();
+                } else if (is_expression(flags.mode)) {
+                    // print nothing
+                } else {
+                    print_newline();
+                }
+
+                print_token();
+                last_word = token_text;
+                break;
+            }
+
+            if (token_text === 'case' || (token_text === 'default' && flags.in_case_statement)) {
+                print_newline();
+                if (flags.case_body) {
+                    // switch cases following one another
+                    flags.indentation_level--;
+                    flags.case_body = false;
+                    remove_indent();
+                }
+                print_token();
+                flags.in_case = true;
+                flags.in_case_statement = true;
+                break;
+            }
+
+            if (last_type === 'TK_END_BLOCK') {
+
+                if (!in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) {
+                    prefix = 'NEWLINE';
+                } else {
+                    if (opt_brace_style === "expand" || opt_brace_style === "end-expand" || opt_brace_style === "expand-strict") {
+                        prefix = 'NEWLINE';
+                    } else {
+                        prefix = 'SPACE';
+                        print_single_space();
+                    }
+                }
+            } else if (last_type === 'TK_SEMICOLON' && (flags.mode === 'BLOCK' || flags.mode === 'DO_BLOCK')) {
+                prefix = 'NEWLINE';
+            } else if (last_type === 'TK_SEMICOLON' && is_expression(flags.mode)) {
+                prefix = 'SPACE';
+            } else if (last_type === 'TK_STRING') {
+                prefix = 'NEWLINE';
+            } else if (last_type === 'TK_WORD') {
+                if (last_text === 'else') {
+                    // eat newlines between ...else *** some_op...
+                    // won't preserve extra newlines in this place (if any), but don't care that much
+                    trim_output(true);
+                }
+                prefix = 'SPACE';
+            } else if (last_type === 'TK_START_BLOCK') {
+                prefix = 'NEWLINE';
+            } else if (last_type === 'TK_END_EXPR') {
+                print_single_space();
+                prefix = 'NEWLINE';
+            }
+
+            if (in_array(token_text, line_starters) && last_text !== ')') {
+                if (last_text === 'else') {
+                    prefix = 'SPACE';
+                } else {
+                    prefix = 'NEWLINE';
+                }
+
+            }
+
+            if (flags.if_line && last_type === 'TK_END_EXPR') {
+                flags.if_line = false;
+            }
+            if (in_array(token_text.toLowerCase(), ['else', 'catch', 'finally'])) {
+                if (last_type !== 'TK_END_BLOCK' || opt_brace_style === "expand" || opt_brace_style === "end-expand" || opt_brace_style === "expand-strict") {
+                    print_newline();
+                } else {
+                    trim_output(true);
+                    print_single_space();
+                }
+            } else if (prefix === 'NEWLINE') {
+                if (is_special_word(last_text)) {
+                    // no newline between 'return nnn'
+                    print_single_space();
+                } else if (last_type !== 'TK_END_EXPR') {
+                    if ((last_type !== 'TK_START_EXPR' || token_text !== 'var') && last_text !== ':') {
+                        // no need to force newline on 'var': for (var x = 0...)
+                        if (token_text === 'if' && last_word === 'else' && last_text !== '{') {
+                            // no newline for } else if {
+                            print_single_space();
+                        } else {
+                            flags.var_line = false;
+                            flags.var_line_reindented = false;
+                            print_newline();
+                        }
+                    }
+                } else if (in_array(token_text, line_starters) && last_text !== ')') {
+                    flags.var_line = false;
+                    flags.var_line_reindented = false;
+                    print_newline();
+                }
+            } else if (is_array(flags.mode) && last_text === ',' && last_last_text === '}') {
+                print_newline(); // }, in lists get a newline treatment
+            } else if (prefix === 'SPACE') {
+                print_single_space();
+            }
+            print_token();
+            last_word = token_text;
+
+            if (token_text === 'var') {
+                flags.var_line = true;
+                flags.var_line_reindented = false;
+                flags.var_line_tainted = false;
+            }
+
+            if (token_text === 'if') {
+                flags.if_line = true;
+            }
+            if (token_text === 'else') {
+                flags.if_line = false;
+            }
+
+            break;
+
+        case 'TK_SEMICOLON':
+
+            print_token();
+            flags.var_line = false;
+            flags.var_line_reindented = false;
+            if (flags.mode === 'OBJECT') {
+                // OBJECT mode is weird and doesn't get reset too well.
+                flags.mode = 'BLOCK';
+            }
+            break;
+
+        case 'TK_STRING':
+
+            if (last_type === 'TK_END_EXPR' && in_array(flags.previous_mode, ['(COND-EXPRESSION)', '(FOR-EXPRESSION)'])) {
+                print_single_space();
+            } else if (last_type === 'TK_COMMENT' || last_type === 'TK_STRING' || last_type === 'TK_START_BLOCK' || last_type === 'TK_END_BLOCK' || last_type === 'TK_SEMICOLON') {
+                print_newline();
+            } else if (last_type === 'TK_WORD') {
+                print_single_space();
+            } else {
+                if (opt_preserve_newlines && wanted_newline) {
+                    print_newline();
+                    output.push(indent_string);
+                }
+            }
+            print_token();
+            break;
+
+        case 'TK_EQUALS':
+            if (flags.var_line) {
+                // just got an '=' in a var-line, different formatting/line-breaking, etc will now be done
+                flags.var_line_tainted = true;
+            }
+            print_single_space();
+            print_token();
+            print_single_space();
+            break;
+
+        case 'TK_COMMA':
+            if (flags.var_line) {
+                if (is_expression(flags.mode) || last_type === 'TK_END_BLOCK' ) {
+                    // do not break on comma, for(var a = 1, b = 2)
+                    flags.var_line_tainted = false;
+                }
+                if (flags.var_line_tainted) {
+                    print_token();
+                    flags.var_line_reindented = true;
+                    flags.var_line_tainted = false;
+                    print_newline();
+                    break;
+                } else {
+                    flags.var_line_tainted = false;
+                }
+
+                print_token();
+                print_single_space();
+                break;
+            }
+
+            if (last_type === 'TK_COMMENT') {
+                print_newline();
+            }
+
+            if (last_type === 'TK_END_BLOCK' && flags.mode !== "(EXPRESSION)") {
+                print_token();
+                if (flags.mode === 'OBJECT' && last_text === '}') {
+                    print_newline();
+                } else {
+                    print_single_space();
+                }
+            } else {
+                if (flags.mode === 'OBJECT') {
+                    print_token();
+                    print_newline();
+                } else {
+                    // EXPR or DO_BLOCK
+                    print_token();
+                    print_single_space();
+                }
+            }
+            break;
+
+
+        case 'TK_OPERATOR':
+
+            var space_before = true;
+            var space_after = true;
+            if (is_special_word(last_text)) {
+                // "return" had a special handling in TK_WORD. Now we need to return the favor
+                print_single_space();
+                print_token();
+                break;
+            }
+
+            // hack for actionscript's import .*;
+            if (token_text === '*' && last_type === 'TK_DOT' && !last_last_text.match(/^\d+$/)) {
+                print_token();
+                break;
+            }
+
+            if (token_text === ':' && flags.in_case) {
+                flags.case_body = true;
+                indent();
+                print_token();
+                print_newline();
+                flags.in_case = false;
+                break;
+            }
+
+            if (token_text === '::') {
+                // no spaces around exotic namespacing syntax operator
+                print_token();
+                break;
+            }
+
+            if (in_array(token_text, ['--', '++', '!']) || (in_array(token_text, ['-', '+']) && (in_array(last_type, ['TK_START_BLOCK', 'TK_START_EXPR', 'TK_EQUALS', 'TK_OPERATOR']) || in_array(last_text, line_starters) || last_text == ','))) {
+                // unary operators (and binary +/- pretending to be unary) special cases
+
+                space_before = false;
+                space_after = false;
+
+                if (last_text === ';' && is_expression(flags.mode)) {
+                    // for (;; ++i)
+                    //        ^^^
+                    space_before = true;
+                }
+                if (last_type === 'TK_WORD' && in_array(last_text, line_starters)) {
+                    space_before = true;
+                }
+
+                if (flags.mode === 'BLOCK' && (last_text === '{' || last_text === ';')) {
+                    // { foo; --i }
+                    // foo(); --bar;
+                    print_newline();
+                }
+            } else if (token_text === ':') {
+                if (flags.ternary_depth === 0) {
+                    if (flags.mode === 'BLOCK') {
+                        flags.mode = 'OBJECT';
+                    }
+                    space_before = false;
+                } else {
+                    flags.ternary_depth -= 1;
+                }
+            } else if (token_text === '?') {
+                flags.ternary_depth += 1;
+            }
+            if (space_before) {
+                print_single_space();
+            }
+
+            print_token();
+
+            if (space_after) {
+                print_single_space();
+            }
+
+            break;
+
+        case 'TK_BLOCK_COMMENT':
+
+            var lines = split_newlines(token_text);
+            var j; // iterator for this case
+
+            if (all_lines_start_with(lines.slice(1), '*')) {
+                // javadoc: reformat and reindent
+                print_newline();
+                output.push(lines[0]);
+                for (j = 1; j < lines.length; j++) {
+                    print_newline();
+                    output.push(' ');
+                    output.push(trim(lines[j]));
+                }
+
+            } else {
+
+                // simple block comment: leave intact
+                if (lines.length > 1) {
+                    // multiline comment block starts with a new line
+                    print_newline();
+                } else {
+                    // single-line /* comment */ stays where it is
+                    if (last_type === 'TK_END_BLOCK') {
+                        print_newline();
+                    } else {
+                        print_single_space();
+                    }
+
+                }
+
+                for (j = 0; j < lines.length; j++) {
+                    output.push(lines[j]);
+                    output.push("\n");
+                }
+
+            }
+            if (look_up('\n') !== '\n') {
+                print_newline();
+            }
+            break;
+
+        case 'TK_INLINE_COMMENT':
+            print_single_space();
+            print_token();
+            if (is_expression(flags.mode)) {
+                print_single_space();
+            } else {
+                force_newline();
+            }
+            break;
+
+        case 'TK_COMMENT':
+
+            if (last_text === ',' && !wanted_newline) {
+                trim_output(true);
+            }
+            if (last_type !== 'TK_COMMENT') {
+                if (wanted_newline) {
+                    print_newline();
+                } else {
+                    print_single_space();
+                }
+            }
+            print_token();
+            print_newline();
+            break;
+
+        case 'TK_UNKNOWN':
+            print_token();
+            break;
+        }
+
+        last_last_text = last_text;
+        last_type = token_type;
+        last_text = token_text;
+    }
+
+    var sweet_code = preindent_string + output.join('').replace(/[\r\n ]+$/, '');
+    return sweet_code;
+
+  }
+
+  // Add support for CommonJS. Just put this file somewhere on your require.paths
+  // and you will be able to `var js_beautify = require("beautify").js_beautify`.
+  // if (typeof exports !== "undefined") {
+  //   exports.js_beautify = js_beautify;
+  // }
+
+  var SimplyBeautiful = function () {
+    var ret = {};
+    ret.js = function(content, options) {
+      options = options || {};
+      options.indent_size = typeof options.indent_size !== 'undefined' ? options.indent_size : 4;
+      options.space_before_conditional = typeof options.space_before_conditional !== 'undefined' ? options.space_before_conditional : true;
+      options.jslint_happy = typeof options.jslint_happy !== 'undefined' ? options.jslint_happy : true;
+      options.max_char = typeof options.max_char !== 'undefined' ? options.max_char : 0;
+      return js_beautify(content, options);
+    }
+    ret.html = function(content, options) {
+      options = options || {};
+      options.indent_size = typeof options.indent_size !== 'undefined' ? options.indent_size : 4;
+      options.max_char = typeof options.max_char !== 'undefined' ? options.max_char : 0;
+      return style_html(content, options);
+    }
+    ret.css = function(content, options) {
+      options = options || {};
+      options.indent_size = typeof options.indent_size !== 'undefined' ? options.indent_size : 4;
+      options.max_char = typeof options.max_char !== 'undefined' ? options.max_char : 0;
+      return css_beautify(content, options);
+    }
+    ret.json = ret.js;
+    ret.javascript = ret.js;
+    return ret;
+  };
+
+  if (environment == 'browser') {
+    try {
+      window.SimplyBeautiful = SimplyBeautiful;
+    } catch (e) {
+    }
+  }
+  // Just return a value to define the module export.
+  // This example returns an object, but the module
+  // can return a function as the exported value.
+  return SimplyBeautiful(); // Enable if using UMD
+
+}));
+
+
 /***/ }),
 
 /***/ "./node_modules/tippy.js/dist/tippy.esm.js":
@@ -41669,12 +43587,16 @@ function getMarkRange($pos, type, attributes = {}) {
         return;
     }
     let start = $pos.parent.childAfter($pos.parentOffset);
-    if ($pos.parentOffset === start.offset && start.offset !== 0) {
+    // If the cursor is at the start of a text node that does not have the mark, look backward
+    if (!start.node || !start.node.marks.some(mark => mark.type === type)) {
         start = $pos.parent.childBefore($pos.parentOffset);
     }
-    if (!start.node) {
+    // If there is no text node with the mark even backward, return undefined
+    if (!start.node || !start.node.marks.some(mark => mark.type === type)) {
         return;
     }
+    // We now know that the cursor is either at the start, middle or end of a text node with the specified mark
+    // so we can look it up on the targeted mark
     const mark = findMarkInSet([...start.node.marks], type, attributes);
     if (!mark) {
         return;
@@ -41964,7 +43886,7 @@ const insertContentAt = (position, value, options) => ({ tr, dispatch, editor })
     var _a;
     if (dispatch) {
         options = {
-            parseOptions: {},
+            parseOptions: editor.options.parseOptions,
             updateSelection: true,
             applyInputRules: false,
             applyPasteRules: false,
@@ -41985,7 +43907,9 @@ const insertContentAt = (position, value, options) => ({ tr, dispatch, editor })
                 editor,
                 error: e,
                 disableCollaboration: () => {
-                    console.error('[tiptap error]: Unable to disable collaboration at this point in time');
+                    if (editor.storage.collaboration) {
+                        editor.storage.collaboration.isDisabled = true;
+                    }
                 },
             });
             return false;
@@ -43964,7 +45888,8 @@ class NodePos {
         const children = [];
         this.node.content.forEach((node, offset) => {
             const isBlock = node.isBlock && !node.isTextblock;
-            const targetPos = this.pos + offset + 1;
+            const isNonTextAtom = node.isAtom && !node.isText;
+            const targetPos = this.pos + offset + (isNonTextAtom ? 0 : 1);
             const $pos = this.resolvedPos.doc.resolve(targetPos);
             if (!isBlock && $pos.depth <= this.depth) {
                 return;
@@ -44040,9 +45965,12 @@ class NodePos {
         return nodes;
     }
     setAttribute(attributes) {
-        const oldSelection = this.editor.state.selection;
-        this.editor.chain().setTextSelection(this.from).updateAttributes(this.node.type.name, attributes).setTextSelection(oldSelection.from)
-            .run();
+        const { tr } = this.editor.state;
+        tr.setNodeMarkup(this.from, undefined, {
+            ...this.node.attrs,
+            ...attributes,
+        });
+        this.editor.view.dispatch(tr);
     }
 }
 
@@ -44294,18 +46222,27 @@ class Editor extends EventEmitter {
     /**
      * Unregister a ProseMirror plugin.
      *
-     * @param nameOrPluginKey The plugins name
+     * @param nameOrPluginKeyToRemove The plugins name
      * @returns The new editor state or undefined if the editor is destroyed
      */
-    unregisterPlugin(nameOrPluginKey) {
+    unregisterPlugin(nameOrPluginKeyToRemove) {
         if (this.isDestroyed) {
             return undefined;
         }
-        // @ts-ignore
-        const name = typeof nameOrPluginKey === 'string' ? `${nameOrPluginKey}$` : nameOrPluginKey.key;
-        const state = this.state.reconfigure({
+        const prevPlugins = this.state.plugins;
+        let plugins = prevPlugins;
+        [].concat(nameOrPluginKeyToRemove).forEach(nameOrPluginKey => {
             // @ts-ignore
-            plugins: this.state.plugins.filter(plugin => !plugin.key.startsWith(name)),
+            const name = typeof nameOrPluginKey === 'string' ? `${nameOrPluginKey}$` : nameOrPluginKey.key;
+            // @ts-ignore
+            plugins = prevPlugins.filter(plugin => !plugin.key.startsWith(name));
+        });
+        if (prevPlugins.length === plugins.length) {
+            // No plugin was removed, so we don’t need to update the state
+            return undefined;
+        }
+        const state = this.state.reconfigure({
+            plugins,
         });
         this.view.updateState(state);
         return state;
@@ -44368,6 +46305,9 @@ class Editor extends EventEmitter {
                 editor: this,
                 error: e,
                 disableCollaboration: () => {
+                    if (this.storage.collaboration) {
+                        this.storage.collaboration.isDisabled = true;
+                    }
                     // To avoid syncing back invalid content, reinitialize the extensions without the collaboration extension
                     this.options.extensions = this.options.extensions.filter(extension => extension.name !== 'collaboration');
                     // Restart the initialization process by recreating the extension manager with the new set of extensions
@@ -44386,6 +46326,12 @@ class Editor extends EventEmitter {
                 selection: selection || undefined,
             }),
         });
+        // add `role="textbox"` to the editor element
+        this.view.dom.setAttribute('role', 'textbox');
+        // add aria-label to the editor element
+        if (!this.view.dom.getAttribute('aria-label')) {
+            this.view.dom.setAttribute('aria-label', 'Rich-Text Editor');
+        }
         // `editor.view` is not yet available at this time.
         // Therefore we will add all plugins and node views directly afterwards.
         const newState = this.state.reconfigure({
@@ -45319,6 +47265,10 @@ const Bold = _tiptap_core__WEBPACK_IMPORTED_MODULE_0__.Mark.create({
                 tag: 'b',
                 getAttrs: node => node.style.fontWeight !== 'normal' && null,
             },
+            {
+                style: 'font-weight=400',
+                clearMark: mark => mark.type.name === this.name,
+            },
             {
                 style: 'font-weight',
                 getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value) && null,
@@ -45626,13 +47576,11 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export */   "default": () => (/* binding */ BulletList),
 /* harmony export */   inputRegex: () => (/* binding */ inputRegex)
 /* harmony export */ });
-/* harmony import */ var _tiptap_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tiptap/core */ "./node_modules/@tiptap/core/dist/index.js");
-/* harmony import */ var _tiptap_extension_list_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tiptap/extension-list-item */ "./node_modules/@tiptap/extension-list-item/dist/index.js");
-/* harmony import */ var _tiptap_extension_text_style__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tiptap/extension-text-style */ "./node_modules/@tiptap/extension-text-style/dist/index.js");
-
-
+/* harmony import */ var _tiptap_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tiptap/core */ "./node_modules/@tiptap/core/dist/index.js");
 
 
+const ListItemName = 'listItem';
+const TextStyleName = 'textStyle';
 /**
  * Matches a bullet list to a dash or asterisk.
  */
@@ -45643,7 +47591,7 @@ const inputRegex = /^\s*([-+*])\s$/;
  * @see https://tiptap.dev/api/nodes/bullet-list
  * @see https://tiptap.dev/api/nodes/list-item.
  */
-const BulletList = _tiptap_core__WEBPACK_IMPORTED_MODULE_2__.Node.create({
+const BulletList = _tiptap_core__WEBPACK_IMPORTED_MODULE_0__.Node.create({
     name: 'bulletList',
     addOptions() {
         return {
@@ -45663,13 +47611,13 @@ const BulletList = _tiptap_core__WEBPACK_IMPORTED_MODULE_2__.Node.create({
         ];
     },
     renderHTML({ HTMLAttributes }) {
-        return ['ul', (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_2__.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes), 0];
+        return ['ul', (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_0__.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes), 0];
     },
     addCommands() {
         return {
             toggleBulletList: () => ({ commands, chain }) => {
                 if (this.options.keepAttributes) {
-                    return chain().toggleList(this.name, this.options.itemTypeName, this.options.keepMarks).updateAttributes(_tiptap_extension_list_item__WEBPACK_IMPORTED_MODULE_0__.ListItem.name, this.editor.getAttributes(_tiptap_extension_text_style__WEBPACK_IMPORTED_MODULE_1__.TextStyle.name)).run();
+                    return chain().toggleList(this.name, this.options.itemTypeName, this.options.keepMarks).updateAttributes(ListItemName, this.editor.getAttributes(TextStyleName)).run();
                 }
                 return commands.toggleList(this.name, this.options.itemTypeName, this.options.keepMarks);
             },
@@ -45681,17 +47629,17 @@ const BulletList = _tiptap_core__WEBPACK_IMPORTED_MODULE_2__.Node.create({
         };
     },
     addInputRules() {
-        let inputRule = (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_2__.wrappingInputRule)({
+        let inputRule = (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_0__.wrappingInputRule)({
             find: inputRegex,
             type: this.type,
         });
         if (this.options.keepMarks || this.options.keepAttributes) {
-            inputRule = (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_2__.wrappingInputRule)({
+            inputRule = (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_0__.wrappingInputRule)({
                 find: inputRegex,
                 type: this.type,
                 keepMarks: this.options.keepMarks,
                 keepAttributes: this.options.keepAttributes,
-                getAttributes: () => { return this.editor.getAttributes(_tiptap_extension_text_style__WEBPACK_IMPORTED_MODULE_1__.TextStyle.name); },
+                getAttributes: () => { return this.editor.getAttributes(TextStyleName); },
                 editor: this.editor,
             });
         }
@@ -49724,6 +51672,10 @@ const Italic = _tiptap_core__WEBPACK_IMPORTED_MODULE_0__.Mark.create({
                 tag: 'i',
                 getAttrs: node => node.style.fontStyle !== 'normal' && null,
             },
+            {
+                style: 'font-style=normal',
+                clearMark: mark => mark.type.name === this.name,
+            },
             {
                 style: 'font-style=italic',
             },
@@ -50223,13 +52175,11 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony export */   "default": () => (/* binding */ OrderedList),
 /* harmony export */   inputRegex: () => (/* binding */ inputRegex)
 /* harmony export */ });
-/* harmony import */ var _tiptap_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @tiptap/core */ "./node_modules/@tiptap/core/dist/index.js");
-/* harmony import */ var _tiptap_extension_list_item__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tiptap/extension-list-item */ "./node_modules/@tiptap/extension-list-item/dist/index.js");
-/* harmony import */ var _tiptap_extension_text_style__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @tiptap/extension-text-style */ "./node_modules/@tiptap/extension-text-style/dist/index.js");
-
-
+/* harmony import */ var _tiptap_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tiptap/core */ "./node_modules/@tiptap/core/dist/index.js");
 
 
+const ListItemName = 'listItem';
+const TextStyleName = 'textStyle';
 /**
  * Matches an ordered list to a 1. on input (or any number followed by a dot).
  */
@@ -50240,7 +52190,7 @@ const inputRegex = /^(\d+)\.\s$/;
  * @see https://www.tiptap.dev/api/nodes/ordered-list
  * @see https://www.tiptap.dev/api/nodes/list-item
  */
-const OrderedList = _tiptap_core__WEBPACK_IMPORTED_MODULE_2__.Node.create({
+const OrderedList = _tiptap_core__WEBPACK_IMPORTED_MODULE_0__.Node.create({
     name: 'orderedList',
     addOptions() {
         return {
@@ -50280,14 +52230,14 @@ const OrderedList = _tiptap_core__WEBPACK_IMPORTED_MODULE_2__.Node.create({
     renderHTML({ HTMLAttributes }) {
         const { start, ...attributesWithoutStart } = HTMLAttributes;
         return start === 1
-            ? ['ol', (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_2__.mergeAttributes)(this.options.HTMLAttributes, attributesWithoutStart), 0]
-            : ['ol', (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_2__.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes), 0];
+            ? ['ol', (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_0__.mergeAttributes)(this.options.HTMLAttributes, attributesWithoutStart), 0]
+            : ['ol', (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_0__.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes), 0];
     },
     addCommands() {
         return {
             toggleOrderedList: () => ({ commands, chain }) => {
                 if (this.options.keepAttributes) {
-                    return chain().toggleList(this.name, this.options.itemTypeName, this.options.keepMarks).updateAttributes(_tiptap_extension_list_item__WEBPACK_IMPORTED_MODULE_0__.ListItem.name, this.editor.getAttributes(_tiptap_extension_text_style__WEBPACK_IMPORTED_MODULE_1__.TextStyle.name)).run();
+                    return chain().toggleList(this.name, this.options.itemTypeName, this.options.keepMarks).updateAttributes(ListItemName, this.editor.getAttributes(TextStyleName)).run();
                 }
                 return commands.toggleList(this.name, this.options.itemTypeName, this.options.keepMarks);
             },
@@ -50299,19 +52249,19 @@ const OrderedList = _tiptap_core__WEBPACK_IMPORTED_MODULE_2__.Node.create({
         };
     },
     addInputRules() {
-        let inputRule = (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_2__.wrappingInputRule)({
+        let inputRule = (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_0__.wrappingInputRule)({
             find: inputRegex,
             type: this.type,
             getAttributes: match => ({ start: +match[1] }),
             joinPredicate: (match, node) => node.childCount + node.attrs.start === +match[1],
         });
         if (this.options.keepMarks || this.options.keepAttributes) {
-            inputRule = (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_2__.wrappingInputRule)({
+            inputRule = (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_0__.wrappingInputRule)({
                 find: inputRegex,
                 type: this.type,
                 keepMarks: this.options.keepMarks,
                 keepAttributes: this.options.keepAttributes,
-                getAttributes: match => ({ start: +match[1], ...this.editor.getAttributes(_tiptap_extension_text_style__WEBPACK_IMPORTED_MODULE_1__.TextStyle.name) }),
+                getAttributes: match => ({ start: +match[1], ...this.editor.getAttributes(TextStyleName) }),
                 joinPredicate: (match, node) => node.childCount + node.attrs.start === +match[1],
                 editor: this.editor,
             });
@@ -50610,7 +52560,7 @@ const TableCell = _tiptap_core__WEBPACK_IMPORTED_MODULE_0__.Node.create({
                 parseHTML: element => {
                     const colwidth = element.getAttribute('colwidth');
                     const value = colwidth
-                        ? [parseInt(colwidth, 10)]
+                        ? colwidth.split(',').map(width => parseInt(width, 10))
                         : null;
                     return value;
                 },
@@ -50675,7 +52625,7 @@ const TableHeader = _tiptap_core__WEBPACK_IMPORTED_MODULE_0__.Node.create({
                 parseHTML: element => {
                     const colwidth = element.getAttribute('colwidth');
                     const value = colwidth
-                        ? [parseInt(colwidth, 10)]
+                        ? colwidth.split(',').map(width => parseInt(width, 10))
                         : null;
                     return value;
                 },
@@ -51192,71 +53142,6 @@ const TextAlign = _tiptap_core__WEBPACK_IMPORTED_MODULE_0__.Extension.create({
 //# sourceMappingURL=index.js.map
 
 
-/***/ }),
-
-/***/ "./node_modules/@tiptap/extension-text-style/dist/index.js":
-/*!*****************************************************************!*\
-  !*** ./node_modules/@tiptap/extension-text-style/dist/index.js ***!
-  \*****************************************************************/
-/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
-
-"use strict";
-__webpack_require__.r(__webpack_exports__);
-/* harmony export */ __webpack_require__.d(__webpack_exports__, {
-/* harmony export */   TextStyle: () => (/* binding */ TextStyle),
-/* harmony export */   "default": () => (/* binding */ TextStyle)
-/* harmony export */ });
-/* harmony import */ var _tiptap_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tiptap/core */ "./node_modules/@tiptap/core/dist/index.js");
-
-
-/**
- * This extension allows you to create text styles. It is required by default
- * for the `textColor` and `backgroundColor` extensions.
- * @see https://www.tiptap.dev/api/marks/text-style
- */
-const TextStyle = _tiptap_core__WEBPACK_IMPORTED_MODULE_0__.Mark.create({
-    name: 'textStyle',
-    priority: 101,
-    addOptions() {
-        return {
-            HTMLAttributes: {},
-        };
-    },
-    parseHTML() {
-        return [
-            {
-                tag: 'span',
-                getAttrs: element => {
-                    const hasStyles = element.hasAttribute('style');
-                    if (!hasStyles) {
-                        return false;
-                    }
-                    return {};
-                },
-            },
-        ];
-    },
-    renderHTML({ HTMLAttributes }) {
-        return ['span', (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_0__.mergeAttributes)(this.options.HTMLAttributes, HTMLAttributes), 0];
-    },
-    addCommands() {
-        return {
-            removeEmptyTextStyle: () => ({ state, commands }) => {
-                const attributes = (0,_tiptap_core__WEBPACK_IMPORTED_MODULE_0__.getMarkAttributes)(state, this.type);
-                const hasStyles = Object.entries(attributes).some(([, value]) => !!value);
-                if (hasStyles) {
-                    return true;
-                }
-                return commands.unsetMark(this.name);
-            },
-        };
-    },
-});
-
-
-//# sourceMappingURL=index.js.map
-
-
 /***/ }),
 
 /***/ "./node_modules/@tiptap/extension-text/dist/index.js":
@@ -52095,22 +53980,8 @@ const EditorContent = (0,vue__WEBPACK_IMPORTED_MODULE_0__.defineComponent)({
             if (!editor) {
                 return;
             }
-            // destroy nodeviews before vue removes dom element
-            if (!editor.isDestroyed) {
-                editor.view.setProps({
-                    nodeViews: {},
-                });
-            }
             editor.contentComponent = null;
             editor.appContext = null;
-            if (!editor.options.element.firstChild) {
-                return;
-            }
-            const newElement = document.createElement('div');
-            newElement.append(...editor.options.element.childNodes);
-            editor.setOptions({
-                element: newElement,
-            });
         });
         return { rootEl };
     },
@@ -120872,28 +122743,41 @@ function splitBlockAs(splitNode) {
                 dispatch(state.tr.split($from.pos).scrollIntoView());
             return true;
         }
-        if (!$from.parent.isBlock)
+        if (!$from.depth)
             return false;
-        let atEnd = $to.parentOffset == $to.parent.content.size;
+        let types = [];
+        let splitDepth, deflt, atEnd = false, atStart = false;
+        for (let d = $from.depth;; d--) {
+            let node = $from.node(d);
+            if (node.isBlock) {
+                atEnd = $from.end(d) == $from.pos + ($from.depth - d);
+                atStart = $from.start(d) == $from.pos - ($from.depth - d);
+                deflt = defaultBlockAt($from.node(d - 1).contentMatchAt($from.indexAfter(d - 1)));
+                let splitType = splitNode && splitNode($to.parent, atEnd, $from);
+                types.unshift(splitType || (atEnd && deflt ? { type: deflt } : null));
+                splitDepth = d;
+                break;
+            }
+            else {
+                if (d == 1)
+                    return false;
+                types.unshift(null);
+            }
+        }
         let tr = state.tr;
         if (state.selection instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.TextSelection || state.selection instanceof prosemirror_state__WEBPACK_IMPORTED_MODULE_1__.AllSelection)
             tr.deleteSelection();
-        let deflt = $from.depth == 0 ? null : defaultBlockAt($from.node(-1).contentMatchAt($from.indexAfter(-1)));
-        let splitType = splitNode && splitNode($to.parent, atEnd, $from);
-        let types = splitType ? [splitType] : atEnd && deflt ? [{ type: deflt }] : undefined;
-        let can = (0,prosemirror_transform__WEBPACK_IMPORTED_MODULE_0__.canSplit)(tr.doc, tr.mapping.map($from.pos), 1, types);
-        if (!types && !can && (0,prosemirror_transform__WEBPACK_IMPORTED_MODULE_0__.canSplit)(tr.doc, tr.mapping.map($from.pos), 1, deflt ? [{ type: deflt }] : undefined)) {
-            if (deflt)
-                types = [{ type: deflt }];
-            can = true;
-        }
-        if (!can)
-            return false;
-        tr.split(tr.mapping.map($from.pos), 1, types);
-        if (!atEnd && !$from.parentOffset && $from.parent.type != deflt) {
-            let first = tr.mapping.map($from.before()), $first = tr.doc.resolve(first);
-            if (deflt && $from.node(-1).canReplaceWith($first.index(), $first.index() + 1, deflt))
-                tr.setNodeMarkup(tr.mapping.map($from.before()), deflt);
+        let splitPos = tr.mapping.map($from.pos);
+        let can = (0,prosemirror_transform__WEBPACK_IMPORTED_MODULE_0__.canSplit)(tr.doc, splitPos, types.length, types);
+        if (!can) {
+            types[0] = deflt ? { type: deflt } : null;
+            can = (0,prosemirror_transform__WEBPACK_IMPORTED_MODULE_0__.canSplit)(tr.doc, splitPos, types.length, types);
+        }
+        tr.split(splitPos, types.length, types);
+        if (!atEnd && atStart && $from.node(splitDepth).type != deflt) {
+            let first = tr.mapping.map($from.before(splitDepth)), $first = tr.doc.resolve(first);
+            if (deflt && $from.node(splitDepth - 1).canReplaceWith($first.index(), $first.index() + 1, deflt))
+                tr.setNodeMarkup(tr.mapping.map($from.before(splitDepth)), deflt);
         }
         if (dispatch)
             dispatch(tr.scrollIntoView());
@@ -127963,7 +129847,7 @@ function drawCellSelection(state) {
   return prosemirror_view__WEBPACK_IMPORTED_MODULE_2__.DecorationSet.create(state.doc, cells);
 }
 function isCellBoundarySelection({ $from, $to }) {
-  if ($from.pos == $to.pos || $from.pos < $from.pos - 6)
+  if ($from.pos == $to.pos || $from.pos < $to.pos - 6)
     return false;
   let afterFrom = $from.pos;
   let beforeTo = $to.pos;
@@ -129192,28 +131076,37 @@ function cellUnderMouse(view, event) {
 
 // src/tableview.ts
 var TableView = class {
-  constructor(node, cellMinWidth) {
+  constructor(node, defaultCellMinWidth) {
     this.node = node;
-    this.cellMinWidth = cellMinWidth;
+    this.defaultCellMinWidth = defaultCellMinWidth;
     this.dom = document.createElement("div");
     this.dom.className = "tableWrapper";
     this.table = this.dom.appendChild(document.createElement("table"));
+    this.table.style.setProperty(
+      "--default-cell-min-width",
+      `${defaultCellMinWidth}px`
+    );
     this.colgroup = this.table.appendChild(document.createElement("colgroup"));
-    updateColumnsOnResize(node, this.colgroup, this.table, cellMinWidth);
+    updateColumnsOnResize(node, this.colgroup, this.table, defaultCellMinWidth);
     this.contentDOM = this.table.appendChild(document.createElement("tbody"));
   }
   update(node) {
     if (node.type != this.node.type)
       return false;
     this.node = node;
-    updateColumnsOnResize(node, this.colgroup, this.table, this.cellMinWidth);
+    updateColumnsOnResize(
+      node,
+      this.colgroup,
+      this.table,
+      this.defaultCellMinWidth
+    );
     return true;
   }
   ignoreMutation(record) {
     return record.type == "attributes" && (record.target == this.table || this.colgroup.contains(record.target));
   }
 };
-function updateColumnsOnResize(node, colgroup, table, cellMinWidth, overrideCol, overrideValue) {
+function updateColumnsOnResize(node, colgroup, table, defaultCellMinWidth, overrideCol, overrideValue) {
   var _a;
   let totalWidth = 0;
   let fixedWidth = true;
@@ -129226,14 +131119,17 @@ function updateColumnsOnResize(node, colgroup, table, cellMinWidth, overrideCol,
     for (let j = 0; j < colspan; j++, col++) {
       const hasWidth = overrideCol == col ? overrideValue : colwidth && colwidth[j];
       const cssWidth = hasWidth ? hasWidth + "px" : "";
-      totalWidth += hasWidth || cellMinWidth;
+      totalWidth += hasWidth || defaultCellMinWidth;
       if (!hasWidth)
         fixedWidth = false;
       if (!nextDOM) {
-        colgroup.appendChild(document.createElement("col")).style.width = cssWidth;
+        const col2 = document.createElement("col");
+        col2.style.width = cssWidth;
+        colgroup.appendChild(col2);
       } else {
-        if (nextDOM.style.width != cssWidth)
+        if (nextDOM.style.width != cssWidth) {
           nextDOM.style.width = cssWidth;
+        }
         nextDOM = nextDOM.nextSibling;
       }
     }
@@ -129259,6 +131155,7 @@ var columnResizingPluginKey = new prosemirror_state__WEBPACK_IMPORTED_MODULE_0__
 function columnResizing({
   handleWidth = 5,
   cellMinWidth = 25,
+  defaultCellMinWidth = 100,
   View = TableView,
   lastColumnResizable = true
 } = {}) {
@@ -129271,7 +131168,7 @@ function columnResizing({
         const tableName = tableNodeTypes(state.schema).table.name;
         if (View && nodeViews) {
           nodeViews[tableName] = (node, view) => {
-            return new View(node, cellMinWidth, view);
+            return new View(node, defaultCellMinWidth, view);
           };
         }
         return new ResizeState(-1, false);
@@ -129287,19 +131184,13 @@ function columnResizing({
       },
       handleDOMEvents: {
         mousemove: (view, event) => {
-          handleMouseMove(
-            view,
-            event,
-            handleWidth,
-            cellMinWidth,
-            lastColumnResizable
-          );
+          handleMouseMove(view, event, handleWidth, lastColumnResizable);
         },
         mouseleave: (view) => {
           handleMouseLeave(view);
         },
         mousedown: (view, event) => {
-          handleMouseDown2(view, event, cellMinWidth);
+          handleMouseDown2(view, event, cellMinWidth, defaultCellMinWidth);
         }
       },
       decorations: (state) => {
@@ -129335,7 +131226,7 @@ var ResizeState = class _ResizeState {
     return state;
   }
 };
-function handleMouseMove(view, event, handleWidth, cellMinWidth, lastColumnResizable) {
+function handleMouseMove(view, event, handleWidth, lastColumnResizable) {
   const pluginState = columnResizingPluginKey.getState(view.state);
   if (!pluginState)
     return;
@@ -129369,7 +131260,7 @@ function handleMouseLeave(view) {
   if (pluginState && pluginState.activeHandle > -1 && !pluginState.dragging)
     updateHandle(view, -1);
 }
-function handleMouseDown2(view, event, cellMinWidth) {
+function handleMouseDown2(view, event, cellMinWidth, defaultCellMinWidth) {
   var _a;
   const win = (_a = view.dom.ownerDocument.defaultView) != null ? _a : window;
   const pluginState = columnResizingPluginKey.getState(view.state);
@@ -129405,9 +131296,20 @@ function handleMouseDown2(view, event, cellMinWidth) {
       return;
     if (pluginState2.dragging) {
       const dragged = draggedWidth(pluginState2.dragging, event2, cellMinWidth);
-      displayColumnWidth(view, pluginState2.activeHandle, dragged, cellMinWidth);
+      displayColumnWidth(
+        view,
+        pluginState2.activeHandle,
+        dragged,
+        defaultCellMinWidth
+      );
     }
   }
+  displayColumnWidth(
+    view,
+    pluginState.activeHandle,
+    width,
+    defaultCellMinWidth
+  );
   win.addEventListener("mouseup", finish);
   win.addEventListener("mousemove", move);
   event.preventDefault();
@@ -129452,9 +131354,9 @@ function edgeCell(view, event, side, handleWidth) {
   const index = map.map.indexOf($cell.pos - start);
   return index % map.width == 0 ? -1 : start + map.map[index - 1];
 }
-function draggedWidth(dragging, event, cellMinWidth) {
+function draggedWidth(dragging, event, resizeMinWidth) {
   const offset = event.clientX - dragging.startX;
-  return Math.max(cellMinWidth, dragging.startWidth + offset);
+  return Math.max(resizeMinWidth, dragging.startWidth + offset);
 }
 function updateHandle(view, value) {
   view.dispatch(
@@ -129482,7 +131384,7 @@ function updateColumnWidth(view, cell, width) {
   if (tr.docChanged)
     view.dispatch(tr);
 }
-function displayColumnWidth(view, cell, width, cellMinWidth) {
+function displayColumnWidth(view, cell, width, defaultCellMinWidth) {
   const $cell = view.state.doc.resolve(cell);
   const table = $cell.node(-1), start = $cell.start(-1);
   const col = TableMap.get(table).colCount($cell.pos - start) + $cell.nodeAfter.attrs.colspan - 1;
@@ -129496,7 +131398,7 @@ function displayColumnWidth(view, cell, width, cellMinWidth) {
     table,
     dom.firstChild,
     dom,
-    cellMinWidth,
+    defaultCellMinWidth,
     col,
     width
   );
@@ -129505,6 +131407,7 @@ function zeroes(n) {
   return Array(n).fill(0);
 }
 function handleDecorations(state, cell) {
+  var _a;
   const decorations = [];
   const $cell = state.doc.resolve(cell);
   const table = $cell.node(-1);
@@ -129521,6 +131424,17 @@ function handleDecorations(state, cell) {
       const pos = start + cellPos + table.nodeAt(cellPos).nodeSize - 1;
       const dom = document.createElement("div");
       dom.className = "column-resize-handle";
+      if ((_a = columnResizingPluginKey.getState(state)) == null ? void 0 : _a.dragging) {
+        decorations.push(
+          prosemirror_view__WEBPACK_IMPORTED_MODULE_2__.Decoration.node(
+            start + cellPos,
+            start + cellPos + table.nodeAt(cellPos).nodeSize,
+            {
+              class: "column-resize-dragging"
+            }
+          )
+        );
+      }
       decorations.push(prosemirror_view__WEBPACK_IMPORTED_MODULE_2__.Decoration.widget(pos, dom));
     }
   }
@@ -132976,16 +134890,17 @@ class CompositionViewDesc extends ViewDesc {
 // some cases they will be split more often than would appear
 // necessary.
 class MarkViewDesc extends ViewDesc {
-    constructor(parent, mark, dom, contentDOM) {
+    constructor(parent, mark, dom, contentDOM, spec) {
         super(parent, [], dom, contentDOM);
         this.mark = mark;
+        this.spec = spec;
     }
     static create(parent, mark, inline, view) {
         let custom = view.nodeViews[mark.type.name];
         let spec = custom && custom(mark, view, inline);
         if (!spec || !spec.dom)
             spec = prosemirror_model__WEBPACK_IMPORTED_MODULE_0__.DOMSerializer.renderSpec(document, mark.type.spec.toDOM(mark, inline), null, mark.attrs);
-        return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom);
+        return new MarkViewDesc(parent, mark, spec.dom, spec.contentDOM || spec.dom, spec);
     }
     parseRule() {
         if ((this.dirty & NODE_DIRTY) || this.mark.type.spec.reparseInView)
@@ -133017,6 +134932,11 @@ class MarkViewDesc extends ViewDesc {
         copy.children = nodes;
         return copy;
     }
+    destroy() {
+        if (this.spec.destroy)
+            this.spec.destroy();
+        super.destroy();
+    }
 }
 // Node view descs are the main, most common type of view desc, and
 // correspond to an actual node in the document. Unlike mark descs,
@@ -133336,7 +135256,7 @@ class CustomNodeViewDesc extends NodeViewDesc {
     update(node, outerDeco, innerDeco, view) {
         if (this.dirty == NODE_DIRTY)
             return false;
-        if (this.spec.update) {
+        if (this.spec.update && (this.node.type == node.type || this.spec.multiType)) {
             let result = this.spec.update(node, outerDeco, innerDeco);
             if (result)
                 this.updateInner(node, outerDeco, innerDeco, view);
@@ -134737,6 +136657,7 @@ let _detachedDoc = null;
 function detachedDoc() {
     return _detachedDoc || (_detachedDoc = document.implementation.createHTMLDocument("title"));
 }
+let _policy = null;
 function maybeWrapTrusted(html) {
     let trustedTypes = window.trustedTypes;
     if (!trustedTypes)
@@ -134744,7 +136665,9 @@ function maybeWrapTrusted(html) {
     // With the require-trusted-types-for CSP, Chrome will block
     // innerHTML, even on a detached document. This wraps the string in
     // a way that makes the browser allow us to use its parser again.
-    return trustedTypes.createPolicy("detachedDocument", { createHTML: (s) => s }).createHTML(html);
+    if (!_policy)
+        _policy = trustedTypes.createPolicy("ProseMirrorClipboard", { createHTML: (s) => s });
+    return _policy.createHTML(html);
 }
 function readHTML(html) {
     let metas = /^(\s*]*>)*/.exec(html);
@@ -134895,9 +136818,7 @@ editHandlers.keydown = (view, _event) => {
     // and handling them eagerly tends to corrupt the input.
     if (android && chrome && event.keyCode == 13)
         return;
-    if (view.domObserver.selectionChanged(view.domSelectionRange()))
-        view.domObserver.flush();
-    else if (event.keyCode != 229)
+    if (event.keyCode != 229)
         view.domObserver.forceFlush();
     // On iOS, if we preventDefault enter key presses, the virtual
     // keyboard gets confused. So the hack here is to set a flag that
@@ -136420,9 +138341,6 @@ class DOMObserver {
                 this.queue.push(mut);
         return this.queue;
     }
-    selectionChanged(sel) {
-        return !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(this.view) && !this.ignoreSelectionChange(sel);
-    }
     flush() {
         let { view } = this;
         if (!view.docView || this.flushingSoon > -1)
@@ -136430,7 +138348,8 @@ class DOMObserver {
         let mutations = this.pendingRecords();
         if (mutations.length)
             this.queue = [];
-        let sel = view.domSelectionRange(), newSel = this.selectionChanged(sel);
+        let sel = view.domSelectionRange();
+        let newSel = !this.suppressingSelectionUpdates && !this.currentSelection.eq(sel) && hasFocusAndSelection(view) && !this.ignoreSelectionChange(sel);
         let from = -1, to = -1, typeOver = false, added = [];
         if (view.editable) {
             for (let i = 0; i < mutations.length; i++) {
@@ -142952,7 +144871,7 @@ const asap = typeof queueMicrotask !== 'undefined' ?
 /******/ 		};
 /******/ 	
 /******/ 		// Execute the module function
-/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
+/******/ 		__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
 /******/ 	
 /******/ 		// Flag the module as loaded
 /******/ 		module.loaded = true;
diff --git a/package.json b/package.json
index 0af3da4..b36d431 100644
--- a/package.json
+++ b/package.json
@@ -38,10 +38,10 @@
         "@tiptap/starter-kit": "^2.4.0",
         "@tiptap/vue-3": "^2.4.0",
         "buffer": "^6.0.3",
-        "html-format": "^1.1.7",
         "laravel-nova-ui": "^0.4.12",
         "lodash": "^4.17.21",
         "lowlight": "^3.1.0",
+        "simply-beautiful": "^1.0.1",
         "tippy.js": "^6.3.7",
         "tiptap-extension-upload-image": "^1.0.1",
         "vue3-sticky-directive": "^0.0.2"
diff --git a/resources/js/components/FormField.vue b/resources/js/components/FormField.vue
index 1110d01..49490ba 100644
--- a/resources/js/components/FormField.vue
+++ b/resources/js/components/FormField.vue
@@ -15,7 +15,7 @@
                 
diff --git a/resources/js/modules/tools/ShowSource.js b/resources/js/modules/tools/ShowSource.js index ba40888..b680c71 100644 --- a/resources/js/modules/tools/ShowSource.js +++ b/resources/js/modules/tools/ShowSource.js @@ -1,24 +1,60 @@ import { CommandLineIcon } from '@heroicons/vue/24/outline' import Standard from '../../components/Tools/Standard.vue' -import format from 'html-format' import { ref } from 'vue' +import beautify from 'simply-beautiful' export default { icon: CommandLineIcon, isActive: ref(false), component: Standard, + + /** + * Toggle show source. + * + * @param {Object} editor + * @param {Object} refs + */ apply (editor, refs) { - if (this.active(editor)) { - editor.commands.setContent(editor.getText()) - this.isActive.value = false - refs.container.classList.remove('show-source') - } else { - editor.commands.setContent(``) - this.isActive.value = true - refs.container.classList.add('show-source') - } + this.active() ? this.disable(editor, refs) : this.enable(editor, refs) + }, + + /** + * Enable show source + * + * @param {Object} editor + * @param {Object} refs + */ + enable (editor, refs) { + this.isActive.value = true + editor.commands.setContent(``) + refs.container.classList.add('show-source') + editor.setOptions({ editable: false }) + }, + + /** + * Get pretty HTML from editor content. + * + * @param {Object} editor + * @returns {string} + */ + getPrettyHtml (editor) { + return beautify.html(editor.getHTML()) + }, + + /** + * Disable show source. + * + * @param {Object} editor + * @param {Object} refs + */ + disable (editor, refs) { + this.isActive.value = false + editor.commands.setContent(editor.getText()) + refs.container.classList.remove('show-source') + editor.setOptions({ editable: true }) }, - active (editor) { - return this.isActive.value || false + + active () { + return this.isActive.value } } diff --git a/resources/scss/field.scss b/resources/scss/field.scss index ba2662f..595ef9f 100644 --- a/resources/scss/field.scss +++ b/resources/scss/field.scss @@ -3,7 +3,7 @@ // ----------------------- .form-input { &.form-input--top { - border-bottom: 0 !important; + border-bottom: 0; border-bottom-left-radius: 0; border-bottom-right-radius: 0; } @@ -36,14 +36,35 @@ &-header { &.top-sticky { border-radius: 0; + border-bottom: 4px dashed rgba(var(--colors-gray-200)); box-shadow: none; } + + button { + transition: 100ms ease-in-out; + } } // Show source / code view styling &.show-source { .nova-canvas-content { + cursor: not-allowed; font-family: Consolas, serif; + white-space: pre-wrap; + + p { + margin: 0; + } + } + } +} + +.dark:root { + .nova-canvas { + &-header { + &.top-sticky { + border-bottom: 4px dashed rgba(var(--colors-gray-700)); + } } } }