From 0266782ff5b4bcc778ac64db218db27897c7d2db Mon Sep 17 00:00:00 2001 From: Dave Townsend Date: Fri, 7 Jan 2011 09:09:09 -0800 Subject: [PATCH] Bug 562790: Support paid results in the add-ons search results. r=Unfocused, a=blocks-betaN --- .../mozapps/extensions/AddonRepository.jsm | 62 +++++- .../mozapps/extensions/content/extensions.js | 32 ++- .../mozapps/extensions/content/extensions.xml | 71 ++++++- .../mozapps/extensions/content/extensions.xul | 3 + .../extensions/test/browser/Makefile.in | 2 + .../test/browser/browser_purchase.js | 192 ++++++++++++++++++ .../test/browser/browser_purchase.xml | 180 ++++++++++++++++ .../xpcshell/data/test_AddonRepository.xml | 90 ++++++++ .../test/xpcshell/test_AddonRepository.js | 33 ++- 9 files changed, 647 insertions(+), 18 deletions(-) create mode 100644 toolkit/mozapps/extensions/test/browser/browser_purchase.js create mode 100644 toolkit/mozapps/extensions/test/browser/browser_purchase.xml diff --git a/toolkit/mozapps/extensions/AddonRepository.jsm b/toolkit/mozapps/extensions/AddonRepository.jsm index fe60fe72a93..b7a483c3ba2 100644 --- a/toolkit/mozapps/extensions/AddonRepository.jsm +++ b/toolkit/mozapps/extensions/AddonRepository.jsm @@ -220,6 +220,22 @@ AddonSearchResult.prototype = { */ contributionAmount: null, + /** + * The URL to visit in order to purchase the add-on + */ + purchaseURL: null, + + /** + * The numerical cost of the add-on in some currency, for sorting purposes + * only + */ + purchaseAmount: null, + + /** + * The display cost of the add-on, for display purposes only + */ + purchaseDisplayAmount: null, + /** * The rating of the add-on, 0-5 */ @@ -278,10 +294,16 @@ AddonSearchResult.prototype = { /** * True or false depending on whether the add-on is compatible with the - * current version and platform of the application + * current version of the application */ isCompatible: true, + /** + * True or false depending on whether the add-on is compatible with the + * current platform + */ + isPlatformCompatible: true, + /** * True if the add-on has a secure means of updating */ @@ -928,6 +950,17 @@ var AddonRepository = { addon.contributionAmount = suggestedAmount; } break + case "payment_data": + let link = this._getDescendantTextContent(node, "link"); + let amountTag = this._getUniqueDescendant(node, "amount"); + let amount = parseFloat(amountTag.getAttribute("amount")); + let displayAmount = this._getTextContent(amountTag); + if (link != null && amount != null && displayAmount != null) { + addon.purchaseURL = link; + addon.purchaseAmount = amount; + addon.purchaseDisplayAmount = displayAmount; + } + break case "rating": let averageRating = parseInt(this._getTextContent(node)); if (averageRating >= 0) @@ -946,6 +979,13 @@ var AddonRepository = { if (!isNaN(repositoryStatus)) addon.repositoryStatus = repositoryStatus; break; + case "all_compatible_os": + let nodes = node.getElementsByTagName("os"); + addon.isPlatformCompatible = Array.some(nodes, function(aNode) { + let text = aNode.textContent.toLowerCase().trim(); + return text == "all" || text == Services.appinfo.OS.toLowerCase(); + }); + break; case "install": // No os attribute means the xpi is compatible with any os if (node.hasAttribute("os")) { @@ -1030,8 +1070,13 @@ var AddonRepository = { if (requiredAttributes.some(function(aAttribute) !result.addon[aAttribute])) continue; - // Add only if there was an xpi compatible with this OS - if (!result.xpiURL) + // Add only if the add-on is compatible with the platform + if (!result.addon.isPlatformCompatible) + continue; + + // Add only if there was an xpi compatible with this OS or there was a + // way to purchase the add-on + if (!result.xpiURL && !result.addon.purchaseURL) continue; results.push(result); @@ -1057,9 +1102,14 @@ var AddonRepository = { self._reportSuccess(results, aTotalResults); } - AddonManager.getInstallForURL(aResult.xpiURL, callback, - "application/x-xpinstall", aResult.xpiHash, - addon.name, addon.iconURL, addon.version); + if (aResult.xpiURL) { + AddonManager.getInstallForURL(aResult.xpiURL, callback, + "application/x-xpinstall", aResult.xpiHash, + addon.name, addon.iconURL, addon.version); + } + else { + callback(null); + } }); }, diff --git a/toolkit/mozapps/extensions/content/extensions.js b/toolkit/mozapps/extensions/content/extensions.js index 17190f9f455..32bb2b020f4 100644 --- a/toolkit/mozapps/extensions/content/extensions.js +++ b/toolkit/mozapps/extensions/content/extensions.js @@ -948,6 +948,16 @@ var gViewController = { } }, + cmd_purchaseItem: { + isEnabled: function(aAddon) { + if (!aAddon) + return false; + return !!aAddon.purchaseURL; + }, + doCommand: function(aAddon) { + openURL(aAddon.purchaseURL); + } + }, cmd_uninstallItem: { isEnabled: function(aAddon) { @@ -1181,7 +1191,7 @@ function createItem(aObj, aIsInstall, aIsRemote) { function sortElements(aElements, aSortBy, aAscending) { const DATE_FIELDS = ["updateDate"]; - const INTEGER_FIELDS = ["size", "relevancescore"]; + const NUMERIC_FIELDS = ["size", "relevancescore", "purchaseAmount"]; function dateCompare(a, b) { var aTime = a.getTime(); @@ -1193,7 +1203,7 @@ function sortElements(aElements, aSortBy, aAscending) { return 0; } - function intCompare(a, b) { + function numberCompare(a, b) { return a - b; } @@ -1218,8 +1228,8 @@ function sortElements(aElements, aSortBy, aAscending) { var sortFunc = stringCompare; if (DATE_FIELDS.indexOf(aSortBy) != -1) sortFunc = dateCompare; - else if (INTEGER_FIELDS.indexOf(aSortBy) != -1) - sortFunc = intCompare; + else if (NUMERIC_FIELDS.indexOf(aSortBy) != -1) + sortFunc = numberCompare; aElements.sort(function(a, b) { if (!aAscending) @@ -1736,6 +1746,7 @@ var gSearchView = { this.showEmptyNotice(false); this.showAllResultsLink(0); this.showLoading(true); + this._sorters.showprice = false; gHeader.searchQuery = aQuery; aQuery = aQuery.trim().toLocaleLowerCase(); @@ -1770,8 +1781,11 @@ var gSearchView = { let item = createItem(aObj, aIsInstall, aIsRemote); item.setAttribute("relevancescore", score); - if (aIsRemote) + if (aIsRemote) { gCachedAddons[aObj.id] = aObj; + if (aObj.purchaseURL) + self._sorters.showprice = true; + } elements.push(item); }); @@ -2244,6 +2258,14 @@ var gDetailView = { contributions.hidden = true; } + if ("purchaseURL" in aAddon && aAddon.purchaseURL) { + var purchase = document.getElementById("detail-purchase-btn"); + purchase.label = gStrings.ext.formatStringFromName("cmd.purchaseAddon.label", + [aAddon.purchaseDisplayAmount], + 1); + purchase.accesskey = gStrings.ext.GetStringFromName("cmd.purchaseAddon.accesskey"); + } + var updateDateRow = document.getElementById("detail-dateUpdated"); if (aAddon.updateDate) { var date = formatDate(aAddon.updateDate); diff --git a/toolkit/mozapps/extensions/content/extensions.xml b/toolkit/mozapps/extensions/content/extensions.xml index 0389b6ac4bc..39c69ef569c 100644 --- a/toolkit/mozapps/extensions/content/extensions.xml +++ b/toolkit/mozapps/extensions/content/extensions.xml @@ -248,6 +248,10 @@ label="&sort.dateUpdated.label;" tooltiptext="&sort.dateUpdated.tooltip;" oncommand="this.parentNode._handleChange('updateDate');"/> +