mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-06-21 09:58:23 +02:00
add static files
This commit is contained in:
162
static/autocomplete_light/autocomplete.init.js
Normal file
162
static/autocomplete_light/autocomplete.init.js
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
This script garantees that this will be called once in django admin.
|
||||
However, its the callback's responsability to clean up if the
|
||||
element was cloned with data - which should be the case.
|
||||
*/
|
||||
|
||||
;(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;
|
||||
}
|
||||
|
||||
var initialized = [];
|
||||
|
||||
function initialize(element) {
|
||||
if (typeof element === 'undefined' || typeof element === 'number') {
|
||||
element = this;
|
||||
}
|
||||
|
||||
if (window.__dal__initListenerIsSet !== true || initialized.indexOf(element) >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(element).trigger('autocompleteLightInitialize');
|
||||
initialized.push(element);
|
||||
}
|
||||
|
||||
if (!window.__dal__initialize) {
|
||||
window.__dal__initialize = initialize;
|
||||
|
||||
$(document).ready(function () {
|
||||
$('[data-autocomplete-light-function=select2]:not([id*="__prefix__"])').each(initialize);
|
||||
});
|
||||
|
||||
$(document).bind('DOMNodeInserted', function (e) {
|
||||
$(e.target).find('[data-autocomplete-light-function=select2]').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;
|
||||
}
|
||||
}
|
||||
})(yl.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));
|
||||
}(yl.jQuery));
|
191
static/autocomplete_light/forward.js
Normal file
191
static/autocomplete_light/forward.js
Normal file
@ -0,0 +1,191 @@
|
||||
;(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);
|
||||
};
|
||||
|
||||
})(yl.jQuery, yl);
|
36
static/autocomplete_light/jquery.init.js
Normal file
36
static/autocomplete_light/jquery.init.js
Normal file
@ -0,0 +1,36 @@
|
||||
var yl = yl || {};
|
||||
if (typeof django !== 'undefined' && typeof django.jQuery !== 'undefined') {
|
||||
// If django.jQuery is already defined, use it.
|
||||
yl.jQuery = django.jQuery;
|
||||
}
|
||||
else {
|
||||
// We include jquery itself in our widget's media, because we need it.
|
||||
// Normally, we expect our widget's reference to admin/js/vendor/jquery/jquery.js
|
||||
// to be skipped, because django's own code has already included it.
|
||||
// However, if django.jQuery is NOT defined, we know that jquery was not
|
||||
// included before we did it ourselves. This can happen if we're not being
|
||||
// rendered in a django admin form.
|
||||
// However, someone ELSE'S jQuery may have been included before ours, in
|
||||
// which case we must ensure that our jquery doesn't override theirs, since
|
||||
// it might be a newer version that other code on the page relies on.
|
||||
// Thus, we must run jQuery.noConflict(true) here to move our jQuery out of
|
||||
// the way.
|
||||
yl.jQuery = jQuery.noConflict(true);
|
||||
}
|
||||
|
||||
// In addition to all of this, we must ensure that the global jQuery and $ are
|
||||
// defined, because Select2 requires that. jQuery will only be undefined at
|
||||
// this point if only we or django included it.
|
||||
if (typeof jQuery === 'undefined') {
|
||||
jQuery = yl.jQuery;
|
||||
$ = yl.jQuery;
|
||||
}
|
||||
else {
|
||||
// jQuery IS still defined, which means someone else also included jQuery.
|
||||
// In this situation, we need to store the old jQuery in a
|
||||
// temp variable, set the global jQuery to our yl.jQuery, then let select2
|
||||
// set itself up. We restore the global jQuery to its original value in
|
||||
// jquery.post-setup.js.
|
||||
dal_jquery_backup = jQuery.noConflict(true);
|
||||
jQuery = yl.jQuery;
|
||||
}
|
7
static/autocomplete_light/jquery.post-setup.js
Normal file
7
static/autocomplete_light/jquery.post-setup.js
Normal file
@ -0,0 +1,7 @@
|
||||
if (typeof dal_jquery_backup !== 'undefined') {
|
||||
// We made a backup of the original global jQuery before forcing it to our
|
||||
// yl.jQuery value. Now that select2 has been set up, we need to restore
|
||||
// our backup to its rightful place.
|
||||
jQuery = dal_jquery_backup;
|
||||
$ = dal_jquery_backup;
|
||||
}
|
14
static/autocomplete_light/select2.css
Normal file
14
static/autocomplete_light/select2.css
Normal file
@ -0,0 +1,14 @@
|
||||
.select2-container {
|
||||
min-width: 20em;
|
||||
}
|
||||
|
||||
ul li.select2-selection__choice,
|
||||
ul li.select2-search {
|
||||
/* Cancel out django's style */
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.errors .select2-selection {
|
||||
/* Highlight select box with error */
|
||||
border-color: #ba2121;
|
||||
}
|
122
static/autocomplete_light/select2.js
Normal file
122
static/autocomplete_light/select2.js
Normal file
@ -0,0 +1,122 @@
|
||||
;(function ($) {
|
||||
if (window.__dal__initListenerIsSet)
|
||||
return;
|
||||
|
||||
$(document).on('autocompleteLightInitialize', '[data-autocomplete-light-function=select2]', function() {
|
||||
var element = $(this);
|
||||
|
||||
// Templating helper
|
||||
function template(text, is_html) {
|
||||
if (is_html) {
|
||||
var $result = $('<span>');
|
||||
$result.html(text);
|
||||
return $result;
|
||||
} else {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
function result_template(item) {
|
||||
var text = template(item.text,
|
||||
element.attr('data-html') !== undefined || element.attr('data-result-html') !== undefined
|
||||
);
|
||||
|
||||
if (item.create_id) {
|
||||
return $('<span></span>').text(text).addClass('dal-create')
|
||||
} else {
|
||||
return text
|
||||
}
|
||||
}
|
||||
|
||||
function selected_template(item) {
|
||||
if (item.selected_text !== undefined) {
|
||||
return template(item.selected_text,
|
||||
element.attr('data-html') !== undefined || element.attr('data-selected-html') !== undefined
|
||||
);
|
||||
} else {
|
||||
return result_template(item);
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var ajax = null;
|
||||
if ($(this).attr('data-autocomplete-light-url')) {
|
||||
ajax = {
|
||||
url: $(this).attr('data-autocomplete-light-url'),
|
||||
dataType: 'json',
|
||||
delay: 250,
|
||||
|
||||
data: function (params) {
|
||||
var data = {
|
||||
q: params.term, // search term
|
||||
page: params.page,
|
||||
create: element.attr('data-autocomplete-light-create') && !element.attr('data-tags'),
|
||||
forward: yl.getForwards(element)
|
||||
};
|
||||
|
||||
return data;
|
||||
},
|
||||
processResults: function (data, page) {
|
||||
if (element.attr('data-tags')) {
|
||||
$.each(data.results, function(index, value) {
|
||||
value.id = value.text;
|
||||
});
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
cache: true
|
||||
};
|
||||
}
|
||||
|
||||
$(this).select2({
|
||||
tokenSeparators: element.attr('data-tags') ? [','] : null,
|
||||
debug: true,
|
||||
containerCssClass: ':all:',
|
||||
placeholder: element.attr('data-placeholder') || '',
|
||||
language: element.attr('data-autocomplete-light-language'),
|
||||
minimumInputLength: element.attr('data-minimum-input-length') || 0,
|
||||
allowClear: ! $(this).is('[required]'),
|
||||
templateResult: result_template,
|
||||
templateSelection: selected_template,
|
||||
ajax: ajax,
|
||||
tags: Boolean(element.attr('data-tags')),
|
||||
});
|
||||
|
||||
$(this).on('select2:selecting', function (e) {
|
||||
var data = e.params.args.data;
|
||||
|
||||
if (data.create_id !== true)
|
||||
return;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
var select = $(this);
|
||||
|
||||
$.ajax({
|
||||
url: $(this).attr('data-autocomplete-light-url'),
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
text: data.id,
|
||||
forward: yl.getForwards($(this))
|
||||
},
|
||||
beforeSend: function(xhr, settings) {
|
||||
xhr.setRequestHeader("X-CSRFToken", document.csrftoken);
|
||||
},
|
||||
success: function(data, textStatus, jqXHR ) {
|
||||
select.append(
|
||||
$('<option>', {value: data.id, text: data.text, selected: true})
|
||||
);
|
||||
select.trigger('change');
|
||||
select.select2('close');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
window.__dal__initListenerIsSet = true;
|
||||
$('[data-autocomplete-light-function=select2]:not([id*="__prefix__"])').each(function() {
|
||||
window.__dal__initialize(this);
|
||||
});
|
||||
})(yl.jQuery);
|
Reference in New Issue
Block a user