Skip to content

Instantly share code, notes, and snippets.

@lorawoodford
Created May 12, 2020 18:34
Show Gist options
  • Save lorawoodford/69cf61d3ea0bae72dc1d6f9297d935bd to your computer and use it in GitHub Desktop.
Save lorawoodford/69cf61d3ea0bae72dc1d6f9297d935bd to your computer and use it in GitHub Desktop.
ANW-700 draft
//= require jquery.tokeninput
$(function() {
$.fn.linker = function() {
$(this).each(function() {
var $this = $(this);
var $linkerWrapper = $this.parents(".linker-wrapper:first");
if ($this.hasClass("initialised")) {
return;
}
$this.addClass("initialised");
// this is a bit hacky, but we need to have some input fields present in
// the form so we don't have to rely on the linker to make sure data
// presists. we can remove those after the linker does its thing.
$(".prelinker", $linkerWrapper).remove();
var config = {
url: decodeURIComponent($this.data("url")),
browse_url: decodeURIComponent($this.data("browse-url")),
span_class: $this.data("span-class"),
format_template: $this.data("format_template"),
format_template_id: $this.data("format_template_id"),
format_property: $this.data("format_property"),
path: $this.data("path"),
name: $this.data("name"),
multiplicity: $this.data("multiplicity") || "many",
label: $this.data("label"),
label_plural: $this.data("label_plural"),
modal_id: $this.data("modal_id") || ($this.attr("id") + "_modal"),
sortable: $this.data("sortable") === true,
types: $this.data("types"),
exclude_ids: $this.data("exclude") || []
};
config.allow_multiple = config.multiplicity === "many";
if (config.format_template && config.format_template.substring(0,2) != "${") {
config.format_template = "${" + config.format_template + "}";
}
var renderCreateFormForObject = function(form_uri) {
var $modal = $("#"+config.modal_id);
var initCreateForm = function(formEl) {
$(".linker-container", $modal).html(formEl);
$("#createAndLinkButton", $modal).removeAttr("disabled");
$("form", $modal).ajaxForm({
data: {
inline: true
},
beforeSubmit: function() {
$("#createAndLinkButton", $modal).attr("disabled","disabled");
},
success: function(response, status, xhr) {
if ($(response).is("form")) {
initCreateForm(response);
} else {
if (config.multiplicity === "one") {
clearTokens();
}
$this.tokenInput("add", {
id: response.uri,
name: response.display_string || response.title,
json: response
});
$this.triggerHandler("change");
$modal.modal("hide");
}
},
error: function(obj, errorText, errorDesc) {
$("#createAndLinkButton", $modal).removeAttr("disabled");
}
});
$modal.scrollTo(".alert");
$modal.trigger("resize");
$(document).triggerHandler("loadedrecordform.aspace", [$modal]);
};
$.ajax({
url: form_uri,
success: initCreateForm
});
$("#createAndLinkButton", $modal).click(function() {
$("form", $modal).triggerHandler("submit");
});
};
var showLinkerCreateModal = function() {
AS.openCustomModal(config.modal_id, "Create "+ config.label, AS.renderTemplate("linker_createmodal_template", config), 'large', {}, this);
if ($(this).hasClass("linker-create-btn")) {
renderCreateFormForObject($(this).data("target"));
} else {
renderCreateFormForObject($(".linker-create-btn:first", $linkerWrapper).data("target"));
}
return false; // IE8 patch
};
var initAndShowLinkerBrowseModal = function() {
var currentlySelected = {};
var renderItemsInModal = function(page) {
$.each($this.tokenInput("get"), function() {
currentlySelected[this.id] = this.json;
});
$.ajax({
url: config.browse_url,
data: {
page: 1,
type: config.types,
linker: true,
exclude: config.exclude_ids,
multiplicity: config.multiplicity
},
type: "GET",
dataType: "html",
success: function(html) {
var $modal = $("#"+config.modal_id);
var $linkerBrowseContainer = $(".linker-container", $modal);
var initBrowseFormInputs = function() {
// add some click handlers to allow clicking of the row
$(":input[name=linker-item]", $linkerBrowseContainer).each(function() {
var $input = $(this);
$input.click(function(event) {
event.stopPropagation();
// If one-to-one, currentlySelected should only ever
// contain one record
if (!config.allow_multiple) {
currentlySelected = {};
$("tr.selected", $input.closest("table")).removeClass("selected");
}
if (currentlySelected.hasOwnProperty($input.val())) {
// remove from the list
delete currentlySelected[$input.val()];
$input.closest("tr").removeClass("selected");
} else {
// add to the selected list
currentlySelected[$input.val()] = $input.data("object");
$input.closest("tr").addClass("selected");
}
});
$("td", $input.closest("tr")).click(function(event) {
event.preventDefault();
$input.trigger("click");
});
});
// select a result if it's currently a selected record
$.each(currentlySelected, function(uri) {
$(":input[value='"+uri+"']", $linkerBrowseContainer)
.attr("checked","checked")
.closest("tr").addClass("selected");
});
$modal.trigger("resize");
};
$linkerBrowseContainer.html(html);
$($linkerBrowseContainer).on("click", "a", function(event) {
event.preventDefault();
$linkerBrowseContainer.load(event.target.href, initBrowseFormInputs);
});
$($linkerBrowseContainer).on("submit", "form", function(event) {
event.preventDefault();
var $form = $(event.target);
var method = ($form.attr("method") || "get").toUpperCase();
if (method == "POST") {
jQuery.post($form.attr("action") + ".js",
$form.serializeArray(),
function(html) {
$linkerBrowseContainer.html(html);
initBrowseFormInputs();
});
} else {
$linkerBrowseContainer.load($form.attr("action") + ".js?" + $form.serialize(), initBrowseFormInputs);
}
});
initBrowseFormInputs();
}
});
};
var addSelected = function() {
selectedItems = [];
$(".token-input-delete-token", $linkerWrapper).each(function() {
$(this).triggerHandler("click");
});
$.each(currentlySelected, function(uri, object) {
$this.tokenInput("add", {
id: uri,
name: object.display_string || object.title,
json: object
});
});
$("#"+config.modal_id).modal('hide');
$this.triggerHandler("change");
};
AS.openCustomModal(config.modal_id, "Browse "+ config.label_plural, AS.renderTemplate("linker_browsemodal_template",config), 'large', {}, this);
renderItemsInModal();
$("#"+config.modal_id).on("click","#addSelectedButton", addSelected);
$("#"+config.modal_id).on("click", ".linker-list .pagination .navigation a", function() {
renderItemsInModal($(this).attr("rel"));
});
return false; // IE patch
};
var formatResults = function(searchData) {
var formattedResults = [];
var currentlySelectedIds = [];
$.each($this.tokenInput("get"), function(obj) {currentlySelectedIds.push(obj.id);});
$.each(searchData.search_data.results, function(index, obj) {
// only allow selection of unselected items
if ($.inArray(obj.uri, currentlySelectedIds) === -1) {
formattedResults.push({
name: (obj.four_part_id !== undefined ? obj.four_part_id + ": " : '') + (obj.display_string || obj.title),
id: obj.id,
json: obj
});
}
});
return formattedResults;
};
var addEventBindings = function() {
$(".linker-browse-btn", $linkerWrapper).on("click", initAndShowLinkerBrowseModal);
$(".linker-create-btn", $linkerWrapper).on("click", showLinkerCreateModal);
// Initialise popover on demand to improve performance
$linkerWrapper.one("mouseenter focus", ".has-popover", function() {
$(document).triggerHandler("init.popovers", [$this.parent()]);
});
};
var clearTokens = function() {
// as tokenInput plugin won't clear a token
// if it has an input.. remove all inputs first!
var $tokenList = $(".token-input-list", $this.parent());
for (var i=0; i<$this.tokenInput("get").length; i++) {
var id_to_remove = $this.tokenInput("get")[i].id.replace(/\//g,"_");
$("#"+id_to_remove + " :input", $tokenList).remove();
}
$this.tokenInput("clear");
};
var enableSorting = function() {
if ($(".token-input-list", $linkerWrapper).data("sortable")) {
$(".token-input-list", $linkerWrapper).sortable("destroy");
}
$(".token-input-list", $linkerWrapper).sortable({
items: 'li.token-input-token'
});
$(".token-input-list", $linkerWrapper).off("sortupdate").on("sortupdate", function() {
$this.parents("form:first").triggerHandler("formchanged.aspace");
});
};
var tokensForPrepopulation = function() {
if ($this.data("multiplicity") === "one") {
if ($.isEmptyObject($this.data("selected"))) {
return [];
}
return [{
id: $this.data("selected").uri,
name: ($this.data("selected").id_0 !== undefined ? $this.data("selected").id_0 : '')
+ ($this.data("selected").id_1 !== undefined ? "." + $this.data("selected").id_1 : '')
+ ($this.data("selected").id_2 !== undefined ? "." + $this.data("selected").id_2 : '')
+ ($this.data("selected").id_3 !== undefined ? "." + $this.data("selected").id_3 : '')
+ ($this.data("selected").id_0 !== undefined ? ": " : '')
+ ($this.data("selected").display_string || $this.data("selected").title),
json: $this.data("selected")
}];
} else {
if (!$this.data("selected") || $this.data("selected").length === 0) {
return [];
}
return $this.data("selected").map(function(item) {
if (typeof item == 'string') {
item = JSON.parse(item);
}
return {
id: item.uri,
name: item.display_string || item.title,
json: item
};
});
}
};
// ANW-521: For subjects, we want to have specialized icons based on the subjects' term type.
var tag_subjects_by_term_type = function(obj) {
if(obj.json.jsonmodel_type == "subject") {
switch(obj.json.first_term_type) {
case "cultural_context":
return "subject_type_cultural_context";
case "function":
return "subject_type_function";
case "genre_form":
return "subject_type_genre_form";
case "geographic":
return "subject_type_geographic";
case "occupation":
return "subject_type_occupation";
case "style_period":
return "subject_type_style_period";
case "technique":
return "subject_type_technique";
case "temporal":
return "subject_type_temporal";
case "topical":
return "subject_type_topical";
case "uniform_title":
return "subject_type_uniform_title";
default:
return "";
}
}
else {
return "";
}
};
var init = function() {
var tokenInputConfig = $.extend({}, AS.linker_locales, {
animateDropdown: false,
preventDuplicates: true,
allowFreeTagging: false,
tokenLimit: (config.multiplicity==="one"? 1 :null),
caching: false,
onCachedResult: formatResults,
onResult: formatResults,
zindex: 1100,
tokenFormatter: function(item) {
var tokenEl = $(AS.renderTemplate("linker_selectedtoken_template", {item: item, config: config}));
tokenEl.children("div").children(".icon-token").addClass(config.span_class);
$("input[name*=resolved]", tokenEl).val(JSON.stringify(item.json));
return tokenEl;
},
resultsFormatter: function(item) {
var string = item.name;
var $resultSpan = $("<span class='"+ item.json.jsonmodel_type + "'>");
var extra_class = tag_subjects_by_term_type(item);
$resultSpan.text(string);
$resultSpan.prepend("<span class='icon-token " + extra_class + "'></span>");
var $resultLi = $("<li>");
$resultLi.append($resultSpan);
return $resultLi[0].outerHTML;
},
prePopulate: tokensForPrepopulation(),
onDelete: function() {
$this.triggerHandler("change");
},
onAdd: function(item) {
// ANW-521: After adding a subject, find the added node and apply the special class for that node.
var extra_class = tag_subjects_by_term_type(item);
var added_node_id = "#" + item.id.replace(/\//g, "_");
added_node = $(added_node_id);
added_node.children("div").children(".icon-token").addClass(extra_class);
if (config.sortable && config.allow_multiple) {
enableSorting();
}
// $this.triggerHandler("change");
$(document).triggerHandler("init.popovers", [$this.parent()]);
},
formatQueryParam: function(q, ajax_params) {
if ($this.tokenInput("get").length > 0 || config.exclude_ids.length > 0) {
var currentlySelectedIds = $.merge([], config.exclude_ids);
$.each($this.tokenInput("get"), function(i, obj) {currentlySelectedIds.push(obj.id);});
ajax_params.data["exclude[]"] = currentlySelectedIds;
}
if (config.types && config.types.length > 0) {
ajax_params.data["type"] = config.types;
}
return (q+"*").toLowerCase();
}
});
setTimeout(function() {
$this.tokenInput(config.url, tokenInputConfig);
$("> :input[type=text]", $(".token-input-input-token", $this.parent())).attr("placeholder", AS.linker_locales.hintText).attr("aria-label", config.label);
$("> :input[type=text]", $(".token-input-input-token", $this.parent())).addClass('form-control');
$this.parent().addClass("multiplicity-"+config.multiplicity);
if (config.sortable && config.allow_multiple) {
enableSorting();
$linkerWrapper.addClass("sortable");
}
});
addEventBindings();
};
init();
});
};
});
$(document).ready(function() {
$(document).bind("loadedrecordsubforms.aspace", function(event, $container) {
$(".linker-wrapper:visible > .linker:not(.initialised)", $container).linker();
// we can go ahead and init dropdowns ( such as those in the toolbars )
$("#archives_tree_toolbar .linker:not(.initialised)").linker();
});
$(document).bind("subrecordcreated.aspace", function(event, object_name, subform) {
$(".linker:not(.initialised)", subform).linker();
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment