| Index: options.js | 
| =================================================================== | 
| --- a/options.js | 
| +++ b/options.js | 
| @@ -68,7 +68,10 @@ | 
| var listItem = document.createElement("li"); | 
| listItem.appendChild(document.importNode(template.content, true)); | 
| listItem.setAttribute("data-access", item.url || item.text); | 
| -        listItem.querySelector(".display").textContent = text; | 
| +        var display = listItem.querySelector(".display"); | 
| +        if (item.type) | 
| +          display.setAttribute("data-tooltip-value", item.type); | 
| +        display.textContent = text; | 
| if (text) | 
| listItem.setAttribute("data-search", text.toLowerCase()); | 
|  | 
| @@ -246,6 +249,7 @@ | 
| } | 
| } | 
| } | 
| +          updateTooltips(); | 
| } | 
|  | 
| if (!Object.observe) | 
| @@ -325,15 +329,16 @@ | 
| for (var i = 0; i < elements.length; i++) | 
| { | 
| var element = elements[i]; | 
| -          var subscription = Object.create(null); | 
| -          subscription.title = element.getAttribute("title"); | 
| -          subscription.url = element.getAttribute("url"); | 
| -          subscription.disabled = null; | 
| -          subscription.downloadStatus = null; | 
| -          subscription.homepage = null; | 
| -          subscription.lastSuccess = null; | 
| -          var recommendation = Object.create(null); | 
| -          recommendation.type = element.getAttribute("type"); | 
| +          var recommendation = {type: element.getAttribute("type")}; | 
| +          var subscription = { | 
| +            title: element.getAttribute("title"), | 
| +            url: element.getAttribute("url"), | 
| +            disabled: null, | 
| +            downloadStatus: null, | 
| +            homepage: null, | 
| +            lastSuccess: null, | 
| +            type: recommendation.type | 
| +          }; | 
| var prefix = element.getAttribute("prefixes"); | 
| if (prefix) | 
| { | 
| @@ -781,6 +786,85 @@ | 
| checkShareResource(shareResources[i], onResult); | 
| } | 
|  | 
| +  function getMessages(id) | 
| +  { | 
| +    var messages = []; | 
| +    for (var i = 1; true; i++) | 
| +    { | 
| +      var message = ext.i18n.getMessage(id + "_" + i); | 
| +      if (!message) | 
| +        break; | 
| + | 
| +      messages.push(message); | 
| +    } | 
| +    return messages; | 
| +  } | 
| + | 
| +  function updateTooltips() | 
| +  { | 
| +    var anchors = document.querySelectorAll(":not(.tooltip) > [data-tooltip]"); | 
| +    for (var i = 0; i < anchors.length; i++) | 
| +    { | 
| +      var anchor = anchors[i]; | 
| +      var id = anchor.getAttribute("data-tooltip"); | 
| +      id = id.replace("%value%", anchor.getAttribute("data-tooltip-value")); | 
| + | 
| +      var wrapper = document.createElement("div"); | 
| +      wrapper.className = "tooltip"; | 
| +      anchor.parentNode.replaceChild(wrapper, anchor); | 
| +      wrapper.appendChild(anchor); | 
| + | 
| +      var topTexts = getMessages(id); | 
| +      var bottomTexts = getMessages(id + "_notes"); | 
| + | 
| +      // We have to use native tooltips to avoid issues when attaching a tooltip | 
| +      // to an element in a scrollable list or otherwise it might get cut off | 
| +      if (anchor.hasAttribute("data-tooltip-native")) | 
| +      { | 
| +        var title = topTexts.concat(bottomTexts).join("\n\n"); | 
| +        anchor.setAttribute("title", title); | 
| +        continue; | 
| +      } | 
| + | 
| +      var tooltip = document.createElement("div"); | 
| +      tooltip.setAttribute("role", "tooltip"); | 
| + | 
| +      var flip = anchor.getAttribute("data-tooltip-flip"); | 
| +      if (flip) | 
| +        tooltip.className = "flip-" + flip; | 
| + | 
| +      var imageSource = anchor.getAttribute("data-tooltip-image"); | 
| +      if (imageSource) | 
| +      { | 
| +        var image = document.createElement("img"); | 
| +        image.src = imageSource; | 
| +        image.alt = ""; | 
| +        tooltip.appendChild(image); | 
| +      } | 
| + | 
| +      for (var j = 0; j < topTexts.length; j++) | 
| +      { | 
| +        var paragraph = document.createElement("p"); | 
| +        paragraph.textContent = topTexts[j]; | 
| +        tooltip.appendChild(paragraph); | 
| +      } | 
| +      if (bottomTexts.length > 0) | 
| +      { | 
| +        var notes = document.createElement("div"); | 
| +        notes.className = "notes"; | 
| +        for (var j = 0; j < bottomTexts.length; j++) | 
| +        { | 
| +          var paragraph = document.createElement("p"); | 
| +          paragraph.textContent = bottomTexts[j]; | 
| +          notes.appendChild(paragraph); | 
| +        } | 
| +        tooltip.appendChild(notes); | 
| +      } | 
| + | 
| +      wrapper.appendChild(tooltip); | 
| +    } | 
| +  } | 
| + | 
| ext.onMessage.addListener(function(message) | 
| { | 
| switch (message.type) | 
|  |