| 1 |
// $Id$
|
| 2 |
|
| 3 |
/**
|
| 4 |
* Enable auto facet generation based on fields in selected feeds in Exhibit node creation
|
| 5 |
*/
|
| 6 |
Drupal.behaviors.exhibit = function(context) {
|
| 7 |
|
| 8 |
Drupal.exhibit.buildForm();
|
| 9 |
// Loads all feeds, attaches change handler to feed checkboxes,
|
| 10 |
// and initializes
|
| 11 |
Drupal.exhibit.loadFeeds(function(){
|
| 12 |
$('input.exhibit-feed-checkbox:not(.exhibit-feed-checkbox-processed)', context).addClass('exhibit-feed-checkbox-processed').each(function () {
|
| 13 |
$(this).bind('change', function(){
|
| 14 |
Drupal.exhibit.selectFeed(this);
|
| 15 |
});
|
| 16 |
|
| 17 |
if (this.checked) {
|
| 18 |
Drupal.exhibit.selectFeed(this);
|
| 19 |
}
|
| 20 |
});
|
| 21 |
|
| 22 |
// Bind insert button click event
|
| 23 |
$('input#edit-insert-facet').bind('click', function(){
|
| 24 |
Drupal.exhibit.insertFacet();
|
| 25 |
return false;
|
| 26 |
});
|
| 27 |
|
| 28 |
$('#edit-exhibit-facet-generator-form-wrapper-field-name').bind('change', function(){
|
| 29 |
Drupal.exhibit.filterFacetTypeByField();
|
| 30 |
return false;
|
| 31 |
});
|
| 32 |
|
| 33 |
$('#edit-exhibit-facet-generator-form-wrapper-facet-type').bind('change', function(){
|
| 34 |
Drupal.exhibit.facetTypeChange();
|
| 35 |
return false;
|
| 36 |
});
|
| 37 |
|
| 38 |
});
|
| 39 |
|
| 40 |
};
|
| 41 |
|
| 42 |
/**
|
| 43 |
* Facet form generator
|
| 44 |
*/
|
| 45 |
Drupal.exhibit = function() {
|
| 46 |
|
| 47 |
var facets = {
|
| 48 |
list: {
|
| 49 |
title:'List',
|
| 50 |
exhibitClass: 'List',
|
| 51 |
types: ['text','number','date','boolean','url','item'],
|
| 52 |
options: {
|
| 53 |
height: {
|
| 54 |
title: 'Height',
|
| 55 |
help: "Height of the facet's body, e.g., \"20em\", \"200px\""
|
| 56 |
},
|
| 57 |
sortMode: {
|
| 58 |
title: 'Sort Mode',
|
| 59 |
help: "How to sort the choices in the facet",
|
| 60 |
choices: ['value', 'count']
|
| 61 |
},
|
| 62 |
sortDirection: {
|
| 63 |
title: 'Sort Direction',
|
| 64 |
help: "Whether to reverse the sort direction",
|
| 65 |
choices: ['forward', 'reverse']
|
| 66 |
},
|
| 67 |
showMissing: {
|
| 68 |
title: 'Show Missiong',
|
| 69 |
help: "Whether to provide a selection for items missing the facet -- this will suppress the '(missing this field)' text",
|
| 70 |
choices: ['true', 'false']
|
| 71 |
},
|
| 72 |
selection: {
|
| 73 |
title: 'Selection',
|
| 74 |
help: "Semicolon-separated list of default selections"
|
| 75 |
},
|
| 76 |
fixedOrder: {
|
| 77 |
title: 'Fixed Order',
|
| 78 |
help: "Semicolon-separated list of values specifying a fixed order for sorting the choices in the facet, e.g., \"Mo;Tu;We;Th;Fr\" for weekdays"
|
| 79 |
},
|
| 80 |
scroll: {
|
| 81 |
title: 'Scroll',
|
| 82 |
help: "If true, facet values are in a scrollable window of fixed size. If false, all facet values are shown in as much space as needed, without a scroll bar.",
|
| 83 |
choices: ['true', 'false']
|
| 84 |
},
|
| 85 |
colorCoder: {
|
| 86 |
title: 'Color Coder',
|
| 87 |
help: "Whcih color coder to use"
|
| 88 |
},
|
| 89 |
collapsible: {
|
| 90 |
title: 'Collapsible',
|
| 91 |
help: "Whether the facet is collapsible or not.",
|
| 92 |
choices: ['false', 'true'],
|
| 93 |
dependency: 'collapsed'
|
| 94 |
},
|
| 95 |
collapsed: {
|
| 96 |
title: 'Collapsed',
|
| 97 |
help: "Whether the facet is defaulted to a collapsed state.",
|
| 98 |
choices: ['false', 'true']
|
| 99 |
}
|
| 100 |
}
|
| 101 |
},
|
| 102 |
cloud: {
|
| 103 |
title: 'Cloud',
|
| 104 |
exhibitClass: 'Cloud',
|
| 105 |
types: ['text','number','date','boolean','url','item'],
|
| 106 |
options: {
|
| 107 |
selectMissing: {
|
| 108 |
title: 'Select Missiong',
|
| 109 |
help: "Whether to provide a selection for items missing the facet -- this will suppress the '(missing this field)' text",
|
| 110 |
choices: ['true', 'false']
|
| 111 |
},
|
| 112 |
selection: {
|
| 113 |
title: 'Selection',
|
| 114 |
help: "Semicolon-separated list of default selections"
|
| 115 |
}
|
| 116 |
}
|
| 117 |
},
|
| 118 |
datePicker: {
|
| 119 |
title: 'Date Picker',
|
| 120 |
exhibitClass: 'DatePicker',
|
| 121 |
types: ['date'],
|
| 122 |
options: {
|
| 123 |
timerLimit: {
|
| 124 |
title: 'Timer Limit',
|
| 125 |
help: "If set, this is the number of miliseconds that will pass between the first date selection and the auto selection of the second date. Timer limit will not apply if selection dragging is enabled."
|
| 126 |
},
|
| 127 |
dragSelection: {
|
| 128 |
title: 'Enable Selection Dragging',
|
| 129 |
help: "If true, users will select a date range by clicking and dragging on the dates they want to pick.",
|
| 130 |
choices: ['false', 'true']
|
| 131 |
}
|
| 132 |
}
|
| 133 |
},
|
| 134 |
hierarchical: {
|
| 135 |
title: 'Hierarchical',
|
| 136 |
exhibitClass: 'Hierarchical',
|
| 137 |
types: ['text','number','date','boolean','url','item'],
|
| 138 |
options: {}
|
| 139 |
},
|
| 140 |
numericRange: {
|
| 141 |
title: 'Numeric Range',
|
| 142 |
exhibitClass: 'NumericRange',
|
| 143 |
types: ['number'],
|
| 144 |
options: {
|
| 145 |
height: {
|
| 146 |
title: 'Height',
|
| 147 |
help: "Height of the facet's body, e.g., \"20em\", \"200px\""
|
| 148 |
},
|
| 149 |
collapsible: {
|
| 150 |
title: 'Collapsible',
|
| 151 |
help: "Whether the facet is collapsible or not.",
|
| 152 |
choices: ['false', 'true'],
|
| 153 |
dependency: 'collapsed'
|
| 154 |
},
|
| 155 |
collapsed: {
|
| 156 |
title: 'Collapsed',
|
| 157 |
help: "Whether the facet is defaulted to a collapsed state.",
|
| 158 |
choices: ['false', 'true']
|
| 159 |
}
|
| 160 |
}
|
| 161 |
},
|
| 162 |
slider: {
|
| 163 |
title: 'Slider',
|
| 164 |
exhibitClass: 'Slider',
|
| 165 |
types: ['number'],
|
| 166 |
options: {
|
| 167 |
scroll: {
|
| 168 |
title: 'Scroll',
|
| 169 |
help: "If true, facet values are in a scrollable window of fixed size. If false, all facet values are shown in as much space as needed, without a scroll bar.",
|
| 170 |
choices: ['true', 'false']
|
| 171 |
},
|
| 172 |
height: {
|
| 173 |
title: 'Height',
|
| 174 |
help: "Height of the facet's body, e.g., \"20em\", \"200px\""
|
| 175 |
},
|
| 176 |
precision: {
|
| 177 |
title: 'Precision',
|
| 178 |
help: "Precision of the slider expressed as a whole or floating point number"
|
| 179 |
},
|
| 180 |
historgram: {
|
| 181 |
title: 'Histogram',
|
| 182 |
help: "Whether or not to show the histogram",
|
| 183 |
choices: ['true', 'false']
|
| 184 |
}
|
| 185 |
}
|
| 186 |
},
|
| 187 |
textSearch: {
|
| 188 |
title: 'Text Search',
|
| 189 |
exhibitClass: 'TextSearch',
|
| 190 |
types: ['text','number','date','boolean','url','item'],
|
| 191 |
options: {
|
| 192 |
queryParamName: {
|
| 193 |
title: 'Query Param Name',
|
| 194 |
help: "Which query param from the URL to auto filter by. E.g. http://example.com?srch=something would automatically set the text search filter to 'something' and filter the results when the page is loaded."
|
| 195 |
},
|
| 196 |
requiresEnter: {
|
| 197 |
title: 'Requires Enter',
|
| 198 |
help: "Whether the facet requires the user to hit the 'enter' key before filtering.",
|
| 199 |
choices: ['false', 'true']
|
| 200 |
}
|
| 201 |
}
|
| 202 |
}
|
| 203 |
};
|
| 204 |
|
| 205 |
var feeds = {};
|
| 206 |
|
| 207 |
var fieldWrapper = function(label, input, fieldId, helpText){
|
| 208 |
return ['<div class="form-item">',
|
| 209 |
'<label for="', fieldId, '">', label, '</label>',
|
| 210 |
input,
|
| 211 |
(helpText === undefined ? '' : '<div class="description">' + helpText + '</div>'),
|
| 212 |
'</div>'].join('');
|
| 213 |
};
|
| 214 |
|
| 215 |
// Build list of facet type options
|
| 216 |
var facetTypeOptions = function() {
|
| 217 |
var options = [],
|
| 218 |
selFieldName = $('#edit-exhibit-facet-generator-form-wrapper-field-name').val(),
|
| 219 |
selField;
|
| 220 |
|
| 221 |
// If a field name is selected, filter the facets by type
|
| 222 |
if ($('#edit-exhibit-facet-generator-form-wrapper-field-name') && selFieldName) {
|
| 223 |
selField = getField(selFieldName);
|
| 224 |
for (facet in facets) {
|
| 225 |
if ($.inArray(selField.valueType, facets[facet].types) >= 0) {
|
| 226 |
options.push('<option value="' + facet + '">' + facets[facet].title + '</option>');
|
| 227 |
}
|
| 228 |
}
|
| 229 |
}
|
| 230 |
else { // No field selected, return them all. Used in initialization
|
| 231 |
for (facet in facets) {
|
| 232 |
options.push('<option value="' + facet + '">' + facets[facet].title + '</option>');
|
| 233 |
}
|
| 234 |
}
|
| 235 |
return options.join('');
|
| 236 |
};
|
| 237 |
|
| 238 |
// Build array of unique fields based on selected feeds
|
| 239 |
var getUniqueFields = function() {
|
| 240 |
var fields = [];
|
| 241 |
|
| 242 |
// Gather selected feed ids
|
| 243 |
selectedIds = $.map($('input.exhibit-feed-checkbox:checked'), function(item) {
|
| 244 |
var parts = item.id.split('-');
|
| 245 |
return parts[parts.length-1];
|
| 246 |
});
|
| 247 |
|
| 248 |
|
| 249 |
// Build list of unique field names from the selected feeds
|
| 250 |
$.each(selectedIds, function(selIdx, feed_id){
|
| 251 |
$.each(feeds[feed_id].fields, function(feedsIdx, field){
|
| 252 |
if($.inArray(field.name, fields) < 0) {
|
| 253 |
fields.push(field.name);
|
| 254 |
}
|
| 255 |
});
|
| 256 |
});
|
| 257 |
|
| 258 |
return fields;
|
| 259 |
};
|
| 260 |
|
| 261 |
var getField = function(fieldName) {
|
| 262 |
var selField;
|
| 263 |
|
| 264 |
$.each(feeds, function(feedIdx, feed){
|
| 265 |
$.each(feed.fields, function(fieldIdx, field){
|
| 266 |
if (field.name === fieldName) {
|
| 267 |
selField = field;
|
| 268 |
}
|
| 269 |
});
|
| 270 |
});
|
| 271 |
|
| 272 |
return selField;
|
| 273 |
};
|
| 274 |
|
| 275 |
return {
|
| 276 |
|
| 277 |
// Build the default facet generation form
|
| 278 |
buildForm: function() {
|
| 279 |
$('div#facet-generator-form').html([fieldWrapper('Select Field: <span class="form-required" title="This field is required.">*</span>',
|
| 280 |
'<select name="exhibit[facet-generator-form-wrapper][field-name]" class="form-select required" id="edit-exhibit-facet-generator-form-wrapper-field-name" ></select>',
|
| 281 |
'edit-exhibit-facet-generator-form-wrapper-field-name'),
|
| 282 |
fieldWrapper('Label: ',
|
| 283 |
'<input type="text" maxlength="128" name="exhibit[facet-generator-form-wrapper][facet-label]" id="edit-exhibit-facet-generator-form-wrapper-facet-label" size="60" value="" class="form-text" />',
|
| 284 |
'edit-exhibit-facet-generator-form-wrapper-facet-label'),
|
| 285 |
fieldWrapper('Facet Type: <span class="form-required" title="This field is required.">*</span>',
|
| 286 |
['<select name="exhibit[facet-generator-form-wrapper][facet-type]" class="form-select" id="edit-exhibit-facet-generator-form-wrapper-facet-type" >',
|
| 287 |
'<option></option>', facetTypeOptions() ,'</select>'].join(''),
|
| 288 |
'edit-exhibit-facet-generator-form-wrapper-facet-type'),
|
| 289 |
'<div id="facet-options"></div>',
|
| 290 |
'<input type="submit" name="insertFacet" id="edit-insert-facet" value="Generate Facet HTML" class="form-submit" />'].join('\n'));
|
| 291 |
},
|
| 292 |
|
| 293 |
// Build a facets options form
|
| 294 |
buildFacetOptionsForm: function(facet) {
|
| 295 |
var selFacet = facets[facet],
|
| 296 |
formHtml = [];
|
| 297 |
|
| 298 |
if (!facet || !selFacet) {
|
| 299 |
return '';
|
| 300 |
}
|
| 301 |
|
| 302 |
for (option in selFacet.options) {
|
| 303 |
// select field
|
| 304 |
if (selFacet.options[option].choices &&
|
| 305 |
selFacet.options[option].choices.length) {
|
| 306 |
formHtml.push(fieldWrapper((selFacet.options[option].title ? selFacet.options[option].title : option) + ': ',
|
| 307 |
['<select name="exhibit[facet-generator-form-wrapper][', facet, '][', option, ']" ',
|
| 308 |
'class="form-select" id="edit-exhibit-facet-generator-form-wrapper-', facet, '-', option, '" >',
|
| 309 |
$.map(selFacet.options[option].choices, function(choice){
|
| 310 |
return '<option value="' + choice + '">' + choice + '</option>';
|
| 311 |
}).join(''),
|
| 312 |
'</select>'].join(''),
|
| 313 |
'edit-exhibit-facet-generator-form-wrapper-' + facet + '-' + option,
|
| 314 |
selFacet.options[option].help));
|
| 315 |
}
|
| 316 |
else { // text field
|
| 317 |
formHtml.push(fieldWrapper((selFacet.options[option].title ? selFacet.options[option].title : option) + ': ',
|
| 318 |
'<input type="text" maxlength="128" name="exhibit[facet-generator-form-wrapper][' + facet + '][' + option + ']" id="edit-exhibit-facet-generator-form-wrapper-' + facet + '-' + option + '" size="60" value="" class="form-text" />',
|
| 319 |
'edit-exhibit-facet-generator-form-wrapper-' + facet + '-' + option,
|
| 320 |
selFacet.options[option].help));
|
| 321 |
}
|
| 322 |
}
|
| 323 |
|
| 324 |
return formHtml.join('');
|
| 325 |
|
| 326 |
},
|
| 327 |
|
| 328 |
// Load all feeds
|
| 329 |
loadFeeds: function(callback) {
|
| 330 |
for (var feed_id in Drupal.settings.exhibit) {
|
| 331 |
feeds[feed_id] = {loaded: false, url: Drupal.settings.exhibit[feed_id], fields: []};
|
| 332 |
}
|
| 333 |
|
| 334 |
for (feed_id in feeds){
|
| 335 |
this.loadFeed(feeds[feed_id], callback);
|
| 336 |
}
|
| 337 |
},
|
| 338 |
|
| 339 |
// Load an individual feed
|
| 340 |
loadFeed: function(feed, callback) {
|
| 341 |
var fieldType,
|
| 342 |
that = this;
|
| 343 |
|
| 344 |
$.ajax({
|
| 345 |
type: "GET",
|
| 346 |
url: '/' + feed.url,
|
| 347 |
dataType: "json",
|
| 348 |
success: function(data) {
|
| 349 |
if (data.items && data.items[0]) { // Make sure the feed contains items
|
| 350 |
$.each(data.items, function(item){ // Loop through each item
|
| 351 |
$.each(data.items[item], function(i) { // Loop through each field in the item
|
| 352 |
if ($.inArray(i, $.map(feed.fields, function(f){ return f.name;})) < 0) { // Make sure the field doesn't already exist
|
| 353 |
if (data.properties &&
|
| 354 |
data.properties[i] &&
|
| 355 |
data.properties[i]['valueType']) { // Check if item has a defined value type
|
| 356 |
fieldType = data.properties[i]['valueType']; // Use specified value type
|
| 357 |
}
|
| 358 |
else {
|
| 359 |
fieldType = 'item'; // Use default 'item' value type
|
| 360 |
}
|
| 361 |
feed.fields.push({name: i, valueType: fieldType}); // Add the field to the fields array
|
| 362 |
}
|
| 363 |
});
|
| 364 |
});
|
| 365 |
}
|
| 366 |
},
|
| 367 |
complete: function() {
|
| 368 |
feed.loaded = true;
|
| 369 |
|
| 370 |
if (typeof callback === 'function' &&
|
| 371 |
that.allFeedsLoaded()) {
|
| 372 |
callback();
|
| 373 |
}
|
| 374 |
}
|
| 375 |
});
|
| 376 |
|
| 377 |
},
|
| 378 |
|
| 379 |
// Check if all feeds have been loaded
|
| 380 |
allFeedsLoaded: function() {
|
| 381 |
var loaded = true;
|
| 382 |
$.each(feeds, function(feed_id){
|
| 383 |
if (!feeds[feed_id].loaded) {
|
| 384 |
loaded = false;
|
| 385 |
}
|
| 386 |
});
|
| 387 |
return loaded;
|
| 388 |
},
|
| 389 |
|
| 390 |
// Handle feed selection
|
| 391 |
selectFeed: function(element) {
|
| 392 |
var selectedIds = [],
|
| 393 |
options,
|
| 394 |
optionsHtml = ['<option></option>'];
|
| 395 |
|
| 396 |
// Hide facet generator form if no checkboxes are selected
|
| 397 |
if (!$('input.exhibit-feed-checkbox:checked').size()){
|
| 398 |
$('#exhibit-facet-builder').hide();
|
| 399 |
return;
|
| 400 |
}
|
| 401 |
|
| 402 |
// Get fields
|
| 403 |
options = getUniqueFields();
|
| 404 |
|
| 405 |
// Show the facet generator form if we have fields
|
| 406 |
if (options.length > 0){
|
| 407 |
|
| 408 |
// Create the options list for each field and
|
| 409 |
// update the field select box
|
| 410 |
$.each(options, function(i, option){
|
| 411 |
optionsHtml.push('<option value="' + option + '">' + option + '</option>');
|
| 412 |
});
|
| 413 |
$('#edit-exhibit-facet-generator-form-wrapper-field-name').html(optionsHtml.join(''));
|
| 414 |
|
| 415 |
|
| 416 |
$('#exhibit-facet-builder').show();
|
| 417 |
}
|
| 418 |
else { // No fields for selected feeds, hide the form
|
| 419 |
$('#exhibit-facet-builder').hide();
|
| 420 |
}
|
| 421 |
},
|
| 422 |
|
| 423 |
// Handles the facet type selection.
|
| 424 |
// Displays the facet's options form
|
| 425 |
facetTypeChange: function() {
|
| 426 |
$('#facet-options').html(this.buildFacetOptionsForm($('#edit-exhibit-facet-generator-form-wrapper-facet-type').val()));
|
| 427 |
},
|
| 428 |
|
| 429 |
buildFacet: function() {
|
| 430 |
if(!$('#edit-exhibit-facet-generator-form-wrapper-facet-type').val() ||
|
| 431 |
!$('#edit-exhibit-facet-generator-form-wrapper-field-name').val()) {
|
| 432 |
return '';
|
| 433 |
}
|
| 434 |
|
| 435 |
var facetType = $('#edit-exhibit-facet-generator-form-wrapper-facet-type').val(),
|
| 436 |
facet = facets[facetType],
|
| 437 |
facetOptionValue;
|
| 438 |
|
| 439 |
if (!facet) {
|
| 440 |
return '';
|
| 441 |
}
|
| 442 |
|
| 443 |
var facetHtml = ['<div class="facet" ex:role="facet"',
|
| 444 |
' ex:expression=".', $('#edit-exhibit-facet-generator-form-wrapper-field-name').val(), '"'];
|
| 445 |
|
| 446 |
if (facetType !== 'list'){
|
| 447 |
facetHtml.push(' ex:facetClass="' + facet.exhibitClass + '"');
|
| 448 |
}
|
| 449 |
|
| 450 |
if ($('#edit-exhibit-facet-generator-form-wrapper-facet-label').val()){
|
| 451 |
facetHtml.push(' ex:facetLabel="' + $('#edit-exhibit-facet-generator-form-wrapper-facet-label').val() + '"');
|
| 452 |
}
|
| 453 |
|
| 454 |
for (option in facet.options) {
|
| 455 |
facetOptionValue = $('#edit-exhibit-facet-generator-form-wrapper-' + facetType + '-' + option).val();
|
| 456 |
|
| 457 |
if (facetOptionValue) {
|
| 458 |
if (facet.options[option].choices &&
|
| 459 |
facet.options[option].choices.length &&
|
| 460 |
facet.options[option].choices.length > 0) {
|
| 461 |
if (facetOptionValue !== facet.options[option].choices[0]) {
|
| 462 |
facetHtml.push(' ex:' + option + '="' + facetOptionValue + '"');
|
| 463 |
}
|
| 464 |
}
|
| 465 |
else {
|
| 466 |
facetHtml.push(' ex:' + option + '="' + facetOptionValue + '"');
|
| 467 |
}
|
| 468 |
}
|
| 469 |
}
|
| 470 |
|
| 471 |
facetHtml.push('></div>');
|
| 472 |
return facetHtml.join('');
|
| 473 |
},
|
| 474 |
|
| 475 |
// Inserts the HTML for a facet based on the given options
|
| 476 |
insertFacet: function() {
|
| 477 |
var currentVal = '',
|
| 478 |
val = [];
|
| 479 |
currentVal = $('#edit-exhibit-facet-definition').val();
|
| 480 |
if (currentVal != '') {
|
| 481 |
val.push($.trim(currentVal));
|
| 482 |
}
|
| 483 |
val.push(this.buildFacet());
|
| 484 |
$('#edit-exhibit-facet-definition').val(val.join('\n'));
|
| 485 |
},
|
| 486 |
|
| 487 |
filterFacetTypeByField: function() {
|
| 488 |
$('#edit-exhibit-facet-generator-form-wrapper-facet-type').html('<option></option>' + facetTypeOptions());
|
| 489 |
return false;
|
| 490 |
}
|
| 491 |
|
| 492 |
};
|
| 493 |
|
| 494 |
}();
|