diff --git a/client/src/assets/squire.js b/client/src/assets/squire.js index 65b7484..219cbc9 100644 --- a/client/src/assets/squire.js +++ b/client/src/assets/squire.js @@ -460,7 +460,6 @@ function fixContainer ( container, root ) { var doc = container.ownerDocument; var wrapper = null; var i, l, child, isBR; - var config = root.__squire__._config; for ( i = 0, l = children.length; i < l; i += 1 ) { child = children[i]; @@ -1762,7 +1761,7 @@ var keyHandlers = { } }, space: function ( self, _, range ) { - var node, parent; + var node; var root = self._root; self._recordUndoState( range ); if ( self._config.addLinks ) { @@ -2225,26 +2224,35 @@ var cleanupBRs = function ( node, root, keepForBlankLine ) { // The (non-standard but supported enough) innerText property is based on the // render tree in Firefox and possibly other browsers, so we must insert the // DOM node into the document to ensure the text part is correct. -var setClipboardData = function ( clipboardData, node, root, config ) { - var body = node.ownerDocument.body; - var willCutCopy = config.willCutCopy; +var setClipboardData = + function ( event, contents, root, willCutCopy, toPlainText, plainTextOnly ) { + var clipboardData = event.clipboardData; + var doc = event.target.ownerDocument; + var body = doc.body; + var node = createElement( doc, 'div' ); var html, text; - // Firefox will add an extra new line for BRs at the end of block when - // calculating innerText, even though they don't actually affect display. - // So we need to remove them first. - cleanupBRs( node, root, true ); + node.appendChild( contents ); - node.setAttribute( 'style', - 'position:fixed;overflow:hidden;bottom:100%;right:100%;' ); - body.appendChild( node ); html = node.innerHTML; - text = node.innerText || node.textContent; - if ( willCutCopy ) { html = willCutCopy( html ); } + if ( toPlainText ) { + text = toPlainText( html ); + } else { + // Firefox will add an extra new line for BRs at the end of block when + // calculating innerText, even though they don't actually affect + // display, so we need to remove them first. + cleanupBRs( node, root, true ); + node.setAttribute( 'style', + 'position:fixed;overflow:hidden;bottom:100%;right:100%;' ); + body.appendChild( node ); + text = node.innerText || node.textContent; + text = text.replace( / /g, ' ' ); // Replace nbsp with regular space + body.removeChild( node ); + } // Firefox (and others?) returns unix line endings (\n) even on Windows. // If on Windows, normalise to \r\n, since Notepad and some other crappy // apps do not understand just \n. @@ -2252,18 +2260,18 @@ var setClipboardData = function ( clipboardData, node, root, config ) { text = text.replace( /\r?\n/g, '\r\n' ); } - clipboardData.setData( 'text/html', html ); + if ( !plainTextOnly && text !== html ) { + clipboardData.setData( 'text/html', html ); + } clipboardData.setData( 'text/plain', text ); - - body.removeChild( node ); + event.preventDefault(); }; var onCut = function ( event ) { - var clipboardData = event.clipboardData; var range = this.getSelection(); var root = this._root; var self = this; - var startBlock, endBlock, copyRoot, contents, parent, newContents, node; + var startBlock, endBlock, copyRoot, contents, parent, newContents; // Nothing to do if ( range.collapsed ) { @@ -2275,7 +2283,7 @@ var onCut = function ( event ) { this.saveUndoState( range ); // Edge only seems to support setting plain text as of 2016-03-11. - if ( !isEdge && clipboardData ) { + if ( !isEdge && event.clipboardData ) { // Clipboard content should include all parents within block, or all // parents up to root if selection across blocks startBlock = getStartBlockOfRange( range, root ); @@ -2295,10 +2303,8 @@ var onCut = function ( event ) { parent = parent.parentNode; } // Set clipboard data - node = this.createElement( 'div' ); - node.appendChild( contents ); - setClipboardData( clipboardData, node, root, this._config ); - event.preventDefault(); + setClipboardData( + event, contents, root, this._config.willCutCopy, null, false ); } else { setTimeout( function () { try { @@ -2313,14 +2319,10 @@ var onCut = function ( event ) { this.setSelection( range ); }; -var onCopy = function ( event ) { - var clipboardData = event.clipboardData; - var range = this.getSelection(); - var root = this._root; - var startBlock, endBlock, copyRoot, contents, parent, newContents, node; - +var _onCopy = function ( event, range, root, willCutCopy, toPlainText, plainTextOnly ) { + var startBlock, endBlock, copyRoot, contents, parent, newContents; // Edge only seems to support setting plain text as of 2016-03-11. - if ( !isEdge && clipboardData ) { + if ( !isEdge && event.clipboardData ) { // Clipboard content should include all parents within block, or all // parents up to root if selection across blocks startBlock = getStartBlockOfRange( range, root ); @@ -2345,13 +2347,21 @@ var onCopy = function ( event ) { parent = parent.parentNode; } // Set clipboard data - node = this.createElement( 'div' ); - node.appendChild( contents ); - setClipboardData( clipboardData, node, root, this._config ); - event.preventDefault(); + setClipboardData( event, contents, root, willCutCopy, toPlainText, plainTextOnly ); } }; +var onCopy = function ( event ) { + _onCopy( + event, + this.getSelection(), + this._root, + this._config.willCutCopy, + null, + false + ); +}; + // Need to monitor for shift key like this, as event.shiftKey is not available // in paste event. function monitorShiftKey ( event ) { @@ -2965,16 +2975,6 @@ proto.setSelection = function ( range ) { // needing restore on focus. if ( !this._isFocused ) { enableRestoreSelection.call( this ); - } else if ( isAndroid && !this._restoreSelection ) { - // Android closes the keyboard on removeAllRanges() and doesn't - // open it again when addRange() is called, sigh. - // Since Android doesn't trigger a focus event in setSelection(), - // use a blur/focus dance to work around this by letting the - // selection be restored on focus. - // Need to check for !this._restoreSelection to avoid infinite loop - enableRestoreSelection.call( this ); - this.blur(); - this.focus(); } else { // iOS bug: if you don't focus the iframe before setting the // selection, you can end up in a state where you type but the input @@ -2984,7 +2984,15 @@ proto.setSelection = function ( range ) { this._win.focus(); } var sel = getWindowSelection( this ); - if ( sel ) { + if ( sel && sel.setBaseAndExtent ) { + sel.setBaseAndExtent( + range.startContainer, + range.startOffset, + range.endContainer, + range.endOffset, + ); + } else if ( sel ) { + // This is just for IE11 sel.removeAllRanges(); sel.addRange( range ); } @@ -3160,7 +3168,7 @@ proto._updatePath = function ( range, force ) { // selectionchange is fired synchronously in IE when removing current selection // and when setting new selection; keyup/mouseup may have processing we want // to do first. Either way, send to next event loop. -proto._updatePathOnEvent = function ( event ) { +proto._updatePathOnEvent = function () { var self = this; if ( self._isFocused && !self._willUpdatePath ) { self._willUpdatePath = true; @@ -4172,8 +4180,7 @@ proto._setHTML = function ( html ) { }; proto.getHTML = function ( withBookMark ) { - var brs = [], - root, node, fixer, html, l, range; + var html, range; if ( withBookMark && ( range = this.getSelection() ) ) { this._saveRangeToBookmark( range ); } @@ -4968,6 +4975,7 @@ Squire.rangeDoesEndAtBlockBoundary = rangeDoesEndAtBlockBoundary; Squire.expandRangeToBlockBoundaries = expandRangeToBlockBoundaries; // Clipboard.js exports +Squire.onCopy = _onCopy; Squire.onPaste = onPaste; // Editor.js exports @@ -4995,4 +5003,4 @@ if ( typeof exports === 'object' ) { } } -}( document ) ); +}( document ) ); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 8c94e1f..60c33f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -530,11 +530,6 @@ "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.1.tgz", "integrity": "sha1-082BIh4+pAdCz83lVtTpnpjdxxs=" }, - "dns-prefetch-control": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz", - "integrity": "sha512-hvSnros73+qyZXhHFjx2CMLwoj3Fe7eR9EJsFsqmcI1bB2OBWL/+0YzaEaKssCHnj/6crawNnUyw74Gm2EKe+Q==" - }, "dom-serializer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", @@ -709,11 +704,6 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, - "expect-ct": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/expect-ct/-/expect-ct-0.2.0.tgz", - "integrity": "sha512-6SK3MG/Bbhm8MsgyJAylg+ucIOU71/FzyFalcfu5nY19dH8y/z0tBJU0wrNBXD4B27EoQtqPF/9wqH0iYAd04g==" - }, "express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", @@ -830,11 +820,6 @@ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" }, - "frameguard": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/frameguard/-/frameguard-3.1.0.tgz", - "integrity": "sha512-TxgSKM+7LTA6sidjOiSZK9wxY0ffMPY3Wta//MqwmX0nZuEHc8QrkV8Fh3ZhMJeiH+Uyh/tcaarImRy8u77O7g==" - }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -922,16 +907,13 @@ "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" }, "helmet": { - "version": "3.23.1", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.23.1.tgz", - "integrity": "sha512-e034HHfRK4065BFjYbffn5jXaTWWrhTNgmLIppsGEOjpdDB1MBQkWlAFW/auULXAu6uKk2X76n7a7gvz5sSjkg==", + "version": "3.23.3", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.23.3.tgz", + "integrity": "sha512-U3MeYdzPJQhtvqAVBPntVgAvNSOJyagwZwyKsFdyRa8TV3pOKVFljalPOCxbw5Wwf2kncGhmP0qHjyazIdNdSA==", "requires": { "depd": "2.0.0", - "dns-prefetch-control": "0.2.0", "dont-sniff-mimetype": "1.1.0", - "expect-ct": "0.2.0", "feature-policy": "0.3.0", - "frameguard": "3.1.0", "helmet-crossdomain": "0.4.0", "helmet-csp": "2.10.0", "hide-powered-by": "1.1.0", @@ -1567,22 +1549,29 @@ } }, "request-promise": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.5.tgz", - "integrity": "sha512-ZgnepCykFdmpq86fKGwqntyTiUrHycALuGggpyCZwMvGaZWgxW6yagT0FHkgo5LzYvOaCNvxYwWYIjevSH1EDg==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz", + "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==", "requires": { "bluebird": "^3.5.0", - "request-promise-core": "1.1.3", + "request-promise-core": "1.1.4", "stealthy-require": "^1.1.1", "tough-cookie": "^2.3.3" } }, "request-promise-core": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", - "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", "requires": { - "lodash": "^4.17.15" + "lodash": "^4.17.19" + }, + "dependencies": { + "lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + } } }, "require-directory": { diff --git a/package.json b/package.json index 741d532..e6c6f90 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "express": "^4.16.4", "express-rate-limit": "^5.1.3", "gm": "^1.23.1", - "helmet": "^3.23.1", + "helmet": "^3.23.3", "jsonwebtoken": "^8.5.1", "module-alias": "^2.2.2", "multer": "^1.4.2", @@ -23,7 +23,7 @@ "node-tesseract-ocr": "^1.0.0", "qrcode": "^1.4.4", "request": "^2.88.2", - "request-promise": "^4.2.5", + "request-promise": "^4.2.6", "socket.io": "^2.3.0", "speakeasy": "^2.0.0" },