Bug 1331931 - Move the popup blocked icon into the identity block draft
authorPrathiksha <prathikshaprasadsuman@gmail.com>
Sun, 17 Sep 2017 18:35:10 +0530
changeset 670274 466e9917c3c7da705b1207e8235c73ce778df716
parent 669596 7e962631ba4298bcefa571008661983d77c3e652
child 733199 40c0ebc26c18a36e240b22af67c98716964bf003
push id81591
push userbmo:prathikshaprasadsuman@gmail.com
push dateTue, 26 Sep 2017 08:35:23 +0000
bugs1331931
milestone58.0a1
Bug 1331931 - Move the popup blocked icon into the identity block MozReview-Commit-ID: 7Q6lFgR1adA
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/test/popups/browser.ini
browser/base/content/test/popups/browser_identity_popup_popup_test.js
browser/base/content/test/popups/popup_blocker2.html
browser/locales/en-US/chrome/browser/browser.dtd
browser/locales/en-US/chrome/browser/browser.properties
browser/themes/shared/jar.inc.mn
browser/themes/shared/notification-icons.inc.css
browser/themes/shared/notification-icons/blocked-popup-indicator-icon.svg
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -589,61 +589,33 @@ function findChildShell(aDocument, aDocS
     docShell = findChildShell(aDocument, docShell, aSoughtURI);
     if (docShell)
       return docShell;
   }
   return null;
 }
 
 var gPopupBlockerObserver = {
-  _reportButton: null,
-
-  onReportButtonMousedown(aEvent) {
-    // The button is part of the textbox that is considered the popup's anchor,
-    // thus consumeoutsideclicks="false" is ignored. Moreover On OS X the popup
-    // is hidden well before mousedown gets dispatched.
-    // Thus, if the popup is open and the user clicks on the button, it gets
-    // hidden before mousedown, and may then be unexpectedly reopened by click.
-    // To avoid this, we check if mousedown is in the same tick as popupHidden,
-    // and, in such a case, we don't handle the click event.
-    // Note we can't just openPopup in mousedown, cause this popup is shared by
-    // multiple anchors, and we could end up opening it just before the other
-    // anchor tries to hide it.
-    if (aEvent.button != 0 || aEvent.target != this._reportButton || this.isPopupHidingTick)
-      return;
-
-    this._reportButton.addEventListener("click", event => {
-      document.getElementById("blockedPopupOptions")
-              .openPopup(event.target, "after_end", 0, 2, false, false, event);
-    }, { once: true });
-  },
-
   handleEvent(aEvent) {
     if (aEvent.originalTarget != gBrowser.selectedBrowser)
       return;
 
-    if (!this._reportButton)
-      this._reportButton = document.getElementById("page-report-button");
+    gIdentityHandler.refreshIdentityBlock();
 
     if (!gBrowser.selectedBrowser.blockedPopups ||
         !gBrowser.selectedBrowser.blockedPopups.length) {
-      // Hide the icon in the location bar (if the location bar exists)
-      this._reportButton.hidden = true;
-
       // Hide the notification box (if it's visible).
       let notificationBox = gBrowser.getNotificationBox();
       let notification = notificationBox.getNotificationWithValue("popup-blocked");
       if (notification) {
         notificationBox.removeNotification(notification, false);
       }
       return;
     }
 
-    this._reportButton.hidden = false;
-
     // Only show the notification again if we've not already shown it. Since
     // notifications are per-browser, we don't need to worry about re-adding
     // it.
     if (!gBrowser.selectedBrowser.blockedPopups.reported) {
       if (gPrefService.getBoolPref("privacy.popups.showBrowserMessage")) {
         var brandBundle = document.getElementById("bundle_brand");
         var brandShortName = brandBundle.getString("brandShortName");
         var popupCount = gBrowser.selectedBrowser.blockedPopups.length;
@@ -733,22 +705,17 @@ var gPopupBlockerObserver = {
     if (PrivateBrowsingUtils.isWindowPrivate(window))
       blockedPopupAllowSite.setAttribute("disabled", "true");
     else
       blockedPopupAllowSite.removeAttribute("disabled");
 
     let blockedPopupDontShowMessage = document.getElementById("blockedPopupDontShowMessage");
     let showMessage = gPrefService.getBoolPref("privacy.popups.showBrowserMessage");
     blockedPopupDontShowMessage.setAttribute("checked", !showMessage);
-    if (aEvent.target.anchorNode.id == "page-report-button") {
-      aEvent.target.anchorNode.setAttribute("open", "true");
-      blockedPopupDontShowMessage.setAttribute("label", gNavigatorBundle.getString("popupWarningDontShowFromLocationbar"));
-    } else {
-      blockedPopupDontShowMessage.setAttribute("label", gNavigatorBundle.getString("popupWarningDontShowFromMessage"));
-    }
+    blockedPopupDontShowMessage.setAttribute("label", gNavigatorBundle.getString("popupWarningDontShowFromMessage"));
 
     let blockedPopupsSeparator =
         document.getElementById("blockedPopupsSeparator");
     blockedPopupsSeparator.setAttribute("hidden", true);
 
     gBrowser.selectedBrowser.retrieveListOfBlockedPopups().then(blockedPopups => {
       let foundUsablePopupURI = false;
       if (blockedPopups) {
@@ -793,23 +760,16 @@ var gPopupBlockerObserver = {
       // Show the separator if we added any
       // showable popup addresses to the menu.
       if (foundUsablePopupURI)
         blockedPopupsSeparator.removeAttribute("hidden");
     }, null);
   },
 
   onPopupHiding(aEvent) {
-    if (aEvent.target.anchorNode.id == "page-report-button") {
-      aEvent.target.anchorNode.removeAttribute("open");
-
-      this.isPopupHidingTick = true;
-      setTimeout(() => this.isPopupHidingTick = false, 0);
-    }
-
     let item = aEvent.target.lastChild;
     while (item && item.getAttribute("observes") != "blockedPopupsSeparator") {
       let next = item.previousSibling;
       item.remove();
       item = next;
     }
   },
 
@@ -7555,16 +7515,26 @@ var gIdentityHandler = {
         hasGrantedPermissions = true;
       }
     }
 
     if (hasGrantedPermissions) {
       this._identityBox.classList.add("grantedPermissions");
     }
 
+    // Show blocked popup icon in the identity-box if popups are blocked
+    // irrespective of popup permission capability value.
+    if (gBrowser.selectedBrowser.blockedPopups &&
+        gBrowser.selectedBrowser.blockedPopups.length) {
+      let icon = permissionAnchors["popup"];
+      if (icon) {
+        icon.setAttribute("showing", "true");
+      }
+    }
+
     // Push the appropriate strings out to the UI
     this._connectionIcon.setAttribute("tooltiptext", tooltip);
 
     if (this._isExtensionPage) {
       let extensionName = extensionNameFromURI(this._uri);
       this._extensionIcon.setAttribute("tooltiptext",
         gNavigatorBundle.getFormattedString("identity.extension.tooltip", [extensionName]));
     }
@@ -7905,19 +7875,41 @@ var gIdentityHandler = {
               state: SitePermissions.ALLOW,
               scope: SitePermissions.SCOPE_REQUEST,
               inUse: true,
             });
           }
         }
       }
     }
