tophf 2018-08-02 20:54:40 +03:00
parent fa4dfd680b
commit 5da1e0fb9b
3 changed files with 30 additions and 22 deletions

View File

@ -25,7 +25,8 @@ const CssToProperty = {'url': 'urls', 'url-prefix': 'urlPrefixes', 'domain': 'do
let editor;
window.onbeforeunload = beforeUnload;
document.addEventListener('visibilitychange', beforeUnload);
chrome.runtime.onMessage.addListener(onRuntimeMessage);
preinit();
@ -176,7 +177,8 @@ function onRuntimeMessage(request) {
break;
case 'styleDeleted':
if (styleId === request.id || editor && editor.getStyle().id === request.id) {
window.onbeforeunload = () => {};
document.removeEventListener('visibilitychange', beforeUnload);
window.onbeforeunload = null;
closeCurrentTab();
break;
}
@ -192,24 +194,27 @@ function onRuntimeMessage(request) {
}
}
/**
* Invoked for 'visibilitychange' event by default.
* Invoked for 'beforeunload' event when the style is modified and unsaved.
* See https://developers.google.com/web/updates/2018/07/page-lifecycle-api#legacy-lifecycle-apis-to-avoid
* > Never add a beforeunload listener unconditionally or use it as an end-of-session signal.
* > Only add it when a user has unsaved work, and remove it as soon as that work has been saved.
*/
function beforeUnload() {
if (saveSizeOnClose) {
rememberWindowSize();
}
document.activeElement.blur();
if (isClean()) {
return;
if (saveSizeOnClose) rememberWindowSize();
const activeElement = document.activeElement;
if (activeElement) {
// blurring triggers 'change' or 'input' event if needed
activeElement.blur();
// refocus if unloading was canceled
setTimeout(() => activeElement.focus());
}
const isDirty = editor ? editor.isDirty() : !isCleanGlobal();
if (isDirty) {
updateLintReportIfEnabled(null, 0);
// neither confirm() nor custom messages work in modern browsers but just in case
return t('styleChangesNotSaved');
function isClean() {
if (editor) {
return !editor.isDirty();
} else {
return isCleanGlobal();
}
}
}
@ -406,6 +411,7 @@ function updateTitle() {
const clean = isCleanGlobal();
const title = styleId === null ? t('addStyleTitle') : t('editStyleTitle', [name]);
document.title = clean ? title : DIRTY_TITLE.replace('$', title);
window.onbeforeunload = clean ? null : beforeUnload;
$('#save-button').disabled = clean;
}

View File

@ -4,6 +4,7 @@ global CodeMirror dirtyReporter
global updateLintReportIfEnabled initLint linterConfig updateLinter
global createAppliesToLineWidget messageBox
global sectionsToMozFormat
global beforeUnload
*/
'use strict';
@ -18,8 +19,10 @@ function createSourceEditor(style) {
const dirty = dirtyReporter();
dirty.onChange(() => {
document.body.classList.toggle('dirty', dirty.isDirty());
$('#save-button').disabled = !dirty.isDirty();
const isDirty = dirty.isDirty();
window.onbeforeunload = isDirty ? beforeUnload : null;
document.body.classList.toggle('dirty', isDirty);
$('#save-button').disabled = !isDirty;
updateTitle();
});

View File

@ -73,8 +73,7 @@ function initGlobalEvents() {
installed.addEventListener('mouseover', handleEvent.lazyAddEntryTitle);
installed.addEventListener('mouseout', handleEvent.lazyAddEntryTitle);
// remember scroll position on normal history navigation
window.onbeforeunload = rememberScrollPosition;
document.addEventListener('visibilitychange', rememberScrollPosition);
$$('[data-toggle-on-click]').forEach(el => {
// dataset on SVG doesn't work in Chrome 49-??, works in 57+