From be2616f7662f7fb4ada9861c42eb066e36068201 Mon Sep 17 00:00:00 2001 From: SamTV12345 <40429738+samtv12345@users.noreply.github.com> Date: Sat, 13 Jul 2024 20:40:56 +0200 Subject: [PATCH] Added POC for browser --- src/node/hooks/express/specialpages.ts | 28 ++++-- src/static/js/AttributeManager.js | 6 +- src/static/js/ace.js | 35 ++++---- src/static/js/ace2_inner.js | 108 ++++++++++++----------- src/static/js/caretPosition.js | 1 + src/static/js/pad_editor.js | 3 +- src/static/js/pad_utils.js | 2 +- src/static/js/pluginfw/client_plugins.js | 25 ++---- src/static/js/scroll.js | 2 +- src/static/js/vendors/farbtastic.js | 6 +- src/templates/padBootstrap.js | 3 +- var/js/.gitignore | 2 + 12 files changed, 117 insertions(+), 104 deletions(-) diff --git a/src/node/hooks/express/specialpages.ts b/src/node/hooks/express/specialpages.ts index 16708f488..714d7b3dd 100644 --- a/src/node/hooks/express/specialpages.ts +++ b/src/node/hooks/express/specialpages.ts @@ -10,6 +10,9 @@ const settings = require('../../utils/Settings'); const util = require('util'); const webaccess = require('./webaccess'); const plugins = require('../../../static/js/pluginfw/plugin_defs'); +import {hash, createHash} from 'node:crypto' + + import {buildSync} from 'esbuild' exports.expressPreSession = async (hookName:string, {app}:any) => { // This endpoint is intended to conform to: @@ -94,18 +97,30 @@ exports.expressCreateServer = async (hookName: string, args: any, cb: Function) })(), settings, })); + const hash = createHash('sha256').update(fs.readFileSync(path.join(settings.root, 'var/js/padbootstrap.js'))).digest('hex'); + const fileName = `padbootstrap-${hash.substring(0,16)}.min.js` const result = buildSync({ - entryPoints: [settings.root + "/src/templates/padBootstrap.js"], // Entry file(s) + entryPoints: [settings.root + "/var/js/padbootstrap.js"], // Entry file(s) bundle: true, // Bundle the files together - minify: true, // Minify the output + minify: false, // Minify the output sourcemap: true, // Generate source maps sourceRoot: settings.root+"/src/static/js/", target: ['es2020'], // Target ECMAScript version - write: false, // Do not write to file system, + metafile: true, + + write: true, // Do not write to file system, + outfile: settings.root + `/var/js/${fileName}`, // Output file }) - const textResult = result.outputFiles[0].text + + args.app.get(`/${fileName}`, (req: any, res: any) => { + res.sendFile(settings.root+`/var/js/${fileName}`) + }) + + args.app.get(`/${fileName}.map`, (req: any, res: any) => { + res.sendFile(settings.root+`/var/js/${fileName}.map`) + }) // serve pad.html under /p @@ -115,7 +130,7 @@ exports.expressCreateServer = async (hookName: string, args: any, cb: Function) hooks.callAll('padInitToolbar', { toolbar, - isReadOnly, + isReadOnly }); // can be removed when require-kernel is dropped @@ -124,6 +139,7 @@ exports.expressCreateServer = async (hookName: string, args: any, cb: Function) req, toolbar, isReadOnly, + entrypoint: "/"+fileName })); }); @@ -145,6 +161,4 @@ exports.expressCreateServer = async (hookName: string, args: any, cb: Function) // express-session automatically calls req.session.touch() so we don't need to do it here. res.json({status: 'ok'}); }); - - return cb(); }; diff --git a/src/static/js/AttributeManager.js b/src/static/js/AttributeManager.js index f508af641..63af431d9 100644 --- a/src/static/js/AttributeManager.js +++ b/src/static/js/AttributeManager.js @@ -4,7 +4,7 @@ const AttributeMap = require('./AttributeMap'); const Changeset = require('./Changeset'); const ChangesetUtils = require('./ChangesetUtils'); const attributes = require('./attributes'); -const _ = require('./underscore'); +const underscore = require("underscore") const lineMarkerAttribute = 'lmkr'; @@ -45,7 +45,7 @@ const AttributeManager = function (rep, applyChangesetCallback) { AttributeManager.DEFAULT_LINE_ATTRIBUTES = DEFAULT_LINE_ATTRIBUTES; AttributeManager.lineAttributes = lineAttributes; -AttributeManager.prototype = _(AttributeManager.prototype).extend({ +AttributeManager.prototype = underscore.default(AttributeManager.prototype).extend({ applyChangeset(changeset) { if (!this.applyChangesetCallback) return changeset; @@ -335,7 +335,7 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({ ChangesetUtils.buildKeepToStartOfRange(this.rep, builder, [lineNum, 0]); - const countAttribsWithMarker = _.chain(attribs).filter((a) => !!a[1]) + const countAttribsWithMarker = underscore.chain(attribs).filter((a) => !!a[1]) .map((a) => a[0]).difference(DEFAULT_LINE_ATTRIBUTES).size().value(); // if we have marker and any of attributes don't need to have marker. we need delete it diff --git a/src/static/js/ace.js b/src/static/js/ace.js index b0a042570..dece1c4c2 100644 --- a/src/static/js/ace.js +++ b/src/static/js/ace.js @@ -27,9 +27,10 @@ const hooks = require('./pluginfw/hooks'); const makeCSSManager = require('./cssmanager').makeCSSManager; const pluginUtils = require('./pluginfw/shared'); - +const ace2_inner = require('ep_etherpad-lite/static/js/ace2_inner') const debugLog = (...args) => {}; - +const cl_plugins = require('ep_etherpad-lite/static/js/pluginfw/client_plugins') +const rJQuery = require('ep_etherpad-lite/static/js/rjquery') // The inner and outer iframe's locations are about:blank, so relative URLs are relative to that. // Firefox and Chrome seem to do what the developer intends if given a relative URL, but Safari // errors out unless given an absolute URL for a JavaScript-created element. @@ -99,6 +100,7 @@ const Ace2Editor = function () { }; const doActionsPendingInit = () => { + console.log('doActionsPendingInit', actionsPendingInit) for (const fn of actionsPendingInit) fn(); actionsPendingInit = []; }; @@ -257,19 +259,19 @@ const Ace2Editor = function () { // tag addStyleTagsFor(innerDocument, includedCSS); - const requireKernel = innerDocument.createElement('script'); - requireKernel.type = 'text/javascript'; - requireKernel.src = - absUrl(`../static/js/require-kernel.js?v=${clientVars.randomVersionString}`); - innerDocument.head.appendChild(requireKernel); + //const requireKernel = innerDocument.createElement('script'); + //requireKernel.type = 'text/javascript'; + //requireKernel.src = + // absUrl(`../static/js/require-kernel.js?v=${clientVars.randomVersionString}`); + //innerDocument.head.appendChild(requireKernel); // Pre-fetch modules to improve load performance. - for (const module of ['ace2_inner', 'ace2_common']) { + /*for (const module of ['ace2_inner', 'ace2_common']) { const script = innerDocument.createElement('script'); script.type = 'text/javascript'; script.src = absUrl(`../javascripts/lib/ep_etherpad-lite/static/js/${module}.js` + `?callback=require.define&v=${clientVars.randomVersionString}`); innerDocument.head.appendChild(script); - } + }*/ const innerStyle = innerDocument.createElement('style'); innerStyle.type = 'text/css'; innerStyle.title = 'dynamicsyntax'; @@ -284,7 +286,7 @@ const Ace2Editor = function () { innerDocument.body.classList.add('innerdocbody'); innerDocument.body.setAttribute('spellcheck', 'false'); innerDocument.body.appendChild(innerDocument.createTextNode('\u00A0')); //   - +/* debugLog('Ace2Editor.init() waiting for require kernel load'); await eventFired(requireKernel, 'load'); debugLog('Ace2Editor.init() require kernel loaded'); @@ -292,17 +294,16 @@ const Ace2Editor = function () { require.setRootURI(absUrl('../javascripts/src')); require.setLibraryURI(absUrl('../javascripts/lib')); require.setGlobalKeyPath('require'); - +*/ // intentially moved before requiring client_plugins to save a 307 - innerWindow.Ace2Inner = require('ep_etherpad-lite/static/js/ace2_inner'); - innerWindow.plugins = require('ep_etherpad-lite/static/js/pluginfw/client_plugins'); - innerWindow.plugins.adoptPluginsFromAncestorsOf(innerWindow); + innerWindow.Ace2Inner = ace2_inner; + innerWindow.plugins = cl_plugins; - innerWindow.$ = innerWindow.jQuery = require('ep_etherpad-lite/static/js/rjquery').jQuery; + innerWindow.$ = innerWindow.jQuery = rJQuery.jQuery; debugLog('Ace2Editor.init() waiting for plugins'); - await new Promise((resolve, reject) => innerWindow.plugins.ensure( - (err) => err != null ? reject(err) : resolve())); + /*await new Promise((resolve, reject) => innerWindow.plugins.ensure( + (err) => err != null ? reject(err) : resolve()));*/ debugLog('Ace2Editor.init() waiting for Ace2Inner.init()'); await innerWindow.Ace2Inner.init(info, { inner: makeCSSManager(innerStyle.sheet), diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index 868906cfd..f62615da2 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -54,13 +54,16 @@ function Ace2Inner(editorInfo, cssManagers) { let thisAuthor = ''; let disposed = false; + const outerWin = document.getElementsByName("ace_outer")[0] + const targetDoc = outerWin.contentWindow.document.getElementsByName("ace_inner")[0].contentWindow.document + const targetBody = targetDoc.body const focus = () => { - window.focus(); + targetBody.focus(); }; - const outerWin = window.parent; - const outerDoc = outerWin.document; + const outerDoc = outerWin.contentWindow.document; + const sideDiv = outerDoc.getElementById('sidediv'); const lineMetricsDiv = outerDoc.getElementById('linemetricsdiv'); const sideDivInner = outerDoc.getElementById('sidedivinner'); @@ -415,7 +418,7 @@ function Ace2Inner(editorInfo, cssManagers) { const setWraps = (newVal) => { doesWrap = newVal; - document.body.classList.toggle('doesWrap', doesWrap); + targetBody.classList.toggle('doesWrap', doesWrap); scheduler.setTimeout(() => { inCallStackIfNecessary('setWraps', () => { fastIncorp(7); @@ -445,7 +448,7 @@ function Ace2Inner(editorInfo, cssManagers) { }; const setTextFace = (face) => { - document.body.style.fontFamily = face; + targetBody.style.fontFamily = face; lineMetricsDiv.style.fontFamily = face; }; @@ -456,8 +459,8 @@ function Ace2Inner(editorInfo, cssManagers) { const setEditable = (newVal) => { isEditable = newVal; - document.body.contentEditable = isEditable ? 'true' : 'false'; - document.body.classList.toggle('static', !isEditable); + targetBody.contentEditable = isEditable ? 'true' : 'false'; + targetBody.classList.toggle('static', !isEditable); }; const enforceEditability = () => setEditable(isEditable); @@ -480,6 +483,8 @@ function Ace2Inner(editorInfo, cssManagers) { newText = `${lines.join('\n')}\n`; } + window.console.log('importText', {text, undoable, dontProcess, newText}) + inCallStackIfNecessary(`importText${undoable ? 'Undoable' : ''}`, () => { setDocText(newText); }); @@ -520,6 +525,7 @@ function Ace2Inner(editorInfo, cssManagers) { const oldLen = rep.lines.totalWidth(); const numLines = rep.lines.length(); + window.console.log(rep, numLines - 1); const upToLastLine = rep.lines.offsetOfIndex(numLines - 1); const lastLineLength = rep.lines.atIndex(numLines - 1).text.length; const assem = Changeset.smartOpAssembler(); @@ -640,8 +646,8 @@ function Ace2Inner(editorInfo, cssManagers) { // These properties are exposed const setters = { wraps: setWraps, - showsauthorcolors: (val) => document.body.classList.toggle('authorColors', !!val), - showsuserselections: (val) => document.body.classList.toggle('userSelections', !!val), + showsauthorcolors: (val) => targetBody.classList.toggle('authorColors', !!val), + showsuserselections: (val) => targetBody.classList.toggle('userSelections', !!val), showslinenumbers: (value) => { hasLineNumbers = !!value; sideDiv.parentNode.classList.toggle('line-numbers-hidden', !hasLineNumbers); @@ -654,8 +660,8 @@ function Ace2Inner(editorInfo, cssManagers) { styled: setStyled, textface: setTextFace, rtlistrue: (value) => { - document.body.classList.toggle('rtl', value); - document.body.classList.toggle('ltr', !value); + targetBody.classList.toggle('rtl', value); + targetBody.classList.toggle('ltr', !value); document.documentElement.dir = value ? 'rtl' : 'ltr'; }, }; @@ -894,11 +900,11 @@ function Ace2Inner(editorInfo, cssManagers) { clearObservedChanges(); const getCleanNodeByKey = (key) => { - let n = document.getElementById(key); + let n = targetDoc.getElementById(key); // copying and pasting can lead to duplicate ids while (n && isNodeDirty(n)) { n.id = ''; - n = document.getElementById(key); + n = targetDoc.getElementById(key); } return n; }; @@ -980,11 +986,11 @@ function Ace2Inner(editorInfo, cssManagers) { const observeSuspiciousNodes = () => { // inspired by Firefox bug #473255, where pasting formatted text // causes the cursor to jump away, making the new HTML never found. - if (document.body.getElementsByTagName) { - const elts = document.body.getElementsByTagName('style'); + if (targetBody.getElementsByTagName) { + const elts = targetBody.getElementsByTagName('style'); for (const elt of elts) { const n = topLevel(elt); - if (n && n.parentNode === document.body) { + if (n && n.parentNode === targetBody) { observeChangesAroundNode(n); } } @@ -999,8 +1005,8 @@ function Ace2Inner(editorInfo, cssManagers) { if (DEBUG && window.DONT_INCORP || window.DEBUG_DONT_INCORP) return false; // returns true if dom changes were made - if (!document.body.firstChild) { - document.body.innerHTML = '
'; + if (!targetBody.firstChild) { + targetBody.innerHTML = '
'; } observeChangesAroundSelection(); @@ -1022,7 +1028,7 @@ function Ace2Inner(editorInfo, cssManagers) { j++; } if (!dirtyRangesCheckOut) { - for (const bodyNode of document.body.childNodes) { + for (const bodyNode of targetBody.childNodes) { if ((bodyNode.tagName) && ((!bodyNode.id) || (!rep.lines.containsKey(bodyNode.id)))) { observeChangesAroundNode(bodyNode); } @@ -1044,11 +1050,11 @@ function Ace2Inner(editorInfo, cssManagers) { const range = dirtyRanges[i]; a = range[0]; b = range[1]; - let firstDirtyNode = (((a === 0) && document.body.firstChild) || + let firstDirtyNode = (((a === 0) && targetBody.firstChild) || getCleanNodeByKey(rep.lines.atIndex(a - 1).key).nextSibling); firstDirtyNode = (firstDirtyNode && isNodeDirty(firstDirtyNode) && firstDirtyNode); - let lastDirtyNode = (((b === rep.lines.length()) && document.body.lastChild) || + let lastDirtyNode = (((b === rep.lines.length()) && targetBody.lastChild) || getCleanNodeByKey(rep.lines.atIndex(b).key).previousSibling); lastDirtyNode = (lastDirtyNode && isNodeDirty(lastDirtyNode) && lastDirtyNode); @@ -1135,7 +1141,7 @@ function Ace2Inner(editorInfo, cssManagers) { callstack: currentCallStack, editorInfo, rep, - root: document.body, + root: targetBody, point: selection.startPoint, documentAttributeManager, }); @@ -1147,7 +1153,7 @@ function Ace2Inner(editorInfo, cssManagers) { callstack: currentCallStack, editorInfo, rep, - root: document.body, + root: targetBody, point: selection.endPoint, documentAttributeManager, }); @@ -1227,9 +1233,9 @@ function Ace2Inner(editorInfo, cssManagers) { info.prepareForAdd(); entry.lineMarker = info.lineMarker; if (!nodeToAddAfter) { - document.body.insertBefore(node, document.body.firstChild); + targetBody.insertBefore(node, targetBody.firstChild); } else { - document.body.insertBefore(node, nodeToAddAfter.nextSibling); + targetBody.insertBefore(node, nodeToAddAfter.nextSibling); } nodeToAddAfter = node; info.notifyAdded(); @@ -1326,7 +1332,7 @@ function Ace2Inner(editorInfo, cssManagers) { // Turn DOM node selection into [line,char] selection. // This method has to work when the DOM is not pristine, // assuming the point is not in a dirty node. - if (point.node === document.body) { + if (point.node === targetBody) { if (point.index === 0) { return [0, 0]; } else { @@ -1345,7 +1351,7 @@ function Ace2Inner(editorInfo, cssManagers) { col = nodeText(n).length; } let parNode, prevSib; - while ((parNode = n.parentNode) !== document.body) { + while ((parNode = n.parentNode) !== targetBody) { if ((prevSib = n.previousSibling)) { n = prevSib; col += nodeText(n).length; @@ -1398,7 +1404,7 @@ function Ace2Inner(editorInfo, cssManagers) { insertDomLines(nodeToAddAfter, lineEntries.map((entry) => entry.domInfo)); for (const k of keysToDelete) { - const n = document.getElementById(k); + const n = targetDoc.getElementById(k); n.parentNode.removeChild(n); } @@ -2087,7 +2093,7 @@ function Ace2Inner(editorInfo, cssManagers) { const a = cleanNodeForIndex(i - 1); const b = cleanNodeForIndex(i); if ((!a) || (!b)) return false; // violates precondition - if ((a === true) && (b === true)) return !document.body.firstChild; + if ((a === true) && (b === true)) return !targetBody.firstChild; if ((a === true) && b.previousSibling) return false; if ((b === true) && a.nextSibling) return false; if ((a === true) || (b === true)) return true; @@ -2232,7 +2238,7 @@ function Ace2Inner(editorInfo, cssManagers) { }; const isNodeDirty = (n) => { - if (n.parentNode !== document.body) return true; + if (n.parentNode !== targetBody) return true; const data = getAssoc(n, 'dirtiness'); if (!data) return true; if (n.id !== data.nodeId) return true; @@ -2856,7 +2862,7 @@ function Ace2Inner(editorInfo, cssManagers) { updateBrowserSelectionFromRep(); // get the current caret selection, can't use rep. here because that only gives // us the start position not the current - const myselection = document.getSelection(); + const myselection = targetDoc.getSelection(); // get the carets selection offset in px IE 214 let caretOffsetTop = myselection.focusNode.parentNode.offsetTop || myselection.focusNode.offsetTop; @@ -2970,13 +2976,13 @@ function Ace2Inner(editorInfo, cssManagers) { // with background doesn't seem to show up... if (isNodeText(p.node) && p.index === p.maxIndex) { let n = p.node; - while (!n.nextSibling && n !== document.body && n.parentNode !== document.body) { + while (!n.nextSibling && n !== targetBody && n.parentNode !== targetBody) { n = n.parentNode; } if (n.nextSibling && !(typeof n.nextSibling.tagName === 'string' && n.nextSibling.tagName.toLowerCase() === 'br') && - n !== p.node && n !== document.body && n.parentNode !== document.body) { + n !== p.node && n !== targetBody && n.parentNode !== targetBody) { // found a parent, go to next node and dive in p.node = n.nextSibling; p.maxIndex = nodeMaxIndex(p.node); @@ -3078,7 +3084,7 @@ function Ace2Inner(editorInfo, cssManagers) { // each of which has node (a magicdom node), index, and maxIndex. If the node // is a text node, maxIndex is the length of the text; else maxIndex is 1. // index is between 0 and maxIndex, inclusive. - const browserSelection = window.getSelection(); + const browserSelection = targetDoc.getSelection(); if (!browserSelection || browserSelection.type === 'None' || browserSelection.rangeCount === 0) { return null; @@ -3096,7 +3102,7 @@ function Ace2Inner(editorInfo, cssManagers) { if (!isInBody(container)) { // command-click in Firefox selects whole document, HEAD and BODY! return { - node: document.body, + node: targetBody, index: 0, maxIndex: 1, }; @@ -3191,7 +3197,7 @@ function Ace2Inner(editorInfo, cssManagers) { // If non-nullish, pasting on a link should be suppressed. let suppressPasteOnLink = null; - $(document.body).on('auxclick', (e) => { + $(targetBody).on('auxclick', (e) => { if (e.originalEvent.button === 1 && (e.target.a || e.target.localName === 'a')) { // The user middle-clicked on a link. Usually users do this to open a link in a new tab, but // in X11 (Linux) this will instead paste the contents of the primary selection at the mouse @@ -3213,7 +3219,7 @@ function Ace2Inner(editorInfo, cssManagers) { } }); - $(document.body).on('paste', (e) => { + $(targetBody).on('paste', (e) => { if (suppressPasteOnLink != null && (e.target.a || e.target.localName === 'a')) { scheduler.clearTimeout(suppressPasteOnLink); suppressPasteOnLink = null; @@ -3233,7 +3239,7 @@ function Ace2Inner(editorInfo, cssManagers) { // We reference document here, this is because if we don't this will expose a bug // in Google Chrome. This bug will cause the last character on the last line to // not fire an event when dropped into.. - $(document).on('drop', (e) => { + $(targetBody).on('drop', (e) => { if (e.target.a || e.target.localName === 'a') { e.preventDefault(); } @@ -3251,7 +3257,7 @@ function Ace2Inner(editorInfo, cssManagers) { const lineAfterSelection = lastLineSelected.nextSibling; const neighbor = lineBeforeSelection || lineAfterSelection; - neighbor.appendChild(document.createElement('style')); + neighbor.appendChild(targetDoc.createElement('style')); } // Call drop hook @@ -3263,10 +3269,10 @@ function Ace2Inner(editorInfo, cssManagers) { }); }); - $(document.documentElement).on('compositionstart', () => { + $(targetDoc.documentElement).on('compositionstart', () => { if (inInternationalComposition) return; inInternationalComposition = new Promise((resolve) => { - $(document.documentElement).one('compositionend', () => { + $(targetDoc.documentElement).one('compositionend', () => { inInternationalComposition = null; resolve(); }); @@ -3275,8 +3281,8 @@ function Ace2Inner(editorInfo, cssManagers) { }; const topLevel = (n) => { - if ((!n) || n === document.body) return null; - while (n.parentNode !== document.body) { + if ((!n) || n === targetBody) return null; + while (n.parentNode !== targetBody) { n = n.parentNode; } return n; @@ -3436,10 +3442,10 @@ function Ace2Inner(editorInfo, cssManagers) { // but as it's non-text type the line-height/margins might not be present and it // could be that this breaks a theme that has a different default line height.. // So instead of using an integer here we get the value from the Editor CSS. - const innerdocbodyStyles = getComputedStyle(document.body); + const innerdocbodyStyles = getComputedStyle(targetBody); const defaultLineHeight = parseInt(innerdocbodyStyles['line-height']); - for (const docLine of document.body.children) { + for (const docLine of targetBody.children) { let h; const nextDocLine = docLine.nextElementSibling; if (nextDocLine) { @@ -3450,7 +3456,7 @@ function Ace2Inner(editorInfo, cssManagers) { // included on the first line. The default stylesheet doesn't add // extra margins/padding, but plugins might. h = nextDocLine.offsetTop - parseInt( - window.getComputedStyle(document.body) + window.getComputedStyle(targetBody) .getPropertyValue('padding-top').split('px')[0]); } else { h = nextDocLine.offsetTop - docLine.offsetTop; @@ -3496,15 +3502,15 @@ function Ace2Inner(editorInfo, cssManagers) { this.init = async () => { await $.ready; inCallStack('setup', () => { - if (browser.firefox) $(document.body).addClass('mozilla'); - if (browser.safari) $(document.body).addClass('safari'); - document.body.classList.toggle('authorColors', true); - document.body.classList.toggle('doesWrap', doesWrap); + if (browser.firefox) $(targetBody).addClass('mozilla'); + if (browser.safari) $(targetBody).addClass('safari'); + targetBody.classList.toggle('authorColors', true); + targetBody.classList.toggle('doesWrap', doesWrap); enforceEditability(); // set up dom and rep - while (document.body.firstChild) document.body.removeChild(document.body.firstChild); + while (targetBody.firstChild) targetBody.removeChild(targetBody.firstChild); const oneEntry = createDomLineEntry(''); doRepLineSplice(0, rep.lines.length(), [oneEntry]); insertDomLines(null, [oneEntry.domInfo]); diff --git a/src/static/js/caretPosition.js b/src/static/js/caretPosition.js index 03af77f33..2814da74a 100644 --- a/src/static/js/caretPosition.js +++ b/src/static/js/caretPosition.js @@ -5,6 +5,7 @@ // is represented by the browser exports.getPosition = () => { const range = getSelectionRange(); + console.log("Getting range", range) if (!range || $(range.endContainer).closest('body')[0].id !== 'innerdocbody') return null; // When there's a
or any element that has no height, we can't get the dimension of the // element where the caret is. As we can't get the element height, we create a text node to get diff --git a/src/static/js/pad_editor.js b/src/static/js/pad_editor.js index 585cccbb5..c02832835 100644 --- a/src/static/js/pad_editor.js +++ b/src/static/js/pad_editor.js @@ -24,9 +24,9 @@ const Cookies = require('./pad_utils').Cookies; const padcookie = require('./pad_cookie').padcookie; const padutils = require('./pad_utils').padutils; +const Ace2Editor = require('./ace').Ace2Editor; const padeditor = (() => { - let Ace2Editor = undefined; let pad = undefined; let settings = undefined; @@ -35,7 +35,6 @@ const padeditor = (() => { // this is accessed directly from other files viewZoom: 100, init: async (initialViewOptions, _pad) => { - Ace2Editor = require('./ace').Ace2Editor; pad = _pad; settings = pad.settings; self.ace = new Ace2Editor(); diff --git a/src/static/js/pad_utils.js b/src/static/js/pad_utils.js index 58105d23c..6601cb2c3 100644 --- a/src/static/js/pad_utils.js +++ b/src/static/js/pad_utils.js @@ -443,7 +443,7 @@ const inThirdPartyIframe = () => { // This file is included from Node so that it can reuse randomString, but Node doesn't have a global // window object. if (typeof window !== 'undefined') { - exports.Cookies = require('js-cookie/dist/js.cookie').withAttributes({ + exports.Cookies = require('js-cookie').withAttributes({ // Use `SameSite=Lax`, unless Etherpad is embedded in an iframe from another site in which case // use `SameSite=None`. For iframes from another site, only `None` has a chance of working // because the cookies are third-party (not same-site). Many browsers/users block third-party diff --git a/src/static/js/pluginfw/client_plugins.js b/src/static/js/pluginfw/client_plugins.js index 221e786f8..3a0687733 100644 --- a/src/static/js/pluginfw/client_plugins.js +++ b/src/static/js/pluginfw/client_plugins.js @@ -7,24 +7,13 @@ exports.baseURL = ''; exports.ensure = (cb) => !defs.loaded ? exports.update(cb) : cb(); -exports.update = (cb) => { - // It appears that this response (see #620) may interrupt the current thread - // of execution on Firefox. This schedules the response in the run-loop, - // which appears to fix the issue. - const callback = () => setTimeout(cb, 0); - - jQuery.getJSON( - `${exports.baseURL}pluginfw/plugin-definitions.json?v=${clientVars.randomVersionString}` - ).done((data) => { - defs.plugins = data.plugins; - defs.parts = data.parts; - defs.hooks = pluginUtils.extractHooks(defs.parts, 'client_hooks'); - defs.loaded = true; - callback(); - }).fail((err) => { - console.error(`Failed to load plugin-definitions: ${err}`); - callback(); - }); +exports.update = async (modules) => { + const data = await jQuery.getJSON( + `${exports.baseURL}pluginfw/plugin-definitions.json?v=${clientVars.randomVersionString}`); + defs.plugins = data.plugins; + defs.parts = data.parts; + defs.hooks = pluginUtils.extractHooks(defs.parts, 'client_hooks', null, modules); + defs.loaded = true; }; const adoptPluginsFromAncestorsOf = (frame) => { diff --git a/src/static/js/scroll.js b/src/static/js/scroll.js index 86d6a3344..6614a1973 100644 --- a/src/static/js/scroll.js +++ b/src/static/js/scroll.js @@ -15,7 +15,7 @@ function Scroll(outerWin) { // DOM reference this.outerWin = outerWin; - this.doc = this.outerWin.document; + this.doc = this.outerWin.contentDocument; this.rootDocument = parent.parent.document; } diff --git a/src/static/js/vendors/farbtastic.js b/src/static/js/vendors/farbtastic.js index ad832dc72..5a187ea47 100644 --- a/src/static/js/vendors/farbtastic.js +++ b/src/static/js/vendors/farbtastic.js @@ -172,7 +172,7 @@ $._farbtastic = function (container, options) { angle2 = d2 * Math.PI * 2, // Endpoints x1 = Math.sin(angle1), y1 = -Math.cos(angle1); - x2 = Math.sin(angle2), y2 = -Math.cos(angle2), + let x2 = Math.sin(angle2), y2 = -Math.cos(angle2), // Midpoint chosen so that the endpoints are tangent to the circle. am = (angle1 + angle2) / 2, tan = 1 / Math.cos((angle2 - angle1) / 2), @@ -329,8 +329,8 @@ $._farbtastic = function (container, options) { // Update the overlay canvas. fb.ctxOverlay.clearRect(-fb.mid, -fb.mid, sz, sz); - for (i in circles) { - var c = circles[i]; + for (let i in circles) { + const c = circles[i]; fb.ctxOverlay.lineWidth = c.lw; fb.ctxOverlay.strokeStyle = c.c; fb.ctxOverlay.beginPath(); diff --git a/src/templates/padBootstrap.js b/src/templates/padBootstrap.js index 5758234ae..77861758c 100644 --- a/src/templates/padBootstrap.js +++ b/src/templates/padBootstrap.js @@ -1,3 +1,4 @@ + (async () => { window.clientVars = { // This is needed to fetch /pluginfw/plugin-definitions.json, which happens before the server @@ -6,7 +7,7 @@ }; // Allow other frames to access this frame's modules. - window.require.resolveTmp = require.resolve('ep_etherpad-lite/static/js/pad_cookie'); + //window.require.resolveTmp = require.resolve('ep_etherpad-lite/static/js/pad_cookie'); const basePath = new URL('..', window.location.href).pathname; window.$ = window.jQuery = require('../../src/static/js/rjquery').jQuery; diff --git a/var/js/.gitignore b/var/js/.gitignore index e69de29bb..086f4e283 100644 --- a/var/js/.gitignore +++ b/var/js/.gitignore @@ -0,0 +1,2 @@ +*.js +*.map