Merge pull request #70 from hideheader/save-me-too
Manage dirty flags on all inputs
This commit is contained in:
commit
0e391f928f
|
@ -199,7 +199,7 @@
|
||||||
<button id="to-mozilla"></button><img id="to-mozilla-help" src="help.png"><br><br>
|
<button id="to-mozilla"></button><img id="to-mozilla-help" src="help.png"><br><br>
|
||||||
<button id="save-button" title="Ctrl-S"></button>
|
<button id="save-button" title="Ctrl-S"></button>
|
||||||
<a href="manage.html"><button id="cancel-button"></button></a>
|
<a href="manage.html"><button id="cancel-button"></button></a>
|
||||||
<div id="options">
|
<form id="options">
|
||||||
<h2 id="options-heading"></h2>
|
<h2 id="options-heading"></h2>
|
||||||
<table cols="2">
|
<table cols="2">
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -229,7 +229,7 @@
|
||||||
<td><select data-option="keyMap" id="editor.keyMap"></select></td>
|
<td><select data-option="keyMap" id="editor.keyMap"></select></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<section id="sections">
|
<section id="sections">
|
||||||
<h2><span id="sections-heading"></span> <img id="sections-help" src="help.png"></h2>
|
<h2><span id="sections-heading"></span> <img id="sections-help" src="help.png"></h2>
|
||||||
|
|
148
edit.js
148
edit.js
|
@ -1,3 +1,5 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
var styleId = null;
|
var styleId = null;
|
||||||
var dirty = false;
|
var dirty = false;
|
||||||
var lockScroll; // ensure the section doesn't jump when clicking selected text
|
var lockScroll; // ensure the section doesn't jump when clicking selected text
|
||||||
|
@ -12,10 +14,73 @@ appliesToEverythingTemplate.innerHTML = t("appliesToEverything") + ' <button cla
|
||||||
var sectionTemplate = document.createElement("div");
|
var sectionTemplate = document.createElement("div");
|
||||||
sectionTemplate.innerHTML = '<label>' + t('sectionCode') + '</label><textarea class="code"></textarea><br><div class="applies-to"><label>' + t("appliesLabel") + ' <img class="applies-to-help" src="help.png" alt="' + t('helpAlt') + '"></label><ul class="applies-to-list"></ul></div><button class="remove-section">' + t('sectionRemove') + '</button><button class="add-section">' + t('sectionAdd') + '</button>';
|
sectionTemplate.innerHTML = '<label>' + t('sectionCode') + '</label><textarea class="code"></textarea><br><div class="applies-to"><label>' + t("appliesLabel") + ' <img class="applies-to-help" src="help.png" alt="' + t('helpAlt') + '"></label><ul class="applies-to-list"></ul></div><button class="remove-section">' + t('sectionRemove') + '</button><button class="add-section">' + t('sectionAdd') + '</button>';
|
||||||
|
|
||||||
|
document.addEventListener("change", function(event) {
|
||||||
|
var node = event.target;
|
||||||
|
if (node.type && !node.form) { // INPUTs that aren't in a FORM are stylesheet
|
||||||
|
switch (node.type) {
|
||||||
|
case "checkbox":
|
||||||
|
setCleanItem(node, node.checked === node.defaultChecked);
|
||||||
|
break;
|
||||||
|
case "text":
|
||||||
|
case "select-one":
|
||||||
|
case "select-multiple":
|
||||||
|
setCleanItem(node, node.value === node.defaultValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set .dirty on stylesheet contributors that have changed
|
||||||
|
var items = {};
|
||||||
|
function isCleanItem(node) {
|
||||||
|
return items[node.id];
|
||||||
|
}
|
||||||
|
function setCleanItem(node, clean) {
|
||||||
|
var id = node.id;
|
||||||
|
if (!id) id = node.id = Date.now().toString(32).substr(-6);
|
||||||
|
items[id] = clean;
|
||||||
|
|
||||||
|
if (clean) node.classList.remove("dirty");
|
||||||
|
else node.classList.add("dirty");
|
||||||
|
|
||||||
|
initTitle();
|
||||||
|
}
|
||||||
|
function isCleanGlobal() {
|
||||||
|
var clean = Object.keys(items)
|
||||||
|
.every(function(item) { return items[item] });
|
||||||
|
|
||||||
|
if (clean) document.body.classList.remove("dirty");
|
||||||
|
else document.body.classList.add("dirty");
|
||||||
|
|
||||||
|
return clean;
|
||||||
|
}
|
||||||
|
function setCleanGlobal(form) {
|
||||||
|
if (!form) form = null;
|
||||||
|
Array.prototype.forEach.call(document.querySelectorAll("input, select"), function(node) {
|
||||||
|
if (node.form === form) {
|
||||||
|
if ("checkbox" === node.type) {
|
||||||
|
node.defaultChecked = node.checked;
|
||||||
|
} else {
|
||||||
|
node.defaultValue = node.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.classList.remove("dirty");
|
||||||
|
delete items[node.id];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
editors.forEach(function(cm) {
|
||||||
|
cm.lastChange = cm.changeGeneration();
|
||||||
|
cm.getTextArea().parentNode.defaultValue = cm.lastChange;
|
||||||
|
indicateCodeChange(cm);
|
||||||
|
});
|
||||||
|
|
||||||
|
initTitle();
|
||||||
|
}
|
||||||
|
|
||||||
var editors = []; // array of all CodeMirror instances
|
var editors = []; // array of all CodeMirror instances
|
||||||
function initCodeMirror() {
|
function initCodeMirror() {
|
||||||
var CM = CodeMirror;
|
var CM = CodeMirror;
|
||||||
|
|
||||||
// default option values
|
// default option values
|
||||||
var userOptions = prefs.getPref("editor.options");
|
var userOptions = prefs.getPref("editor.options");
|
||||||
var stylishOptions = {
|
var stylishOptions = {
|
||||||
|
@ -153,10 +218,6 @@ document.addEventListener("keydown", function(e) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function makeDirty() {
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onbeforeunload = function() {
|
window.onbeforeunload = function() {
|
||||||
prefs.setPref('windowPosition', {
|
prefs.setPref('windowPosition', {
|
||||||
left: screenLeft,
|
left: screenLeft,
|
||||||
|
@ -164,25 +225,13 @@ window.onbeforeunload = function() {
|
||||||
width: outerWidth,
|
width: outerWidth,
|
||||||
height: outerHeight
|
height: outerHeight
|
||||||
});
|
});
|
||||||
return dirty || isCodeDirty() ? t('styleChangesNotSaved') : null;
|
document.activeElement.blur();
|
||||||
}
|
return !isCleanGlobal() ? t('styleChangesNotSaved') : null;
|
||||||
|
|
||||||
function isCodeDirty() {
|
|
||||||
for(var i=0; i < editors.length; i++) {
|
|
||||||
if (!editors[i].isClean(editors[i].lastChange)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function indicateCodeChange(cm) {
|
function indicateCodeChange(cm) {
|
||||||
var clean = cm.isClean(cm.lastChange);
|
setCleanItem(cm.getTextArea().parentNode, cm.isClean(cm.lastChange));
|
||||||
if (clean != cm.lastClean) {
|
}
|
||||||
cm.lastClean = clean;
|
|
||||||
cm.getTextArea().parentNode.classList[clean ? "remove" : "add"]("dirty");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function addAppliesTo(list, name, value) {
|
function addAppliesTo(list, name, value) {
|
||||||
var showingEverything = list.querySelector(".applies-to-everything") != null;
|
var showingEverything = list.querySelector(".applies-to-everything") != null;
|
||||||
|
@ -196,16 +245,12 @@ function addAppliesTo(list, name, value) {
|
||||||
e.querySelector("[name=applies-type]").value = name;
|
e.querySelector("[name=applies-type]").value = name;
|
||||||
e.querySelector("[name=applies-value]").value = value;
|
e.querySelector("[name=applies-value]").value = value;
|
||||||
e.querySelector(".remove-applies-to").addEventListener("click", removeAppliesTo, false);
|
e.querySelector(".remove-applies-to").addEventListener("click", removeAppliesTo, false);
|
||||||
e.querySelector(".applies-value").addEventListener("input", makeDirty, false);
|
|
||||||
e.querySelector(".applies-type").addEventListener("change", makeDirty, false);
|
|
||||||
} else if (showingEverything || list.hasChildNodes()) {
|
} else if (showingEverything || list.hasChildNodes()) {
|
||||||
e = appliesToTemplate.cloneNode(true);
|
e = appliesToTemplate.cloneNode(true);
|
||||||
if (list.hasChildNodes()) {
|
if (list.hasChildNodes()) {
|
||||||
e.querySelector("[name=applies-type]").value = list.querySelector("li:last-child [name='applies-type']").value;
|
e.querySelector("[name=applies-type]").value = list.querySelector("li:last-child [name='applies-type']").value;
|
||||||
}
|
}
|
||||||
e.querySelector(".remove-applies-to").addEventListener("click", removeAppliesTo, false);
|
e.querySelector(".remove-applies-to").addEventListener("click", removeAppliesTo, false);
|
||||||
e.querySelector(".applies-value").addEventListener("input", makeDirty, false);
|
|
||||||
e.querySelector(".applies-type").addEventListener("change", makeDirty, false);
|
|
||||||
} else {
|
} else {
|
||||||
e = appliesToEverythingTemplate.cloneNode(true);
|
e = appliesToEverythingTemplate.cloneNode(true);
|
||||||
}
|
}
|
||||||
|
@ -224,7 +269,8 @@ function addSection(event, section) {
|
||||||
if (section) {
|
if (section) {
|
||||||
var codeElement = div.querySelector(".code");
|
var codeElement = div.querySelector(".code");
|
||||||
codeElement.value = section.code;
|
codeElement.value = section.code;
|
||||||
codeElement.addEventListener("change", makeDirty, false);
|
// codeElement.addEventListener("change", makeDirty, false);
|
||||||
|
// // Why is this here? Is it possible for CM to not load?
|
||||||
if (section.urls) {
|
if (section.urls) {
|
||||||
section.urls.forEach(function(url) {
|
section.urls.forEach(function(url) {
|
||||||
addAppliesTo(appliesTo, "url", url);
|
addAppliesTo(appliesTo, "url", url);
|
||||||
|
@ -269,24 +315,32 @@ function addSection(event, section) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeAppliesTo(event) {
|
function removeAppliesTo(event) {
|
||||||
var appliesToList = event.target.parentNode.parentNode;
|
var appliesTo = event.target.parentNode,
|
||||||
appliesToList.removeChild(event.target.parentNode);
|
appliesToList = appliesTo.parentNode;
|
||||||
|
appliesToList.removeChild(appliesTo);
|
||||||
if (!appliesToList.hasChildNodes()) {
|
if (!appliesToList.hasChildNodes()) {
|
||||||
var e = appliesToEverythingTemplate.cloneNode(true);
|
var e = appliesToEverythingTemplate.cloneNode(true);
|
||||||
e.querySelector(".add-applies-to").addEventListener("click", function() {addAppliesTo(this.parentNode.parentNode)}, false);
|
e.querySelector(".add-applies-to").addEventListener("click", function() {addAppliesTo(this.parentNode.parentNode)}, false);
|
||||||
appliesToList.appendChild(e);
|
appliesToList.appendChild(e);
|
||||||
}
|
}
|
||||||
makeDirty();
|
Array.prototype.forEach.call(appliesTo.querySelectorAll("input, select"), function(node) {
|
||||||
|
setCleanItem(node, !node.defaultValue);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeSection(event) {
|
function removeSection(event) {
|
||||||
var section = event.target.parentNode;
|
var section = event.target.parentNode;
|
||||||
var cm = section.querySelector(".CodeMirror-wrap");
|
var wrapper = section.querySelector(".CodeMirror-wrap");
|
||||||
if (cm && editors.indexOf(cm.CodeMirror) >= 0) {
|
var idx = editors.indexOf(wrapper && wrapper.CodeMirror);
|
||||||
editors.splice(editors.indexOf(cm.CodeMirror), 1);
|
if (idx >= 0) {
|
||||||
|
editors.splice(idx, 1);
|
||||||
|
setCleanItem(wrapper.parentNode, true);
|
||||||
}
|
}
|
||||||
section.parentNode.removeChild(section);
|
section.parentNode.removeChild(section);
|
||||||
makeDirty();
|
Array.prototype.forEach.call(section.querySelectorAll("input, select"), function(node) {
|
||||||
|
setCleanItem(node, !node.defaultValue);
|
||||||
|
});
|
||||||
|
setCleanItem(section, !section.defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupGlobalSearch() {
|
function setupGlobalSearch() {
|
||||||
|
@ -406,9 +460,10 @@ function init() {
|
||||||
addSection(null, section);
|
addSection(null, section);
|
||||||
// default to enabled
|
// default to enabled
|
||||||
document.getElementById("enabled").checked = true
|
document.getElementById("enabled").checked = true
|
||||||
document.title = t("addStyleTitle");
|
|
||||||
tE("heading", "addStyleTitle");
|
tE("heading", "addStyleTitle");
|
||||||
setupGlobalSearch();
|
setupGlobalSearch();
|
||||||
|
setCleanGlobal(null);
|
||||||
|
initTitle();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// This is an edit
|
// This is an edit
|
||||||
|
@ -423,17 +478,23 @@ function initWithStyle(style) {
|
||||||
document.getElementById("name").value = style.name;
|
document.getElementById("name").value = style.name;
|
||||||
document.getElementById("enabled").checked = style.enabled == "true";
|
document.getElementById("enabled").checked = style.enabled == "true";
|
||||||
document.getElementById("heading").innerHTML = t("editStyleHeading");
|
document.getElementById("heading").innerHTML = t("editStyleHeading");
|
||||||
initTitle(style.name);
|
|
||||||
// if this was done in response to an update, we need to clear existing sections
|
// if this was done in response to an update, we need to clear existing sections
|
||||||
Array.prototype.forEach.call(document.querySelectorAll("#sections > div"), function(div) {
|
Array.prototype.forEach.call(document.querySelectorAll("#sections > div"), function(div) {
|
||||||
div.parentNode.removeChild(div);
|
div.parentNode.removeChild(div);
|
||||||
});
|
});
|
||||||
style.sections.forEach(function(section) { addSection(null, section) });
|
style.sections.forEach(function(section) { addSection(null, section) });
|
||||||
setupGlobalSearch();
|
setupGlobalSearch();
|
||||||
|
setCleanGlobal(null);
|
||||||
|
initTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
function initTitle(name) {
|
function initTitle() {
|
||||||
document.title = t('editStyleTitle', [name]);
|
const DIRTY_TITLE = "* $";
|
||||||
|
|
||||||
|
var name = document.getElementById("name").defaultValue;
|
||||||
|
var dirty = !isCleanGlobal();
|
||||||
|
var title = styleId === null ? t("addStyleTitle") : t('editStyleTitle', [name]);
|
||||||
|
document.title = !dirty ? title : DIRTY_TITLE.replace("$", title);
|
||||||
}
|
}
|
||||||
|
|
||||||
function validate() {
|
function validate() {
|
||||||
|
@ -534,20 +595,15 @@ function getMeta(e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveComplete(style) {
|
function saveComplete(style) {
|
||||||
dirty = false;
|
styleId = style.id;
|
||||||
|
setCleanGlobal(null);
|
||||||
for(var i=0; i < editors.length; i++) {
|
|
||||||
var cm = editors[i];
|
|
||||||
cm.lastChange = cm.changeGeneration(true);
|
|
||||||
indicateCodeChange(cm);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go from new style URL to edit style URL
|
// Go from new style URL to edit style URL
|
||||||
if (location.href.indexOf("id=") == -1) {
|
if (location.href.indexOf("id=") == -1) {
|
||||||
// give the code above a moment before we kill the page
|
// give the code above a moment before we kill the page
|
||||||
setTimeout(function() {location.href = "edit.html?id=" + style.id;}, 200);
|
setTimeout(function() {location.href = "edit.html?id=" + style.id;}, 200);
|
||||||
} else {
|
} else {
|
||||||
initTitle(document.getElementById("name").value);
|
initTitle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,8 +686,6 @@ tE("cancel-button", "styleCancelEditLabel");
|
||||||
tE("sections-heading", "styleSectionsTitle");
|
tE("sections-heading", "styleSectionsTitle");
|
||||||
tE("options-heading", "optionsHeading");
|
tE("options-heading", "optionsHeading");
|
||||||
|
|
||||||
document.getElementById("name").addEventListener("change", makeDirty, false);
|
|
||||||
document.getElementById("enabled").addEventListener("change", makeDirty, false);
|
|
||||||
document.getElementById("to-mozilla").addEventListener("click", showMozillaFormat, false);
|
document.getElementById("to-mozilla").addEventListener("click", showMozillaFormat, false);
|
||||||
document.getElementById("to-mozilla-help").addEventListener("click", showToMozillaHelp, false);
|
document.getElementById("to-mozilla-help").addEventListener("click", showToMozillaHelp, false);
|
||||||
document.getElementById("save-button").addEventListener("click", save, false);
|
document.getElementById("save-button").addEventListener("click", save, false);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user