72920506 by Adam Heath

Split files.

1 parent bbb7f7fb
{
"directory": "src/lib/bower"
}
......@@ -11,7 +11,7 @@ module.exports = function(grunt) {
browserOptions: {
},
model: [
'src/scripts/solr-search/model/**/*.js',
'src/scripts/solr/model/**/*.js',
],
};
/*
......
......@@ -3,1133 +3,588 @@ define(function(require) {
var _ = require('underscore');
var Backbone = require('backbone');
var NestedModels = require('backbone-nested-models');
//var module = require('module');
function getField(obj, key) {
return obj[key];
}
function mergeStaticProps(startPtr, endPtr, obj, fieldName) {
var result = obj;
var ptr = startPtr;
while (true) {
result = _.extend(result, _.result(ptr, fieldName));
if (ptr === endPtr) {
break;
}
ptr = ptr.__super__.constructor;
}
return result;
}
function mergeStaticSets(startPtr, endPtr, obj, fieldName) {
function arrayToMap(array) {
var result = {};
_.each(array, function(value) {
result[value] = true;
});
return result;
}
var set = arrayToMap(obj);
var ptr = startPtr;
while (true) {
set = _.extend(set, arrayToMap(_.result(ptr, fieldName)));
if (ptr === endPtr) {
break;
}
ptr = ptr.__super__.constructor;
}
return _.keys(set);
}
function getItemKeyAccessor(item) {
return item.get('key');
}
var SolrFacets = (function() {
var Facets = NestedModels.mixin(Backbone.Model.extend({
initialize: function(data, options) {
this.url = function() {
return options.search.url();
};
_.each(this.keys(), _.bind(function(facetName) {
var facet = this.get(facetName);
_.each({
'item-change': 'item-change',
'change:query': 'child-query',
'change:queryMin': 'item-change',
'change:queryMax': 'item-change',
}, function(eventValue, eventKey) {
facet.on(eventKey, function(model, value, options) {
this.trigger(eventValue, facet, null, options);
}, this);
var Facets = NestedModels.mixin(Backbone.Model.extend({
initialize: function(data, options) {
this.url = function() {
return options.search.url();
};
_.each(this.keys(), _.bind(function(facetName) {
var facet = this.get(facetName);
_.each({
'item-change': 'item-change',
'change:query': 'child-query',
'change:queryMin': 'item-change',
'change:queryMax': 'item-change',
}, function(eventValue, eventKey) {
facet.on(eventKey, function(model, value, options) {
this.trigger(eventValue, facet, null, options);
}, this);
}, this));
}, this);
}, this));
this._doSuggestions = _.debounce(_.bind(function(childFacet) {
if (childFacet.get('query')) {
this.fetch({
data: this.toJSON({childFacet: childFacet, facetSuggestions: true}),
childFacet: childFacet,
facetSuggestions: true,
merge: true,
traditional: true,
});
} else {
childFacet.set('suggestions', []);
}
}, this), 250);
this.on('child-query', this._doSuggestions, this);
this._doSuggestions = _.debounce(_.bind(function(childFacet) {
if (childFacet.get('query')) {
this.fetch({
data: this.toJSON({childFacet: childFacet, facetSuggestions: true}),
childFacet: childFacet,
facetSuggestions: true,
merge: true,
traditional: true,
});
} else {
childFacet.set('suggestions', []);
}
}, this), 250);
this.on('child-query', this._doSuggestions, this);
return Facets.__super__.initialize.apply(this, arguments);
},
resetSearch: function(options) {
_.each(this.values(), function(facet) {
facet.get('items').reset(null, options);
});
},
applyFacetResults: function(data, options) {
options = options || {};
var facetCounts = getField(data, 'facet_counts');
var facetIntervals = getField(facetCounts, 'facet_intervals');
var facetRanges = getField(facetCounts, 'facet_ranges');
var facetFields = getField(facetCounts, 'facet_fields');
var facetQueries = getField(facetCounts, 'facet_queries');
var statsFields = getField(data.stats, 'stats_fields');
function getFacetList(facetName, type) {
switch (type) {
case 'year':
case 'range':
return facetRanges[facetName] ? facetRanges[facetName].counts : null;
case 'interval':
return facetIntervals[facetName] ? facetIntervals[facetName].counts : null;
case 'year-field':
case 'field':
return facetFields[facetName];
}
return Facets.__super__.initialize.apply(this, arguments);
},
resetSearch: function(options) {
_.each(this.values(), function(facet) {
facet.get('items').reset(null, options);
});
},
applyFacetResults: function(data, options) {
options = options || {};
var facetCounts = getField(data, 'facet_counts');
var facetIntervals = getField(facetCounts, 'facet_intervals');
var facetRanges = getField(facetCounts, 'facet_ranges');
var facetFields = getField(facetCounts, 'facet_fields');
var facetQueries = getField(facetCounts, 'facet_queries');
var statsFields = getField(data.stats, 'stats_fields');
function getFacetList(facetName, type) {
switch (type) {
case 'year':
case 'range':
return facetRanges[facetName] ? facetRanges[facetName].counts : null;
case 'interval':
return facetIntervals[facetName] ? facetIntervals[facetName].counts : null;
case 'year-field':
case 'field':
return facetFields[facetName];
}
_.each(this.keys(), _.bind(function(facetName) {
var facet = this.get(facetName);
var type = facet.facetType;
}
_.each(this.keys(), _.bind(function(facetName) {
var facet = this.get(facetName);
var type = facet.facetType;
var suggestions = [];
_.each(getFacetList('suggestions:' + facetName, type), function(value, index) {
if (index % 2 === 0) {
key = value;
} else if (value > 0) {
suggestions.push({key: key, value: value});
}
});
facet.set('suggestions', suggestions);
if (!!options.facetSuggestions && options.childFacet === facet) {
return;
var suggestions = [];
_.each(getFacetList('suggestions:' + facetName, type), function(value, index) {
if (index % 2 === 0) {
key = value;
} else if (value > 0) {
suggestions.push({key: key, value: value});
}
});
facet.set('suggestions', suggestions);
if (!!options.facetSuggestions && options.childFacet === facet) {
return;
}
var key;
var list = getFacetList(facetName, type);
var newItems = [];
var items = facet.get('items');
items.invoke('set', 'hidden', true);
var valueOverrides = {};
var excludeValues = {};
function recordIncludeValueIntoExclude(includeValue, key) {
excludeValues[includeValue] = true;
}
switch (type) {
case 'year-field':
case 'field':
_.each(facet.bins, function(includeValues, key) {
var tag = facetName + ':' + key;
valueOverrides[key] = facetQueries[tag];
_.each(includeValues, recordIncludeValueIntoExclude);
});
break;
}
var addNewItem = _.bind(function addNewItem(key, value) {
if (valueOverrides[key] !== undefined) {
value = valueOverrides[key];
if (!value) {
return;
}
} else if (excludeValues[key]) {
var key;
var list = getFacetList(facetName, type);
var newItems = [];
var items = facet.get('items');
items.invoke('set', 'hidden', true);
var valueOverrides = {};
var excludeValues = {};
function recordIncludeValueIntoExclude(includeValue, key) {
excludeValues[includeValue] = true;
}
switch (type) {
case 'year-field':
case 'field':
_.each(facet.bins, function(includeValues, key) {
var tag = facetName + ':' + key;
valueOverrides[key] = facetQueries[tag];
_.each(includeValues, recordIncludeValueIntoExclude);
});
break;
}
var addNewItem = _.bind(function addNewItem(key, value) {
if (valueOverrides[key] !== undefined) {
value = valueOverrides[key];
if (!value) {
return;
}
var item = items.get({id: key});
if (item) {
item.set({hidden: value === 0, value: value});
} else {
item = new Item({key: key, value: value});
item.on('change:checked', function() {
this.trigger('item-change');
facet.trigger('item-change');
}, this);
}
newItems.push(item);
}, this);
function checkOther(set, key) {
if (set.indexOf(facet.other) !== -1) {
addNewItem(key, facetRanges[facetName][key]);
}
}
checkOther(['all', 'before'], 'before');
_.each(list, function(value, index) {
if (index % 2 === 0) {
key = value;
} else if (value > 0) {
addNewItem(key, value);
}
});
switch (type) {
case 'year-field':
case 'field':
_.each(facet.bins, function(includeValues, key) {
var tag = facetName + ':' + key;
addNewItem(key, facetQueries[tag]);
});
break;
}
items.set(newItems, {remove: false});
if (facet.facetStats) {
var thisFacetStats = statsFields[facetName];
facet.set({minValue: thisFacetStats.min, maxValue: thisFacetStats.max});
}
}, this));
},
getFacetFormData: function(options) {
options = options || {};
var result = {
facet: true,
stats: true,
'facet.missing': true,
'facet.field': [],
'facet.range': [],
'facet.interval': [],
'facet.query': [],
'stats.field': [],
fq: [],
};
_.each(this.keys(), _.bind(function(facetName) {
var facet = this.get(facetName);
var queryField = facet.queryField;
var facetField = facet.facetField ? facet.facetField : queryField;
var type = facet.facetType;
var valueFormatter;
var facetOptions = {};
var quoteFormatter = function(value) {
return value.replace ? ('"' + value.replace(/"/, '\\"') + '"') : value;
};
var rangeFormatter = function(from, to) {
return '[' + quoteFormatter(from) + ' TO ' + quoteFormatter(to) + ']';
};
switch (type) {
case 'year':
type = 'range';
quoteFormatter = function(value) {
return value.toISOString();
};
valueFormatter = function(item) {
var key = item.get('key');
var fromDate, toDate;
if (key === 'before') {
return rangeFormatter('*', facet.rangeStart + '-1SECOND');
}
fromDate = new Date(key);
toDate = new Date(key);
toDate.setUTCFullYear(toDate.getUTCFullYear() + 1);
return rangeFormatter(fromDate, toDate);
};
if (facet.other) {
facetOptions['facet.range.other'] = facet.other;
}
break;
case 'range':
case 'interval':
valueFormatter = function(item) {
var key = parseInt(item.get('key'));
return rangeFormatter(key, key + facet.rangeGap);
};
break;
case 'year-field':
type = 'field';
quoteFormatter = function(value) {
return new Date(value).toISOString();
};
valueFormatter = facet.queryValue ? facet.queryValue : function(value) {
return quoteFormatter(getItemKeyAccessor(value));
};
_.each(facet.bins, function(includeValues, key) {
var query = _.map(includeValues, function(includeValue, index) {
return queryField + ':\'' + includeValue + '\'';
}).join(' OR ');
result['facet.query'].push('{!key=' + facetName + ':' + key + ' tag=' + facetName + ':' + key + '}(' + query + ')');
});
break;
case 'field':
valueFormatter = facet.queryValue ? facet.queryValue : function(value) {
return quoteFormatter(getItemKeyAccessor(value));
};
_.each(facet.bins, function(includeValues, key) {
var query = _.map(includeValues, function(includeValue, index) {
return queryField + ':' + includeValue;
}).join(' OR ');
result['facet.query'].push('{!key=' + facetName + ':' + key + ' tag=' + facetName + ':' + key + '}(' + query + ')');
});
break;
}
switch (type) {
case 'range':
facetOptions['facet.range.start'] = facet.rangeStart;
facetOptions['facet.range.end'] = facet.rangeEnd;
facetOptions['facet.range.gap'] = facet.rangeGap;
break;
case 'interval':
facetOptions['facet.interval.set'] = '[*,*]';
break;
}
var facetValues = [];
var queryMax = facet.get('queryMax');
var queryMin = facet.get('queryMin');
if (queryMax !== undefined && queryMin !== undefined) {
facetValues.push(rangeFormatter(queryMin, queryMax));
} else if (excludeValues[key]) {
return;
}
facet.get('items').each(function(item, index) {
if (!item.get('hidden') && item.get('checked')) {
facetValues.push(valueFormatter(item));
}
});
facetOptions.key = facetName;
if (facetValues.length) {
facetOptions.ex = facetName;
result.fq.push('{!tag=' + facetName + '}' + facetField + ':(' + facetValues.join(' OR ') + ')');
var item = items.get({id: key});
if (item) {
item.set({hidden: value === 0, value: value});
} else {
facetOptions.tag = facetName;
}
if (!!options.facetSuggestions) {
var childFacet = options.childFacet;
if (childFacet === facet) {
facetOptions['facet.contains'] = facet.get('query');
facetOptions['facet.contains.ignoreCase'] = true;
facetOptions['facet.mincount'] = 1;
}
}
var facetOptionList = [];
_.each(facetOptions, function(value, key) {
if (value !== undefined) {
facetOptionList.push(key + '=' + value);
}
});
result['facet.' + type].push('{!' + facetOptionList.join(' ') + '}' + queryField);
if (facet.facetStats) {
result['stats.field'].push('{!' + facetOptionList.join(' ') + '}' + queryField);
}
var facetQuery = facet.get('query');
if (facetQuery !== null && facetQuery !== '') {
facetOptions.key = 'suggestions:' + facetName;
facetOptionList = [];
_.each(facetOptions, function(value, key) {
if (value !== undefined) {
facetOptionList.push(key + '=' + value);
}
});
result['facet.' + type].push('{!' + facetOptionList.join(' ') + '}' + queryField);
item = new Item({key: key, value: value});
item.on('change:checked', function() {
this.trigger('item-change');
facet.trigger('item-change');
}, this);
}
}, this));
return result;
},
newItems.push(item);
}, this);
toJSON: function toJSON(options) {
if (!!options.facetSuggestions) {
return _.extend({
rows: 0,
facet: true,
wt: 'json',
q: '*:*',
}, this.getFacetFormData(options));
}
},
parse: function parse(data, options) {
if (!!options.facetSuggestions) {
this.applyFacetResults(data, options);
}
return null;
},
}));
var Sort = Facets.Sort = {
standard: function standardSort(a, b) {
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
},
date: function dateSort(a, b) {
return Sort.standard.call(this, a, b);
},
number: function numberSort(a, b) {
return Sort.standard.call(this, parseInt(a), parseInt(b));
},
};
function wrapComparatorForAllBeforeAfter(comparator, doBefore, doAfter) {
if (!doBefore && !doAfter) {
return comparator;
}
return function beforeAfterComparator(a, b) {
if (doBefore) {
if (a === 'before') {
return -1;
} else if (b === 'before') {
return 1;
function checkOther(set, key) {
if (set.indexOf(facet.other) !== -1) {
addNewItem(key, facetRanges[facetName][key]);
}
}
if (doAfter) {
if (a === 'after') {
return 1;
} else if (b === 'after') {
return -1;
checkOther(['all', 'before'], 'before');
_.each(list, function(value, index) {
if (index % 2 === 0) {
key = value;
} else if (value > 0) {
addNewItem(key, value);
}
});
switch (type) {
case 'year-field':
case 'field':
_.each(facet.bins, function(includeValues, key) {
var tag = facetName + ':' + key;
addNewItem(key, facetQueries[tag]);
});
break;
}
items.set(newItems, {remove: false});
if (facet.facetStats) {
var thisFacetStats = statsFields[facetName];
facet.set({minValue: thisFacetStats.min, maxValue: thisFacetStats.max});
}
return comparator.call(this, a, b);
}, this));
},
getFacetFormData: function(options) {
options = options || {};
var result = {
facet: true,
stats: true,
'facet.missing': true,
'facet.field': [],
'facet.range': [],
'facet.interval': [],
'facet.query': [],
'stats.field': [],
fq: [],
};
}
var Facet = Facets.Facet = Backbone.Model.extend({
defaults: function defaults() {
return {
formName: null,
query: null,
suggestions: [],
_.each(this.keys(), _.bind(function(facetName) {
var facet = this.get(facetName);
var queryField = facet.queryField;
var facetField = facet.facetField ? facet.facetField : queryField;
var type = facet.facetType;
var valueFormatter;
var facetOptions = {};
var quoteFormatter = function(value) {
return value.replace ? ('"' + value.replace(/"/, '\\"') + '"') : value;
};
},
initialize: function(data, options) {
this.set('all', true);
this.on('change:queryMax change:queryMin', function() {
this.set('hasQuery', this.get('queryMin') !== undefined && this.get('queryMax') !== undefined);
}, this);
(function(self) {
var skipCallback;
self.on('item-change change:queryMax change:queryMin', function() {
switch (skipCallback) {
case 'change:checkedKeys':
case 'change:all':
return;
}
var checkedKeys = [];
this.get('items').each(function(facetItem) {
if (facetItem.get('checked')) {
checkedKeys.push(facetItem.get('key'));
var rangeFormatter = function(from, to) {
return '[' + quoteFormatter(from) + ' TO ' + quoteFormatter(to) + ']';
};
switch (type) {
case 'year':
type = 'range';
quoteFormatter = function(value) {
return value.toISOString();
};
valueFormatter = function(item) {
var key = item.get('key');
var fromDate, toDate;
if (key === 'before') {
return rangeFormatter('*', facet.rangeStart + '-1SECOND');
}
});
var checkedCount = checkedKeys.length;
if (this.get('queryMin') !== undefined && this.get('queryMax') !== undefined) {
checkedCount++;
}
skipCallback = 'item-change';
try {
this.set({
all: checkedCount === 0,
checkedKeys: checkedKeys,
});
} finally {
skipCallback = null;
}
}, self);
self.on('change:all', function() {
switch (skipCallback) {
case 'change:checkedKeys':
case 'item-change':
return;
}
skipCallback = 'change:all';
try {
this.get('items').invoke('set', {checked: false});
this.set({
checkedKeys: [],
queryMax: undefined,
queryMin: undefined,
});
} finally {
skipCallback = null;
}
}, self);
self.on('change:checkedKeys', function() {
switch (skipCallback) {
case 'item-change':
case 'change:all':
return;
}
var checkedKeys = {};
_.each(this.get('checkedKeys'), function(value, i) {
checkedKeys[value] = true;
});
skipCallback = 'change:checkedKeys';
var checkedCount = 0;
if (this.get('queryMin') !== undefined && this.get('queryMax') !== undefined) {
checkedCount++;
}
try {
this.get('items').each(function(facetItem) {
var newChecked = checkedKeys[facetItem.get('key')];
var currentChecked = facetItem.get('checked');
if (newChecked !== currentChecked) {
facetItem.set('checked', newChecked);
}
if (facetItem.get('checked')) {
checkedCount++;
}
});
this.set({
all: checkedCount === 0,
});
} finally {
skipCallback = null;
fromDate = new Date(key);
toDate = new Date(key);
toDate.setUTCFullYear(toDate.getUTCFullYear() + 1);
return rangeFormatter(fromDate, toDate);
};
if (facet.other) {
facetOptions['facet.range.other'] = facet.other;
}
}, self);
})(this);
var sortKeyExtractor = options.sortKeyExtractor;
if (!sortKeyExtractor) {
sortKeyExtractor = getItemKeyAccessor;
}
var comparator = options.comparator;
if (!comparator) {
comparator = Sort.standard;
} else if (typeof comparator === 'string') {
comparator = Sort[comparator];
}
switch (options.facetType) {
case 'year':
break;
case 'range':
case 'interval':
comparator = wrapComparatorForAllBeforeAfter(comparator, ['all', 'before'].indexOf(options.other) !== -1, ['all', 'after'].indexOf(options.other) !== -1);
valueFormatter = function(item) {
var key = parseInt(item.get('key'));
return rangeFormatter(key, key + facet.rangeGap);
};
break;
}
var formatter = options.formatter;
if (!formatter) {
var labelMap = options.labelMap;
if (labelMap) {
formatter = function(item) {
var value = item.get('key');
var label = options.labelMap[value.toUpperCase()];
return label ? label : value;
case 'year-field':
type = 'field';
quoteFormatter = function(value) {
return new Date(value).toISOString();
};
} else {
formatter = getItemKeyAccessor;
}
}
this.formatter = formatter;
comparator = (function(comparator) {
return function facetItemValue(a, b) {
var keyA = sortKeyExtractor(a);
var keyB = sortKeyExtractor(b);
switch (this.get('orderByDirection')) {
case 'desc':
var tmp = keyA;
keyA = keyB;
keyB = tmp;
break;
}
return comparator.call(this, sortKeyExtractor(a), sortKeyExtractor(b));
};
})(comparator);
this.set('items', new ItemCollection([], {comparator: comparator}));
this.facetType = options.facetType;
this.facetStats = options.facetStats;
this.other = options.other;
this.facetField = options.facetField;
this.queryField = options.queryField;
this.queryValue = options.queryValue;
this.bins = options.bins;
switch (this.facetType) {
case 'year':
this.rangeStart = options.start;
this.rangeEnd = options.end;
this.rangeGap = '+' + (options.gap ? options.gap : 1) + 'YEAR';
valueFormatter = facet.queryValue ? facet.queryValue : function(value) {
return quoteFormatter(getItemKeyAccessor(value));
};
_.each(facet.bins, function(includeValues, key) {
var query = _.map(includeValues, function(includeValue, index) {
return queryField + ':\'' + includeValue + '\'';
}).join(' OR ');
result['facet.query'].push('{!key=' + facetName + ':' + key + ' tag=' + facetName + ':' + key + '}(' + query + ')');
});
break;
case 'field':
valueFormatter = facet.queryValue ? facet.queryValue : function(value) {
return quoteFormatter(getItemKeyAccessor(value));
};
_.each(facet.bins, function(includeValues, key) {
var query = _.map(includeValues, function(includeValue, index) {
return queryField + ':' + includeValue;
}).join(' OR ');
result['facet.query'].push('{!key=' + facetName + ':' + key + ' tag=' + facetName + ':' + key + '}(' + query + ')');
});
break;
}
switch (type) {
case 'range':
this.rangeStart = options.start;
this.rangeEnd = options.end;
this.rangeGap = options.gap;
facetOptions['facet.range.start'] = facet.rangeStart;
facetOptions['facet.range.end'] = facet.rangeEnd;
facetOptions['facet.range.gap'] = facet.rangeGap;
break;
case 'field':
case 'year-field':
case 'interval':
facetOptions['facet.interval.set'] = '[*,*]';
break;
default:
var e = new Error('Unsupported facet type: ' + this.facetType);
e.facet = this;
throw e;
}
return Facet.__super__.initialize.apply(this, arguments);
},
/*
toJSON: function toJSON(options) {
if (!!options.facetSuggestions) {
return {
rows: 0,
facet: true,
wt: 'json',
q: '*:*',
'facet.contains': this.get('query'),
'facet.contains.ignoreCase': true,
'facet.field': this.queryField,
'facet.mincount': 1,
};
var facetValues = [];
var queryMax = facet.get('queryMax');
var queryMin = facet.get('queryMin');
if (queryMax !== undefined && queryMin !== undefined) {
facetValues.push(rangeFormatter(queryMin, queryMax));
}
facet.get('items').each(function(item, index) {
if (!item.get('hidden') && item.get('checked')) {
facetValues.push(valueFormatter(item));
}
});
facetOptions.key = facetName;
if (facetValues.length) {
facetOptions.ex = facetName;
result.fq.push('{!tag=' + facetName + '}' + facetField + ':(' + facetValues.join(' OR ') + ')');
} else {
facetOptions.tag = facetName;
}
},
parse: function parse(data, options) {
if (!!options.facetSuggestions) {
var suggestions = [];
var key;
_.each(data.facet_counts.facet_fields[this.queryField], function(value, index) {
if (index % 2 === 0) {
key = value;
} else if (value > 0) {
suggestions.push({key: key, value: value});
var childFacet = options.childFacet;
if (childFacet === facet) {
facetOptions['facet.contains'] = facet.get('query');
facetOptions['facet.contains.ignoreCase'] = true;
facetOptions['facet.mincount'] = 1;
}
}
var facetOptionList = [];
_.each(facetOptions, function(value, key) {
if (value !== undefined) {
facetOptionList.push(key + '=' + value);
}
});
result['facet.' + type].push('{!' + facetOptionList.join(' ') + '}' + queryField);
if (facet.facetStats) {
result['stats.field'].push('{!' + facetOptionList.join(' ') + '}' + queryField);
}
var facetQuery = facet.get('query');
if (facetQuery !== null && facetQuery !== '') {
facetOptions.key = 'suggestions:' + facetName;
facetOptionList = [];
_.each(facetOptions, function(value, key) {
if (value !== undefined) {
facetOptionList.push(key + '=' + value);
}
});
return {
suggestions: suggestions,
};
result['facet.' + type].push('{!' + facetOptionList.join(' ') + '}' + queryField);
}
return null;
},
*/
});
var ItemCollection = Backbone.Collection.extend({
remove: function() {
}
});
var Item = Facet.Item = Backbone.Model.extend({
idAttribute: 'key',
defaults: {
checked: false,
hidden: false,
},
_initialize: function(data, options) {
this.on('add', function(model, parent, options) {
// added to a collection
this.on('change:checked', function() {
parent.trigger('item-change');
});
}, this);
return Item.__super__.initialize.apply(this, arguments);
}
});
}, this));
return result;
},
return Facets;
})();
var Pagination = (function() {
function stepFalse(e) {
e.preventDefault();
return false;
}
var Pagination = Backbone.Model.extend({
defaults: {
currentPage: 1,
hasNext: false,
hasNextJumpPage: false,
hasPrevious: false,
hasPreviousJumpPage: false,
nextJumpPage: undefined,
nextPage: undefined,
pages: [],
pageJump: 5,
pageSize: 10,
previousJumpPage: undefined,
previousPage: undefined,
totalCount: 0,
totalPages: 0,
},
initialize: function(data, options) {
var buildPages = function buildPages() {
var currentPage = parseInt(this.get('currentPage'));
var pageSize = parseInt(this.get('pageSize'));
var totalCount = parseInt(this.get('totalCount'));
if (!currentPage || !pageSize || !totalCount) {
return;
}
var pages = [];
var totalPages = Math.floor((totalCount + pageSize - 1) / pageSize);
function addPage(self, i) {
pages.push({
current: i === currentPage,
jump: function() {
self.set('currentPage', i);
return true;
},
number: i,
});
}
var startAt = currentPage - 4, endAt = currentPage + 5;
if (startAt < 1) {
endAt += (1 - startAt);
}
if (endAt > totalPages) {
startAt -= endAt - totalPages - 1;
endAt = totalPages + 1;
}
if (startAt < 1) {
startAt = 1;
}
if (endAt - startAt < 9) {
/* global console:false */
console.log('foo');
}
for (var i = startAt; i < endAt; i++) {
if (i > 0 && i <= totalPages) {
addPage(this, i);
}
}
var hasPrevious = currentPage > 1;
var hasNext = currentPage < totalPages;
var pageJump = this.get('pageJump');
var nextJumpPage, previousJumpPage, hasNextJump, hasPreviousJump;
if (pageJump) {
nextJumpPage = currentPage + pageJump;
previousJumpPage = currentPage - pageJump;
hasNextJump = nextJumpPage < totalPages;
hasPreviousJump = previousJumpPage > 0;
} else {
hasNextJump = false;
hasPreviousJump = false;
}
this.set({
hasNext: hasNext,
hasNextJump: hasNextJump,
hasPrevious: hasPrevious,
hasPreviousJump: hasPreviousJump,
nextJumpPage: hasNextJump ? nextJumpPage : undefined,
nextPage: hasNext ? currentPage + 1 : undefined,
pages: pages,
previousJumpPage: hasNextJump ? previousJumpPage : undefined,
previousPage: hasPrevious ? currentPage - 1 : undefined,
totalPages: totalPages,
});
};
this.on('change:pageSize change:currentPage change:totalCount', buildPages, this);
var installActions = _.bind(function installActions(eventName, nextName, hasNextName, previousName, hasPreviousName, pageCount) {
this.on(eventName, function() {
var hasNext = this.get(hasNextName);
var hasPrevious = this.get(hasPreviousName);
var next, previous;
if (hasNext) {
next = _.bind(function(e) {
e.preventDefault();
this.set('currentPage', this.get('currentPage') + pageCount);
return false;
}, this);
} else {
next = stepFalse;
}
if (hasPrevious) {
previous = _.bind(function(e) {
e.preventDefault();
this.set('currentPage', this.get('currentPage') - pageCount);
return false;
}, this);
} else {
previous = stepFalse;
}
this.set(nextName, next);
this.set(previousName, previous);
}, this);
this[nextName] = _.bind(function() {
return this.get(nextName)();
}, this);
this[previousName] = _.bind(function() {
return this.get(previousName)();
}, this);
}, this);
this.on('change:pageJump', function() {
var pageJump = this.get('pageJump');
installActions('change:hasNextJump change:hasPreviousJump', 'nextJump', 'hasNextJump', 'previousJump', 'hasPreviousJump', pageJump);
}, this);
installActions('change:hasNext change:hasPrevious', 'next', 'hasNext', 'previous', 'hasPrevious', 1);
buildPages.apply(this);
this.trigger('change:pageJump');
return Pagination.__super__.initialize.apply(this, arguments);
toJSON: function toJSON(options) {
if (!!options.facetSuggestions) {
return _.extend({
rows: 0,
facet: true,
wt: 'json',
q: '*:*',
}, this.getFacetFormData(options));
}
});
return Pagination;
})();
var Ordering = Backbone.Model.extend({
defaults: {
value: null,
items: new Backbone.Collection(),
},
initialize: function(data, options) {
if (this.get('value') === null) {
var firstItem = this.get('items').at(0);
if (firstItem) {
this.set('value', firstItem.get('value'));
}
parse: function parse(data, options) {
if (!!options.facetSuggestions) {
this.applyFacetResults(data, options);
}
return null;
},
parse: function(data) {
var result = _.clone(data);
if (result.items && !(result.items instanceof Backbone.Collection)) {
result.items = new Backbone.Collection(result.items, {parse: true});
}));
var Sort = Facets.Sort = {
standard: function standardSort(a, b) {
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
return result;
},
});
var QueryTextField = Backbone.Model.extend({
defaults: {
formName: null,
name: null,
queries: [],
fields: null,
multi: false
date: function dateSort(a, b) {
return Sort.standard.call(this, a, b);
},
});
var SolrSearch = Pagination.extend({
url: function url() {
return this.constructor.selectUrl;
number: function numberSort(a, b) {
return Sort.standard.call(this, parseInt(a), parseInt(b));
},
defaults: function defaults() {
var constructor = this.constructor;
var formNameMap = {};
var facets = new SolrFacets(this.constructor.facets, {search: this});
_.each(facets.values(), function(facet) {
var formName = facet.get('formName');
if (formName) {
formNameMap[formName] = facet;
};
function wrapComparatorForAllBeforeAfter(comparator, doBefore, doAfter) {
if (!doBefore && !doAfter) {
return comparator;
}
return function beforeAfterComparator(a, b) {
if (doBefore) {
if (a === 'before') {
return -1;
} else if (b === 'before') {
return 1;
}
});
var queryFields = new Backbone.Model();
_.each(constructor.queryTextFields, function(definition, queryName) {
var qtf = new QueryTextField({formName: definition.formName, name: queryName, queries: [], fields: definition.fields, multi: !!definition.multi});
var formName = qtf.get('formName');
if (formName) {
formNameMap[formName] = qtf;
}
if (doAfter) {
if (a === 'after') {
return 1;
} else if (b === 'after') {
return -1;
}
queryFields.set(queryName, qtf);
}, this);
return _.extend(_.result(SolrSearch.__super__, 'defaults'), {
initializing: true,
initialized: false,
query: '',
formNameMap: formNameMap,
results: new Backbone.Collection(),
ordering: new Ordering({items: constructor.orderingItems}, {parse: true}),
facets: facets,
queryFields: queryFields,
});
},
applyQueryParameters: function() {
var skipOptions = {skipSearch: true};
var parts = document.location.href.match(/.*\?(.*)/);
var facets = this.get('facets');
facets.resetSearch();
_.each(this.get('queryFields').values(), function(qtf) {
qtf.set({
query: null,
queries: [],
}, skipOptions);
});
if (parts) {
var formNameMap = this.get('formNameMap');
var keyValueParts = parts[1].split('&');
_.each(keyValueParts, function(keyValuePart, i) {
var keyFieldValue = keyValuePart.match(/^([^.]+)(?:\.([^.]+))?=(.*)$/);
if (keyFieldValue) {
var key = keyFieldValue[1];
var field = keyFieldValue[2];
var value = keyFieldValue[3];
value = value.replace(/(\+|%20)/g, ' ');
var impl = formNameMap[key];
if (impl) {
if (impl instanceof QueryTextField) {
impl.set('query', value, skipOptions);
} else if (impl.facetType === 'field' && value) {
if (field === 'min') {
impl.set('queryMin', parseInt(value), skipOptions);
} else if (field === 'max') {
impl.set('queryMax', parseInt(value), skipOptions);
} else if (field === 'items') {
var items = impl.get('items');
var item = items.get(value);
if (!item) {
item = new SolrFacets.Facet.Item({key: value, value: 0});
items.add(item);
item.on('change:checked', function(model, value, options) {
this.trigger('item-change', null, null, options);
impl.trigger('item-change', null, null, options);
}, facets);
}
item.set('checked', true, skipOptions);
}
}
}
}
}, this);
}
return comparator.call(this, a, b);
};
}
var Facet = Facets.Facet = Backbone.Model.extend({
defaults: function defaults() {
return {
formName: null,
query: null,
suggestions: [],
};
},
initialize: function(data, options) {
options = (options || {});
this.set('options', new Backbone.Model({
faceting: !!options.faceting,
highlighting: !!options.highlighting,
showAll: !!options.showAll,
}));
this._doSearchImmediately = _.bind(function(options) {
this.fetch(_.extend({}, options, {
data: this.toJSON(),
merge: false,
traditional: true,
}));
this.set('all', true);
this.on('change:queryMax change:queryMin', function() {
this.set('hasQuery', this.get('queryMin') !== undefined && this.get('queryMax') !== undefined);
}, this);
this._doSearch = _.debounce(this._doSearchImmediately, 250);
this._doSearch = (function(doSearch) {
return function(options) {
var skipSearch = this._skipSearch || (options || {}).skipSearch;
if (!skipSearch) {
doSearch(options);
(function(self) {
var skipCallback;
self.on('item-change change:queryMax change:queryMin', function() {
switch (skipCallback) {
case 'change:checkedKeys':
case 'change:all':
return;
}
};
})(this._doSearch);
_.each(this.get('queryFields').values(), function(subQueryModel) {
subQueryModel.on('change:query change:queries', function(model, value, options) {
this.trigger('change:queryFields', null, null, options);
}, this);
}, this);
this.on('change:queryFields', function(model, value, options) {
this.trigger('change:query', null, null, options);
}, this);
this.get('options').on('change:faceting change:highlighting', function(model, value, options) {
this._doSearch(options);
}, this);
this.on('change:query', function(model, value, options) {
// this is silent, which causes the change events to not fire;
// this is ok, because the next .on will also see the change
// event on query, and resend the search
this._doSearch(_.extend({}, options, {resetCurrentPage: true, resetFacets: true, resetOrdering: true}));
}, this);
this.on('change:pageSize', function(model, value, options) {
this._doSearch(_.extend({}, options, {resetCurrentPage: true}));
}, this);
this.on('change:currentPage', function(model, value, options) {
this._doSearch(options);
}, this);
this.get('facets').on('item-change', function(model, value, options) {
this._doSearch(_.extend({}, options, {resetCurrentPage: true}));
}, this);
this.get('ordering').on('change:value', function(model, value, options) {
this._doSearch(_.extend({}, options, {resetCurrentPage: true}));
}, this);
return SolrSearch.__super__.initialize.apply(this, arguments);
},
parse: function parse(data, options) {
if (options.facetSuggestions) {
return null;
}
var skipOptions = _.extend({}, options, {skipSearch: true});
if (options.resetCurrentPage) {
this.set('currentPage', 1, skipOptions);
}
if (options.resetFacets) {
this.get('facets').resetSearch(skipOptions);
}
if (options.resetOrdering) {
this.get('ordering').set('value', this.get('ordering').get('items').at(0).get('value'), skipOptions);
}
var facets = this.get('facets');
if (this.get('options').get('faceting')) {
facets.applyFacetResults(data);
} else {
facets.resetSearch(options);
}
var list = [];
var highlighting = this.get('options').get('highlighting') ? data.highlighting : {};
var self = this;
_.each(data.response.docs, function(doc, index) {
var itemHighlighting = highlighting[doc.id];
if (!itemHighlighting) {
itemHighlighting = {};
}
list.push(self.searchParseDoc(doc, index, itemHighlighting));
});
var checkedKeys = [];
this.get('items').each(function(facetItem) {
if (facetItem.get('checked')) {
checkedKeys.push(facetItem.get('key'));
}
});
var checkedCount = checkedKeys.length;
if (this.get('queryMin') !== undefined && this.get('queryMax') !== undefined) {
checkedCount++;
}
skipCallback = 'item-change';
try {
this.set({
all: checkedCount === 0,
checkedKeys: checkedKeys,
return {
initializing: false,
initialized: true,
results: new Backbone.Collection(list),
facets: facets,
options: this.get('options'),
totalCount: data.response.numFound,
queryTime: (data.responseHeader.QTime / 1000).toFixed(2),
hasResults: list.length > 0,
};
},
searchParseDoc: function searchParseDoc(doc, index, itemHighlighting) {
var fieldsToParse = mergeStaticProps(this.constructor, SolrSearch, {}, 'parsedFieldMap');
var result = {};
_.each(fieldsToParse, function(value, key) {
var parsed;
if (_.isFunction(value)) {
parsed = value.call(this, doc, index, itemHighlighting, key);
} else if (_.isArray(value)) {
parsed = [];
_.each(value, function(item, i) {
var rawValue = doc[item.name];
if (rawValue) {
var parsedValue = item.parse.call(this, doc, index, itemHighlighting, rawValue, item.name);
if (parsedValue) {
parsed.push(parsedValue);
});
} finally {
skipCallback = null;
}
}, self);
self.on('change:all', function() {
switch (skipCallback) {
case 'change:checkedKeys':
case 'item-change':
return;
}
skipCallback = 'change:all';
try {
this.get('items').invoke('set', {checked: false});
this.set({
checkedKeys: [],
queryMax: undefined,
queryMin: undefined,
});
} finally {
skipCallback = null;
}
}, self);
self.on('change:checkedKeys', function() {
switch (skipCallback) {
case 'item-change':
case 'change:all':
return;
}
var checkedKeys = {};
_.each(this.get('checkedKeys'), function(value, i) {
checkedKeys[value] = true;
});
skipCallback = 'change:checkedKeys';
var checkedCount = 0;
if (this.get('queryMin') !== undefined && this.get('queryMax') !== undefined) {
checkedCount++;
}
try {
this.get('items').each(function(facetItem) {
var newChecked = checkedKeys[facetItem.get('key')];
var currentChecked = facetItem.get('checked');
if (newChecked !== currentChecked) {
facetItem.set('checked', newChecked);
}
}
}, this);
} else {
parsed = doc[value];
}
result[key] = parsed;
}, this);
return result;
},
toJSON: function(options) {
if (!options) {
options = {};
}
var facets = this.get('facets');
var constructor = this.constructor;
var result = {
defType: 'edismax',
qf: constructor.queryField,
wt: 'json',
};
var ordering = this.get('ordering');
var sort = ordering.get('value');
if (options.resetOrdering) {
sort = ordering.get('items').at(0).get('value');
if (facetItem.get('checked')) {
checkedCount++;
}
});
this.set({
all: checkedCount === 0,
});
} finally {
skipCallback = null;
}
}, self);
})(this);
var sortKeyExtractor = options.sortKeyExtractor;
if (!sortKeyExtractor) {
sortKeyExtractor = getItemKeyAccessor;
}
var currentPage = this.get('currentPage');
var pageSize = this.get('pageSize');
if (options.resetCurrentPage) {
currentPage = 1;
var comparator = options.comparator;
if (!comparator) {
comparator = Sort.standard;
} else if (typeof comparator === 'string') {
comparator = Sort[comparator];
}
result.sort = sort;
result.rows = pageSize;
result.start = (currentPage - 1) * pageSize;
result.fl = mergeStaticSets(constructor, SolrSearch, [], 'returnFields');
if (this.get('options').get('highlighting')) {
result.hl = true;
result['hl.fl'] = ['content', 'title'].concat(constructor.extraHighlightFields);
switch (options.facetType) {
case 'year':
case 'range':
case 'interval':
comparator = wrapComparatorForAllBeforeAfter(comparator, ['all', 'before'].indexOf(options.other) !== -1, ['all', 'after'].indexOf(options.other) !== -1);
break;
}
if (this.get('options').get('faceting')) {
var facetFormData = facets.getFacetFormData();
var fq = facetFormData.fq;
delete(facetFormData.fq);
result = _.extend(result, facetFormData);
if (fq.length) {
if (result.fq) {
result.fq = result.fq.concat(fq);
} else {
result.fq = fq;
}
var formatter = options.formatter;
if (!formatter) {
var labelMap = options.labelMap;
if (labelMap) {
formatter = function(item) {
var value = item.get('key');
var label = options.labelMap[value.toUpperCase()];
return label ? label : value;
};
} else {
formatter = getItemKeyAccessor;
}
}
var queryParts = [];
var queryFields = this.get('queryFields');
_.each(queryFields.keys(), function(queryName) {
var subQueryModel = queryFields.get(queryName);
var fields = subQueryModel.get('fields');
var queries = subQueryModel.get('queries');
var query = subQueryModel.get('query');
if (query) {
queries = queries.concat([query]);
}
var subQuery = [];
for (var i = 0; i < fields.length; i++) {
var fieldName = fields[i];
for (var j = 0; j < queries.length; j++) {
// FIXME: quote the query
subQuery.push(fieldName + ':\'' + queries[j] + '\'');
this.formatter = formatter;
comparator = (function(comparator) {
return function facetItemValue(a, b) {
var keyA = sortKeyExtractor(a);
var keyB = sortKeyExtractor(b);
switch (this.get('orderByDirection')) {
case 'desc':
var tmp = keyA;
keyA = keyB;
keyB = tmp;
break;
}
}
if (subQuery.length) {
queryParts.push(subQuery.join(' OR '));
}
}, this);
var query = queryParts.join(' AND ');
if (!query) {
query = '*:*';
if (!this.get('options').get('showAll') && !result.fq) {
result.rows = 0;
}
return comparator.call(this, sortKeyExtractor(a), sortKeyExtractor(b));
};
})(comparator);
this.set('items', new ItemCollection([], {comparator: comparator}));
this.facetType = options.facetType;
this.facetStats = options.facetStats;
this.other = options.other;
this.facetField = options.facetField;
this.queryField = options.queryField;
this.queryValue = options.queryValue;
this.bins = options.bins;
switch (this.facetType) {
case 'year':
this.rangeStart = options.start;
this.rangeEnd = options.end;
this.rangeGap = '+' + (options.gap ? options.gap : 1) + 'YEAR';
break;
case 'range':
this.rangeStart = options.start;
this.rangeEnd = options.end;
this.rangeGap = options.gap;
break;
case 'field':
case 'year-field':
case 'interval':
break;
default:
var e = new Error('Unsupported facet type: ' + this.facetType);
e.facet = this;
throw e;
}
var dateBoostField = constructor.dateBoostField;
var popularityBoostField = constructor.popularityBoostField;
if (result.rows !== 0 && (dateBoostField || popularityBoostField)) {
var boostSum = [];
if (dateBoostField) {
result.dateBoost = 'recip(ms(NOW,' + dateBoostField + '),3.16e-11,1,1)';
boostSum.push('$dateBoost');
}
if (popularityBoostField) {
result.popularityBoost = 'def(' + popularityBoostField + ',0)';
boostSum.push('$popularityBoost');
}
result.qq = query;
result.q = '{!boost b=sum(' + boostSum.join(',') + ') v=$qq defType=$defType}';
} else {
result.q = query;
return Facet.__super__.initialize.apply(this, arguments);
},
/*
toJSON: function toJSON(options) {
if (!!options.facetSuggestions) {
return {
rows: 0,
facet: true,
wt: 'json',
q: '*:*',
'facet.contains': this.get('query'),
'facet.contains.ignoreCase': true,
'facet.field': this.queryField,
'facet.mincount': 1,
};
}
return result;
},
}, {
cleanup: function cleanup(txt) {
if (txt) {
txt = txt.replace(/&amp;/g, '&');
txt = txt.replace(/&#39;/g, '\'');
txt = txt.replace(/[^a-zA-Z0-9 -\.,:;%<>\/'"|]/g, ' ');
parse: function parse(data, options) {
if (!!options.facetSuggestions) {
var suggestions = [];
var key;
_.each(data.facet_counts.facet_fields[this.queryField], function(value, index) {
if (index % 2 === 0) {
key = value;
} else if (value > 0) {
suggestions.push({key: key, value: value});
}
});
return {
suggestions: suggestions,
};
}
return txt;
return null;
},
returnFields: [
'keywords',
'last_modified',
'path',
'score',
'title',
],
parsedFieldMap: {
content: function(doc, index, itemHighlighting) {
var content = itemHighlighting.content;
if (content && content.constructor === Array) {
content = content.join(' ');
}
if (!content) {
content = '';
}
return this.constructor.cleanup(content);
},
keywords: 'keywords',
lastModified: 'last_modified',
path: 'url',
score: 'score',
title: function(doc, index, itemHighlighting) {
var title;
if (itemHighlighting.title) {
title = itemHighlighting.title.join(' ');
} else {
title = doc.title[0];
}
return this.constructor.cleanup(title);
},
*/
});
var ItemCollection = Backbone.Collection.extend({
remove: function() {
}
});
var Item = Facet.Item = Backbone.Model.extend({
idAttribute: 'key',
defaults: {
checked: false,
hidden: false,
},
_initialize: function(data, options) {
this.on('add', function(model, parent, options) {
// added to a collection
this.on('change:checked', function() {
parent.trigger('item-change');
});
}, this);
return Item.__super__.initialize.apply(this, arguments);
}
});
SolrSearch.Facets = SolrFacets;
SolrSearch.Pagination = Pagination;
return SolrSearch;
return Facets;
});
......
define(function(require) {
'use strict';
var Backbone = require('backbone');
var Ordering = Backbone.Model.extend({
defaults: {
value: null,
items: new Backbone.Collection(),
},
initialize: function(data, options) {
if (this.get('value') === null) {
var firstItem = this.get('items').at(0);
if (firstItem) {
this.set('value', firstItem.get('value'));
}
}
},
parse: function(data) {
var result = _.clone(data);
if (result.items && !(result.items instanceof Backbone.Collection)) {
result.items = new Backbone.Collection(result.items, {parse: true});
}
return result;
},
});
return Ordering;
});
define(function(require) {
'use strict';
var Backbone = require('backbone');
function stepFalse(e) {
e.preventDefault();
return false;
}
var Pagination = Backbone.Model.extend({
defaults: {
currentPage: 1,
hasNext: false,
hasNextJumpPage: false,
hasPrevious: false,
hasPreviousJumpPage: false,
nextJumpPage: undefined,
nextPage: undefined,
pages: [],
pageJump: 5,
pageSize: 10,
previousJumpPage: undefined,
previousPage: undefined,
totalCount: 0,
totalPages: 0,
},
initialize: function(data, options) {
var buildPages = function buildPages() {
var currentPage = parseInt(this.get('currentPage'));
var pageSize = parseInt(this.get('pageSize'));
var totalCount = parseInt(this.get('totalCount'));
if (!currentPage || !pageSize || !totalCount) {
return;
}
var pages = [];
var totalPages = Math.floor((totalCount + pageSize - 1) / pageSize);
function addPage(self, i) {
pages.push({
current: i === currentPage,
jump: function() {
self.set('currentPage', i);
return true;
},
number: i,
});
}
var startAt = currentPage - 4, endAt = currentPage + 5;
if (startAt < 1) {
endAt += (1 - startAt);
}
if (endAt > totalPages) {
startAt -= endAt - totalPages - 1;
endAt = totalPages + 1;
}
if (startAt < 1) {
startAt = 1;
}
if (endAt - startAt < 9) {
/* global console:false */
console.log('foo');
}
for (var i = startAt; i < endAt; i++) {
if (i > 0 && i <= totalPages) {
addPage(this, i);
}
}
var hasPrevious = currentPage > 1;
var hasNext = currentPage < totalPages;
var pageJump = this.get('pageJump');
var nextJumpPage, previousJumpPage, hasNextJump, hasPreviousJump;
if (pageJump) {
nextJumpPage = currentPage + pageJump;
previousJumpPage = currentPage - pageJump;
hasNextJump = nextJumpPage < totalPages;
hasPreviousJump = previousJumpPage > 0;
} else {
hasNextJump = false;
hasPreviousJump = false;
}
this.set({
hasNext: hasNext,
hasNextJump: hasNextJump,
hasPrevious: hasPrevious,
hasPreviousJump: hasPreviousJump,
nextJumpPage: hasNextJump ? nextJumpPage : undefined,
nextPage: hasNext ? currentPage + 1 : undefined,
pages: pages,
previousJumpPage: hasNextJump ? previousJumpPage : undefined,
previousPage: hasPrevious ? currentPage - 1 : undefined,
totalPages: totalPages,
});
};
this.on('change:pageSize change:currentPage change:totalCount', buildPages, this);
var installActions = _.bind(function installActions(eventName, nextName, hasNextName, previousName, hasPreviousName, pageCount) {
this.on(eventName, function() {
var hasNext = this.get(hasNextName);
var hasPrevious = this.get(hasPreviousName);
var next, previous;
if (hasNext) {
next = _.bind(function(e) {
e.preventDefault();
this.set('currentPage', this.get('currentPage') + pageCount);
return false;
}, this);
} else {
next = stepFalse;
}
if (hasPrevious) {
previous = _.bind(function(e) {
e.preventDefault();
this.set('currentPage', this.get('currentPage') - pageCount);
return false;
}, this);
} else {
previous = stepFalse;
}
this.set(nextName, next);
this.set(previousName, previous);
}, this);
this[nextName] = _.bind(function() {
return this.get(nextName)();
}, this);
this[previousName] = _.bind(function() {
return this.get(previousName)();
}, this);
}, this);
this.on('change:pageJump', function() {
var pageJump = this.get('pageJump');
installActions('change:hasNextJump change:hasPreviousJump', 'nextJump', 'hasNextJump', 'previousJump', 'hasPreviousJump', pageJump);
}, this);
installActions('change:hasNext change:hasPrevious', 'next', 'hasNext', 'previous', 'hasPrevious', 1);
buildPages.apply(this);
this.trigger('change:pageJump');
return Pagination.__super__.initialize.apply(this, arguments);
}
});
return Pagination;
});
define(function(require) {
'use strict';
var Backbone = require('backbone');
var QueryTextField = Backbone.Model.extend({
defaults: {
formName: null,
name: null,
queries: [],
fields: null,
multi: false
},
});
return QueryTextField;
});
define(function(require) {
'use strict';
var _ = require('underscore');
var Backbone = require('backbone');
var Facets = require('solr/model/Facets');
var Ordering = require('solr/model/Ordering');
var Pagination = require('solr/model/Pagination');
var QueryTextField = require('solr/model/QueryTextField');
//var module = require('module');
function mergeStatic(startPtr, endPtr, obj, fieldName, filterFunc) {
var result = filterFunc(obj);
var ptr = startPtr;
while (true) {
result = _.extend(result, filterFunc(_.result(ptr, fieldName)));
if (ptr === endPtr) {
break;
}
ptr = ptr.__super__.constructor;
}
return result;
}
function mergeStaticProps(startPtr, endPtr, obj, fieldName) {
return mergeStaticFunc(startPtr, endPtr, obj, fieldName, _.identity);
}
function mergeStaticSets(startPtr, endPtr, obj, fieldName) {
return _.keys(mergeStaticFunc(startPtr, endPtr, obj, fieldName, function arrayToMap(array) {
var result = {};
_.each(array, function(value) {
result[value] = true;
});
return result;
}));
}
function getItemKeyAccessor(item) {
return item.get('key');
}
var Solr = Pagination.extend({
url: function url() {
return this.constructor.selectUrl;
},
defaults: function defaults() {
var constructor = this.constructor;
var formNameMap = {};
var facets = new Facets(this.constructor.facets, {search: this});
_.each(facets.values(), function(facet) {
var formName = facet.get('formName');
if (formName) {
formNameMap[formName] = facet;
}
});
var queryFields = new Backbone.Model();
_.each(constructor.queryTextFields, function(definition, queryName) {
var qtf = new QueryTextField({formName: definition.formName, name: queryName, queries: [], fields: definition.fields, multi: !!definition.multi});
var formName = qtf.get('formName');
if (formName) {
formNameMap[formName] = qtf;
}
queryFields.set(queryName, qtf);
}, this);
return _.extend(_.result(Solr.__super__, 'defaults'), {
initializing: true,
initialized: false,
query: '',
formNameMap: formNameMap,
results: new Backbone.Collection(),
ordering: new Ordering({items: constructor.orderingItems}, {parse: true}),
facets: facets,
queryFields: queryFields,
});
},
applyQueryParameters: function() {
var skipOptions = {skipSearch: true};
var parts = document.location.href.match(/.*\?(.*)/);
var facets = this.get('facets');
facets.resetSearch();
_.each(this.get('queryFields').values(), function(qtf) {
qtf.set({
query: null,
queries: [],
}, skipOptions);
});
if (parts) {
var formNameMap = this.get('formNameMap');
var keyValueParts = parts[1].split('&');
_.each(keyValueParts, function(keyValuePart, i) {
var keyFieldValue = keyValuePart.match(/^([^.]+)(?:\.([^.]+))?=(.*)$/);
if (keyFieldValue) {
var key = keyFieldValue[1];
var field = keyFieldValue[2];
var value = keyFieldValue[3];
value = value.replace(/(\+|%20)/g, ' ');
var impl = formNameMap[key];
if (impl) {
if (impl instanceof QueryTextField) {
impl.set('query', value, skipOptions);
} else if (impl.facetType === 'field' && value) {
if (field === 'min') {
impl.set('queryMin', parseInt(value), skipOptions);
} else if (field === 'max') {
impl.set('queryMax', parseInt(value), skipOptions);
} else if (field === 'items') {
var items = impl.get('items');
var item = items.get(value);
if (!item) {
item = new Facets.Facet.Item({key: value, value: 0});
items.add(item);
item.on('change:checked', function(model, value, options) {
this.trigger('item-change', null, null, options);
impl.trigger('item-change', null, null, options);
}, facets);
}
item.set('checked', true, skipOptions);
}
}
}
}
}, this);
}
},
initialize: function(data, options) {
options = (options || {});
this.set('options', new Backbone.Model({
faceting: !!options.faceting,
highlighting: !!options.highlighting,
showAll: !!options.showAll,
}));
this._doSearchImmediately = _.bind(function(options) {
this.fetch(_.extend({}, options, {
data: this.toJSON(),
merge: false,
traditional: true,
}));
}, this);
this._doSearch = _.debounce(this._doSearchImmediately, 250);
this._doSearch = (function(doSearch) {
return function(options) {
var skipSearch = this._skipSearch || (options || {}).skipSearch;
if (!skipSearch) {
doSearch(options);
}
};
})(this._doSearch);
_.each(this.get('queryFields').values(), function(subQueryModel) {
subQueryModel.on('change:query change:queries', function(model, value, options) {
this.trigger('change:queryFields', null, null, options);
}, this);
}, this);
this.on('change:queryFields', function(model, value, options) {
this.trigger('change:query', null, null, options);
}, this);
this.get('options').on('change:faceting change:highlighting', function(model, value, options) {
this._doSearch(options);
}, this);
this.on('change:query', function(model, value, options) {
// this is silent, which causes the change events to not fire;
// this is ok, because the next .on will also see the change
// event on query, and resend the search
this._doSearch(_.extend({}, options, {resetCurrentPage: true, resetFacets: true, resetOrdering: true}));
}, this);
this.on('change:pageSize', function(model, value, options) {
this._doSearch(_.extend({}, options, {resetCurrentPage: true}));
}, this);
this.on('change:currentPage', function(model, value, options) {
this._doSearch(options);
}, this);
this.get('facets').on('item-change', function(model, value, options) {
this._doSearch(_.extend({}, options, {resetCurrentPage: true}));
}, this);
this.get('ordering').on('change:value', function(model, value, options) {
this._doSearch(_.extend({}, options, {resetCurrentPage: true}));
}, this);
return Solr.__super__.initialize.apply(this, arguments);
},
parse: function parse(data, options) {
if (options.facetSuggestions) {
return null;
}
var skipOptions = _.extend({}, options, {skipSearch: true});
if (options.resetCurrentPage) {
this.set('currentPage', 1, skipOptions);
}
if (options.resetFacets) {
this.get('facets').resetSearch(skipOptions);
}
if (options.resetOrdering) {
this.get('ordering').set('value', this.get('ordering').get('items').at(0).get('value'), skipOptions);
}
var facets = this.get('facets');
if (this.get('options').get('faceting')) {
facets.applyFacetResults(data);
} else {
facets.resetSearch(options);
}
var list = [];
var highlighting = this.get('options').get('highlighting') ? data.highlighting : {};
var self = this;
_.each(data.response.docs, function(doc, index) {
var itemHighlighting = highlighting[doc.id];
if (!itemHighlighting) {
itemHighlighting = {};
}
list.push(self.searchParseDoc(doc, index, itemHighlighting));
});
return {
initializing: false,
initialized: true,
results: new Backbone.Collection(list),
facets: facets,
options: this.get('options'),
totalCount: data.response.numFound,
queryTime: (data.responseHeader.QTime / 1000).toFixed(2),
hasResults: list.length > 0,
};
},
searchParseDoc: function searchParseDoc(doc, index, itemHighlighting) {
var fieldsToParse = mergeStaticProps(this.constructor, Solr, {}, 'parsedFieldMap');
var result = {};
_.each(fieldsToParse, function(value, key) {
var parsed;
if (_.isFunction(value)) {
parsed = value.call(this, doc, index, itemHighlighting, key);
} else if (_.isArray(value)) {
parsed = [];
_.each(value, function(item, i) {
var rawValue = doc[item.name];
if (rawValue) {
var parsedValue = item.parse.call(this, doc, index, itemHighlighting, rawValue, item.name);
if (parsedValue) {
parsed.push(parsedValue);
}
}
}, this);
} else {
parsed = doc[value];
}
result[key] = parsed;
}, this);
return result;
},
toJSON: function(options) {
if (!options) {
options = {};
}
var facets = this.get('facets');
var constructor = this.constructor;
var result = {
defType: 'edismax',
qf: constructor.queryField,
wt: 'json',
};
var ordering = this.get('ordering');
var sort = ordering.get('value');
if (options.resetOrdering) {
sort = ordering.get('items').at(0).get('value');
}
var currentPage = this.get('currentPage');
var pageSize = this.get('pageSize');
if (options.resetCurrentPage) {
currentPage = 1;
}
result.sort = sort;
result.rows = pageSize;
result.start = (currentPage - 1) * pageSize;
result.fl = mergeStaticSets(constructor, Solr, [], 'returnFields');
if (this.get('options').get('highlighting')) {
result.hl = true;
result['hl.fl'] = ['content', 'title'].concat(constructor.extraHighlightFields);
}
if (this.get('options').get('faceting')) {
var facetFormData = facets.getFacetFormData();
var fq = facetFormData.fq;
delete(facetFormData.fq);
result = _.extend(result, facetFormData);
if (fq.length) {
if (result.fq) {
result.fq = result.fq.concat(fq);
} else {
result.fq = fq;
}
}
}
var queryParts = [];
var queryFields = this.get('queryFields');
_.each(queryFields.keys(), function(queryName) {
var subQueryModel = queryFields.get(queryName);
var fields = subQueryModel.get('fields');
var queries = subQueryModel.get('queries');
var query = subQueryModel.get('query');
if (query) {
queries = queries.concat([query]);
}
var subQuery = [];
for (var i = 0; i < fields.length; i++) {
var fieldName = fields[i];
for (var j = 0; j < queries.length; j++) {
// FIXME: quote the query
subQuery.push(fieldName + ':\'' + queries[j] + '\'');
}
}
if (subQuery.length) {
queryParts.push(subQuery.join(' OR '));
}
}, this);
var query = queryParts.join(' AND ');
if (!query) {
query = '*:*';
if (!this.get('options').get('showAll') && !result.fq) {
result.rows = 0;
}
}
var dateBoostField = constructor.dateBoostField;
var popularityBoostField = constructor.popularityBoostField;
if (result.rows !== 0 && (dateBoostField || popularityBoostField)) {
var boostSum = [];
if (dateBoostField) {
result.dateBoost = 'recip(ms(NOW,' + dateBoostField + '),3.16e-11,1,1)';
boostSum.push('$dateBoost');
}
if (popularityBoostField) {
result.popularityBoost = 'def(' + popularityBoostField + ',0)';
boostSum.push('$popularityBoost');
}
result.qq = query;
result.q = '{!boost b=sum(' + boostSum.join(',') + ') v=$qq defType=$defType}';
} else {
result.q = query;
}
return result;
},
}, {
cleanup: function cleanup(txt) {
if (txt) {
txt = txt.replace(/&amp;/g, '&');
txt = txt.replace(/&#39;/g, '\'');
txt = txt.replace(/[^a-zA-Z0-9 -\.,:;%<>\/'"|]/g, ' ');
}
return txt;
},
returnFields: [
'keywords',
'last_modified',
'path',
'score',
'title',
],
parsedFieldMap: {
content: function(doc, index, itemHighlighting) {
var content = itemHighlighting.content;
if (content && content.constructor === Array) {
content = content.join(' ');
}
if (!content) {
content = '';
}
return this.constructor.cleanup(content);
},
keywords: 'keywords',
lastModified: 'last_modified',
path: 'url',
score: 'score',
title: function(doc, index, itemHighlighting) {
var title;
if (itemHighlighting.title) {
title = itemHighlighting.title.join(' ');
} else {
title = doc.title[0];
}
return this.constructor.cleanup(title);
},
},
});
Solr.Facets = Facets;
Solr.Pagination = Pagination;
return Solr;
});