summaryrefslogtreecommitdiffstats
path: root/src/js/htmlutils.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/htmlutils.js')
-rw-r--r--src/js/htmlutils.js283
1 files changed, 283 insertions, 0 deletions
diff --git a/src/js/htmlutils.js b/src/js/htmlutils.js
new file mode 100644
index 0000000..2c015d4
--- /dev/null
+++ b/src/js/htmlutils.js
@@ -0,0 +1,283 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ *
+ * Privacy Badger is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Privacy Badger is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require.scopes.htmlutils = (function() {
+
+const i18n = chrome.i18n;
+const constants = require("constants");
+
+let htmlUtils = {
+
+ // default Tooltipster config
+ TOOLTIPSTER_DEFAULTS: {
+ // allow per-instance option overriding
+ functionInit: function (instance, helper) {
+ let dataOptions = helper.origin.dataset.tooltipster;
+
+ if (dataOptions) {
+ try {
+ dataOptions = JSON.parse(dataOptions);
+ } catch (e) {
+ console.error(e);
+ }
+
+ for (let name in dataOptions) {
+ instance.option(name, dataOptions[name]);
+ }
+ }
+ },
+ },
+
+ // Tooltipster config for domain list tooltips
+ DOMAIN_TOOLTIP_CONF: {
+ delay: 100,
+ side: 'bottom',
+ },
+
+ /**
+ * Gets localized description for given action and origin.
+ *
+ * @param {String} action The action to get description for.
+ * @param {String} origin The origin to get description for.
+ * @returns {String} Localized action description with origin.
+ */
+ getActionDescription: (function () {
+ const messages = {
+ block: i18n.getMessage('badger_status_block', "XXX"),
+ cookieblock: i18n.getMessage('badger_status_cookieblock', "XXX"),
+ noaction: i18n.getMessage('badger_status_noaction', "XXX"),
+ allow: i18n.getMessage('badger_status_allow', "XXX"),
+ dntTooltip: i18n.getMessage('dnt_tooltip')
+ };
+ return function (action, origin) {
+ if (action == constants.DNT) {
+ return messages.dntTooltip;
+ }
+
+ const rv_action = messages[action];
+
+ if (!rv_action) {
+ return origin;
+ }
+
+ return rv_action.replace("XXX", origin);
+ };
+ }()),
+
+ /**
+ * Gets HTML for origin action toggle switch (block, block cookies, allow).
+ *
+ * @param {String} origin Origin to get toggle for.
+ * @param {String} action Current action of given origin.
+ * @returns {String} HTML for toggle switch.
+ */
+ getToggleHtml: (function () {
+
+ function is_checked(input_action, origin_action) {
+ if ((origin_action == constants.NO_TRACKING) || (origin_action == constants.DNT)) {
+ origin_action = constants.ALLOW;
+ }
+ return (input_action === origin_action ? 'checked' : '');
+ }
+
+ let tooltips = {
+ block: i18n.getMessage('domain_slider_block_tooltip'),
+ cookieblock: i18n.getMessage('domain_slider_cookieblock_tooltip'),
+ allow: i18n.getMessage('domain_slider_allow_tooltip')
+ };
+
+ return function (origin, action) {
+ let origin_id = origin.replace(/\./g, '-');
+
+ return `
+<div class="switch-container ${action}">
+ <div class="switch-toggle switch-3 switch-candy">
+ <input id="block-${origin_id}" name="${origin}" value="${constants.BLOCK}" type="radio" ${is_checked(constants.BLOCK, action)}>
+ <label title="${tooltips.block}" class="tooltip" for="block-${origin_id}"></label>
+ <input id="cookieblock-${origin_id}" name="${origin}" value="${constants.COOKIEBLOCK}" type="radio" ${is_checked(constants.COOKIEBLOCK, action)}>
+ <label title="${tooltips.cookieblock}" class="tooltip" for="cookieblock-${origin_id}"></label>
+ <input id="allow-${origin_id}" name="${origin}" value="${constants.ALLOW}" type="radio" ${is_checked(constants.ALLOW, action)}>
+ <label title="${tooltips.allow}" class="tooltip" for="allow-${origin_id}"></label>
+ <a></a>
+ </div>
+</div>
+ `.trim();
+ };
+
+ }()),
+
+ /**
+ * Get HTML for tracker container.
+ *
+ * @returns {String} HTML for empty tracker container.
+ */
+ getTrackerContainerHtml: function() {
+ return `
+<div class="keyContainer">
+ <div class="key">
+ <img src="/icons/UI-icons-red.svg" class="tooltip" title="${i18n.getMessage("tooltip_block")}"><img src="/icons/UI-icons-yellow.svg" class="tooltip" title="${i18n.getMessage("tooltip_cookieblock")}"><img src="/icons/UI-icons-green.svg" class="tooltip" title="${i18n.getMessage("tooltip_allow")}">
+ </div>
+</div>
+<div class="spacer"></div>
+<div id="blockedResourcesInner" class="clickerContainer"></div>
+ `.trim();
+ },
+
+ /**
+ * Generates HTML for given origin.
+ *
+ * @param {String} origin Origin to get HTML for.
+ * @param {String} action Action for given origin.
+ * @param {Boolean} show_breakage_warning
+ * @returns {String} Origin HTML.
+ */
+ getOriginHtml: (function () {
+
+ const breakage_warning_tooltip = i18n.getMessage('breakage_warning_tooltip'),
+ undo_arrow_tooltip = i18n.getMessage('feed_the_badger_title'),
+ dnt_icon_url = chrome.runtime.getURL('/icons/dnt-16.png');
+
+ return function (origin, action, show_breakage_warning) {
+ action = _.escape(action);
+ origin = _.escape(origin);
+
+ // Get classes for main div.
+ let classes = ['clicker'];
+ if (action.startsWith('user')) {
+ classes.push('userset');
+ action = action.slice(5);
+ }
+ // show warning when manually blocking a domain
+ // that would have been cookieblocked otherwise
+ if (show_breakage_warning) {
+ classes.push('show-breakage-warning');
+ }
+
+ // If origin has been whitelisted set text for DNT.
+ let dnt_html = '';
+ if (action == constants.DNT) {
+ dnt_html = `
+<div id="dnt-compliant">
+ <a target=_blank href="https://privacybadger.org/#-I-am-an-online-advertising-tracking-company.--How-do-I-stop-Privacy-Badger-from-blocking-me"><img src="${dnt_icon_url}"></a>
+</div>
+ `.trim();
+ }
+
+ // Construct HTML for origin.
+ let origin_tooltip = htmlUtils.getActionDescription(action, origin);
+ return `
+<div class="${classes.join(' ')}" data-origin="${origin}">
+ <div class="origin">
+ <span class="ui-icon ui-icon-alert tooltip breakage-warning" title="${breakage_warning_tooltip}"></span>
+ <span class="origin-inner tooltip" title="${origin_tooltip}">${dnt_html}${origin}</span>
+ </div>
+ <a href="" class="removeOrigin">&#10006</a>
+ ${htmlUtils.getToggleHtml(origin, action)}
+ <a href="" class="honeybadgerPowered tooltip" title="${undo_arrow_tooltip}"></a>
+</div>
+ `.trim();
+ };
+
+ }()),
+
+ /**
+ * Toggles undo arrows and breakage warnings in domain slider rows.
+ * TODO rename/refactor with updateOrigin()
+ *
+ * @param {jQuery} $clicker
+ * @param {Boolean} userset whether to show a revert control arrow
+ * @param {Boolean} show_breakage_warning whether to show a breakage warning
+ */
+ toggleBlockedStatus: function ($clicker, userset, show_breakage_warning) {
+ $clicker.removeClass([
+ "userset",
+ "show-breakage-warning",
+ ].join(" "));
+
+ // toggles revert control arrow via CSS
+ if (userset) {
+ $clicker.addClass("userset");
+ }
+
+ // show warning when manually blocking a domain
+ // that would have been cookieblocked otherwise
+ if (show_breakage_warning) {
+ $clicker.addClass("show-breakage-warning");
+ }
+ },
+
+ /**
+ * Compare two domains, reversing them to start comparing the least
+ * significant parts (TLD) first.
+ *
+ * @param {Array} domains The domains to sort.
+ * @returns {Array} Sorted domains.
+ */
+ sortDomains: (domains) => {
+ // optimization: cache makeSortable output by walking the array once
+ // to extract the actual values used for sorting into a temporary array
+ return domains.map((domain, i) => {
+ return {
+ index: i,
+ value: htmlUtils.makeSortable(domain)
+ };
+ // sort the temporary array
+ }).sort((a, b) => {
+ if (a.value > b.value) {
+ return 1;
+ }
+ if (a.value < b.value) {
+ return -1;
+ }
+ return 0;
+ // walk the temporary array to achieve the right order
+ }).map(item => domains[item.index]);
+ },
+
+ /**
+ * Reverse order of domain items to have the least exact (TLD) first.
+ *
+ * @param {String} domain The domain to shuffle
+ * @returns {String} The 'reversed' domain
+ */
+ makeSortable: (domain) => {
+ let base = window.getBaseDomain(domain),
+ base_minus_tld = base,
+ dot_index = base.indexOf('.'),
+ rest_of_it_reversed = '';
+
+ if (domain.length > base.length) {
+ rest_of_it_reversed = domain
+ .slice(0, domain.length - base.length - 1)
+ .split('.').reverse().join('.');
+ }
+
+ if (dot_index > -1 && !window.isIPv4(domain) && !window.isIPv6(domain)) {
+ base_minus_tld = base.slice(0, dot_index);
+ }
+
+ return (base_minus_tld + '.' + rest_of_it_reversed);
+ },
+
+};
+
+let exports = {
+ htmlUtils,
+};
+return exports;
+
+})();