PageRenderTime 26ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

/share/spice/board_game_geek/search/board_game_geek_search.js

http://github.com/duckduckgo/zeroclickinfo-spice
JavaScript | 152 lines | 105 code | 20 blank | 27 comment | 22 complexity | 4f6ecb00dc0fe036ce28d4f949e4e089 MD5 | raw file
Possible License(s): Apache-2.0
  1. (function (env) {
  2. "use strict";
  3. env.ddg_spice_board_game_geek_search = function(api_result){
  4. // Validate the response (customize for your Spice)
  5. if (!api_result || api_result.error || !api_result.items || !api_result.items.item) {
  6. return Spice.failed('board_game_geek');
  7. }
  8. var items = api_result.items.item,
  9. // Get the query without the trigger words.
  10. script = $('[src*="/js/spice/board_game_geek/"]')[0],
  11. source = $(script).attr("src"),
  12. query = source.match(/board_game_geek\/search\/([^\/]+)/)[1];
  13. // because of the XML parsing, a response with 1 item gets
  14. // turned into an object rather than array
  15. if (!(items instanceof Array)) {
  16. items = [items];
  17. }
  18. // in some cases BGG returns FAR TOO MANY results, including expansions
  19. // this is especially a problem with games with fan expansions,
  20. // e.g. Ticket To Ride has 100+ results
  21. //
  22. // to eliminate most of the expansions, we get the earliest result by year
  23. // (using the numeric ID as a tiebreaker) and grab the first 25 entries only
  24. items.sort(function (a, b) {
  25. var aYear = Number(a.yearpublished && a.yearpublished.value) || 5000,
  26. bYear = Number(b.yearpublished && b.yearpublished.value) || 5000;
  27. if (aYear === bYear) {
  28. return Number(a.id) < Number(b.id) ? -1 : 1;
  29. } else {
  30. return aYear < bYear ? -1 : 1;
  31. }
  32. });
  33. items = items.slice(0, 25);
  34. // Render the response
  35. Spice.add({
  36. id: "board_game_geek",
  37. name: "Board Games",
  38. data: items,
  39. meta: {
  40. itemType: "Board Games",
  41. searchTerm: decodeURIComponent(query),
  42. sourceName: "BoardGameGeek",
  43. sourceUrl: "http://boardgamegeek.com/geeksearch.php?action=search&objecttype=boardgame&q=" + query,
  44. sourceIcon: true,
  45. rerender: ["img", "img_m", "abstract", "rating", "reviewCount", "players", "playTime", "age"]
  46. },
  47. normalize: function(item) {
  48. return {
  49. bggId: item.id, // store id to use it in onItemShown
  50. heading: item.name.value,
  51. img: "",
  52. img_m: "",
  53. url: "http://boardgamegeek.com/boardgame/" + item.id,
  54. url_review: "http://boardgamegeek.com/boardgame/" + item.id + "/reviews"
  55. };
  56. },
  57. onItemShown: function (item) {
  58. if (item.loadedDetails) {
  59. return;
  60. }
  61. $.getJSON("/js/spice/board_game_geek/get_details/" + item.bggId, function (response) {
  62. var responseItem = response.items.item,
  63. rating = DDG.getProperty(responseItem, "statistics.ratings.average.value"),
  64. img_m = DDG.getProperty(responseItem, "image.text"),
  65. img = DDG.getProperty(responseItem, "thumbnail.text");
  66. // the BGG rating is out of 10 so divide to get a five star rating
  67. if (rating) {
  68. rating /= 2;
  69. }
  70. item.set({
  71. img_m: addProtocol(img_m),
  72. img: addProtocol(img),
  73. abstract: DDG.getProperty(responseItem, "description.text"),
  74. rating: rating,
  75. reviewCount: DDG.getProperty(responseItem, "statistics.ratings.usersrated.value"),
  76. players: getRange(responseItem, "players"),
  77. playTime: getRange(responseItem, "playtime"),
  78. age: getRange(responseItem, "age")
  79. });
  80. })
  81. item.loadedDetails = true;
  82. },
  83. templates: {
  84. group: 'products',
  85. options: {
  86. price: false,
  87. hideReviewText: true,
  88. subtitle_content: Spice.board_game_geek_search.subtitle,
  89. buy: Spice.board_game_geek_search.buy
  90. }
  91. }
  92. });
  93. };
  94. /**
  95. * Images with a placeholder protocol seem to break when we try and request
  96. * https images - so force http:// on them
  97. *
  98. * They'll be proxied via https://images.duckduckgo.com anyway so it's not a problem
  99. */
  100. function addProtocol(img) {
  101. if (img.indexOf("//") === 0) {
  102. img = "http:" + img;
  103. }
  104. return img;
  105. }
  106. /**
  107. * Possible values this returns are based on
  108. * what the min/max values are, and whether they're defined:
  109. *
  110. * 15 (if min and max are the same)
  111. * 5-15 (min and max)
  112. * 5+ (min only)
  113. * <5 (max only)
  114. */
  115. function getRange(responseItem, rangeName) {
  116. var min = Number(DDG.getProperty(responseItem, "min" + rangeName + ".value")),
  117. max = Number(DDG.getProperty(responseItem, "max" + rangeName + ".value")),
  118. range = "";
  119. if (min && max) {
  120. if (min === max) {
  121. range = min;
  122. } else {
  123. range = min + "-" + max;
  124. }
  125. } else if (min) {
  126. range = min + "+";
  127. } else if (max) {
  128. range = "<" + max;
  129. }
  130. return range;
  131. }
  132. }(this));