function AllocationRenderer(allocationChosenCallback) {
var self = this;
var locale = PickyI18n.locale;
var qualifiers = Localization.qualifiers && Localization.qualifiers[locale] || {};
var explanations = Localization.explanations && Localization.explanations[locale] || {};
var location_delimiter = Localization.location_delimiters[locale];
var explanation_delimiter = Localization.explanation_delimiters[locale];
// Those are of interest to the public.
//
this.text = '';
this.query = '';
this.explanation = '';
// TODO parametrize.
//
var no_ellipses = ['street_number', 'zipcode'];
// Contracts the originals of the zipped.
//
function contract(zipped) {
var hash = {}; // remembers the values
var insert = {}; // remembers the insertion locations
var remove = []; // remembers the remove indexes
var i;
for (i = 0, l = zipped.length; i < l; i++) {
var key = zipped[i][0];
if (key in hash) {
hash[key] = hash[key] + ' ' + zipped[i][1];
remove.push(i);
} else {
hash[key] = zipped[i][1];
insert[i] = key;
}
}
// Insert the ones from the hash.
for (i in insert) {
zipped[i][1] = hash[insert[i]];
}
// Remove the ones from zipped we don't like. From the end.
for (i = remove.length-1; i >= 0; i--) {
zipped.remove(remove[i]);
}
return zipped;
};
this.contract = contract;
// TODO Parametrize!
var specialWhoCases = {
// Use the actual methods, not strings.
"maiden_name" : { format:"(-%1$s)", method:'capitalize', ignoreSingle:true },
"name" : { format:"%1$s", method:'toUpperCase', ignoreSingle:true },
"first_name" : { format:"%1$s", method:"capitalize" }
};
function handleWho(both, singleParam) {
var single = singleParam || false;
var allocation = both[0];
var word = both[1];
var formatting = specialWhoCases[allocation];
if (formatting) {
if (formatting.method) { word = word[formatting.method](); }
if (formatting.format) { word = formatting.format.replace(/%1\$s/, word); }
}
var explanation = explanations[allocation] || allocation;
if (single && !(formatting && formatting.ignoreSingle)) { return word + ' (' + explanation + ')'; }
return word;
}
// Handles the first (who) part.
//
// Rules:
// * If there is no thing, do return an empty string.
// * If there is only one thing, add an explanation.
// * If there are multiple things, handle special cases.
// Without special cases, the name is always in front.
// The things are separated by commas, and explained.
// If there are multiple instances of the same category, they are contracted.
//
// Note: to not disconnect the explanation from the query text.
//
function who(zipped) {
if (zipped.length == 0) {
return '';
} else if (zipped.length == 1) {
return handleWho(zipped[0], true);
} else {
// else, sort, special cases etc.
var result = [];
var append = [];
zipped = contract(zipped);
for (var i = 0, l = zipped.length; i < l; i++) {
if (zipped[i][0] == 'first_name') {
result.unshift(handleWho(zipped[i])); // prepend the first name
} else {
if (zipped[i][0] == 'maiden_name') {
append.push(handleWho(zipped[i]));
} else {
result.push(handleWho(zipped[i]));
}
}
};
if (append.length > 0) { result.push(append); };
return result.join(' ');
}
}
this.who = who;
function replacerFor(zipped) {
return function(_, category) {
for (var i = 0, l = zipped.length; i < l; i++) {
if (zipped[i][0] == category) { return zipped[i][1]; };
};
return '';
};
};
// Handles the second (where) part.
//
// Rules:
// * If there is no location, do return an empty string.
// * If there is only a zipcode, add a [].
// * If there is only a city, add nothing.
// * If there are both, zipcode needs to be first.
// TODO Contraction of multiple "cities" and/or zipcode.
//
var locations = {
'zipcode':(':zipcode [' + explanations.city + ']'),
'city':':city',
'city,zipcode':':zipcode :city'
};
function where(zipped) {
if (zipped.length == 0) { return ''; };
zipped = contract(zipped);
var key_ary = zipped;
key_ary.sort(function(zipped1, zipped2) {
return zipped1[0] < zipped2[0] ? -1 : 1;
});
// Now that it's sorted, get the right string.
var key = [];
for (var i = 0, l = key_ary.length; i < l; i++) {
key.push(key_ary[i][0]);
};
var loc = locations[key];
// Replace inside string.
var result = loc.replace(/:(zipcode|city)/g, replacerFor(zipped));
return result;
};
this.where = where;
function handleSingleWhat(both) {
var allocation = both[0];
var word = both[1];
var explanation = explanations[allocation] || allocation;
return word + ' (' + explanation + ')';
}
function what(zipped) {
if (zipped.length == 0) { return ''; };
result = [];
zipped = contract(zipped);
for (var i = 0, l = zipped.length; i < l; i++) {
result.push(handleSingleWhat(zipped[i]));
}
return result.join(', ');
};
this.what = what;
// Orders the allocation identifiers according to
// [, , ]
// Returns a reordered array.
//
// TODO Rename "group".
//
var who_qualifiers = ['first_name', 'name', 'maiden_name'];
var where_qualifiers = ['zipcode', 'city'];
function trisect(zipped) {
var who_parts = [];
var what_parts = [];
var where_parts = [];
for (var i = 0, l = zipped.length; i < l; i++) {
var combination = zipped[i];
if (where_qualifiers.include(combination[0])) {
where_parts.push(combination);
} else if (who_qualifiers.include(combination[0])) {
who_parts.push(combination);
} else {
what_parts.push(combination);
}
}
// Ellipsisize the last part
var alloc_part;
if (where_parts.length > 0) {
alloc_part = where_parts[where_parts.length-1];
} else if (what_parts.length > 0) {
alloc_part = what_parts[what_parts.length-1];
} else if (who_parts.length > 0) {
alloc_part = who_parts[who_parts.length-1];
} // always results in a part
if (!no_ellipses.include(alloc_part[0])) { alloc_part[1] += '...'; } // TODO *
var rendered_who = who(who_parts);
var rendered_what = what(what_parts);
var rendered_where = where(where_parts);
return [rendered_who, rendered_what, rendered_where];
};
this.trisect = trisect;
// Fuses a possible who part to a possible what part to a possible where part.
//
// e.g. , in
//
// Note: to not disconnect the location delimiter (e.g. "in") from the location.
//
// TODO Parametrize!
//
var who_what_join = ', ';
var whowhat_where_join = ' ' + location_delimiter + ' ';
function fuse(parts) {
var who = parts[0], what = parts[1], where = parts[2];
var who_what = '';
if (who != '') {
if (what != '') { who_what = [who, what].join(who_what_join); } else { who_what = who; }
} else {
who_what = what;
}
if (where == '') { return who_what; };
return [who_what, where].join(whowhat_where_join);
};
this.fuse = fuse;
// Creates a query string from combination and originals.
//
function querify(zipped) {
var query_parts = [];
var qualifier;
for (var i in zipped) {
qualifier = zipped[i][0];
qualifier = qualifiers[qualifier] || qualifier; // Use the returned qualifier if none is given.
query_parts[i] = qualifier + ':' + zipped[i][1];
};
return query_parts.join(' ');
};
this.querify = querify;
//
//
function suggestify(zipped) {
return fuse(trisect(zipped));
};
// Generates the text and the link.
//
var generate = function() {
this.query = querify(combination);
this.text = suggestify(combination);
return self;
};
//
//
var listItem = function(text, count) {
return $('' + text + '
' + count + '
');
};
var render = function(allocation) {
var combination = allocation.combination;
var type = allocation.type;
var count = allocation.count;
var query = querify(combination);
var item = listItem(suggestify(combination), count);
// TODO Move this outwards?
//
item.bind('click', { query: query }, allocationChosenCallback);
return item;
};
this.render = render;
};