0

pdf: Warn about form changes entering annotation

This is a contingency for the event that the annotation feature is
enabled but form saving is not.
* A new field hasUnsavedChanges is added to the save result, this
  is set when there are edits but form saving is not enabled.
* When this field is true, a dialog is shown to the user allowing
  a choice whether to continue to enter annotation mode or not.
* The annotation toggle event is made custom to avoid re-entrancy
  when entering anntation mode is aborted.

Bug: 902646
Change-Id: I885aa9ee76afb500a086097aed08422ececdf052
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1502255
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: dsinclair <dsinclair@chromium.org>
Commit-Queue: dstockwell <dstockwell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#637893}
This commit is contained in:
dstockwell
2019-03-05 23:27:17 +00:00
committed by Commit Bot
parent 6b7213a453
commit c90ebdda97
11 changed files with 118 additions and 4 deletions

@ -118,6 +118,12 @@ void AddStringsForPdf(base::DictionaryValue* dict) {
SetL10nString(dict, "annotationSize12", IDS_PDF_ANNOTATION_SIZE12);
SetL10nString(dict, "annotationSize16", IDS_PDF_ANNOTATION_SIZE16);
SetL10nString(dict, "annotationSize20", IDS_PDF_ANNOTATION_SIZE20);
SetL10nString(dict, "annotationFormWarningTitle",
IDS_PDF_DISCARD_FORM_CHANGES);
SetL10nString(dict, "annotationFormWarningDetail",
IDS_PDF_DISCARD_FORM_CHANGES_DETAIL);
SetL10nString(dict, "annotationFormWarningKeepEditing", IDS_PDF_KEEP_EDITING);
SetL10nString(dict, "annotationFormWarningDiscard", IDS_PDF_DISCARD);
#endif
}

@ -131,6 +131,8 @@
<include name="IDR_PDF_VIEWER_INK_HOST_JS" file="pdf/elements/viewer-ink-host/viewer-ink-host.js" type="BINDATA" />
<include name="IDR_PDF_VIEWER_PEN_OPTIONS_HTML" file="pdf/elements/viewer-pen-options/viewer-pen-options.html" type="BINDATA" />
<include name="IDR_PDF_VIEWER_PEN_OPTIONS_JS" file="pdf/elements/viewer-pen-options/viewer-pen-options.js" type="BINDATA" />
<include name="IDR_PDF_VIEWER_FORM_WARNING_HTML" file="pdf/elements/viewer-form-warning/viewer-form-warning.html" type="BINDATA" />
<include name="IDR_PDF_VIEWER_FORM_WARNING_JS" file="pdf/elements/viewer-form-warning/viewer-form-warning.js" type="BINDATA" />
</if>
<include name="IDR_PDF_VIEWER_PAGE_INDICATOR_HTML" file="pdf/elements/viewer-page-indicator/viewer-page-indicator.html" type="BINDATA" />
<include name="IDR_PDF_VIEWER_PAGE_INDICATOR_JS" file="pdf/elements/viewer-page-indicator/viewer-page-indicator.js" type="BINDATA" flattenhtml="true" />