+
+    let hasPopupIndicatorItem = false;
     for (let permission of permissions) {
       let item = this._createPermissionItem(permission);
       this._permissionList.appendChild(item);
+
+      if (permission.id == "popup" &&
+          gBrowser.selectedBrowser.blockedPopups &&
+          gBrowser.selectedBrowser.blockedPopups.length) {
+        this._createBlockedPopupIndicator();
+        hasPopupIndicatorItem = true;
+      }
+    }
+
+    if (gBrowser.selectedBrowser.blockedPopups &&
+        gBrowser.selectedBrowser.blockedPopups.length &&
+        !hasPopupIndicatorItem) {
+      let permission = {
+        id: "popup",
+        state: SitePermissions.BLOCK,
+        scope: SitePermissions.SCOPE_PERSISTENT,
+      };
+      let item = this._createPermissionItem(permission);
+      this._permissionList.appendChild(item);
+      this._createBlockedPopupIndicator();
     }
 
     // Show a placeholder text if there's no permission and no reload hint.
     if (!this._permissionList.hasChildNodes() &&
         this._permissionReloadHint.hasAttribute("hidden")) {
       this._permissionEmptyHint.removeAttribute("hidden");
     } else {
       this._permissionEmptyHint.setAttribute("hidden", "true");
@@ -7937,16 +7929,45 @@ var gIdentityHandler = {
       classes += " in-use";
     img.setAttribute("class", classes);
 
     let nameLabel = document.createElement("label");
     nameLabel.setAttribute("flex", "1");
     nameLabel.setAttribute("class", "identity-popup-permission-label");
     nameLabel.textContent = SitePermissions.getPermissionLabel(aPermission.id);
 
+    if (aPermission.id == "popup") {
+      let menulist = document.createElement("menulist");
+      let menupopup = document.createElement("menupopup");
+      let block = document.createElement("vbox");
+      block.setAttribute("id", "identity-popup-popup-container");
+      menulist.setAttribute("class", "identity-popup-popup-menulist");
+
+      for (let state of SitePermissions.getAvailableStates(aPermission.id)) {
+        let menuitem = document.createElement("menuitem");
+        menuitem.setAttribute("value", state);
+        menuitem.setAttribute("label", SitePermissions.getMultichoiceStateLabel(state));
+        menupopup.appendChild(menuitem);
+      }
+
+      menulist.appendChild(menupopup);
+      menulist.setAttribute("value", aPermission.state);
+
+      menulist.addEventListener("select", () => {
+        SitePermissions.set(gBrowser.currentURI, "popup", menulist.selectedItem.value);
+      });
+
+      container.appendChild(img);
+      container.appendChild(nameLabel);
+      container.appendChild(menulist);
+      block.appendChild(container);
+
+      return block;
+    }
+
     let stateLabel = document.createElement("label");
     stateLabel.setAttribute("flex", "1");
     stateLabel.setAttribute("class", "identity-popup-permission-state-label");
     let {state, scope} = aPermission;
     // If the user did not permanently allow this device but it is currently
     // used, set the variables to display a "temporarily allowed" info.
     if (state != SitePermissions.ALLOW && aPermission.inUse) {
       state = SitePermissions.ALLOW;
@@ -8018,17 +8039,46 @@ var gIdentityHandler = {
     });
 
     container.appendChild(img);
     container.appendChild(nameLabel);
     container.appendChild(stateLabel);
     container.appendChild(button);
 
     return container;
-  }
+  },
+
+  _createBlockedPopupIndicator() {
+    let indicator = document.createElement("hbox");
+    indicator.setAttribute("class", "identity-popup-permission-item");
+    indicator.setAttribute("align", "center");
+    indicator.setAttribute("id", "blocked-popup-indicator-item");
+
+    let icon = document.createElement("image");
+    icon.setAttribute("class", "blocked-popup-indicator-icon");
+
+    let text = document.createElement("label");
+    text.setAttribute("flex", "1");
+    text.setAttribute("class", "identity-popup-permission-label text-link");
+
+    let popupCount = gBrowser.selectedBrowser.blockedPopups.length;
+    let messageBase = gNavigatorBundle.getString("popupShowBlockedPopupsIndicatorText");
+    let message = PluralForm.get(popupCount, messageBase)
+                                 .replace("#1", popupCount);
+    text.setAttribute("value", message);
+
+    text.addEventListener("click", () => {
+      gPopupBlockerObserver.showAllBlockedPopups(gBrowser.selectedBrowser);
+    });
+
+    indicator.appendChild(icon);
+    indicator.appendChild(text);
+
+    document.getElementById("identity-popup-popup-container").appendChild(indicator);
+  },
 };
 
 /**
  * Fired on the "marionette-remote-control" system notification,
  * indicating if the browser session is under remote control.
  */
 const gRemoteControl = {
   observe(subject, topic, data) {
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -809,16 +809,18 @@
                   <image data-permission-id="indexedDB" class="blocked-permission-icon indexedDB-icon" role="button"
                          tooltiptext="&urlbar.indexedDBBlocked.tooltip;"/>
                   <image data-permission-id="microphone" class="blocked-permission-icon microphone-icon" role="button"
                          tooltiptext="&urlbar.microphoneBlocked.tooltip;"/>
                   <image data-permission-id="screen" class="blocked-permission-icon screen-icon" role="button"
                          tooltiptext="&urlbar.screenBlocked.tooltip;"/>
                   <image data-permission-id="persistent-storage" class="blocked-permission-icon persistent-storage-icon" role="button"
                          tooltiptext="&urlbar.persistentStorageBlocked.tooltip;"/>
+                  <image data-permission-id="popup" class="blocked-permission-icon popup-icon" role="button"
+                         tooltiptext="&urlbar.popupBlocked.tooltip;"/>
                 </box>
                 <box id="notification-popup-box"
                      hidden="true"
                      onmouseover="document.getElementById('identity-box').classList.add('no-hover');"
                      onmouseout="document.getElementById('identity-box').classList.remove('no-hover');"
                      align="center">
                   <image id="default-notification-icon" class="notification-anchor-icon" role="button"
                          tooltiptext="&urlbar.defaultNotificationAnchor.tooltip;"/>
@@ -867,22 +869,16 @@
                 <label id="switchtab" class="urlbar-display urlbar-display-switchtab" value="&urlbar.switchToTab.label;"/>
                 <label id="extension" class="urlbar-display urlbar-display-extension" value="&urlbar.extension.label;"/>
               </box>
               <hbox id="page-action-buttons">
                 <hbox id="userContext-icons" hidden="true">
                   <label id="userContext-label"/>
                   <image id="userContext-indicator"/>
                 </hbox>
-                <image id="page-report-button"
-                       class="urlbar-icon urlbar-page-action"
-                       role="button"
-                       hidden="true"
-                       tooltiptext="&pageReportIcon.tooltip;"
-                       onmousedown="gPopupBlockerObserver.onReportButtonMousedown(event);"/>
                 <image id="reader-mode-button"
                        class="urlbar-icon urlbar-page-action"
                        role="button"
                        hidden="true"
                        onclick="ReaderParent.buttonClick(event);"/>
                 <toolbarbutton id="urlbar-zoom-button"
                        onclick="FullZoom.reset();"
                        tooltip="dynamic-shortcut-tooltip"
--- a/browser/base/content/test/popups/browser.ini
+++ b/browser/base/content/test/popups/browser.ini
@@ -5,8 +5,12 @@ support-files =
   popup_blocker_a.html
   popup_blocker_b.html
 skip-if = (os == 'linux') || (e10s && debug) # Frequent bug 1081925 and bug 1125520 failures
 [browser_popup_frames.js]
 support-files =
   popup_blocker.html
   popup_blocker_a.html
   popup_blocker_b.html
+[browser_identity_popup_popup_test.js]
+support-files =
+  popup_blocker2.html
+  popup_blocker_a.html
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/popups/browser_identity_popup_popup_test.js
@@ -0,0 +1,83 @@
+"use strict";
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+const {interfaces: Ci, classes: Cc, results: Cr, utils: Cu} = Components;
+Cu.import("resource:///modules/SitePermissions.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+const baseURL = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "http://example.com");
+const URL = baseURL + "popup_blocker2.html";
+const URI = Services.io.newURI(URL);
+
+function openIdentityPopup() {
+  let promise = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
+  gIdentityHandler._identityBox.click();
+  return promise;
+}
+
+add_task(async function testPopupPermissionUnknownState(){
+  await BrowserTestUtils.withNewTab(baseURL + "popup_blocker2.html", async () => {
+    // The blocked popup indicator icon and text in the identity popup should not exist.
+    let hasIndicator = document.getElementById("blocked-popup-indicator-item") !== null;
+    Assert.equal(hasIndicator, false);
+
+    // The blocked popup icon in the identity block must be hidden.
+    let icon = gIdentityHandler._identityBox
+      .querySelector(".blocked-permission-icon[data-permission-id='popup']");
+    Assert.equal(icon.hasAttribute("showing"), false);
+
+    await ContentTask.spawn(gBrowser.selectedBrowser, null, async () => {
+      let open = content.document.getElementById("pop");
+      open.click();
+    });
+
+    // Wait for the popup-blocked notification.
+    let notification;
+    await BrowserTestUtils.waitForCondition(() =>
+      notification = gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"));
+
+    // A popup is blocked because SitePermissions.UNKNOWN = SitePermissions.BLOCK for popups.
+    // Blocked popup icon is now seen in the identity block.
+    Assert.equal(icon.getAttribute("showing"), true);
+
+    document.getElementById("identity-icon").click();
+    await openIdentityPopup();
+    hasIndicator = document.getElementById("blocked-popup-indicator-item");
+    Assert.equal(hasIndicator, true);
+
+    SitePermissions.remove(URI, "popup");
+    gBrowser.removeCurrentTab();
+  });
+});
+
+/*
+add_task(async function testPopupPermissionBlockState(){
+  await BrowserTestUtils.withNewTab(baseURL + "popup_blocker2.html", async () => {
+    SitePermissions.set(URI, "popup", SitePermissions.BLOCK);
+
+    document.getElementById("identity-icon").click();
+    await openIdentityPopup();
+
+    let hasIndicator = document.getElementById("blocked-popup-indicator-item") !== null;
+    Assert.equal(hasIndicator, false);
+
+    let icon = getIdentityBlockIcon();
+    let show = icon.getAttribute("showing");
+    Assert.equal(show, true);
+
+    await ContentTask.spawn(gBrowser.selectedBrowser, null, async () => {
+      let doc = content.document;
+      let open = doc.getElementById("pop");
+      open.click();
+    });
+
+    show = icon.getAttribute("showing");
+    Assert.equal(show, true);
+
+    gBrowser.removeCurrentTab();
+  });
+});
+*/
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/popups/popup_blocker2.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="UTF-8">
+    <title>Page creating a popup</title>
+  </head>
+  <body>
+    <button id="pop" onclick='window.setTimeout(() => {window.open("popup_blocker_a.html", "a");}, 1000);'>Open Popup</button>
+  </body>
+</html>
\ No newline at end of file
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -223,16 +223,17 @@ These should match what Safari and other
 
 <!ENTITY urlbar.cameraBlocked.tooltip            "You have blocked your camera for this website.">
 <!ENTITY urlbar.microphoneBlocked.tooltip        "You have blocked your microphone for this website.">
 <!ENTITY urlbar.screenBlocked.tooltip            "You have blocked this website from sharing your screen.">
 <!ENTITY urlbar.geolocationBlocked.tooltip       "You have blocked location information for this website.">
 <!ENTITY urlbar.indexedDBBlocked.tooltip         "You have blocked data storage for this website.">
 <!ENTITY urlbar.webNotificationsBlocked.tooltip  "You have blocked notifications for this website.">
 <!ENTITY urlbar.persistentStorageBlocked.tooltip "You have blocked persistent storage for this website.">
+<!ENTITY urlbar.popupBlocked.tooltip             "You have blocked popups for this website.">
 
 <!ENTITY urlbar.openHistoryPopup.tooltip                "Show history">
 
 <!ENTITY searchItem.title             "Search">
 
 <!-- Toolbar items -->
 <!ENTITY homeButton.label             "Home">
 
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -258,18 +258,18 @@ lwthemeNeedsRestart.accesskey=R
 popupWarning.message=#1 prevented this site from opening a pop-up window.;#1 prevented this site from opening #2 pop-up windows.
 popupWarningButton=Options
 popupWarningButton.accesskey=O
 popupWarningButtonUnix=Preferences
 popupWarningButtonUnix.accesskey=P
 popupAllow=Allow pop-ups for %S
 popupBlock=Block pop-ups for %S
 popupWarningDontShowFromMessage=Don’t show this message when pop-ups are blocked
-popupWarningDontShowFromLocationbar=Don’t show info bar when pop-ups are blocked
 popupShowPopupPrefix=Show ‘%S’
+popupShowBlockedPopupsIndicatorText=Show #1 blocked popup...;Show #1 blocked popups…
 
 # Bad Content Blocker Doorhanger Notification
 # %S is brandShortName
 badContentBlocked.blocked.message=%S is blocking content on this page.
 badContentBlocked.notblocked.message=%S is not blocking any content on this page.
 
 crashedpluginsMessage.title=The %S plugin has crashed.
 crashedpluginsMessage.reloadButton.label=Reload page
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -70,16 +70,17 @@
   skin/classic/browser/notification-icons/microphone-detailed.svg           (../shared/notification-icons/microphone-detailed.svg)
   skin/classic/browser/notification-icons/microphone.svg                    (../shared/notification-icons/microphone.svg)
   skin/classic/browser/notification-icons/persistent-storage-blocked.svg    (../shared/notification-icons/persistent-storage-blocked.svg)
   skin/classic/browser/notification-icons/persistent-storage.svg            (../shared/notification-icons/persistent-storage.svg)
   skin/classic/browser/notification-icons/plugin-badge.svg                  (../shared/notification-icons/plugin-badge.svg)
   skin/classic/browser/notification-icons/plugin-blocked.svg                (../shared/notification-icons/plugin-blocked.svg)
   skin/classic/browser/notification-icons/plugin.svg                        (../shared/notification-icons/plugin.svg)
   skin/classic/browser/notification-icons/popup.svg                         (../shared/notification-icons/popup.svg)
+  skin/classic/browser/notification-icons/blocked-popup-indicator-icon.svg  (../shared/notification-icons/blocked-popup-indicator-icon.svg)
   skin/classic/browser/notification-icons/screen-blocked.svg                (../shared/notification-icons/screen-blocked.svg)
   skin/classic/browser/notification-icons/screen.svg                        (../shared/notification-icons/screen.svg)
   skin/classic/browser/notification-icons/update.svg                        (../shared/notification-icons/update.svg)
 
   skin/classic/browser/tracking-protection-16.svg              (../shared/identity-block/tracking-protection-16.svg)
   skin/classic/browser/newtab/close.png                        (../shared/newtab/close.png)
   skin/classic/browser/newtab/controls.svg                     (../shared/newtab/controls.svg)
   skin/classic/browser/panel-icon-arrow-left.svg               (../shared/panel-icon-arrow-left.svg)
--- a/browser/themes/shared/notification-icons.inc.css
+++ b/browser/themes/shared/notification-icons.inc.css
@@ -145,16 +145,27 @@ html|*#webRTC-previewVideo {
   margin-inline-start: 0;
 }
 
 /* This icon has a block sign in it, so we don't need a blocked version. */
 .popup-icon {
   list-style-image: url("chrome://browser/skin/notification-icons/popup.svg");
 }
 
+.blocked-popup-indicator-icon {
+  list-style-image: url("chrome://browser/skin/notification-icons/blocked-popup-indicator-icon.svg");
+  margin-inline-start: 30px;
+  -moz-context-properties: fill;
+  fill: GrayText;
+}
+
+.identity-popup-popup-menulist {
+  width: 72px;
+}
+
 /* EME */
 
 .popup-notification-icon[popupid="drmContentPlaying"],
 .drm-icon {
   list-style-image: url("chrome://browser/skin/drm-icon.svg");
 }
 
 #eme-notification-icon[firstplay=true] {
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/notification-icons/blocked-popup-indicator-icon.svg
@@ -0,0 +1,6 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="context-fill" fill-opacity="context-fill-opacity">
+  <path fill="context-fill" d="M13.707 7.293l-3-3a1 1 0 0 0-1.414 1.414L10.586 7H6.012A.918.918 0 0 1 5 6V3a1 1 0 0 0-2 0v3a2.916 2.916 0 0 0 3 3h4.586l-1.293 1.293a1 1 0 1 0 1.414 1.414l3-3a1 1 0 0 0 0-1.414z"/>
+</svg>