diff --git a/background.js b/background.js index dc4371f..f8c0f10 100644 --- a/background.js +++ b/background.js @@ -483,13 +483,17 @@ function checkTab(id, url, isRepeat) { // Check override condition let override = (overrideEndTime > now) && allowOverride; + // Check if the set has been allowed after a delay + let delayAllowSetEndTime = gOptions[`delayAllowedEndTimes${set}`]; + let delayAllowSet = delayAllowSetEndTime && delayAllowSetEndTime > now; + // Determine whether this page should now be blocked let doBlock = lockdown || (!conjMode && (withinTimePeriods || afterTimeLimit)) || (conjMode && (withinTimePeriods && afterTimeLimit)); // Apply block if all relevant block conditions are fulfilled - if (!override && doBlock && (!isRepeat || activeBlock)) { + if (!override && !delayAllowSet && doBlock && (!isRepeat || activeBlock)) { // Get final URL for block page blockURL = blockURL.replace(/\$S/g, set).replace(/\$U/g, pageURLWithHash); @@ -535,7 +539,7 @@ function checkTab(id, url, isRepeat) { } // Clear filter if no longer blocked - if (set == gTabs[id].filterSet && (override || !doBlock)) { + if (set == gTabs[id].filterSet && (override || delayAllowSet || !doBlock)) { gTabs[id].filterSet = undefined; // Send message to tab @@ -555,6 +559,9 @@ function checkTab(id, url, isRepeat) { if (override) { secsLeft = Math.max(secsLeft, overrideEndTime - now); } + if (delayAllowSet) { + secsLeft = Math.max(secsLeft, delayAllowSetEndTime - now); + } if (showTimer && secsLeft < gTabs[id].secsLeft) { gTabs[id].secsLeft = secsLeft; gTabs[id].secsLeftSet = set; @@ -852,6 +859,12 @@ function createBlockInfo(url) { // Get delaying time for block set let delaySecs = gOptions[`delaySecs${blockedSet}`]; + // Get whether a duration should be selected by the user after the delay + let delayPickDuration = gOptions[`delayMethod${blockedSet}`] == "setTimer"; + + // Get the max duration that can be selected + let delayMaxDuration = gOptions[`delayAllowMaxDuration${blockedSet}`] + // Get reloading time (if specified) let reloadSecs = gOptions[`reloadSecs${blockedSet}`]; @@ -862,6 +875,8 @@ function createBlockInfo(url) { blockedURL: blockedURL, unblockTime: unblockTime, delaySecs: delaySecs, + delayPickDuration: delayPickDuration, + delayMaxDuration: delayMaxDuration, reloadSecs: reloadSecs }; } @@ -1093,7 +1108,7 @@ function openExtensionPage(url) { // Open page blocked by delaying page // -function openDelayedPage(id, url, set) { +function openDelayedPage(id, url, set, pickedAllowSecs) { //log("openDelayedPage: " + id + " " + url); if (!gGotOptions || set < 1 || set > gNumSets) { @@ -1103,10 +1118,36 @@ function openDelayedPage(id, url, set) { // Get parsed URL for this page let parsedURL = getParsedURL(url); - // Set parameters for allowing host - gTabs[id].allowedHost = parsedURL.host; - gTabs[id].allowedPath = gOptions[`delayFirst${set}`] ? null : parsedURL.path; - gTabs[id].allowedSet = set; + // Allow pages according to delay method + let delayMethod = gOptions[`delayMethod${set}`]; + if (delayMethod == "consecutive" || delayMethod == "first") { + // Allowing should be associated with the tab so set parameters accordingly + gTabs[id].allowedHost = parsedURL.host; + gTabs[id].allowedPath = delayMethod == "consecutive" ? null : parsedURL.path; + gTabs[id].allowedSet = set; + } else { + // Allowing should happen globally so do not track at the tab level + gTabs[id].allowedHost = null; + gTabs[id].allowedPath = null; + gTabs[id].allowedSet = 0; + + // Track it globally for the set + if (delayMethod == "setTimer") { + let clockOffset = gOptions["clockOffset"]; + let now = Math.floor(Date.now() / 1000) + (clockOffset * 60); + let delayAllowedEndTime = now + pickedAllowSecs; + gOptions[`delayAllowedEndTimes${set}`] = delayAllowedEndTime; + + // Write to local storage + let options = {}; + options[`delayAllowedEndTimes${set}`] = delayAllowedEndTime; + gStorage.set(options).catch( + function (error) { warn("Cannot set options: " + error); } + ); + } else { + warn("Did not recognize selected delay method"); + } + } // Redirect page browser.tabs.update(id, { url: url }); @@ -1210,7 +1251,7 @@ function handleMessage(message, sender, sendResponse) { sendResponse(info); } else if (message.type == "delayed") { // Redirect requested by delaying page - openDelayedPage(sender.tab.id, message.blockedURL, message.blockedSet); + openDelayedPage(sender.tab.id, message.blockedURL, message.blockedSet, message.pickedAllowSecs); } } diff --git a/blocked.js b/blocked.js index 9ec6eef..29976cf 100644 --- a/blocked.js +++ b/blocked.js @@ -2,11 +2,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +var gBlockInfo; + // Processes info for blocking/delaying page // function processBlockInfo(info) { if (!info) return; + gBlockInfo = info; + if (info.theme) { // Set theme let link = document.getElementById("themeLink"); @@ -44,16 +48,27 @@ function processBlockInfo(info) { unblockTime.innerText = info.unblockTime; } + let loadedText = document.getElementById("lbLoaded"); + let availableText = document.getElementById("lbAvailable"); + if (info.delayPickDuration && loadedText && availableText) { + loadedText.style = "display: none;"; + availableText.style = "display: inline;"; + } + + let durationSelect = document.getElementById("durationSelect"); + if (info.delayPickDuration && info.delayMaxDuration && durationSelect) { + durationSelect.onchange = function() { pickDuration(this.value); }; + + // Right now the select just contains the null element so fill it up with options + addDelayAllowDurationsToSelectElement(durationSelect, info.delayMaxDuration); + } + let delaySecs = document.getElementById("lbDelaySeconds"); if (info.delaySecs && delaySecs) { delaySecs.innerText = info.delaySecs; // Start countdown timer - let countdown = { - blockedURL: info.blockedURL, - blockedSet: info.blockedSet, - delaySecs: info.delaySecs - }; + let countdown = { delaySecs: info.delaySecs }; countdown.interval = window.setInterval(onCountdownTimer, 1000, countdown); } @@ -91,17 +106,42 @@ function onCountdownTimer(countdown) { if (countdown.delaySecs == 0) { // Clear countdown timer window.clearInterval(countdown.interval); - - // Request extension allow blocked page and redirect - let message = { - type: "delayed", - blockedURL: countdown.blockedURL, - blockedSet: countdown.blockedSet - }; - browser.runtime.sendMessage(message); + + // Present duration choice if appropriate and otherwise allow page + let pickDuration = document.getElementById("pickDuration"); + let countdownText = document.getElementById("lbCountdownText"); + if (gBlockInfo.delayPickDuration && pickDuration && countdownText) { + // Let the user pick a duration + pickDuration.style = "display: block;"; + countdownText.style = "display: none;"; + } else { + // Request extension allow blocked page and redirect + let message = { + type: "delayed", + blockedURL: gBlockInfo.blockedURL, + blockedSet: gBlockInfo.blockedSet + }; + browser.runtime.sendMessage(message); + } } } +// Handle user selecting a duration +// +function pickDuration(value) { + if (value == "") return; + secs = Number(value) * 60; + + // Request extension allow the set for duration and redirect + let message = { + type: "delayed", + blockedURL: gBlockInfo.blockedURL, + blockedSet: gBlockInfo.blockedSet, + pickedAllowSecs: secs + }; + browser.runtime.sendMessage(message); +} + // Attempt to reload blocked page // function reloadBlockedPage() { diff --git a/common.js b/common.js index ad583da..58f1c18 100644 --- a/common.js +++ b/common.js @@ -13,6 +13,17 @@ const PARSE_URL = /^((([\w-]+):\/*(\w+(?::\w+)?@)?([\w-\.]+)(?::(\d*))?)([^\?#]* const LEECHBLOCK_URL = "https://www.proginosko.com/leechblock/"; +const DELAY_ALLOW_DURATIONS = [ + { minutes: 5, text: "5 minutes" }, + { minutes: 10, text: "10 minutes" }, + { minutes: 15, text: "15 minutes" }, + { minutes: 30, text: "30 minutes" }, + { minutes: 60, text: "1 hour (60 minutes)" }, + { minutes: 90, text: "1.5 hours (90 minutes)" }, + { minutes: 120, text: "2 hours (120 minutes)" }, + { minutes: 180, text: "3 hours (180 minutes)" } +]; + const PER_SET_OPTIONS = { // def: default value, id: form element identifier (see options.html) setName: { type: "string", def: "", id: "setName" }, @@ -29,7 +40,8 @@ const PER_SET_OPTIONS = { filterName: { type: "string", def: "grayscale", id: "filterName" }, activeBlock: { type: "boolean", def: false, id: "activeBlock" }, countFocus: { type: "boolean", def: true, id: "countFocus" }, - delayFirst: { type: "boolean", def: true, id: "delayFirst" }, + delayMethod: { type: "string", def: "consecutive", id: "delayMethod" }, + delayAllowMaxDuration: { type: "string", def: "60", id: "delayAllowMaxDuration" }, delaySecs: { type: "string", def: "60", id: "delaySecs" }, reloadSecs: { type: "string", def: "", id: "reloadSecs" }, allowOverride: { type: "boolean", def: false, id: "allowOverride" }, @@ -385,6 +397,18 @@ function getTimePeriodStart(now, limitPeriod, limitOffset) { return 0; } +// Add new options for each duration in DELAY_ALLOW_DURATIONS into a select element up to limitMins +// +function addDelayAllowDurationsToSelectElement(selectElem, limitMins) { + for (let duration of DELAY_ALLOW_DURATIONS) { + if (limitMins && duration.minutes > limitMins) break; + let option = document.createElement("option"); + option.value = "" + duration.minutes; + option.text = duration.text; + selectElem.add(option); + } +} + // Format a time in seconds to HH:MM:SS format // function formatTime(secs) { diff --git a/delayed.html b/delayed.html index 749a861..3bb5c3e 100644 --- a/delayed.html +++ b/delayed.html @@ -26,10 +26,24 @@

The page you're trying to access has been temporarily blocked by (Block Set) -

The page will be loaded in 0 second(s).

+ +

+ The page will be + loaded + + in 0 second(s). +

+ + + @@ -39,6 +53,7 @@

The page you're trying to access has been temporarily blocked by writing a review. + diff --git a/options.html b/options.html index ca4344d..ae3edb9 100644 --- a/options.html +++ b/options.html @@ -154,8 +154,14 @@

- - + Allow pages after a delay by when delaying page is used +

+

+ When unblocking the block set for a specified duration, limit duration to

Delay access to sites by seconds when delaying page is used diff --git a/options.js b/options.js index fd8f1f6..ac168e9 100644 --- a/options.js +++ b/options.js @@ -55,6 +55,7 @@ function initForm(numSets) { $(`#defaultPage${set}`).click(function (e) { $(`#blockURL${set}`).val(DEFAULT_BLOCK_URL); }); $(`#delayingPage${set}`).click(function (e) { $(`#blockURL${set}`).val(DELAYED_BLOCK_URL); }); $(`#blankPage${set}`).click(function (e) { $(`#blockURL${set}`).val("about:blank"); }); + addDelayAllowDurationsToSelectElement($(`#delayAllowMaxDuration${set}`)[0]); $(`#resetOpts${set}`).click(function (e) { resetSetOptions(set); $("#alertResetOptions").dialog("open");