@ -10,6 +10,7 @@ group("closure_compile") {
":pdf_resources",
"elements/viewer-bookmark:closure_compile",
"elements/viewer-error-screen:closure_compile",
"elements/viewer-form-warning:closure_compile",
"elements/viewer-page-indicator:closure_compile",
"elements/viewer-page-selector:closure_compile",
"elements/viewer-password-screen:closure_compile",

@ -0,0 +1,18 @@
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//third_party/closure_compiler/compile_js.gni")
js_type_check("closure_compile") {
deps = [
":viewer-form-warning",
]
}
js_library("viewer-form-warning") {
deps = [
"//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
"//ui/webui/resources/js:promise_resolver",
]
}

@ -0,0 +1,25 @@
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
<link rel="import" href="chrome://resources/cr_elements/paper_button_style_css.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
<dom-module id="viewer-form-warning">
<template>
<style include="paper-button-style cr-hidden-style"></style>
<cr-dialog id="dialog" no-cancel>
<div slot="title">[[strings.annotationFormWarningTitle]]</div>
<div slot="body">[[strings.annotationFormWarningDetail]]</div>
<div slot="button-container">
<paper-button class="cancel-button" on-click="onCancel">
[[strings.annotationFormWarningKeepEditing]]
</paper-button>
<paper-button class="action-button" on-click="onAction">
[[strings.annotationFormWarningDiscard]]
</paper-button>
</div>
</cr-dialog>
</template>
<script src="viewer-form-warning.js"></script>
</dom-module>

@ -0,0 +1,29 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
Polymer({
is: 'viewer-form-warning',
properties: {
strings: Object,
},
/** @private {PromiseResolver} */
resolver_: null,
show: function() {
this.resolver_ = new PromiseResolver();
/** @type {!CrDialogElement} */ (this.$.dialog).showModal();
return this.resolver_.promise;
},
onCancel: function() {
this.resolver_.reject();
this.$.dialog.cancel();
},
onAction: function() {
this.resolver_.resolve();
this.$.dialog.close();
},
});

@ -190,6 +190,11 @@ Polymer({
// Select pen tool when entering annotation mode.
this.updateAnnotationTool_(this.$.pen);
}
this.dispatchEvent(new CustomEvent('annotation-mode-toggled', {
detail: {
value: this.annotationMode,
},
}));
},
/** @param {Event} e */

@ -9,9 +9,11 @@
<link rel="import" href="elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html">
<link rel="import" href="elements/viewer-zoom-toolbar/viewer-zoom-toolbar.html">
<link rel="import" href="elements/shared-vars.html">
<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
<if expr="chromeos">
<link rel="import" href="elements/viewer-ink-host/viewer-ink-host.html">
<link rel="import" href="elements/viewer-form-warning/viewer-form-warning.html">
</if>
<link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
@ -30,6 +32,10 @@
<viewer-error-screen id="error-screen"></viewer-error-screen>
<if expr="chromeos">
<viewer-form-warning id="form-warning"></viewer-form-warning>
</if>
<div id="content"></div>
</body>

@ -256,7 +256,7 @@ function PDFViewer(browserApi) {
this.toolbar_.addEventListener(
'rotate-right', () => this.rotateClockwise());
this.toolbar_.addEventListener(
'annotation-mode-changed', e => this.annotationModeChanged_(e));
'annotation-mode-toggled', e => this.annotationModeToggled_(e));
this.toolbar_.addEventListener(
'annotation-tool-changed',
e => this.inkController_.setAnnotationTool(e.detail.value));
@ -500,17 +500,28 @@ PDFViewer.prototype = {
* @param {!CustomEvent<{value: boolean}>} e
* @private
*/
annotationModeChanged_: async function(e) {
annotationModeToggled_: async function(e) {
const annotationMode = e.detail.value;
if (annotationMode) {
// Enter annotation mode.
PDFMetrics.record(PDFMetrics.UserAction.ENTER_ANNOTATION_MODE);
this.hasEnteredAnnotationMode_ = true;
assert(this.currentController_ == this.pluginController_);
// TODO(dstockwell): set plugin read-only, begin transition
this.updateProgress(0);
// TODO(dstockwell): handle save failure
const result = await this.pluginController_.save(true);
if (result.hasUnsavedChanges) {
assert(!loadTimeData.getBoolean('pdfFormSaveEnabled'));
try {
await $('form-warning').show();
} catch (e) {
// The user aborted entering annotation mode. Revert to the plugin.
this.toolbar_.annotationMode = false;
this.updateProgress(100);
return;
}
}
PDFMetrics.record(PDFMetrics.UserAction.ENTER_ANNOTATION_MODE);
this.hasEnteredAnnotationMode_ = true;
// TODO(dstockwell): feed real progress data from the Ink component
this.updateProgress(50);
await this.inkController_.load(result.fileName, result.dataToSave);
@ -737,6 +748,9 @@ PDFViewer.prototype = {
$('zoom-toolbar').strings = strings;
$('password-screen').strings = strings;
$('error-screen').strings = strings;
if ($('form-warning')) {
$('form-warning').strings = strings;
}
},
/**

@ -364,6 +364,10 @@ std::vector<std::string> SetupPrintPreviewPlugin(
{"pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js",
IDR_PDF_VIEWER_PDF_TOOLBAR_JS},
#if defined(OS_CHROMEOS)
{"pdf/elements/viewer-form-warning/viewer-form-warning.html",
IDR_PDF_VIEWER_FORM_WARNING_HTML},
{"pdf/elements/viewer-form-warning/viewer-form-warning.js",
IDR_PDF_VIEWER_FORM_WARNING_JS},
{"pdf/elements/viewer-pen-options/viewer-pen-options.html",
IDR_PDF_VIEWER_PEN_OPTIONS_HTML},
{"pdf/elements/viewer-pen-options/viewer-pen-options.js",

@ -106,6 +106,7 @@ constexpr char kJSForce[] = "force";
constexpr char kJSSaveDataType[] = "saveData";
constexpr char kJSFileName[] = "fileName";
constexpr char kJSDataToSave[] = "dataToSave";
constexpr char kJSHasUnsavedChanges[] = "hasUnsavedChanges";
// Consume save token (Plugin -> Page)
constexpr char kJSConsumeSaveTokenType[] = "consumeSaveToken";
// Go to page (Plugin -> Page)
@ -1453,6 +1454,9 @@ void OutOfProcessInstance::SaveToBuffer(const std::string& token) {
message.Set(kJSFileName, pp::Var(file_name));
// This will be overwritten if the save is successful.
message.Set(kJSDataToSave, pp::Var(pp::Var::Null()));
const bool hasUnsavedChanges =
edit_mode_ && !base::FeatureList::IsEnabled(features::kSaveEditedPDFForm);
message.Set(kJSHasUnsavedChanges, pp::Var(hasUnsavedChanges));
if (ShouldSaveEdits()) {
std::vector<uint8_t> data = engine_->GetSaveData();