Add preliminary support for dynamic content js and css.
Change-Id: I1dbc92356e8d4beb712b8872e9b6cf873bdb70be
diff --git a/tools/droiddoc/templates-sdk/assets/js/jd_tag_helpers.js b/tools/droiddoc/templates-sdk/assets/js/jd_tag_helpers.js
new file mode 100644
index 0000000..d179cbc
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/js/jd_tag_helpers.js
@@ -0,0 +1,106 @@
+function mergeArrays() {
+ var arr = arguments[0] || [];
+ for (var i = 1; i < arguments.length; i++) {
+ arr = arr.concat(arguments[i]);
+ }
+ return arr;
+}
+
+var ALL_RESOURCES = mergeArrays(
+ DESIGN_RESOURCES,
+ DISTRIBUTE_RESOURCES,
+ GOOGLE_RESOURCES,
+ GUIDE_RESOURCES,
+ SAMPLES_RESOURCES,
+ TOOLS_RESOURCES,
+ TRAINING_RESOURCES,
+ YOUTUBE_RESOURCES,
+ BLOGGER_RESOURCES
+);
+
+for (var i = 0; i < ALL_RESOURCES.length; i++) {
+ ALL_RESOURCES[i].index = i;
+}
+
+function mergeMaps() {
+ var allRes = {};
+ var offset = 0;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var r = arguments[i];
+ for (var tag in r.map) {
+ allRes[tag] = allRes[tag] || [];
+ allRes[tag] = allRes[tag].concat(r.map[tag].map(function(i){ return ALL_RESOURCES[i + offset]; }));
+ }
+ offset += r.arr.length;
+ }
+
+ return allRes;
+}
+
+function setFromArray(arr) {
+ arr = arr || [];
+ var set = {};
+ for (var i = 0; i < arr.length; i++) {
+ set[arr[i]] = true;
+ }
+ return set;
+}
+
+function buildResourceLookupMap(resourceDict) {
+ var map = {};
+ for (var key in resourceDict) {
+ var dictForKey = {};
+ var srcArr = resourceDict[key];
+ for (var i = 0; i < srcArr.length; i++) {
+ dictForKey[srcArr[i].index] = true;
+ }
+ map[key] = dictForKey;
+ }
+ return map;
+}
+
+// Type lookups
+
+var ALL_RESOURCES_BY_TYPE = {
+ 'design': DESIGN_RESOURCES,
+ 'distribute': DISTRIBUTE_RESOURCES,
+ 'google': GOOGLE_RESOURCES,
+ 'guide': GUIDE_RESOURCES,
+ 'samples': SAMPLES_RESOURCES,
+ 'tools': TOOLS_RESOURCES,
+ 'training': TRAINING_RESOURCES,
+ 'youtube': YOUTUBE_RESOURCES,
+ 'blog': BLOGGER_RESOURCES
+};
+var IS_RESOURCE_OF_TYPE = buildResourceLookupMap(ALL_RESOURCES_BY_TYPE);
+
+// Tag lookups
+
+var ALL_RESOURCES_BY_TAG = mergeMaps(
+ {map:DESIGN_BY_TAG,arr:DESIGN_RESOURCES},
+ {map:DISTRIBUTE_BY_TAG,arr:DISTRIBUTE_RESOURCES},
+ {map:GOOGLE_BY_TAG,arr:GOOGLE_RESOURCES},
+ {map:GUIDE_BY_TAG,arr:GUIDE_RESOURCES},
+ {map:SAMPLES_BY_TAG,arr:SAMPLES_RESOURCES},
+ {map:TOOLS_BY_TAG,arr:TOOLS_RESOURCES},
+ {map:TRAINING_BY_TAG,arr:TRAINING_RESOURCES},
+ {map:YOUTUBE_BY_TAG,arr:YOUTUBE_RESOURCES},
+ {map:BLOGGER_BY_TAG,arr:BLOGGER_RESOURCES}
+);
+var IS_RESOURCE_TAGGED = buildResourceLookupMap(ALL_RESOURCES_BY_TAG);
+
+// Language lookups
+
+var ALL_RESOURCES_BY_LANG = {};
+for (var i = 0; i < ALL_RESOURCES.length; i++) {
+ var res = ALL_RESOURCES[i];
+ var lang = res.lang;
+ if (!lang) {
+ continue;
+ }
+
+ ALL_RESOURCES_BY_LANG[lang] = ALL_RESOURCES_BY_LANG[lang] || [];
+ ALL_RESOURCES_BY_LANG[lang].push(res);
+}
+var IS_RESOURCE_IN_LANG = buildResourceLookupMap(ALL_RESOURCES_BY_LANG);
\ No newline at end of file
diff --git a/tools/droiddoc/templates-sdk/assets/js/resourcecards.js b/tools/droiddoc/templates-sdk/assets/js/resourcecards.js
new file mode 100644
index 0000000..fbba201
--- /dev/null
+++ b/tools/droiddoc/templates-sdk/assets/js/resourcecards.js
@@ -0,0 +1,244 @@
+// Requires jd_tag_helpers.js and the data JS to be loaded.
+
+$(document).ready(function() {
+ $('.resource-widget').each(function() {
+ initResourceWidget(this);
+ });
+});
+
+
+function initResourceWidget(widget) {
+ var $widget = $(widget);
+ var isFlow, isCarousel;
+ isFlow = $widget.hasClass('resource-flow-layout');
+ if (!isFlow) {
+ isCarousel = $widget.hasClass('resource-carousel-layout');
+ }
+
+ // find size of widget by pulling out its class name
+ var sizeCols = 1;
+ var m = $widget.get(0).className.match(/\bcol-(\d+)\b/);
+ if (m) {
+ sizeCols = parseInt(m[1], 10);
+ }
+
+ var opts = {
+ source: $widget.data('source'),
+ cardSizes: ($widget.data('cardsizes') || '').split(','),
+ maxResults: parseInt($widget.data('maxresults') || '100'),
+ itemsPerPage: $widget.data('itemsperpage'),
+ sortOrder: $widget.data('sortorder'),
+ query: $widget.data('query'),
+ collectionId: $widget.data('collectionid'),
+ sizeCols: sizeCols
+ };
+
+ // run the search for the set of resources to show
+ var resources = buildResourceList(opts);
+
+ if (isFlow) {
+ drawResourcesFlowWidget($widget, opts, resources);
+ }
+}
+
+
+function drawResourcesFlowWidget($widget, opts, resources) {
+ $widget.empty();
+ var cardSizes = opts.cardSizes || ['4x3'];
+
+ for (var i = 0; i < resources.length; i++) {
+ var resource = resources[i];
+
+ var cardSize = i >= cardSizes.length ? cardSizes[cardSizes.length - 1] : cardSizes[i];
+ cardSize = cardSize.replace(/^\s+|\s+$/,'');
+
+ var $card = $('<a>')
+ .addClass('resource-card resource-card-' + cardSize + ' resource-card-' + resource.type)
+ .attr('href', resource.url);
+
+ $('<img>')
+ .addClass('photo')
+ .attr('src', resource.image || '')
+ .appendTo($card);
+
+ var subtitle = resource.type;
+ if (resource.timestamp) {
+ var d = new Date(resource.timestamp);
+ // TODO: localize, humanize
+ subtitle = (1 + d.getMonth()) + '/' + d.getDate() + '/' + d.getFullYear() + ' on ' + subtitle;
+ }
+
+ $('<div>')
+ .addClass('resource-card-text')
+ .append($('<div>').addClass('icon'))
+ .append($('<div>').addClass('title').text(resource.title))
+ .append($('<div>').addClass('subtitle').text(subtitle))
+ .append($('<div>').addClass('abstract').text(resource.summary))
+ .appendTo($card);
+
+ $card.appendTo($widget);
+ }
+
+ $widget.find('.resource-card .photo').each(function() {
+ var src = $(this).attr('src');
+ if (!src) {
+ $(this).parents('.resource-card').addClass('nophoto');
+ $(this).replaceWith($('<div>')
+ .addClass('photo'));
+ } else {
+ $(this).replaceWith($('<div>')
+ .addClass('photo')
+ .css('background-image', 'url(' + $(this).attr('src') + ')'));
+ }
+ });
+}
+
+
+function buildResourceList(opts) {
+ var maxResults = opts.maxResults || 100;
+
+ switch (opts.source) {
+ case 'query':
+ var query = opts.query || '';
+ var expressions = parseResourceQuery(query);
+ var alreadyAddedResources = {};
+ var allResources = [];
+ for (var i = 0; i < expressions.length; i++) {
+ var clauses = expressions[i];
+
+ // build initial set of resources from first clause
+ var firstClause = clauses[0];
+ var resources = [];
+ switch (firstClause.attr) {
+ case 'type':
+ resources = ALL_RESOURCES_BY_TYPE[firstClause.value];
+ break;
+ case 'lang':
+ resources = ALL_RESOURCES_BY_LANG[firstClause.value];
+ break;
+ case 'tag':
+ resources = ALL_RESOURCES_BY_TAG[firstClause.value];
+ break;
+ }
+ resources = resources || [];
+
+ // use additional clauses to filter corpus
+ if (clauses.length > 1) {
+ var otherClauses = clauses.slice(1);
+ resources = resources.filter(getResourceMatchesClausesFilter(otherClauses));
+ }
+
+ // filter out resources already added
+ if (i > 1) {
+ resources = resources.filter(getResourceNotAlreadyAddedFilter(alreadyAddedResources));
+ }
+
+ allResources = allResources.concat(resources);
+ if (allResources.length > maxResults) {
+ break;
+ }
+ }
+ if (opts.sortOrder) {
+ var attr = opts.sortOrder;
+ var desc = attr.charAt(0) == '-';
+ if (desc) {
+ attr = attr.substring(1);
+ }
+ allResources = allResources.sort(function(x,y) {
+ return (desc ? -1 : 1) * (parseInt(x[attr], 10) - parseInt(y[attr], 10));
+ });
+ }
+ return allResources.slice(0, maxResults);
+
+ case 'related':
+ // TODO
+ break;
+
+ case 'collection':
+ // TODO
+ break;
+ }
+}
+
+
+function getResourceNotAlreadyAddedFilter(addedResources) {
+ return function(x) {
+ return !!addedResources[x];
+ };
+}
+
+
+function getResourceMatchesClausesFilter(clauses) {
+ return function(x) {
+ return doesResourceMatchClauses(x, clauses);
+ };
+}
+
+
+function doesResourceMatchClauses(resource, clauses) {
+ for (var i = 0; i < clauses.length; i++) {
+ var map;
+ switch (clauses[i].attr) {
+ case 'type':
+ map = IS_RESOURCE_OF_TYPE[clauses[i].value];
+ break;
+ case 'lang':
+ map = IS_RESOURCE_IN_LANG[clauses[i].value];
+ break;
+ case 'tag':
+ map = IS_RESOURCE_TAGGED[clauses[i].value];
+ break;
+ }
+
+ if (!map || (!!clauses[i].negative ? map[resource.index] : !map[resource.index])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+function parseResourceQuery(query) {
+ // Parse query into array of expressions (expression e.g. 'tag:foo + type:video')
+ var expressions = [];
+ var expressionStrs = query.split(',') || [];
+ for (var i = 0; i < expressionStrs.length; i++) {
+ var expr = expressionStrs[i] || '';
+
+ // Break expression into clauses (clause e.g. 'tag:foo')
+ var clauses = [];
+ var clauseStrs = expr.split(/(?=[\+\-])/);
+ for (var j = 0; j < clauseStrs.length; j++) {
+ var clauseStr = clauseStrs[j] || '';
+
+ // Get attribute and value from clause (e.g. attribute='tag', value='foo')
+ var parts = clauseStr.split(':');
+ var clause = {};
+
+ clause.attr = parts[0].replace(/\s+/g,'');
+ if (clause.attr) {
+ if (clause.attr.charAt(0) == '+') {
+ clause.attr = clause.attr.substring(1);
+ } else if (clause.attr.charAt(0) == '-') {
+ clause.negative = true;
+ clause.attr = clause.attr.substring(1);
+ }
+ }
+
+ if (parts.length > 1) {
+ clause.value = parts[1].replace(/\s+/g,'');
+ }
+
+ clauses.push(clause);
+ }
+
+ if (!clauses.length) {
+ continue;
+ }
+
+ expressions.push(clauses);
+ }
+
+ return expressions;
+}
+