236 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			236 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| (function() { // anonymize
 | |
| 
 | |
| var allTags = {};
 | |
| var loadedResults = [];
 | |
| 
 | |
| /**
 | |
|  * Initialization code run upon the DOM being ready.
 | |
|  */
 | |
| $(document).ready(function() {
 | |
|   // Parse page query parameters.
 | |
|   var params = parseParams(document.location.search);
 | |
|   params.tag = params.tag ? makeArray(params.tag) : null;
 | |
| 
 | |
|   // Load tag and resource dataset.
 | |
|   loadTags();
 | |
|   loadResources();
 | |
| 
 | |
|   showResults(params);
 | |
| 
 | |
|   // Watch for keypresses in the keyword filter textbox, and update
 | |
|   // search results to reflect the keyword filter.
 | |
|   $('#resource-browser-keyword-filter').keyup(function() {
 | |
|     // Filter results on screen by keyword.
 | |
|     var keywords = $(this).val().split(/\s+/g);
 | |
|     for (var i = 0; i < loadedResults.length; i++) {
 | |
|       var hide = false;
 | |
|       for (var j = 0; j < keywords.length; j++) {
 | |
|         if (!resultMatchesKeyword(loadedResults[i].result, keywords[j])) {
 | |
|           hide = true;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       loadedResults[i].node[hide ? 'hide' : 'show']();
 | |
|     }
 | |
|   });
 | |
| });
 | |
| 
 | |
| /**
 | |
|  * Returns whether or not the given search result contains the given keyword.
 | |
|  */
 | |
| function resultMatchesKeyword(result, keyword) {
 | |
|   keyword = keyword.toLowerCase();
 | |
|   if (result.title &&
 | |
|       result.title.en.toLowerCase().indexOf(keyword) >= 0)
 | |
|     return true;
 | |
|   else if (result.description &&
 | |
|            result.description.en.toLowerCase().indexOf(keyword) >= 0)
 | |
|     return true;
 | |
|   else if (result.topicsHtml &&
 | |
|            result.topicsHtml.replace(/\<.*?\>/g,'').toLowerCase().indexOf(keyword) >= 0)
 | |
|     return true;
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Populates the allTags array with tag data from the ANDROID_TAGS
 | |
|  * variable in the resource data JS file.
 | |
|  */
 | |
| function loadTags() {
 | |
|   for (var tagClass in ANDROID_TAGS) {
 | |
|     for (var tag in ANDROID_TAGS[tagClass]) {
 | |
|       allTags[tag] = {
 | |
|         displayTag: ANDROID_TAGS[tagClass][tag],
 | |
|         tagClass: tagClass
 | |
|       };
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Massage the ANDROID_RESOURCES resource list in the resource data JS file.
 | |
|  */
 | |
| function loadResources() {
 | |
|   for (var i = 0; i < ANDROID_RESOURCES.length; i++) {
 | |
|     var resource = ANDROID_RESOURCES[i];
 | |
| 
 | |
|     // Convert the tags array to a tags hash for easier querying.
 | |
|     resource.tagsHash = {};
 | |
|     for (var j = 0; j < resource.tags.length; j++)
 | |
|       resource.tagsHash[resource.tags[j]] = true;
 | |
| 
 | |
|     // Determine the type and topics of the resource by inspecting its tags.
 | |
|     resource.topics = [];
 | |
|     for (tag in resource.tagsHash)
 | |
|       if (tag in allTags) {
 | |
|         if (allTags[tag].tagClass == 'type') {
 | |
|           resource.type = tag;
 | |
|         } else if (allTags[tag].tagClass == 'topic') {
 | |
|           resource.topics.push(tag);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|     // Add a humanized topics list string.
 | |
|     resource.topicsHtml = humanizeList(resource.topics, function(item) {
 | |
|       return '<strong>' + allTags[item].displayTag + '</strong>';
 | |
|     });
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Loads resources for the given query parameters.
 | |
|  */
 | |
| function showResults(params) {
 | |
|   loadedResults = [];
 | |
|   $('#resource-browser-search-params').empty();
 | |
|   $('#resource-browser-results').empty();
 | |
| 
 | |
|   var i, j;
 | |
|   var searchTags = [];
 | |
|   if (params.tag) {
 | |
|     for (i = 0; i < params.tag.length; i++) {
 | |
|       var tag = params.tag[i];
 | |
|       if (tag.toLowerCase() in allTags) {
 | |
|         searchTags.push(tag.toLowerCase());
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (searchTags.length) {
 | |
|     // Show query params.
 | |
|     var taggedWithHtml = ['Showing technical resources tagged with '];
 | |
|     taggedWithHtml.push(humanizeList(searchTags, function(item) {
 | |
|       return '<strong>' + allTags[item].displayTag + '</strong>';
 | |
|     }));
 | |
|     $('#resource-browser-search-params').html(taggedWithHtml.join('') + ':');
 | |
|   } else {
 | |
|     $('#resource-browser-search-params').html('Showing all technical resources:');
 | |
|   }
 | |
| 
 | |
|   var results = [];
 | |
| 
 | |
|   // Create the list of resources to show.
 | |
|   for (i = 0; i < ANDROID_RESOURCES.length; i++) {
 | |
|     var resource = ANDROID_RESOURCES[i];
 | |
|     var skip = false;
 | |
| 
 | |
|     if (searchTags.length) {
 | |
|       for (j = 0; j < searchTags.length; j++)
 | |
|         if (!(searchTags[j] in resource.tagsHash)) {
 | |
|           skip = true;
 | |
|           break;
 | |
|         }
 | |
| 
 | |
|       if (skip)
 | |
|         continue;
 | |
| 
 | |
|       results.push(resource);
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     results.push(resource);
 | |
|   }
 | |
| 
 | |
|   // Format and show the list of resource results.
 | |
|   if (results.length) {
 | |
|     $('#resource-browser-results .no-results').hide();
 | |
|     for (i = 0; i < results.length; i++) {
 | |
|       var result = results[i];
 | |
|       var resultJqNode = $(tmpl('tmpl_resource_browser_result', result));
 | |
|       for (tag in result.tagsHash)
 | |
|         resultJqNode.addClass('tagged-' + tag);
 | |
|       $('#resource-browser-results').append(resultJqNode);
 | |
| 
 | |
|       loadedResults.push({ node: resultJqNode, result: result });
 | |
|     }
 | |
|   } else {
 | |
|     $('#resource-browser-results .no-results').show();
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Formats the given array into a human readable, English string, ala
 | |
|  * 'a, b and c', with an optional item formatter/wrapper function.
 | |
|  */
 | |
| function humanizeList(arr, itemFormatter) {
 | |
|   itemFormatter = itemFormatter || function(o){ return o; };
 | |
|   arr = arr || [];
 | |
| 
 | |
|   var out = [];
 | |
|   for (var i = 0; i < arr.length; i++) {
 | |
|     out.push(itemFormatter(arr[i]) +
 | |
|         ((i < arr.length - 2) ? ', ' : '') +
 | |
|         ((i == arr.length - 2) ? ' and ' : ''));
 | |
|   }
 | |
| 
 | |
|   return out.join('');
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Parses a parameter string, i.e. foo=1&bar=2 into
 | |
|  * a dictionary object.
 | |
|  */
 | |
| function parseParams(paramStr) {
 | |
|   var params = {};
 | |
|   paramStr = paramStr.replace(/^[?#]/, '');
 | |
| 
 | |
|   var pairs = paramStr.split('&');
 | |
|   for (var i = 0; i < pairs.length; i++) {
 | |
|     var p = pairs[i].split('=');
 | |
|     var key = p[0] ? decodeURIComponent(p[0]) : p[0];
 | |
|     var val = p[1] ? decodeURIComponent(p[1]) : p[1];
 | |
|     if (val === '0')
 | |
|       val = 0;
 | |
|     if (val === '1')
 | |
|       val = 1;
 | |
| 
 | |
|     if (key in params) {
 | |
|       // Handle array values.
 | |
|       params[key] = makeArray(params[key]);
 | |
|       params[key].push(val);
 | |
|     } else {
 | |
|       params[key] = val;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return params;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Returns the argument as a single-element array, or the argument itself
 | |
|  * if it's already an array.
 | |
|  */
 | |
| function makeArray(o) {
 | |
|   if (!o)
 | |
|     return [];
 | |
| 
 | |
|   if (typeof o === 'object' && 'splice' in o) {
 | |
|     return o;
 | |
|   } else {
 | |
|     return [o];
 | |
|   }
 | |
| }
 | |
| 
 | |
| })();
 |