-
Notifications
You must be signed in to change notification settings - Fork 10.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[editor] Add a FreeText editor (#14970) #14976
Conversation
calixteman
commented
Jun 1, 2022
- add a basic UI to edit some text in a pdf;
- an editor can be moved, suppressed, cut, copied, pasted, selected;
- add an undo/redo manager.
60cfaad
to
aa0b618
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sure is a lot of code all at once :-)
The following comments are based on a first brief look, and so far I've not really looked at the main part of the patch i.e. src/display/annotation_editor_layer.js
(given its size).
Looking at the viewer-integration in particular, there's room for improvement to make this better and easier to work with (especially when adding support for additional annotation-types later).
#id; | ||
|
||
constructor() { | ||
this.#id = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't you just directly define #id = 0
above and remove the constructor?
The same (or similar) comment also applies in other spots further down in this file.
src/display/annotation_storage.js
Outdated
|
||
const clone = new Map(); | ||
for (const [key, value] of this._storage) { | ||
if ("serialize" in value) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels brittle, i.e. there's nothing stopping a user from manually adding something to the storage that'd fail here; so can we please not do this?
Instead, let's use something like value instanceof AnnotationEditor
here (which I think is what the value should be).
const isMac = | ||
typeof navigator !== "undefined" && | ||
(navigator.platform.startsWith("Mac") || navigator.platform === "iPhone"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make this more maintainable/clearer, please add a method similar to the following one in this class as well:
pdf.js/src/display/annotation_layer.js
Lines 554 to 561 in 1ac33c9
static get platform() { | |
const platform = typeof navigator !== "undefined" ? navigator.platform : ""; | |
return shadow(this, "platform", { | |
isWin: platform.includes("Win"), | |
isMac: platform.includes("Mac"), | |
}); | |
} |
src/display/display_utils.js
Outdated
@@ -241,6 +241,7 @@ class PageViewport { | |||
offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY, | |||
offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY, | |||
]; | |||
this.inverseTransform = Util.inverseTransform(this.transform); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that this isn't used by default (at least I don't think so), can we use a (shadowed) getter for this instead?
} | ||
|
||
.annotationEditorLayer .freeTextEditor .internal:empty::before { | ||
content: "Enter some text..."; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This must be properly localizable!
Please refer to how the AnnotationLayer handles localization, and follow a similar pattern for the annotationEditorLayer as well.
web/viewer.html
Outdated
@@ -263,6 +263,12 @@ | |||
<span id="numPages" class="toolbarLabel"></span> | |||
</div> | |||
<div id="toolbarViewerRight"> | |||
<div id="editionButtons" role="radiogroup"> | |||
<button id="freeTextMode" class="toolbarButton" title="Add some free text" role="radio" aria-checked="false" tabindex="31" data-l10n-id="freetext_mode"> | |||
<span data-l10n-id="freetext_mode_label">Free Text</span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
editor_free_text_label
and "FreeText Annotation" here.
web/app.js
Outdated
if (AppOptions.get("annotationEditionMode")) { | ||
document.getElementById("freeTextMode").style.visibility = "visible"; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (AppOptions.get("annotationEditionMode")) { | |
document.getElementById("freeTextMode").style.visibility = "visible"; | |
} | |
if (AppOptions.get("annotationEditorEnabled")) { | |
document.getElementById("editorModeButtons").classList.remove("hidden"); | |
} | |
web/app.js
Outdated
@@ -1878,6 +1889,7 @@ const PDFViewerApplication = { | |||
eventBus._on("namedaction", webViewerNamedAction); | |||
eventBus._on("presentationmodechanged", webViewerPresentationModeChanged); | |||
eventBus._on("presentationmode", webViewerPresentationMode); | |||
eventBus._on("freetextmode", webViewerFreeTextMode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please note the comment in web/toolbar.js
about the event name/format.
web/app.js
Outdated
@@ -1851,6 +1857,11 @@ const PDFViewerApplication = { | |||
this.pdfPresentationMode?.request(); | |||
}, | |||
|
|||
requestFreeTextMode() { | |||
AnnotationEditorLayerBuilder.setEditorType("FreeText"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(While the viewer only really supports being used standalone, it seems a bit weird that the editor-mode is global. However, I guess that this considerably simplifies the overall implementation?)
web/app.js
Outdated
requestFreeTextMode() { | ||
AnnotationEditorLayerBuilder.setEditorType("FreeText"); | ||
this.appConfig.toolbar.freeTextModeButton.classList.toggle("toggled"); | ||
}, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please handle this in the BaseViewer
instead, again similar to how the scroll/spread-modes are implemented.
Basically, let's add a annotationEditorMode
getter/setter-pair in the BaseViewer that takes care of updating the editor-mode and then dispatches a annotationeditormodechanged
event that the Toolbar listens to and updates the buttons correctly.
* Base class for editors. | ||
*/ | ||
class AnnotationEditor { | ||
#isInEditMode; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned previously, I believe that this can be directly initialized here (rather than in the constructor).
/** | ||
* @param {AnnotationEditorParameters} parameters | ||
*/ | ||
constructor(parameters) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that this is an abstract base class, how about enforcing that it cannot be used directly with something similar to e.g.
pdf.js/src/core/base_stream.js
Lines 20 to 22 in 1ac33c9
if (this.constructor === BaseStream) { | |
unreachable("Cannot initialize BaseStream."); | |
} |
* @returns {AnnotationEditor} | ||
*/ | ||
copy() { | ||
throw new Error("An editor must be copyable"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In other abstract base classes, we usually use unreachable
in these cases (applies both here and below).
); | ||
|
||
return { | ||
type: "FreeText", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned in the other PR, how about using AnnotationType
instead here?
default: | ||
this._currentEditorClass = null; | ||
} | ||
this._currentEditorType = type; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this allow setting the property to any value, i.e. even one that's completely bogus; does that not matter?
/** | ||
* Class to handle undo/redo. | ||
* Commands are just saved in a buffer. | ||
* If we hit some memory issues we could likely use a circular buffer. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you have some idea of the number of commands where this might start to become an issue?
To be defensive here, perhaps we could simply prune the commands from the start of the Array once a large number has been added (e.g. more than 100 commands)?
static _keyboardManager = new KeyboardManager([ | ||
[["ctrl+a", "mac+meta+a"], AnnotationEditorLayer.prototype.selectAll], | ||
[ | ||
["ctrl+shift+A", "mac+alt+meta+æ"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do these shortcuts actually make sense?
When using Firefox, on Windows, the "ctrl+shift+A" shortcut will open the about:addons
page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Acrobat has a shortcut to select/deselect all and I thought it was for newly added annotations but I was wrong.
So I'll remove them.
eef68ae
to
90497c3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Splitting this into multiple files definitely helps a lot here!
This is looking much better already, and I think that we can probably land this pretty soon, however I've added some more comments as I try to get through all of this (will try to look more during the weekend).
l10n/en-US/viewer.properties
Outdated
@@ -249,3 +249,8 @@ password_cancel=Cancel | |||
printing_not_supported=Warning: Printing is not fully supported by this browser. | |||
printing_not_ready=Warning: The PDF is not fully loaded for printing. | |||
web_fonts_disabled=Web fonts are disabled: unable to use embedded PDF fonts. | |||
|
|||
# Edition |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use "Editor" here.
l10n/en-US/viewer.properties
Outdated
# Edition | ||
freetext_default_content=Enter some text... | ||
editor_free_text.title=Add FreeText Annotation | ||
editor_free_text_label=FreeText Annotation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing new-line here.
@@ -0,0 +1,432 @@ | |||
/* Copyright 2022 Mozilla Foundation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this, and the other new files, please change the directory name to editor/
instead.
web/base_viewer.js
Outdated
this.#annotationEditorEnabled = options.annotationEditorEnabled === true; | ||
if (this.#annotationEditorEnabled) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we actually need this property now, or if we could just do the following here and then just check for this.#annotationEditorUIManager
below in the setDocument
-method?
if (options.annotationEditorEnabled === true) {
web/base_viewer.js
Outdated
if (this.#annotationEditorMode === mode) { | ||
this.#annotationEditorMode = AnnotationEditorType.NONE; | ||
} else { | ||
this.#annotationEditorMode = mode; | ||
} | ||
this.#annotationEditorUIManager.updateMode(this.#annotationEditorMode); | ||
this.eventBus.dispatch("annotationeditormodechanged", { | ||
source: this, | ||
mode: this.#annotationEditorMode, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following the Scroll/Spread-mode setters, this should look something like the following:
if (this.#annotationEditorMode === mode) { | |
this.#annotationEditorMode = AnnotationEditorType.NONE; | |
} else { | |
this.#annotationEditorMode = mode; | |
} | |
this.#annotationEditorUIManager.updateMode(this.#annotationEditorMode); | |
this.eventBus.dispatch("annotationeditormodechanged", { | |
source: this, | |
mode: this.#annotationEditorMode, | |
}); | |
if (!this.#annotationEditorUIManager) { | |
throw new Error(`The AnnotationEditor is not enabled.`); | |
} | |
if (this.#annotationEditorMode === mode) { | |
return; // The AnnotationEditor mode didn't change. | |
} | |
if (!isValidAnnotationEditorMode(mode)) { | |
throw new Error(`Invalid AnnotationEditor mode: ${mode}`); | |
} | |
this.#annotationEditorMode = mode; | |
this.eventBus.dispatch("annotationeditormodechanged", { | |
source: this, | |
mode, | |
}); | |
this.#annotationEditorUIManager.updateMode(mode); |
web/toolbar.js
Outdated
this.editorButtons = [ | ||
[AnnotationEditorType.FREE_TEXT, options.editorFreeTextButton], | ||
]; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please follow the same pattern as in these methods here instead:
pdf.js/web/secondary_toolbar.js
Lines 160 to 162 in 1953967
this.#bindCursorToolsListener(options); | |
this.#bindScrollModeListener(options); | |
this.#bindSpreadModeListener(options); |
Basically, you want to add a #bindEditorModeListener
-method and please make sure that it implements the toggled
and aria-checked
attributes the same way as e.g.
pdf.js/web/secondary_toolbar.js
Lines 219 to 230 in 1953967
#bindCursorToolsListener({ cursorSelectToolButton, cursorHandToolButton }) { | |
this.eventBus._on("cursortoolchanged", function ({ tool }) { | |
const isSelect = tool === CursorTool.SELECT, | |
isHand = tool === CursorTool.HAND; | |
cursorSelectToolButton.classList.toggle("toggled", isSelect); | |
cursorHandToolButton.classList.toggle("toggled", isHand); | |
cursorSelectToolButton.setAttribute("aria-checked", isSelect); | |
cursorHandToolButton.setAttribute("aria-checked", isHand); | |
}); | |
} |
web/viewer.html
Outdated
@@ -263,30 +263,36 @@ | |||
<span id="numPages" class="toolbarLabel"></span> | |||
</div> | |||
<div id="toolbarViewerRight"> | |||
<button id="presentationMode" class="toolbarButton hiddenLargeView" title="Switch to Presentation Mode" tabindex="31" data-l10n-id="presentation_mode"> | |||
<div id="editionModeButtons" class="splitToolbarButton hidden" role="radiogroup"> | |||
<button id="editorFreeText" class="toolbarButton" title="Add some free text" role="radio" aria-checked="false" tabindex="31" data-l10n-id="editor_free_text"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned previously, I still firmly believe that we need a button for the (default) "no editing is currently happening"-state to make it clear when editing is not being used (or how to toggle the feature off).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a mode is enabled, here FreeText, the button is in a toggled state:
and when it's clicked, then it switches to untoggled state and then no more edition is possible.
It is the way it works in Edge (I don't pretend that Edge is a model to follow: I don't have any strong opinions on this kind of stuff and I hope some UX people could help on this kind of stuff).
Anyway, could we considering doing that in a follow-up ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and when it's clicked, then it switches to untoggled state and then no more edition is possible.
As soon as you add support for at least one more kind of Annotation, this will start becoming really confusing as far as I'm concerned.
Hence why I think that we should fix this now, since it will simplify future changes and would also be consistent with all of our other buttons that control related state (see e.g. the Sidebar buttons, or Scroll/Spread-mode buttons).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing that's not particularly nice, in my opinion, about the current implementation is that it makes the BaseViewer
-setter look inconsistent/strange when compared to many of the other ones (since they purposely ignore the "value is the same"-case).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, as said I don't have any opinion on UX stuff: usually I rely on people who know.... and you're definitely a better expert than me.
Any idea for an icon ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not an expert on UX matters either, but I just want to try and make it as easily as possible to work with this w.r.t. any future changes (since I assume INK-annotations may be next in line here, given e.g. the code comments in BaseViewer
).
Assuming that the icons are indeed only temporary, and given that all of this is disabled by default, how about maybe adding a copy of the selectTool.svg
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ink stuff is ready ;)
Ok for selectTool.
src/display/edition/freetext.js
Outdated
} | ||
|
||
static setL10n(l10n) { | ||
l10n?.get("freetext_default_content").then(msg => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add this new string to the list in https://github.com/mozilla/pdf.js/blob/master/web/l10n_utils.js, to ensure that a fallback value is always available.
Furthermore, is there ever a risk that the localized string becomes available after the attribute has been set below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question: I asked it to myself.
So l10n
is queried at the first layer creation, in order to see it (or not) the user need to click on the text editor button then move their mouse somewhere on the page, click and then the div is created with an attribute having (or not) the localized value. My feeling is it's very unlikely possible to have a wrong string. I thought to try to implement something in js to emulate the empty::before
behaviour, but I wasn't super excited by the idea... compared the easy solution we've right now.
Anyway, as usual if you have a good idea, I take it !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it work if the attribute is always updated asynchronously instead, or does that not work?
Because in that case we could just store the Promise here, rather than the raw string, with something like
this._defaultContentPromise = l10n.get("freetext_default_content");
and then set the attribute with
FreeTextEditor._defaultContentPromise.then(msg => {
this.editorDiv.setAttribute("default-content", msg);
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested here:
https://jsfiddle.net/ub7tmxdo/13/
and it works.
|
||
const data = "Hello PDF.js World !!"; | ||
await page.mouse.click(rect.x + 10, rect.y + 10); | ||
await page.type("#pdfjs_internal_editor_0 .internal", data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, and elsewhere in the tests, I suggest using the new constant in these strings to avoid having to edit the test-cases if we ever need to update the prefix.
src/display/edition/freetext.js
Outdated
|
||
/** @inheritdoc */ | ||
isEmpty() { | ||
return this.editorDiv.innerText.trim() === ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, and elsewhere below, can we perhaps use textContent
since I believe that's generally recommended over innerText
these days?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, I think innerText
is better than textContent
mainly because of <br>
:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText
I wanted to use a basic textarea
but I didn't manage to make it growable so I fall back on a div
, hence the <br>
...
this.pageDiv = options.pageDiv; | ||
this.pdfPage = options.pdfPage; | ||
this.annotationStorage = options.annotationStorage || null; | ||
this.l10n = options.l10n; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following the web/annotation_layer_builder.js
implementation, I believe that you want ... || NullL10n
here.
One bonus is that the code in src/display/editor/...
can then just assume that the l10n is always available.
src/shared/util.js
Outdated
}; | ||
|
||
function isValidAnnotationEditorMode(mode) { | ||
return mode >= 0 && mode < Object.keys(AnnotationEditorType).length; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems generally safer, with any future changes, to use Object.values(AnnotationEditorType).includes(mode)
here similar to the pre-existing helper functions.
Also, if we're only using this in the BaseViewer
the helper function can possible live in that file for now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
r=me, with the final comments addressed and all tests passing.
Thank you, and sorry about the back-and-forth during review!
src/shared/util.js
Outdated
|
||
const AnnotationEditorType = { | ||
NONE: 0, | ||
FREE_TEXT: 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To prevent future errors and typos, we should probably use the exact same names/values as in AnnotationType
for these ones as well.
Hence, please let's use FREETEXT: 3,
instead here.
if (evt.toggle) { | ||
PDFViewerApplication.pdfViewer.annotionEditorEnabled = true; | ||
} else { | ||
PDFViewerApplication.pdfViewer.annotationEditorMode = evt.mode; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, but why?
This really ought to be simply PDFViewerApplication.pdfViewer.annotationEditorMode = evt.mode;
and nothing else here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, ok I think I understand what you want.
So to sum up and to be sure that we're ok:
- clicking on
select
:- when off, switch to on and set tool buttons to off
- when on, switch to off and set tool buttons to off
- when clicking on a tool button:
- when off, switch to one and set other tool buttons to off
- when on do nothing
Finally, each tool button (FreeText, Ink, ....) is equivalent to a radio button.
Is it correct ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea was actually that all buttons behave as if they were radio-buttons, including the editorNone
-one (hence no special handling for that one).
Basically, it's only possible to have one of the None/FreeText/Ink/... buttons toggled at any one time. Does that help?
web/base_viewer.js
Outdated
get annotionEditorEnabled() { | ||
return this.#annotionEditorEnabled; | ||
} | ||
|
||
set annotionEditorEnabled(toggle) { | ||
this.#annotionEditorEnabled = !this.#annotionEditorEnabled; | ||
this.eventBus.dispatch("annotationeditormodechanged", { | ||
source: this, | ||
mode: this.#annotationEditorMode, | ||
enable: this.#annotionEditorEnabled, | ||
}); | ||
this.#annotationEditorUIManager.enableEdition(this.#annotionEditorEnabled); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, but why?
Please remove this getter/setter pair.
web/base_viewer.js
Outdated
if (!this.#annotationEditorUIManager) { | ||
throw new Error(`The AnnotationEditor is not enabled.`); | ||
} | ||
|
||
if (!this.#annotionEditorEnabled) { | ||
return; | ||
} | ||
|
||
if (!Object.values(AnnotationEditorType).includes(mode)) { | ||
throw new Error(`Invalid AnnotationEditor mode: ${mode}`); | ||
} | ||
|
||
// If the mode is the same as before, it means that this mode is disabled | ||
// and consequently the mode is NONE. | ||
this.#annotationEditorMode = | ||
this.#annotationEditorMode === mode ? AnnotationEditorType.NONE : mode; | ||
this.eventBus.dispatch("annotationeditormodechanged", { | ||
source: this, | ||
mode: this.#annotationEditorMode, | ||
}); | ||
this.#annotationEditorUIManager.updateMode(this.#annotationEditorMode); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please implement this as suggested in #14976 (comment) instead.
@@ -0,0 +1,4 @@ | |||
<!-- This Source Code Form is subject to the terms of the Mozilla Public |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please let's call this file toolbarButton-editorNone.svg
instead.
web/viewer.html
Outdated
<button id="editorFreeText" class="toolbarButton" title="Add some free text" role="radio" aria-checked="false" tabindex="32" data-l10n-id="editor_free_text"> | ||
<span data-l10n-id="editor_free_text_label">Free Text Annotation</span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<button id="editorFreeText" class="toolbarButton" title="Add some free text" role="radio" aria-checked="false" tabindex="32" data-l10n-id="editor_free_text"> | |
<span data-l10n-id="editor_free_text_label">Free Text Annotation</span> | |
<button id="editorFreeText" class="toolbarButton" title="Add FreeText Annotation" role="radio" aria-checked="false" tabindex="32" data-l10n-id="editor_free_text"> | |
<span data-l10n-id="editor_free_text_label">FreeText Annotation</span> |
web/viewer.html
Outdated
</button> | ||
</div> | ||
|
||
<button id="presentationMode" class="toolbarButton hiddenLargeView" title="Switch to Presentation Mode" tabindex="33" data-l10n-id="presentation_mode"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How many new buttons do you foresee adding?
To avoid changing the blame again, can you please increase this and the following tabindex
s to account for additional buttons above such that we don't need to touch them again in just a couple of days?
web/viewer.js
Outdated
editorFreeTextButton: document.getElementById("editorFreeText"), | ||
editorSelectButton: document.getElementById("editorSelect"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
editorFreeTextButton: document.getElementById("editorFreeText"), | |
editorSelectButton: document.getElementById("editorSelect"), | |
editorNoneButton: document.getElementById("editorNone"), | |
editorFreeTextButton: document.getElementById("editorFreeText"), |
* @property {HTMLButtonElement} editorFreeTextButton - Button to switch to Free | ||
* Text edition. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @property {HTMLButtonElement} editorFreeTextButton - Button to switch to Free | |
* Text edition. | |
* @property {HTMLButtonElement} editorNoneButton - Button to disable editing. | |
* @property {HTMLButtonElement} editorFreeTextButton - Button to switch to | |
* FreeText editing. |
* Change the edition mode (FreeText, Ink, ...) | ||
* @param {number} mode | ||
*/ | ||
updateMode(mode) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make sure that this method handles AnnotationEditorType.NONE
, and use that to disable editing.
Most likely, the method below is no longer necessary in that case.
web/viewer.html
Outdated
<button id="editorSelect" class="toolbarButton" title="Enter in edit mode" role="radio" aria-checked="false" tabindex="31" data-l10n-id="editor_select"> | ||
<span data-l10n-id="editor_select_label">Edit Mode</span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<button id="editorSelect" class="toolbarButton" title="Enter in edit mode" role="radio" aria-checked="false" tabindex="31" data-l10n-id="editor_select"> | |
<span data-l10n-id="editor_select_label">Edit Mode</span> | |
<button id="editorNone" class="toolbarButton toggled" title="Disable Annotation Editing" role="radio" aria-checked="false" tabindex="31" data-l10n-id="editor_none"> | |
<span data-l10n-id="editor_none_label">Disable Editing</span> |
/botio integrationtest |
From: Bot.io (Linux m4)ReceivedCommand cmd_integrationtest from @calixteman received. Current queue size: 0 Live output at: http://54.241.84.105:8877/d853ee10b3122b1/output.txt |
From: Bot.io (Windows)ReceivedCommand cmd_integrationtest from @calixteman received. Current queue size: 0 Live output at: http://54.193.163.58:8877/a2f0fd5583b4c56/output.txt |
From: Bot.io (Linux m4)FailedFull output at http://54.241.84.105:8877/d853ee10b3122b1/output.txt Total script time: 4.54 mins
|
From: Bot.io (Windows)FailedFull output at http://54.193.163.58:8877/a2f0fd5583b4c56/output.txt Total script time: 7.89 mins
|
Same error on the two bots and I can't of course reproduce locally... |
/botio-windows integrationtest |
From: Bot.io (Windows)ReceivedCommand cmd_integrationtest from @calixteman received. Current queue size: 0 Live output at: http://54.193.163.58:8877/edb23ce17a55f03/output.txt |
From: Bot.io (Windows)FailedFull output at http://54.193.163.58:8877/edb23ce17a55f03/output.txt Total script time: 6.94 mins
|
It's an issue with Chrome: I'm fixing. |
- add a basic UI to edit some text in a pdf; - an editor can be moved, suppressed, cut, copied, pasted, selected; - add an undo/redo manager.
/botio integrationtest |
From: Bot.io (Linux m4)ReceivedCommand cmd_integrationtest from @calixteman received. Current queue size: 0 Live output at: http://54.241.84.105:8877/e2020feb72c7228/output.txt |
From: Bot.io (Windows)ReceivedCommand cmd_integrationtest from @calixteman received. Current queue size: 0 Live output at: http://54.193.163.58:8877/c55e90fe291cdea/output.txt |
From: Bot.io (Linux m4)SuccessFull output at http://54.241.84.105:8877/e2020feb72c7228/output.txt Total script time: 4.61 mins
|
From: Bot.io (Windows)FailedFull output at http://54.193.163.58:8877/c55e90fe291cdea/output.txt Total script time: 9.43 mins
|
/botio unittest |
From: Bot.io (Windows)ReceivedCommand cmd_unittest from @calixteman received. Current queue size: 0 Live output at: http://54.193.163.58:8877/887c7989e838d28/output.txt |
From: Bot.io (Linux m4)ReceivedCommand cmd_unittest from @calixteman received. Current queue size: 0 Live output at: http://54.241.84.105:8877/21374491f164cc0/output.txt |
From: Bot.io (Linux m4)FailedFull output at http://54.241.84.105:8877/21374491f164cc0/output.txt Total script time: 3.27 mins
|
From: Bot.io (Windows)SuccessFull output at http://54.193.163.58:8877/887c7989e838d28/output.txt Total script time: 5.44 mins
|
To come back to this question, which I originally missed in all the comments here, I did indeed make the original enumeration based on the order in the specification, but I wouldn't mind adding a |