1(function() { // anonymize
2
3var allTags = {};
4var loadedResults = [];
5
6/**
7 * Initialization code run upon the DOM being ready.
8 */
9$(document).ready(function() {
10  // Parse page query parameters.
11  var params = parseParams(document.location.search);
12  params.tag = params.tag ? makeArray(params.tag) : null;
13
14  // Load tag and resource dataset.
15  loadTags();
16  loadResources();
17
18  showResults(params);
19
20  // Watch for keypresses in the keyword filter textbox, and update
21  // search results to reflect the keyword filter.
22  $('#resource-browser-keyword-filter').keyup(function() {
23    // Filter results on screen by keyword.
24    var keywords = $(this).val().split(/\s+/g);
25    for (var i = 0; i < loadedResults.length; i++) {
26      var hide = false;
27      for (var j = 0; j < keywords.length; j++) {
28        if (!resultMatchesKeyword(loadedResults[i].result, keywords[j])) {
29          hide = true;
30          break;
31        }
32      }
33
34      loadedResults[i].node[hide ? 'hide' : 'show']();
35    }
36  });
37});
38
39/**
40 * Returns whether or not the given search result contains the given keyword.
41 */
42function resultMatchesKeyword(result, keyword) {
43  keyword = keyword.toLowerCase();
44  if (result.title &&
45      result.title.en.toLowerCase().indexOf(keyword) >= 0)
46    return true;
47  else if (result.description &&
48           result.description.en.toLowerCase().indexOf(keyword) >= 0)
49    return true;
50  else if (result.topicsHtml &&
51           result.topicsHtml.replace(/\<.*?\>/g,'').toLowerCase().indexOf(keyword) >= 0)
52    return true;
53  return false;
54}
55
56/**
57 * Populates the allTags array with tag data from the ANDROID_TAGS
58 * variable in the resource data JS file.
59 */
60function loadTags() {
61  for (var tagClass in ANDROID_TAGS) {
62    for (var tag in ANDROID_TAGS[tagClass]) {
63      allTags[tag] = {
64        displayTag: ANDROID_TAGS[tagClass][tag],
65        tagClass: tagClass
66      };
67    }
68  }
69}
70
71/**
72 * Massage the ANDROID_RESOURCES resource list in the resource data JS file.
73 */
74function loadResources() {
75  for (var i = 0; i < ANDROID_RESOURCES.length; i++) {
76    var resource = ANDROID_RESOURCES[i];
77
78    // Convert the tags array to a tags hash for easier querying.
79    resource.tagsHash = {};
80    for (var j = 0; j < resource.tags.length; j++)
81      resource.tagsHash[resource.tags[j]] = true;
82
83    // Determine the type and topics of the resource by inspecting its tags.
84    resource.topics = [];
85    for (tag in resource.tagsHash)
86      if (tag in allTags) {
87        if (allTags[tag].tagClass == 'type') {
88          resource.type = tag;
89        } else if (allTags[tag].tagClass == 'topic') {
90          resource.topics.push(tag);
91        }
92      }
93
94    // Add a humanized topics list string.
95    resource.topicsHtml = humanizeList(resource.topics, function(item) {
96      return '<strong>' + allTags[item].displayTag + '</strong>';
97    });
98  }
99}
100
101/**
102 * Loads resources for the given query parameters.
103 */
104function showResults(params) {
105  loadedResults = [];
106  $('#resource-browser-search-params').empty();
107  $('#resource-browser-results').empty();
108
109  var i, j;
110  var searchTags = [];
111  if (params.tag) {
112    for (i = 0; i < params.tag.length; i++) {
113      var tag = params.tag[i];
114      if (tag.toLowerCase() in allTags) {
115        searchTags.push(tag.toLowerCase());
116      }
117    }
118  }
119
120  if (searchTags.length) {
121    // Show query params.
122    var taggedWithHtml = ['Showing technical resources tagged with '];
123    taggedWithHtml.push(humanizeList(searchTags, function(item) {
124      return '<strong>' + allTags[item].displayTag + '</strong>';
125    }));
126    $('#resource-browser-search-params').html(taggedWithHtml.join('') + ':');
127  } else {
128    $('#resource-browser-search-params').html('Showing all technical resources:');
129  }
130
131  var results = [];
132
133  // Create the list of resources to show.
134  for (i = 0; i < ANDROID_RESOURCES.length; i++) {
135    var resource = ANDROID_RESOURCES[i];
136    var skip = false;
137
138    if (searchTags.length) {
139      for (j = 0; j < searchTags.length; j++)
140        if (!(searchTags[j] in resource.tagsHash)) {
141          skip = true;
142          break;
143        }
144
145      if (skip)
146        continue;
147
148      results.push(resource);
149      continue;
150    }
151
152    results.push(resource);
153  }
154
155  // Format and show the list of resource results.
156  if (results.length) {
157    $('#resource-browser-results .no-results').hide();
158    for (i = 0; i < results.length; i++) {
159      var result = results[i];
160      var resultJqNode = $(tmpl('tmpl_resource_browser_result', result));
161      for (tag in result.tagsHash)
162        resultJqNode.addClass('tagged-' + tag);
163      $('#resource-browser-results').append(resultJqNode);
164
165      loadedResults.push({ node: resultJqNode, result: result });
166    }
167  } else {
168    $('#resource-browser-results .no-results').show();
169  }
170}
171
172/**
173 * Formats the given array into a human readable, English string, ala
174 * 'a, b and c', with an optional item formatter/wrapper function.
175 */
176function humanizeList(arr, itemFormatter) {
177  itemFormatter = itemFormatter || function(o){ return o; };
178  arr = arr || [];
179
180  var out = [];
181  for (var i = 0; i < arr.length; i++) {
182    out.push(itemFormatter(arr[i]) +
183        ((i < arr.length - 2) ? ', ' : '') +
184        ((i == arr.length - 2) ? ' and ' : ''));
185  }
186
187  return out.join('');
188}
189
190/**
191 * Parses a parameter string, i.e. foo=1&bar=2 into
192 * a dictionary object.
193 */
194function parseParams(paramStr) {
195  var params = {};
196  paramStr = paramStr.replace(/^[?#]/, '');
197
198  var pairs = paramStr.split('&');
199  for (var i = 0; i < pairs.length; i++) {
200    var p = pairs[i].split('=');
201    var key = p[0] ? decodeURIComponent(p[0]) : p[0];
202    var val = p[1] ? decodeURIComponent(p[1]) : p[1];
203    if (val === '0')
204      val = 0;
205    if (val === '1')
206      val = 1;
207
208    if (key in params) {
209      // Handle array values.
210      params[key] = makeArray(params[key]);
211      params[key].push(val);
212    } else {
213      params[key] = val;
214    }
215  }
216
217  return params;
218}
219
220/**
221 * Returns the argument as a single-element array, or the argument itself
222 * if it's already an array.
223 */
224function makeArray(o) {
225  if (!o)
226    return [];
227
228  if (typeof o === 'object' && 'splice' in o) {
229    return o;
230  } else {
231    return [o];
232  }
233}
234
235})();
236