diff --git a/ChangeLog b/ChangeLog index 51cb973..ae39d89 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ # ChangeLog for squashmount +*bookmarkdupes-1.0 + Martin Väth : + - Show progress when removing/stripping + - Add emergency stop button + - More specific messages + - Use textContent instead of redundant child text nodes + - Bugfix: Removing/stripping empty lists might have locked buttons + - Code cleanup: remove unused arguments + *bookmarkdupes-0.5 Martin Väth : - Avoid unsafe assignment to innerHTML diff --git a/_locales/de/messages.json b/_locales/de/messages.json index 28dacf1..96e15fb 100644 --- a/_locales/de/messages.json +++ b/_locales/de/messages.json @@ -47,6 +47,14 @@ "message": "Beschreibungen markierter Lesezeichen entfernen", "description": "Button for stripping descriptions of marked bookmarks" }, + "buttonStopRemoving": { + "message": "Löschen abbrechen!", + "description": "Button for emergency stop of bookmark removing" + }, + "buttonStopStripping": { + "message": "Entfernen abbrechen!", + "description": "Button for emergency stop of description stripping" + }, "messageExactMatchesGroups": { "message": "Exakte Duplikate ($TOTAL$ Lesezeichen in $GROUPS$ Gruppen)", "description": "Report specified numbers of exact matches and groups", @@ -109,6 +117,28 @@ } } }, + "messageRemoveMarked": { + "message": "Markierte Lesezeichen werden gelöscht.", + "description": "Report that removal of marked bookmarks started" + }, + "messageRemoveProgress": { + "message": "($PERCENTAGE$ %) $TOTAL$ of $TODO$ Lesezeichen entfernt", + "description": "Report that specified number/total/percentage of bookmarks are removed", + "placeholders": { + "total": { + "content": "$1", + "example": "0" + }, + "todo": { + "content": "$2", + "example": "1" + }, + "percentage": { + "content": "$3", + "example": "0" + } + } + }, "messageRemoveSuccess": { "message": "$TOTAL$ Lesezeichen gelöscht!", "description": "Report success when removing specified number of bookmarks", @@ -133,6 +163,28 @@ } } }, + "messageStripMarked": { + "message": "Beschreibungen markierter Lesezeichen werden entfernt.", + "description": "Report that description stripping started" + }, + "messageStripProgress": { + "message": "($PERCENTAGE$ %) $TOTAL$ von $TODO$ Beschreibungen entfernt", + "description": "Report that specified number/total/percentage of descriptions are stripped", + "placeholders": { + "total": { + "content": "$1", + "example": "0" + }, + "todo": { + "content": "$2", + "example": "1" + }, + "percentage": { + "content": "$3", + "example": "0" + } + } + }, "messageStripSuccess": { "message": "$TOTAL$ Beschreibungen entfernt!", "description": "Report success when stripping specified number of descriptions", @@ -157,10 +209,6 @@ } } }, - "messageRemovingMarked": { - "message": "Lösche", - "description": "Report that removal of marked items started" - }, "errorNodeNotFound": { "message": "Eintrag nicht gefunden", "description": "Report error that node could not be found" diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 88968f0..3903bf8 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -47,6 +47,14 @@ "message": "Strip descriptions of marked bookmarks", "description": "Button for stripping descriptions of marked bookmarks" }, + "buttonStopRemoving": { + "message": "Stop removing!", + "description": "Button for emergency stop of bookmark removing" + }, + "buttonStopStripping": { + "message": "Stop stripping!", + "description": "Button for emergency stop of description stripping" + }, "messageExactMatchesGroups": { "message": "Exact dupes ($TOTAL$ matches in $GROUPS$ groups)", "description": "Report specified numbers of exact matches and groups", @@ -109,6 +117,28 @@ } } }, + "messageRemoveMarked": { + "message": "Removing marked bookmarks", + "description": "Report that removal of marked bookmarks started" + }, + "messageRemoveProgress": { + "message": "($PERCENTAGE$ %) $TOTAL$ of $TODO$ bookmarks removed", + "description": "Report that specified number/total/percentage of bookmarks are removed", + "placeholders": { + "total": { + "content": "$1", + "example": "0" + }, + "todo": { + "content": "$2", + "example": "1" + }, + "percentage": { + "content": "$3", + "example": "0" + } + } + }, "messageRemoveSuccess": { "message": "$TOTAL$ bookmarks removed!", "description": "Report success when removing specified number of bookmarks", @@ -133,6 +163,28 @@ } } }, + "messageStripMarked": { + "message": "Stripping descriptions of marked bookmarks", + "description": "Report that description stripping started" + }, + "messageStripProgress": { + "message": "($PERCENTAGE$ %) $TOTAL$ of $TODO$ descriptions stripped", + "description": "Report that specified number/total/percentage of descriptions are stripped", + "placeholders": { + "total": { + "content": "$1", + "example": "0" + }, + "todo": { + "content": "$2", + "example": "1" + }, + "percentage": { + "content": "$3", + "example": "0" + } + } + }, "messageStripSuccess": { "message": "$TOTAL$ descriptions stripped!", "description": "Report success when stripping specified number of descriptions", @@ -157,10 +209,6 @@ } } }, - "messageRemovingMarked": { - "message": "Removing", - "description": "Report that removal of marked items started" - }, "errorNodeNotFound": { "message": "node not found", "description": "Report error that node could not be found" diff --git a/data/panel/dupes.js b/data/panel/dupes.js index 36de372..c36bc8c 100644 --- a/data/panel/dupes.js +++ b/data/panel/dupes.js @@ -7,6 +7,10 @@ "use strict"; +function getButtonStop() { + return document.getElementById("buttonStop"); +} + function getButtonsExtra() { return document.getElementById("buttonsExtra"); } @@ -19,6 +23,10 @@ function getTop() { return document.getElementById("tableBookmarks"); } +function displayMessage(msg) { + document.getElementById("textMessage").textContent = msg; +} + function addButton(parent, id, text) { let button = document.createElement("button"); button.type = "button"; @@ -26,8 +34,7 @@ function addButton(parent, id, text) { if (!text) { text = browser.i18n.getMessage(id); } - let buttontext = document.createTextNode(text); - button.appendChild(buttontext); + button.textContent = text; parent.appendChild(button); } @@ -44,12 +51,21 @@ function addButtons(mode) { addButton(parent, (mode == 2) ? "buttonStripMarked" : "buttonRemoveMarked"); } +function addButtonStop(text) { + let parent = getButtonStop(); + addButton(parent, "buttonStop", text); +} + function clearItem(top) { while (top.lastChild) { top.removeChild(top.lastChild); } } +function clearButtonStop() { + clearItem(getButtonStop()); +} + function clearButtonsExtra() { clearItem(getButtonsExtra()); clearItem(getButtonsRemove()); @@ -60,27 +76,21 @@ function clearBookmarks() { } function clearWindow() { + clearButtonStop(); clearButtonsExtra(); clearBookmarks(); } -function displayMessage(msg) { - var toptext = document.getElementById("textMessage"); - clearItem(toptext); - let text = document.createTextNode(msg); - toptext.appendChild(text); -} - function addRuler() { let ruler = document.createElement("HR"); let top = getTop(); top.appendChild(ruler); } -function addBookmark(text, id, checked) { +function addBookmark(text, id) { let checkbox = document.createElement("INPUT"); checkbox.type = "checkbox"; - checkbox.checked = checked; + checkbox.checked = false; checkbox.id = id; let col = document.createElement("TD"); col.appendChild(checkbox); @@ -241,7 +251,7 @@ function calculate(mode, callback) { if (typeof(bookmark.extra) != "undefined") { text += " (" + bookmark.extra + ")"; } - addBookmark(text, bookmark.id, false); + addBookmark(text, bookmark.id); } } displayMessage(browser.i18n.getMessage((exact ? @@ -257,7 +267,7 @@ function calculate(mode, callback) { if (total) { addButtons(1); for (let bookmark of result) { - addBookmark(bookmark.text, bookmark.id, false); + addBookmark(bookmark.text, bookmark.id); } } displayMessage(browser.i18n.getMessage("messageEmpty", String(total))); @@ -271,8 +281,7 @@ function calculate(mode, callback) { if (total) { addButtons(2); for (let bookmark of result) { - addBookmark(bookmark.text, String(bookmark.index) + "X" + bookmark.id, - false); + addBookmark(bookmark.text, String(bookmark.index) + "X" + bookmark.id); } } displayMessage(browser.i18n.getMessage("messageAll", String(total))); @@ -332,18 +341,53 @@ function stripBookmark(indexXId, callback, errorCallback) { }, errorCallback); } -function processMarked(remove, callback) { - displayMessage(browser.i18n.getMessage("messageRemovingMarked")); +function processMarked(remove, callback, getEmergencyStop) { + displayMessage(browser.i18n.getMessage( + (remove ? "messageRemovMarked" : "messageStripMarked"))); + + let total = 0; + + function processFinish(error) { + if (typeof(error) != "undefined") { + displayMessage(browser.i18n.getMessage( + (remove ? "messageRemoveError" : "messageStripError"), + [error, String(total)])); + } else { + displayMessage(browser.i18n.getMessage( + (remove ? "messageRemoveSuccess" : "messageStripSuccess"), + String(total))); + } + clearWindow(); + callback(); + } + let top = getTop(); - if (!top.hasChildNodes()) { + let todo = 0; + if (top.hasChildNodes()) { + for (let child of top.childNodes) { + if (child.nodeName != "TR") { + continue; + } + if (getCheckBox(child).checked) { + ++todo; + } + } + } + if (todo == 0) { + processFinish(); return; } + addButtonStop(browser.i18n.getMessage( + remove ? "buttonStopRemoving" : "buttonStopStripping")); let current = 0; - let total = -1; let process = (remove ? removeFolder : stripBookmark); - function processRecurse(a) { + function processRecurse(dummy) { ++total; + displayMessage(browser.i18n.getMessage( + (remove ? "messageRemoveProgress" : "messageStripProgress"), + [String(total), String(todo), + String(Math.round((100 * total) / todo))])); while (current < top.childNodes.length) { let child = top.childNodes[current++]; if (child.nodeName != "TR") { @@ -353,36 +397,41 @@ function processMarked(remove, callback) { if (!checkBox.checked) { continue; } - process(checkBox.id, processRecurse, function (error) { - displayMessage(browser.i18n.getMessage( - (remove ? "messageRemoveError" : "messageStripError"), - [error, String(total)])); - clearWindow(); - callback(); - }); + if (getEmergencyStop()) { + break; + } + process(checkBox.id, processRecurse, processFinish); return; } - displayMessage(browser.i18n.getMessage( - (remove ? "messageRemoveSuccess" : "messageStripSuccess"), - String(total))); - clearWindow(); - callback(); + processFinish(); } - processRecurse(null); + --total; + processRecurse(); } { let lock = false; + let emergencyStop; function unlock() { lock = false; } + function getEmergencyStop() { + return emergencyStop; + } + function clickListener(event) { + if (!event.target || !event.target.id) { + return; + } + if (event.target.id == "buttonStop") { + emergencyStop = true; + return; + } if (lock || (event.button && (event.button != 1)) || - (event.buttons && (event.buttons != 1)) || - (!event.target) || !event.target.id) { + (event.buttons && (event.buttons != 1))) { return; } lock = true; @@ -400,10 +449,12 @@ function processMarked(remove, callback) { calculate(3, unlock); return; case "buttonRemoveMarked": - processMarked(true, unlock); + emergencyStop = false; + processMarked(true, unlock, getEmergencyStop); return; case "buttonStripMarked": - processMarked(false, unlock); + emergencyStop = false; + processMarked(false, unlock, getEmergencyStop); return; case "buttonMarkAll": mark(2); diff --git a/data/panel/index.html b/data/panel/index.html index a2ca5e0..ba29a82 100644 --- a/data/panel/index.html +++ b/data/panel/index.html @@ -7,7 +7,7 @@

-

+
diff --git a/manifest.json b/manifest.json index 989a3cc..1ee7f02 100644 --- a/manifest.json +++ b/manifest.json @@ -3,7 +3,7 @@ "short_name": "bookmarkdupes", "description": "__MSG_extensionDescription__", "author": "Martin Väth", - "version": "0.5", + "version": "1.0", "manifest_version": 2, "homepage_url": "https://github.com/vaeth/bookmarkdupes.git", "default_locale": "en",