.
This commit is contained in:
@@ -0,0 +1,461 @@
|
||||
/*!
|
||||
* Django Autocomplete Light
|
||||
*/
|
||||
|
||||
var yl = yl || {};
|
||||
yl.functions = {};
|
||||
/**
|
||||
* Register your own JS function for DAL.
|
||||
*
|
||||
* @param name The name of your function. This should be the same as the widget
|
||||
* `autocomplete_function` property value.
|
||||
* @param func The callback that will initialize your custom autocomplete.
|
||||
*/
|
||||
yl.registerFunction = function (name, func) {
|
||||
if (this.functions.hasOwnProperty(name)) {
|
||||
// This function already exists to show an error and skip.
|
||||
console.error('The DAL function "' + name + '" has already been registered.');
|
||||
return
|
||||
}
|
||||
if (typeof func != 'function') {
|
||||
// It's not a function kill it.
|
||||
throw new Error('The custom DAL function must be a function.');
|
||||
}
|
||||
this.functions[name] = func;
|
||||
var event = new CustomEvent('dal-function-registered.' + name, {detail: {name: name, func: func}})
|
||||
window.dispatchEvent(event);
|
||||
};
|
||||
|
||||
|
||||
window.addEventListener("load", function () {
|
||||
|
||||
// Check if `django.jQuery` exists otherwise set `django.jQuery` to non namespaced jQuery.
|
||||
window.django = window.django || {};
|
||||
if (!django.hasOwnProperty('jQuery') && jQuery !== 'undefined') {
|
||||
django.jQuery = jQuery;
|
||||
}
|
||||
|
||||
(function ($) {
|
||||
$.fn.getFormPrefix = function () {
|
||||
/* Get the form prefix for a field.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* $(':input[name$=owner]').getFormsetPrefix()
|
||||
*
|
||||
* Would return an empty string for an input with name 'owner' but would return
|
||||
* 'inline_model-0-' for an input named 'inline_model-0-owner'.
|
||||
*/
|
||||
var parts = $(this).attr('name').split('-');
|
||||
var prefix = '';
|
||||
|
||||
for (var i in parts) {
|
||||
var testPrefix = parts.slice(0, -i).join('-');
|
||||
if (!testPrefix.length) continue;
|
||||
testPrefix += '-';
|
||||
|
||||
var result = $(':input[name^=' + testPrefix + ']')
|
||||
|
||||
if (result.length) {
|
||||
return testPrefix;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
$.fn.getFormPrefixes = function () {
|
||||
/*
|
||||
* Get the form prefixes for a field, from the most specific to the least.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* $(':input[name$=owner]').getFormPrefixes()
|
||||
*
|
||||
* Would return:
|
||||
* - [''] for an input named 'owner'.
|
||||
* - ['inline_model-0-', ''] for an input named 'inline_model-0-owner' (i.e. nested with a nested inline).
|
||||
* - ['sections-0-items-0-', 'sections-0-', ''] for an input named 'sections-0-items-0-product'
|
||||
* (i.e. nested multiple time with django-nested-admin).
|
||||
*/
|
||||
var parts = $(this).attr('name').split('-').slice(0, -1);
|
||||
var prefixes = [];
|
||||
|
||||
for (i = 0; i < parts.length; i += 2) {
|
||||
var testPrefix = parts.slice(0, -i || parts.length).join('-');
|
||||
if (!testPrefix.length)
|
||||
continue;
|
||||
|
||||
testPrefix += '-';
|
||||
|
||||
var result = $(':input[name^=' + testPrefix + ']')
|
||||
|
||||
if (result.length)
|
||||
prefixes.push(testPrefix);
|
||||
}
|
||||
|
||||
prefixes.push('');
|
||||
|
||||
return prefixes;
|
||||
}
|
||||
|
||||
/*
|
||||
* This ensures the Language file is loaded and passes it our jQuery.
|
||||
*/
|
||||
if (typeof dalLoadLanguage !== 'undefined') {
|
||||
dalLoadLanguage($);
|
||||
} else {
|
||||
document.addEventListener('dal-language-loaded', function (e) {
|
||||
// `e.lang` is the language that was loaded.
|
||||
dalLoadLanguage($);
|
||||
})
|
||||
}
|
||||
|
||||
// Fire init event for yl.registerFunction() execution.
|
||||
var event = new CustomEvent('dal-init-function');
|
||||
document.dispatchEvent(event);
|
||||
|
||||
var initialized = [];
|
||||
|
||||
$.fn.excludeTemplateForms = function() {
|
||||
// exclude elements that contain '__prefix__' in their id
|
||||
// these are used by django formsets for template forms
|
||||
return this.not('[id*=__prefix__]').filter(function() {
|
||||
// exclude elements that contain '-empty-' in their ids
|
||||
// these are used by django-nested-admin for nested template formsets
|
||||
// note that the filter also ensures that 'empty' is not actually the related_name for some relation
|
||||
// by ensuring that it is not surrounded by numbers on both sides
|
||||
return !this.id.match(/(?<!-\d+)-empty-(?!\d+-)/);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a field element. This function calls the registered init function
|
||||
* and ensures that the element is only initialized once.
|
||||
*
|
||||
* @param element The field to be initialized
|
||||
*/
|
||||
function initialize(element) {
|
||||
if (typeof element === 'undefined' || typeof element === 'number') {
|
||||
element = this;
|
||||
}
|
||||
|
||||
// Ensure element is not already initialized.
|
||||
if (initialized.indexOf(element) >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The DAL function to execute.
|
||||
var dalFunction = $(element).attr('data-autocomplete-light-function');
|
||||
|
||||
if (yl.functions.hasOwnProperty(dalFunction) && typeof yl.functions[dalFunction] == 'function') {
|
||||
// If the function has been registered call it.
|
||||
yl.functions[dalFunction]($, element);
|
||||
} else if (yl.functions.hasOwnProperty(dalFunction)) {
|
||||
// If the function exists but has not been registered wait for it to be registered.
|
||||
window.addEventListener('dal-function-registered.' + dalFunction, function (e) {
|
||||
yl.functions[dalFunction]($, element);
|
||||
})
|
||||
} else {
|
||||
// Otherwise notify that the function should be registered.
|
||||
console.warn('Your custom DAL function "' + dalFunction + '" uses a deprecated event listener that will be removed in future versions. https://django-autocomplete-light.readthedocs.io/en/master/tutorial.html#overriding-javascript-code')
|
||||
}
|
||||
|
||||
// Fire init event for custom function execution.
|
||||
// DEPRECATED
|
||||
$(element).trigger('autocompleteLightInitialize');
|
||||
|
||||
// Add element to the array of already initialized fields
|
||||
initialized.push(element);
|
||||
}
|
||||
|
||||
if (!window.__dal__initialize) {
|
||||
window.__dal__initialize = initialize;
|
||||
|
||||
$(document).ready(function () {
|
||||
$('[data-autocomplete-light-function]').excludeTemplateForms().each(initialize);
|
||||
});
|
||||
|
||||
if ('MutationObserver' in window) {
|
||||
new MutationObserver(function (mutations) {
|
||||
var mutationRecord;
|
||||
var addedNode;
|
||||
|
||||
for (var i = 0; i < mutations.length; i++) {
|
||||
mutationRecord = mutations[i];
|
||||
|
||||
if (mutationRecord.addedNodes.length > 0) {
|
||||
for (var j = 0; j < mutationRecord.addedNodes.length; j++) {
|
||||
addedNode = mutationRecord.addedNodes[j];
|
||||
|
||||
$(addedNode).find('[data-autocomplete-light-function]').excludeTemplateForms().each(initialize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}).observe(document.documentElement, {childList: true, subtree: true});
|
||||
} else {
|
||||
$(document).on('DOMNodeInserted', function (e) {
|
||||
$(e.target).find('[data-autocomplete-light-function]').excludeTemplateForms().each(initialize);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// using jQuery
|
||||
function getCookie(name) {
|
||||
var cookieValue = null;
|
||||
if (document.cookie && document.cookie != '') {
|
||||
var cookies = document.cookie.split(';');
|
||||
for (var i = 0; i < cookies.length; i++) {
|
||||
var cookie = $.trim(cookies[i]);
|
||||
// Does this cookie string begin with the name we want?
|
||||
if (cookie.substring(0, name.length + 1) == (name + '=')) {
|
||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cookieValue;
|
||||
}
|
||||
|
||||
document.csrftoken = getCookie('csrftoken');
|
||||
if (document.csrftoken === null) {
|
||||
// Try to get CSRF token from DOM when cookie is missing
|
||||
var $csrf = $('form :input[name="csrfmiddlewaretoken"]');
|
||||
if ($csrf.length > 0) {
|
||||
document.csrftoken = $csrf[0].value;
|
||||
}
|
||||
}
|
||||
})(django.jQuery);
|
||||
|
||||
// Does the same thing as django's admin/js/autocomplete.js, but uses yl.jQuery.
|
||||
(function ($) {
|
||||
'use strict';
|
||||
var init = function ($element, options) {
|
||||
var settings = $.extend({
|
||||
ajax: {
|
||||
data: function (params) {
|
||||
return {
|
||||
term: params.term,
|
||||
page: params.page
|
||||
};
|
||||
}
|
||||
}
|
||||
}, options);
|
||||
$element.select2(settings);
|
||||
};
|
||||
|
||||
$.fn.djangoAdminSelect2 = function (options) {
|
||||
var settings = $.extend({}, options);
|
||||
$.each(this, function (i, element) {
|
||||
var $element = $(element);
|
||||
init($element, settings);
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
$(function () {
|
||||
// Initialize all autocomplete widgets except the one in the template
|
||||
// form used when a new formset is added.
|
||||
$('.admin-autocomplete').not('[name*=__prefix__]').djangoAdminSelect2();
|
||||
});
|
||||
|
||||
$(document).on('formset:added', (function () {
|
||||
return function (event, $newFormset) {
|
||||
return $newFormset.find('.admin-autocomplete').djangoAdminSelect2();
|
||||
};
|
||||
})(this));
|
||||
}(django.jQuery));
|
||||
|
||||
(function ($, yl) {
|
||||
yl.forwardHandlerRegistry = yl.forwardHandlerRegistry || {};
|
||||
|
||||
yl.registerForwardHandler = function (name, handler) {
|
||||
yl.forwardHandlerRegistry[name] = handler;
|
||||
};
|
||||
|
||||
yl.getForwardHandler = function (name) {
|
||||
return yl.forwardHandlerRegistry[name];
|
||||
};
|
||||
|
||||
function getForwardStrategy(element) {
|
||||
var checkForCheckboxes = function () {
|
||||
var all = true;
|
||||
$.each(element, function (ix, e) {
|
||||
if ($(e).attr("type") !== "checkbox") {
|
||||
all = false;
|
||||
}
|
||||
});
|
||||
return all;
|
||||
};
|
||||
|
||||
if (element.length === 1 &&
|
||||
element.attr("type") === "checkbox" &&
|
||||
element.attr("value") === undefined) {
|
||||
// Single checkbox without 'value' attribute
|
||||
// Boolean field
|
||||
return "exists";
|
||||
} else if (element.length === 1 &&
|
||||
element.attr("multiple") !== undefined) {
|
||||
// Multiple by HTML semantics. E. g. multiple select
|
||||
// Multiple choice field
|
||||
return "multiple";
|
||||
} else if (checkForCheckboxes()) {
|
||||
// Multiple checkboxes or one checkbox with 'value' attribute.
|
||||
// Multiple choice field represented by checkboxes
|
||||
return "multiple";
|
||||
} else {
|
||||
// Other cases
|
||||
return "single";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fields with name `name` relative to `element` with considering form
|
||||
* prefixes.
|
||||
* @param element the element
|
||||
* @param name name of the field
|
||||
* @returns jQuery object with found fields or empty jQuery object if no
|
||||
* field was found
|
||||
*/
|
||||
yl.getFieldRelativeTo = function (element, name) {
|
||||
var prefixes = $(element).getFormPrefixes();
|
||||
|
||||
for (var i = 0; i < prefixes.length; i++) {
|
||||
var fieldSelector = "[name=" + prefixes[i] + name + "]";
|
||||
var field = $(fieldSelector);
|
||||
|
||||
if (field.length) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
return $();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get field value which is put to forwarded dictionary
|
||||
* @param field the field
|
||||
* @returns forwarded value
|
||||
*/
|
||||
yl.getValueFromField = function (field) {
|
||||
var strategy = getForwardStrategy(field);
|
||||
var serializedField = $(field).serializeArray();
|
||||
|
||||
if ((serializedField == false) && ($(field).prop('disabled'))) {
|
||||
$(field).prop('disabled', false);
|
||||
serializedField = $(field).serializeArray();
|
||||
$(field).prop('disabled', true);
|
||||
}
|
||||
|
||||
var getSerializedFieldElementAt = function (index) {
|
||||
// Return serializedField[index]
|
||||
// or null if something went wrong
|
||||
if (serializedField.length > index) {
|
||||
return serializedField[index];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
var getValueOf = function (elem) {
|
||||
// Return elem.value
|
||||
// or null if something went wrong
|
||||
if (elem.hasOwnProperty("value") &&
|
||||
elem.value !== undefined
|
||||
) {
|
||||
return elem.value;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
var getSerializedFieldValueAt = function (index) {
|
||||
// Return serializedField[index].value
|
||||
// or null if something went wrong
|
||||
var elem = getSerializedFieldElementAt(index);
|
||||
if (elem !== null) {
|
||||
return getValueOf(elem);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
if (strategy === "multiple") {
|
||||
return serializedField.map(
|
||||
function (item) {
|
||||
return getValueOf(item);
|
||||
}
|
||||
);
|
||||
} else if (strategy === "exists") {
|
||||
return serializedField.length > 0;
|
||||
} else {
|
||||
return getSerializedFieldValueAt(0);
|
||||
}
|
||||
};
|
||||
|
||||
yl.getForwards = function (element) {
|
||||
var forwardElem,
|
||||
forwardList,
|
||||
forwardedData,
|
||||
divSelector,
|
||||
form;
|
||||
divSelector = "div.dal-forward-conf#dal-forward-conf-for-" +
|
||||
element.attr("id") + ", " +
|
||||
"div.dal-forward-conf#dal-forward-conf-for_" +
|
||||
element.attr("id");
|
||||
form = element.length > 0 ? $(element[0].form) : $();
|
||||
|
||||
forwardElem =
|
||||
form.find(divSelector).find('script');
|
||||
if (forwardElem.length === 0) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
forwardList = JSON.parse(forwardElem.text());
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Array.isArray(forwardList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
forwardedData = {};
|
||||
|
||||
$.each(forwardList, function (ix, field) {
|
||||
var srcName, dstName;
|
||||
if (field.type === "const") {
|
||||
forwardedData[field.dst] = field.val;
|
||||
} else if (field.type === "self") {
|
||||
if (field.hasOwnProperty("dst")) {
|
||||
dstName = field.dst;
|
||||
} else {
|
||||
dstName = "self";
|
||||
}
|
||||
forwardedData[dstName] = yl.getValueFromField(element);
|
||||
} else if (field.type === "field") {
|
||||
srcName = field.src;
|
||||
if (field.hasOwnProperty("dst")) {
|
||||
dstName = field.dst;
|
||||
} else {
|
||||
dstName = srcName;
|
||||
}
|
||||
var forwardedField = yl.getFieldRelativeTo(element, srcName);
|
||||
|
||||
if (!forwardedField.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
forwardedData[dstName] = yl.getValueFromField(forwardedField);
|
||||
} else if (field.type === "javascript") {
|
||||
var handler = yl.getForwardHandler(field.handler);
|
||||
forwardedData[field.dst || field.handler] = handler(element);
|
||||
}
|
||||
|
||||
});
|
||||
return JSON.stringify(forwardedData);
|
||||
};
|
||||
|
||||
})(django.jQuery, yl);
|
||||
});
|
||||
Reference in New Issue
Block a user