blob: fbba201ea24aee797596e775765ef782bcb1c33b [file] [log] [blame]
Dirk Dougherty1f121602014-01-23 19:10:05 -08001// Requires jd_tag_helpers.js and the data JS to be loaded.
2
3$(document).ready(function() {
4 $('.resource-widget').each(function() {
5 initResourceWidget(this);
6 });
7});
8
9
10function initResourceWidget(widget) {
11 var $widget = $(widget);
12 var isFlow, isCarousel;
13 isFlow = $widget.hasClass('resource-flow-layout');
14 if (!isFlow) {
15 isCarousel = $widget.hasClass('resource-carousel-layout');
16 }
17
18 // find size of widget by pulling out its class name
19 var sizeCols = 1;
20 var m = $widget.get(0).className.match(/\bcol-(\d+)\b/);
21 if (m) {
22 sizeCols = parseInt(m[1], 10);
23 }
24
25 var opts = {
26 source: $widget.data('source'),
27 cardSizes: ($widget.data('cardsizes') || '').split(','),
28 maxResults: parseInt($widget.data('maxresults') || '100'),
29 itemsPerPage: $widget.data('itemsperpage'),
30 sortOrder: $widget.data('sortorder'),
31 query: $widget.data('query'),
32 collectionId: $widget.data('collectionid'),
33 sizeCols: sizeCols
34 };
35
36 // run the search for the set of resources to show
37 var resources = buildResourceList(opts);
38
39 if (isFlow) {
40 drawResourcesFlowWidget($widget, opts, resources);
41 }
42}
43
44
45function drawResourcesFlowWidget($widget, opts, resources) {
46 $widget.empty();
47 var cardSizes = opts.cardSizes || ['4x3'];
48
49 for (var i = 0; i < resources.length; i++) {
50 var resource = resources[i];
51
52 var cardSize = i >= cardSizes.length ? cardSizes[cardSizes.length - 1] : cardSizes[i];
53 cardSize = cardSize.replace(/^\s+|\s+$/,'');
54
55 var $card = $('<a>')
56 .addClass('resource-card resource-card-' + cardSize + ' resource-card-' + resource.type)
57 .attr('href', resource.url);
58
59 $('<img>')
60 .addClass('photo')
61 .attr('src', resource.image || '')
62 .appendTo($card);
63
64 var subtitle = resource.type;
65 if (resource.timestamp) {
66 var d = new Date(resource.timestamp);
67 // TODO: localize, humanize
68 subtitle = (1 + d.getMonth()) + '/' + d.getDate() + '/' + d.getFullYear() + ' on ' + subtitle;
69 }
70
71 $('<div>')
72 .addClass('resource-card-text')
73 .append($('<div>').addClass('icon'))
74 .append($('<div>').addClass('title').text(resource.title))
75 .append($('<div>').addClass('subtitle').text(subtitle))
76 .append($('<div>').addClass('abstract').text(resource.summary))
77 .appendTo($card);
78
79 $card.appendTo($widget);
80 }
81
82 $widget.find('.resource-card .photo').each(function() {
83 var src = $(this).attr('src');
84 if (!src) {
85 $(this).parents('.resource-card').addClass('nophoto');
86 $(this).replaceWith($('<div>')
87 .addClass('photo'));
88 } else {
89 $(this).replaceWith($('<div>')
90 .addClass('photo')
91 .css('background-image', 'url(' + $(this).attr('src') + ')'));
92 }
93 });
94}
95
96
97function buildResourceList(opts) {
98 var maxResults = opts.maxResults || 100;
99
100 switch (opts.source) {
101 case 'query':
102 var query = opts.query || '';
103 var expressions = parseResourceQuery(query);
104 var alreadyAddedResources = {};
105 var allResources = [];
106 for (var i = 0; i < expressions.length; i++) {
107 var clauses = expressions[i];
108
109 // build initial set of resources from first clause
110 var firstClause = clauses[0];
111 var resources = [];
112 switch (firstClause.attr) {
113 case 'type':
114 resources = ALL_RESOURCES_BY_TYPE[firstClause.value];
115 break;
116 case 'lang':
117 resources = ALL_RESOURCES_BY_LANG[firstClause.value];
118 break;
119 case 'tag':
120 resources = ALL_RESOURCES_BY_TAG[firstClause.value];
121 break;
122 }
123 resources = resources || [];
124
125 // use additional clauses to filter corpus
126 if (clauses.length > 1) {
127 var otherClauses = clauses.slice(1);
128 resources = resources.filter(getResourceMatchesClausesFilter(otherClauses));
129 }
130
131 // filter out resources already added
132 if (i > 1) {
133 resources = resources.filter(getResourceNotAlreadyAddedFilter(alreadyAddedResources));
134 }
135
136 allResources = allResources.concat(resources);
137 if (allResources.length > maxResults) {
138 break;
139 }
140 }
141 if (opts.sortOrder) {
142 var attr = opts.sortOrder;
143 var desc = attr.charAt(0) == '-';
144 if (desc) {
145 attr = attr.substring(1);
146 }
147 allResources = allResources.sort(function(x,y) {
148 return (desc ? -1 : 1) * (parseInt(x[attr], 10) - parseInt(y[attr], 10));
149 });
150 }
151 return allResources.slice(0, maxResults);
152
153 case 'related':
154 // TODO
155 break;
156
157 case 'collection':
158 // TODO
159 break;
160 }
161}
162
163
164function getResourceNotAlreadyAddedFilter(addedResources) {
165 return function(x) {
166 return !!addedResources[x];
167 };
168}
169
170
171function getResourceMatchesClausesFilter(clauses) {
172 return function(x) {
173 return doesResourceMatchClauses(x, clauses);
174 };
175}
176
177
178function doesResourceMatchClauses(resource, clauses) {
179 for (var i = 0; i < clauses.length; i++) {
180 var map;
181 switch (clauses[i].attr) {
182 case 'type':
183 map = IS_RESOURCE_OF_TYPE[clauses[i].value];
184 break;
185 case 'lang':
186 map = IS_RESOURCE_IN_LANG[clauses[i].value];
187 break;
188 case 'tag':
189 map = IS_RESOURCE_TAGGED[clauses[i].value];
190 break;
191 }
192
193 if (!map || (!!clauses[i].negative ? map[resource.index] : !map[resource.index])) {
194 return false;
195 }
196 }
197 return true;
198}
199
200
201function parseResourceQuery(query) {
202 // Parse query into array of expressions (expression e.g. 'tag:foo + type:video')
203 var expressions = [];
204 var expressionStrs = query.split(',') || [];
205 for (var i = 0; i < expressionStrs.length; i++) {
206 var expr = expressionStrs[i] || '';
207
208 // Break expression into clauses (clause e.g. 'tag:foo')
209 var clauses = [];
210 var clauseStrs = expr.split(/(?=[\+\-])/);
211 for (var j = 0; j < clauseStrs.length; j++) {
212 var clauseStr = clauseStrs[j] || '';
213
214 // Get attribute and value from clause (e.g. attribute='tag', value='foo')
215 var parts = clauseStr.split(':');
216 var clause = {};
217
218 clause.attr = parts[0].replace(/\s+/g,'');
219 if (clause.attr) {
220 if (clause.attr.charAt(0) == '+') {
221 clause.attr = clause.attr.substring(1);
222 } else if (clause.attr.charAt(0) == '-') {
223 clause.negative = true;
224 clause.attr = clause.attr.substring(1);
225 }
226 }
227
228 if (parts.length > 1) {
229 clause.value = parts[1].replace(/\s+/g,'');
230 }
231
232 clauses.push(clause);
233 }
234
235 if (!clauses.length) {
236 continue;
237 }
238
239 expressions.push(clauses);
240 }
241
242 return expressions;
243}
244