summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrey Hunner <trey@treyhunner.com>2015-04-27 21:12:31 -0700
committerTim Graham <timograham@gmail.com>2015-06-27 16:36:26 -0400
commitec4f219ecb7a5e43d0353633fac4dac42d0ee492 (patch)
tree149080086a963899ec8ca36f7ad8e086f81ce521
parent1e63652e44f1c12c6e0fec6dacfae0c865b7cdbf (diff)
downloaddjango-ec4f219ecb7a5e43d0353633fac4dac42d0ee492.tar.gz
Fixed #22463 -- Added code style guide and JavaScript linting (EditorConfig and ESLint)
-rw-r--r--.editorconfig37
-rw-r--r--.eslintignore3
-rw-r--r--.eslintrc51
-rw-r--r--.gitignore1
-rw-r--r--django/contrib/admin/static/admin/js/SelectBox.js17
-rw-r--r--django/contrib/admin/static/admin/js/SelectFilter2.js365
-rw-r--r--django/contrib/admin/static/admin/js/actions.js283
-rw-r--r--django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js69
-rw-r--r--django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js23
-rw-r--r--django/contrib/admin/static/admin/js/calendar.js41
-rw-r--r--django/contrib/admin/static/admin/js/collapse.js45
-rw-r--r--django/contrib/admin/static/admin/js/collapse.min.js4
-rw-r--r--django/contrib/admin/static/admin/js/core.js57
-rw-r--r--django/contrib/admin/static/admin/js/inlines.js471
-rw-r--r--django/contrib/admin/static/admin/js/inlines.min.js18
-rw-r--r--django/contrib/admin/static/admin/js/jquery.init.js1
-rw-r--r--django/contrib/admin/static/admin/js/prepopulate.js1
-rw-r--r--django/contrib/admin/static/admin/js/prepopulate.min.js2
-rw-r--r--django/contrib/admin/static/admin/js/timeparse.js14
-rw-r--r--django/contrib/gis/static/gis/js/OLMapWidget.js42
-rw-r--r--django/contrib/gis/templates/gis/admin/openlayers.js180
-rw-r--r--docs/internals/contributing/writing-code/coding-style.txt12
-rw-r--r--docs/internals/contributing/writing-code/index.txt1
-rw-r--r--docs/internals/contributing/writing-code/javascript.txt64
-rw-r--r--docs/internals/contributing/writing-code/submitting-patches.txt37
-rw-r--r--package.json10
26 files changed, 1007 insertions, 842 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000..30d6fcc1e3
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,37 @@
+# http://editorconfig.org
+
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+insert_final_newline = true
+trim_trailing_whitespace = true
+end_of_line = lf
+charset = utf-8
+
+# Use 2 spaces for the HTML files
+[*.html]
+indent_size = 2
+
+# The JSON files contain newlines inconsistently
+[*.json]
+indent_size = 2
+insert_final_newline = ignore
+
+[**/admin/js/vendor/**]
+indent_style = ignore
+indent_size = ignore
+
+# Minified JavaScript files shouldn't be changed
+[**.min.js]
+indent_style = ignore
+insert_final_newline = ignore
+
+# Makefiles always use tabs for indentation
+[Makefile]
+indent_style = tab
+
+# Batch files use tabs for indentation
+[*.bat]
+indent_style = tab
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000000..cb0447577b
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,3 @@
+**/{*.min,jquery}.js
+django/contrib/gis/templates/**/*.js
+node_modules/**.js
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000000..4d8f385896
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,51 @@
+{
+ "rules": {
+ "camelcase": [1, {"properties": "always"}],
+ "comma-spacing": [1, {"before": false, "after": true}],
+ "dot-notation": [1, {"allowKeywords": true}],
+ "curly": [1, "all"],
+ "indent": [
+ 2,
+ 4
+ ],
+ "key-spacing": [1, {
+ "beforeColon": false,
+ "afterColon": true
+ }],
+ "new-cap": [1, {"newIsCap": true, "capIsNew": true}],
+ "no-alert": [0],
+ "no-eval": [1],
+ "no-extend-native": [2, {"exceptions": ["Date", "String"]}],
+ "no-multi-spaces": [1],
+ "no-octal-escape": [1],
+ "no-underscore-dangle": [1],
+ "no-unused-vars": [2, {"vars": "local", "args": "none"}],
+ "no-script-url": [1],
+ "no-shadow": [1, {"hoist": "functions"}],
+ "quotes": [
+ 1,
+ "single"
+ ],
+ "linebreak-style": [
+ 2,
+ "unix"
+ ],
+ "semi": [
+ 2,
+ "always"
+ ],
+ "space-before-blocks": [2, "always"],
+ "space-before-function-paren": [1, {"anonymous": "always", "named": "never"}],
+ "space-infix-ops": [
+ 1,
+ {"int32Hint": false}
+ ],
+ "strict": [1, "function"]
+ },
+ "env": {
+ "browser": true
+ },
+ "globals": {
+ "django": false
+ }
+} \ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 5f1338f232..e873831f50 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ MANIFEST
dist/
docs/_build/
docs/locale/
+node_modules/
tests/coverage_html/
tests/.coverage
build/
diff --git a/django/contrib/admin/static/admin/js/SelectBox.js b/django/contrib/admin/static/admin/js/SelectBox.js
index db3206ccf5..bbd30a2c58 100644
--- a/django/contrib/admin/static/admin/js/SelectBox.js
+++ b/django/contrib/admin/static/admin/js/SelectBox.js
@@ -1,9 +1,10 @@
+/*eslint no-cond-assign:1*/
var SelectBox = {
- cache: new Object(),
+ cache: {},
init: function(id) {
var box = document.getElementById(id);
var node;
- SelectBox.cache[id] = new Array();
+ SelectBox.cache[id] = [];
var cache = SelectBox.cache[id];
for (var i = 0; (node = box.options[i]); i++) {
cache.push({value: node.value, text: node.text, displayed: 1});
@@ -31,7 +32,7 @@ var SelectBox = {
for (var i = 0; (node = SelectBox.cache[id][i]); i++) {
node.displayed = 1;
for (var j = 0; (token = tokens[j]); j++) {
- if (node.text.toLowerCase().indexOf(token) == -1) {
+ if (node.text.toLowerCase().indexOf(token) === -1) {
node.displayed = 0;
}
}
@@ -41,13 +42,13 @@ var SelectBox = {
delete_from_cache: function(id, value) {
var node, delete_index = null;
for (var i = 0; (node = SelectBox.cache[id][i]); i++) {
- if (node.value == value) {
+ if (node.value === value) {
delete_index = i;
break;
}
}
var j = SelectBox.cache[id].length - 1;
- for (var i = delete_index; i < j; i++) {
+ for (i = delete_index; i < j; i++) {
SelectBox.cache[id][i] = SelectBox.cache[id][i+1];
}
SelectBox.cache[id].length--;
@@ -59,7 +60,7 @@ var SelectBox = {
// Check if an item is contained in the cache
var node;
for (var i = 0; (node = SelectBox.cache[id][i]); i++) {
- if (node.value == value) {
+ if (node.value === value) {
return true;
}
}
@@ -67,7 +68,6 @@ var SelectBox = {
},
move: function(from, to) {
var from_box = document.getElementById(from);
- var to_box = document.getElementById(to);
var option;
for (var i = 0; (option = from_box.options[i]); i++) {
if (option.selected && SelectBox.cache_contains(from, option.value)) {
@@ -80,7 +80,6 @@ var SelectBox = {
},
move_all: function(from, to) {
var from_box = document.getElementById(from);
- var to_box = document.getElementById(to);
var option;
for (var i = 0; (option = from_box.options[i]); i++) {
if (SelectBox.cache_contains(from, option.value)) {
@@ -111,4 +110,4 @@ var SelectBox = {
box.options[i].selected = 'selected';
}
}
-}
+};
diff --git a/django/contrib/admin/static/admin/js/SelectFilter2.js b/django/contrib/admin/static/admin/js/SelectFilter2.js
index 8f417dd9df..f8aba12fd6 100644
--- a/django/contrib/admin/static/admin/js/SelectFilter2.js
+++ b/django/contrib/admin/static/admin/js/SelectFilter2.js
@@ -1,196 +1,197 @@
+/*global SelectBox, addEvent, gettext, interpolate, quickElement, SelectFilter*/
/*
SelectFilter2 - Turns a multiple-select box into a filter interface.
Requires core.js, SelectBox.js and addevent.js.
*/
(function($) {
-function findForm(node) {
- // returns the node of the form containing the given node
- if (node.tagName.toLowerCase() != 'form') {
- return findForm(node.parentNode);
- }
- return node;
-}
-
-window.SelectFilter = {
- init: function(field_id, field_name, is_stacked) {
- if (field_id.match(/__prefix__/)){
- // Don't initialize on empty forms.
- return;
- }
- var from_box = document.getElementById(field_id);
- from_box.id += '_from'; // change its ID
- from_box.className = 'filtered';
-
- var ps = from_box.parentNode.getElementsByTagName('p');
- for (var i=0; i<ps.length; i++) {
- if (ps[i].className.indexOf("info") != -1) {
- // Remove <p class="info">, because it just gets in the way.
- from_box.parentNode.removeChild(ps[i]);
- } else if (ps[i].className.indexOf("help") != -1) {
- // Move help text up to the top so it isn't below the select
- // boxes or wrapped off on the side to the right of the add
- // button:
- from_box.parentNode.insertBefore(ps[i], from_box.parentNode.firstChild);
- }
+ function findForm(node) {
+ // returns the node of the form containing the given node
+ if (node.tagName.toLowerCase() !== 'form') {
+ return findForm(node.parentNode);
}
+ return node;
+ }
- // <div class="selector"> or <div class="selector stacked">
- var selector_div = quickElement('div', from_box.parentNode);
- selector_div.className = is_stacked ? 'selector stacked' : 'selector';
-
- // <div class="selector-available">
- var selector_available = quickElement('div', selector_div);
- selector_available.className = 'selector-available';
- var title_available = quickElement('h2', selector_available, interpolate(gettext('Available %s') + ' ', [field_name]));
- quickElement(
- 'span', title_available, '',
- 'class', 'help help-tooltip help-icon',
- 'title', interpolate(
- gettext(
- 'This is the list of available %s. You may choose some by ' +
- 'selecting them in the box below and then clicking the ' +
- '"Choose" arrow between the two boxes.'
- ),
- [field_name]
- )
- );
-
- var filter_p = quickElement('p', selector_available, '', 'id', field_id + '_filter');
- filter_p.className = 'selector-filter';
-
- var search_filter_label = quickElement('label', filter_p, '', 'for', field_id + "_input");
-
- var search_selector_img = quickElement(
- 'span', search_filter_label, '',
- 'class', 'help-tooltip search-label-icon',
- 'title', interpolate(gettext("Type into this box to filter down the list of available %s."), [field_name])
- );
-
- filter_p.appendChild(document.createTextNode(' '));
-
- var filter_input = quickElement('input', filter_p, '', 'type', 'text', 'placeholder', gettext("Filter"));
- filter_input.id = field_id + '_input';
-
- selector_available.appendChild(from_box);
- var choose_all = quickElement('a', selector_available, gettext('Choose all'), 'title', interpolate(gettext('Click to choose all %s at once.'), [field_name]), 'href', 'javascript:void(0);', 'id', field_id + '_add_all_link');
- choose_all.className = 'selector-chooseall';
-
- // <ul class="selector-chooser">
- var selector_chooser = quickElement('ul', selector_div);
- selector_chooser.className = 'selector-chooser';
- var add_link = quickElement('a', quickElement('li', selector_chooser), gettext('Choose'), 'title', gettext('Choose'), 'href', 'javascript:void(0);', 'id', field_id + '_add_link');
- add_link.className = 'selector-add';
- var remove_link = quickElement('a', quickElement('li', selector_chooser), gettext('Remove'), 'title', gettext('Remove'), 'href', 'javascript:void(0);', 'id', field_id + '_remove_link');
- remove_link.className = 'selector-remove';
-
- // <div class="selector-chosen">
- var selector_chosen = quickElement('div', selector_div);
- selector_chosen.className = 'selector-chosen';
- var title_chosen = quickElement('h2', selector_chosen, interpolate(gettext('Chosen %s') + ' ', [field_name]));
- quickElement(
- 'span', title_chosen, '',
- 'class', 'help help-tooltip help-icon',
- 'title', interpolate(
- gettext(
- 'This is the list of chosen %s. You may remove some by ' +
- 'selecting them in the box below and then clicking the ' +
- '"Remove" arrow between the two boxes.'
- ),
- [field_name]
- )
- );
-
- var to_box = quickElement('select', selector_chosen, '', 'id', field_id + '_to', 'multiple', 'multiple', 'size', from_box.size, 'name', from_box.getAttribute('name'));
- to_box.className = 'filtered';
- var clear_all = quickElement('a', selector_chosen, gettext('Remove all'), 'title', interpolate(gettext('Click to remove all chosen %s at once.'), [field_name]), 'href', 'javascript:void(0);', 'id', field_id + '_remove_all_link');
- clear_all.className = 'selector-clearall';
-
- from_box.setAttribute('name', from_box.getAttribute('name') + '_old');
-
- // Set up the JavaScript event handlers for the select box filter interface
- addEvent(choose_all, 'click', function() { SelectBox.move_all(field_id + '_from', field_id + '_to'); SelectFilter.refresh_icons(field_id); });
- addEvent(add_link, 'click', function() { SelectBox.move(field_id + '_from', field_id + '_to'); SelectFilter.refresh_icons(field_id); });
- addEvent(remove_link, 'click', function() { SelectBox.move(field_id + '_to', field_id + '_from'); SelectFilter.refresh_icons(field_id); });
- addEvent(clear_all, 'click', function() { SelectBox.move_all(field_id + '_to', field_id + '_from'); SelectFilter.refresh_icons(field_id); });
- addEvent(filter_input, 'keypress', function(e) { SelectFilter.filter_key_press(e, field_id); });
- addEvent(filter_input, 'keyup', function(e) { SelectFilter.filter_key_up(e, field_id); });
- addEvent(filter_input, 'keydown', function(e) { SelectFilter.filter_key_down(e, field_id); });
- addEvent(from_box, 'change', function(e) { SelectFilter.refresh_icons(field_id) });
- addEvent(to_box, 'change', function(e) { SelectFilter.refresh_icons(field_id) });
- addEvent(from_box, 'dblclick', function() { SelectBox.move(field_id + '_from', field_id + '_to'); SelectFilter.refresh_icons(field_id); });
- addEvent(to_box, 'dblclick', function() { SelectBox.move(field_id + '_to', field_id + '_from'); SelectFilter.refresh_icons(field_id); });
- addEvent(findForm(from_box), 'submit', function() { SelectBox.select_all(field_id + '_to'); });
- SelectBox.init(field_id + '_from');
- SelectBox.init(field_id + '_to');
- // Move selected from_box options to to_box
- SelectBox.move(field_id + '_from', field_id + '_to');
-
- if (!is_stacked) {
- // In horizontal mode, give the same height to the two boxes.
- var j_from_box = $(from_box);
- var j_to_box = $(to_box);
- var resize_filters = function() { j_to_box.height($(filter_p).outerHeight() + j_from_box.outerHeight()); }
- if (j_from_box.outerHeight() > 0) {
- resize_filters(); // This fieldset is already open. Resize now.
- } else {
- // This fieldset is probably collapsed. Wait for its 'show' event.
- j_to_box.closest('fieldset').one('show.fieldset', resize_filters);
+ window.SelectFilter = {
+ init: function(field_id, field_name, is_stacked) {
+ if (field_id.match(/__prefix__/)) {
+ // Don't initialize on empty forms.
+ return;
+ }
+ var from_box = document.getElementById(field_id);
+ from_box.id += '_from'; // change its ID
+ from_box.className = 'filtered';
+
+ var ps = from_box.parentNode.getElementsByTagName('p');
+ for (var i=0; i<ps.length; i++) {
+ if (ps[i].className.indexOf("info") !== -1) {
+ // Remove <p class="info">, because it just gets in the way.
+ from_box.parentNode.removeChild(ps[i]);
+ } else if (ps[i].className.indexOf("help") !== -1) {
+ // Move help text up to the top so it isn't below the select
+ // boxes or wrapped off on the side to the right of the add
+ // button:
+ from_box.parentNode.insertBefore(ps[i], from_box.parentNode.firstChild);
+ }
}
- }
- // Initial icon refresh
- SelectFilter.refresh_icons(field_id);
- },
- refresh_icons: function(field_id) {
- var from = $('#' + field_id + '_from');
- var to = $('#' + field_id + '_to');
- var is_from_selected = from.find('option:selected').length > 0;
- var is_to_selected = to.find('option:selected').length > 0;
- // Active if at least one item is selected
- $('#' + field_id + '_add_link').toggleClass('active', is_from_selected);
- $('#' + field_id + '_remove_link').toggleClass('active', is_to_selected);
- // Active if the corresponding box isn't empty
- $('#' + field_id + '_add_all_link').toggleClass('active', from.find('option').length > 0);
- $('#' + field_id + '_remove_all_link').toggleClass('active', to.find('option').length > 0);
- },
- filter_key_press: function(event, field_id) {
- var from = document.getElementById(field_id + '_from');
- // don't submit form if user pressed Enter
- if ((event.which && event.which == 13) || (event.keyCode && event.keyCode == 13)) {
- from.selectedIndex = 0;
- SelectBox.move(field_id + '_from', field_id + '_to');
- from.selectedIndex = 0;
- event.preventDefault()
- return false;
- }
- },
- filter_key_up: function(event, field_id) {
- var from = document.getElementById(field_id + '_from');
- var temp = from.selectedIndex;
- SelectBox.filter(field_id + '_from', document.getElementById(field_id + '_input').value);
- from.selectedIndex = temp;
- return true;
- },
- filter_key_down: function(event, field_id) {
- var from = document.getElementById(field_id + '_from');
- // right arrow -- move across
- if ((event.which && event.which == 39) || (event.keyCode && event.keyCode == 39)) {
- var old_index = from.selectedIndex;
+ // <div class="selector"> or <div class="selector stacked">
+ var selector_div = quickElement('div', from_box.parentNode);
+ selector_div.className = is_stacked ? 'selector stacked' : 'selector';
+
+ // <div class="selector-available">
+ var selector_available = quickElement('div', selector_div);
+ selector_available.className = 'selector-available';
+ var title_available = quickElement('h2', selector_available, interpolate(gettext('Available %s') + ' ', [field_name]));
+ quickElement(
+ 'span', title_available, '',
+ 'class', 'help help-tooltip help-icon',
+ 'title', interpolate(
+ gettext(
+ 'This is the list of available %s. You may choose some by ' +
+ 'selecting them in the box below and then clicking the ' +
+ '"Choose" arrow between the two boxes.'
+ ),
+ [field_name]
+ )
+ );
+
+ var filter_p = quickElement('p', selector_available, '', 'id', field_id + '_filter');
+ filter_p.className = 'selector-filter';
+
+ var search_filter_label = quickElement('label', filter_p, '', 'for', field_id + '_input');
+
+ quickElement(
+ 'span', search_filter_label, '',
+ 'class', 'help-tooltip search-label-icon',
+ 'title', interpolate(gettext("Type into this box to filter down the list of available %s."), [field_name])
+ );
+
+ filter_p.appendChild(document.createTextNode(' '));
+
+ var filter_input = quickElement('input', filter_p, '', 'type', 'text', 'placeholder', gettext("Filter"));
+ filter_input.id = field_id + '_input';
+
+ selector_available.appendChild(from_box);
+ var choose_all = quickElement('a', selector_available, gettext('Choose all'), 'title', interpolate(gettext('Click to choose all %s at once.'), [field_name]), 'href', 'javascript:void(0);', 'id', field_id + '_add_all_link');
+ choose_all.className = 'selector-chooseall';
+
+ // <ul class="selector-chooser">
+ var selector_chooser = quickElement('ul', selector_div);
+ selector_chooser.className = 'selector-chooser';
+ var add_link = quickElement('a', quickElement('li', selector_chooser), gettext('Choose'), 'title', gettext('Choose'), 'href', 'javascript:void(0);', 'id', field_id + '_add_link');
+ add_link.className = 'selector-add';
+ var remove_link = quickElement('a', quickElement('li', selector_chooser), gettext('Remove'), 'title', gettext('Remove'), 'href', 'javascript:void(0);', 'id', field_id + '_remove_link');
+ remove_link.className = 'selector-remove';
+
+ // <div class="selector-chosen">
+ var selector_chosen = quickElement('div', selector_div);
+ selector_chosen.className = 'selector-chosen';
+ var title_chosen = quickElement('h2', selector_chosen, interpolate(gettext('Chosen %s') + ' ', [field_name]));
+ quickElement(
+ 'span', title_chosen, '',
+ 'class', 'help help-tooltip help-icon',
+ 'title', interpolate(
+ gettext(
+ 'This is the list of chosen %s. You may remove some by ' +
+ 'selecting them in the box below and then clicking the ' +
+ '"Remove" arrow between the two boxes.'
+ ),
+ [field_name]
+ )
+ );
+
+ var to_box = quickElement('select', selector_chosen, '', 'id', field_id + '_to', 'multiple', 'multiple', 'size', from_box.size, 'name', from_box.getAttribute('name'));
+ to_box.className = 'filtered';
+ var clear_all = quickElement('a', selector_chosen, gettext('Remove all'), 'title', interpolate(gettext('Click to remove all chosen %s at once.'), [field_name]), 'href', 'javascript:void(0);', 'id', field_id + '_remove_all_link');
+ clear_all.className = 'selector-clearall';
+
+ from_box.setAttribute('name', from_box.getAttribute('name') + '_old');
+
+ // Set up the JavaScript event handlers for the select box filter interface
+ addEvent(choose_all, 'click', function() { SelectBox.move_all(field_id + '_from', field_id + '_to'); SelectFilter.refresh_icons(field_id); });
+ addEvent(add_link, 'click', function() { SelectBox.move(field_id + '_from', field_id + '_to'); SelectFilter.refresh_icons(field_id); });
+ addEvent(remove_link, 'click', function() { SelectBox.move(field_id + '_to', field_id + '_from'); SelectFilter.refresh_icons(field_id); });
+ addEvent(clear_all, 'click', function() { SelectBox.move_all(field_id + '_to', field_id + '_from'); SelectFilter.refresh_icons(field_id); });
+ addEvent(filter_input, 'keypress', function(e) { SelectFilter.filter_key_press(e, field_id); });
+ addEvent(filter_input, 'keyup', function(e) { SelectFilter.filter_key_up(e, field_id); });
+ addEvent(filter_input, 'keydown', function(e) { SelectFilter.filter_key_down(e, field_id); });
+ addEvent(from_box, 'change', function(e) { SelectFilter.refresh_icons(field_id); });
+ addEvent(to_box, 'change', function(e) { SelectFilter.refresh_icons(field_id); });
+ addEvent(from_box, 'dblclick', function() { SelectBox.move(field_id + '_from', field_id + '_to'); SelectFilter.refresh_icons(field_id); });
+ addEvent(to_box, 'dblclick', function() { SelectBox.move(field_id + '_to', field_id + '_from'); SelectFilter.refresh_icons(field_id); });
+ addEvent(findForm(from_box), 'submit', function() { SelectBox.select_all(field_id + '_to'); });
+ SelectBox.init(field_id + '_from');
+ SelectBox.init(field_id + '_to');
+ // Move selected from_box options to to_box
SelectBox.move(field_id + '_from', field_id + '_to');
- from.selectedIndex = (old_index == from.length) ? from.length - 1 : old_index;
- return false;
- }
- // down arrow -- wrap around
- if ((event.which && event.which == 40) || (event.keyCode && event.keyCode == 40)) {
- from.selectedIndex = (from.length == from.selectedIndex + 1) ? 0 : from.selectedIndex + 1;
- }
- // up arrow -- wrap around
- if ((event.which && event.which == 38) || (event.keyCode && event.keyCode == 38)) {
- from.selectedIndex = (from.selectedIndex == 0) ? from.length - 1 : from.selectedIndex - 1;
+
+ if (!is_stacked) {
+ // In horizontal mode, give the same height to the two boxes.
+ var j_from_box = $(from_box);
+ var j_to_box = $(to_box);
+ var resize_filters = function() { j_to_box.height($(filter_p).outerHeight() + j_from_box.outerHeight()); };
+ if (j_from_box.outerHeight() > 0) {
+ resize_filters(); // This fieldset is already open. Resize now.
+ } else {
+ // This fieldset is probably collapsed. Wait for its 'show' event.
+ j_to_box.closest('fieldset').one('show.fieldset', resize_filters);
+ }
+ }
+
+ // Initial icon refresh
+ SelectFilter.refresh_icons(field_id);
+ },
+ refresh_icons: function(field_id) {
+ var from = $('#' + field_id + '_from');
+ var to = $('#' + field_id + '_to');
+ var is_from_selected = from.find('option:selected').length > 0;
+ var is_to_selected = to.find('option:selected').length > 0;
+ // Active if at least one item is selected
+ $('#' + field_id + '_add_link').toggleClass('active', is_from_selected);
+ $('#' + field_id + '_remove_link').toggleClass('active', is_to_selected);
+ // Active if the corresponding box isn't empty
+ $('#' + field_id + '_add_all_link').toggleClass('active', from.find('option').length > 0);
+ $('#' + field_id + '_remove_all_link').toggleClass('active', to.find('option').length > 0);
+ },
+ filter_key_press: function(event, field_id) {
+ var from = document.getElementById(field_id + '_from');
+ // don't submit form if user pressed Enter
+ if ((event.which && event.which === 13) || (event.keyCode && event.keyCode === 13)) {
+ from.selectedIndex = 0;
+ SelectBox.move(field_id + '_from', field_id + '_to');
+ from.selectedIndex = 0;
+ event.preventDefault();
+ return false;
+ }
+ },
+ filter_key_up: function(event, field_id) {
+ var from = document.getElementById(field_id + '_from');
+ var temp = from.selectedIndex;
+ SelectBox.filter(field_id + '_from', document.getElementById(field_id + '_input').value);
+ from.selectedIndex = temp;
+ return true;
+ },
+ filter_key_down: function(event, field_id) {
+ var from = document.getElementById(field_id + '_from');
+ // right arrow -- move across
+ if ((event.which && event.which === 39) || (event.keyCode && event.keyCode === 39)) {
+ var old_index = from.selectedIndex;
+ SelectBox.move(field_id + '_from', field_id + '_to');
+ from.selectedIndex = (old_index === from.length) ? from.length - 1 : old_index;
+ return false;
+ }
+ // down arrow -- wrap around
+ if ((event.which && event.which === 40) || (event.keyCode && event.keyCode === 40)) {
+ from.selectedIndex = (from.length === from.selectedIndex + 1) ? 0 : from.selectedIndex + 1;
+ }
+ // up arrow -- wrap around
+ if ((event.which && event.which === 38) || (event.keyCode && event.keyCode === 38)) {
+ from.selectedIndex = (from.selectedIndex === 0) ? from.length - 1 : from.selectedIndex - 1;
+ }
+ return true;
}
- return true;
- }
-}
+ };
})(django.jQuery);
diff --git a/django/contrib/admin/static/admin/js/actions.js b/django/contrib/admin/static/admin/js/actions.js
index 58f572f252..e899000ab3 100644
--- a/django/contrib/admin/static/admin/js/actions.js
+++ b/django/contrib/admin/static/admin/js/actions.js
@@ -1,144 +1,145 @@
+/*global _actions_icnt, gettext, interpolate, ngettext*/
(function($) {
- var lastChecked;
+ var lastChecked;
- $.fn.actions = function(opts) {
- var options = $.extend({}, $.fn.actions.defaults, opts);
- var actionCheckboxes = $(this);
- var list_editable_changed = false;
- var checker = function(checked) {
- if (checked) {
- showQuestion();
- } else {
- reset();
- }
- $(actionCheckboxes).prop("checked", checked)
- .parent().parent().toggleClass(options.selectedClass, checked);
- },
- updateCounter = function() {
- var sel = $(actionCheckboxes).filter(":checked").length;
- // _actions_icnt is defined in the generated HTML
- // and contains the total amount of objects in the queryset
- $(options.counterContainer).html(interpolate(
- ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), {
- sel: sel,
- cnt: _actions_icnt
- }, true));
- $(options.allToggle).prop("checked", function() {
- var value;
- if (sel == actionCheckboxes.length) {
- value = true;
- showQuestion();
- } else {
- value = false;
- clearAcross();
- }
- return value;
- });
- },
- showQuestion = function() {
- $(options.acrossClears).hide();
- $(options.acrossQuestions).show();
- $(options.allContainer).hide();
- },
- showClear = function() {
- $(options.acrossClears).show();
- $(options.acrossQuestions).hide();
- $(options.actionContainer).toggleClass(options.selectedClass);
- $(options.allContainer).show();
- $(options.counterContainer).hide();
- },
- reset = function() {
- $(options.acrossClears).hide();
- $(options.acrossQuestions).hide();
- $(options.allContainer).hide();
- $(options.counterContainer).show();
- },
- clearAcross = function() {
- reset();
- $(options.acrossInput).val(0);
- $(options.actionContainer).removeClass(options.selectedClass);
- };
- // Show counter by default
- $(options.counterContainer).show();
- // Check state of checkboxes and reinit state if needed
- $(this).filter(":checked").each(function(i) {
- $(this).parent().parent().toggleClass(options.selectedClass);
- updateCounter();
- if ($(options.acrossInput).val() == 1) {
- showClear();
- }
- });
- $(options.allToggle).show().click(function() {
- checker($(this).prop("checked"));
- updateCounter();
- });
- $("a", options.acrossQuestions).click(function(event) {
- event.preventDefault();
- $(options.acrossInput).val(1);
- showClear();
- });
- $("a", options.acrossClears).click(function(event) {
- event.preventDefault();
- $(options.allToggle).prop("checked", false);
- clearAcross();
- checker(0);
- updateCounter();
- });
- lastChecked = null;
- $(actionCheckboxes).click(function(event) {
- if (!event) { event = window.event; }
- var target = event.target ? event.target : event.srcElement;
- if (lastChecked && $.data(lastChecked) != $.data(target) && event.shiftKey === true) {
- var inrange = false;
- $(lastChecked).prop("checked", target.checked)
- .parent().parent().toggleClass(options.selectedClass, target.checked);
- $(actionCheckboxes).each(function() {
- if ($.data(this) == $.data(lastChecked) || $.data(this) == $.data(target)) {
- inrange = (inrange) ? false : true;
- }
- if (inrange) {
- $(this).prop("checked", target.checked)
- .parent().parent().toggleClass(options.selectedClass, target.checked);
- }
- });
- }
- $(target).parent().parent().toggleClass(options.selectedClass, target.checked);
- lastChecked = target;
- updateCounter();
- });
- $('form#changelist-form table#result_list tr').find('td:gt(0) :input').change(function() {
- list_editable_changed = true;
- });
- $('form#changelist-form button[name="index"]').click(function(event) {
- if (list_editable_changed) {
- return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."));
- }
- });
- $('form#changelist-form input[name="_save"]').click(function(event) {
- var action_changed = false;
- $('select option:selected', options.actionContainer).each(function() {
- if ($(this).val()) {
- action_changed = true;
- }
- });
- if (action_changed) {
- if (list_editable_changed) {
- return confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action."));
- } else {
- return confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."));
- }
- }
- });
- };
- /* Setup plugin defaults */
- $.fn.actions.defaults = {
- actionContainer: "div.actions",
- counterContainer: "span.action-counter",
- allContainer: "div.actions span.all",
- acrossInput: "div.actions input.select-across",
- acrossQuestions: "div.actions span.question",
- acrossClears: "div.actions span.clear",
- allToggle: "#action-toggle",
- selectedClass: "selected"
- };
+ $.fn.actions = function(opts) {
+ var options = $.extend({}, $.fn.actions.defaults, opts);
+ var actionCheckboxes = $(this);
+ var list_editable_changed = false;
+ var showQuestion = function() {
+ $(options.acrossClears).hide();
+ $(options.acrossQuestions).show();
+ $(options.allContainer).hide();
+ },
+ showClear = function() {
+ $(options.acrossClears).show();
+ $(options.acrossQuestions).hide();
+ $(options.actionContainer).toggleClass(options.selectedClass);
+ $(options.allContainer).show();
+ $(options.counterContainer).hide();
+ },
+ reset = function() {
+ $(options.acrossClears).hide();
+ $(options.acrossQuestions).hide();
+ $(options.allContainer).hide();
+ $(options.counterContainer).show();
+ },
+ clearAcross = function() {
+ reset();
+ $(options.acrossInput).val(0);
+ $(options.actionContainer).removeClass(options.selectedClass);
+ },
+ checker = function(checked) {
+ if (checked) {
+ showQuestion();
+ } else {
+ reset();
+ }
+ $(actionCheckboxes).prop("checked", checked)
+ .parent().parent().toggleClass(options.selectedClass, checked);
+ },
+ updateCounter = function() {
+ var sel = $(actionCheckboxes).filter(":checked").length;
+ // _actions_icnt is defined in the generated HTML
+ // and contains the total amount of objects in the queryset
+ $(options.counterContainer).html(interpolate(
+ ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), {
+ sel: sel,
+ cnt: _actions_icnt
+ }, true));
+ $(options.allToggle).prop("checked", function() {
+ var value;
+ if (sel === actionCheckboxes.length) {
+ value = true;
+ showQuestion();
+ } else {
+ value = false;
+ clearAcross();
+ }
+ return value;
+ });
+ };
+ // Show counter by default
+ $(options.counterContainer).show();
+ // Check state of checkboxes and reinit state if needed
+ $(this).filter(":checked").each(function(i) {
+ $(this).parent().parent().toggleClass(options.selectedClass);
+ updateCounter();
+ if ($(options.acrossInput).val() === 1) {
+ showClear();
+ }
+ });
+ $(options.allToggle).show().click(function() {
+ checker($(this).prop("checked"));
+ updateCounter();
+ });
+ $("a", options.acrossQuestions).click(function(event) {
+ event.preventDefault();
+ $(options.acrossInput).val(1);
+ showClear();
+ });
+ $("a", options.acrossClears).click(function(event) {
+ event.preventDefault();
+ $(options.allToggle).prop("checked", false);
+ clearAcross();
+ checker(0);
+ updateCounter();
+ });
+ lastChecked = null;
+ $(actionCheckboxes).click(function(event) {
+ if (!event) { event = window.event; }
+ var target = event.target ? event.target : event.srcElement;
+ if (lastChecked && $.data(lastChecked) !== $.data(target) && event.shiftKey === true) {
+ var inrange = false;
+ $(lastChecked).prop("checked", target.checked)
+ .parent().parent().toggleClass(options.selectedClass, target.checked);
+ $(actionCheckboxes).each(function() {
+ if ($.data(this) === $.data(lastChecked) || $.data(this) === $.data(target)) {
+ inrange = (inrange) ? false : true;
+ }
+ if (inrange) {
+ $(this).prop("checked", target.checked)
+ .parent().parent().toggleClass(options.selectedClass, target.checked);
+ }
+ });
+ }
+ $(target).parent().parent().toggleClass(options.selectedClass, target.checked);
+ lastChecked = target;
+ updateCounter();
+ });
+ $('form#changelist-form table#result_list tr').find('td:gt(0) :input').change(function() {
+ list_editable_changed = true;
+ });
+ $('form#changelist-form button[name="index"]').click(function(event) {
+ if (list_editable_changed) {
+ return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."));
+ }
+ });
+ $('form#changelist-form input[name="_save"]').click(function(event) {
+ var action_changed = false;
+ $('select option:selected', options.actionContainer).each(function() {
+ if ($(this).val()) {
+ action_changed = true;
+ }
+ });
+ if (action_changed) {
+ if (list_editable_changed) {
+ return confirm(gettext("You have selected an action, but you haven't saved your changes to individual fields yet. Please click OK to save. You'll need to re-run the action."));
+ } else {
+ return confirm(gettext("You have selected an action, and you haven't made any changes on individual fields. You're probably looking for the Go button rather than the Save button."));
+ }
+ }
+ });
+ };
+ /* Setup plugin defaults */
+ $.fn.actions.defaults = {
+ actionContainer: "div.actions",
+ counterContainer: "span.action-counter",
+ allContainer: "div.actions span.all",
+ acrossInput: "div.actions input.select-across",
+ acrossQuestions: "div.actions span.question",
+ acrossClears: "div.actions span.clear",
+ allToggle: "#action-toggle",
+ selectedClass: "selected"
+ };
})(django.jQuery);
diff --git a/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js b/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js
index 9b25b9df36..987ee9004f 100644
--- a/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js
+++ b/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js
@@ -1,3 +1,4 @@
+/*global addEvent, Calendar, cancelEventPropagation, findPosX, findPosY, getStyle, get_format, gettext, interpolate, ngettext, quickElement, removeEvent*/
// Inserts shortcut buttons after all of the following:
// <input type="text" class="vDateField">
// <input type="text" class="vTimeField">
@@ -17,20 +18,20 @@ var DateTimeShortcuts = {
timezoneWarningClass: 'timezonewarning', // class of the warning for timezone mismatch
timezoneOffset: 0,
init: function() {
- if (window.__admin_utc_offset__ != undefined) {
+ if (window.__admin_utc_offset__ !== undefined) {
var serverOffset = window.__admin_utc_offset__;
var localOffset = new Date().getTimezoneOffset() * -60;
DateTimeShortcuts.timezoneOffset = localOffset - serverOffset;
}
var inputs = document.getElementsByTagName('input');
- for (i=0; i<inputs.length; i++) {
+ for (var i=0; i<inputs.length; i++) {
var inp = inputs[i];
- if (inp.getAttribute('type') == 'text' && inp.className.match(/vTimeField/)) {
+ if (inp.getAttribute('type') === 'text' && inp.className.match(/vTimeField/)) {
DateTimeShortcuts.addClock(inp);
DateTimeShortcuts.addTimezoneWarning(inp);
}
- else if (inp.getAttribute('type') == 'text' && inp.className.match(/vDateField/)) {
+ else if (inp.getAttribute('type') === 'text' && inp.className.match(/vDateField/)) {
DateTimeShortcuts.addCalendar(inp);
DateTimeShortcuts.addTimezoneWarning(inp);
}
@@ -38,7 +39,7 @@ var DateTimeShortcuts = {
},
// Return the current time while accounting for the server timezone.
now: function() {
- if (window.__admin_utc_offset__ != undefined) {
+ if (window.__admin_utc_offset__ !== undefined) {
var serverOffset = window.__admin_utc_offset__;
var localNow = new Date();
var localOffset = localNow.getTimezoneOffset() * -60;
@@ -71,7 +72,7 @@ var DateTimeShortcuts = {
);
}
else {
- timezoneOffset *= -1
+ timezoneOffset *= -1;
message = ngettext(
'Note: You are %s hour behind server time.',
'Note: You are %s hours behind server time.',
@@ -86,7 +87,7 @@ var DateTimeShortcuts = {
$(inp).parent()
.append($('<br>'))
- .append($warning)
+ .append($warning);
},
// Add clock widget to a given field
addClock: function(inp) {
@@ -150,7 +151,7 @@ var DateTimeShortcuts = {
cancel_p.className = 'calendar-cancel';
quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissClock(' + num + ');');
django.jQuery(document).bind('keyup', function(event) {
- if (event.which == 27) {
+ if (event.which === 27) {
// ESC key closes popup
DateTimeShortcuts.dismissClock(num);
event.preventDefault();
@@ -158,12 +159,12 @@ var DateTimeShortcuts = {
});
},
openClock: function(num) {
- var clock_box = document.getElementById(DateTimeShortcuts.clockDivName+num)
- var clock_link = document.getElementById(DateTimeShortcuts.clockLinkName+num)
+ var clock_box = document.getElementById(DateTimeShortcuts.clockDivName+num);
+ var clock_link = document.getElementById(DateTimeShortcuts.clockLinkName+num);
// Recalculate the clockbox position
// is it left-to-right or right-to-left layout ?
- if (getStyle(document.body,'direction')!='rtl') {
+ if (getStyle(document.body,'direction')!=='rtl') {
clock_box.style.left = findPosX(clock_link) + 17 + 'px';
}
else {
@@ -180,20 +181,20 @@ var DateTimeShortcuts = {
addEvent(document, 'click', DateTimeShortcuts.dismissClockFunc[num]);
},
dismissClock: function(num) {
- document.getElementById(DateTimeShortcuts.clockDivName + num).style.display = 'none';
- removeEvent(document, 'click', DateTimeShortcuts.dismissClockFunc[num]);
+ document.getElementById(DateTimeShortcuts.clockDivName + num).style.display = 'none';
+ removeEvent(document, 'click', DateTimeShortcuts.dismissClockFunc[num]);
},
handleClockQuicklink: function(num, val) {
- var d;
- if (val == -1) {
- d = DateTimeShortcuts.now();
- }
- else {
- d = new Date(1970, 1, 1, val, 0, 0, 0)
- }
- DateTimeShortcuts.clockInputs[num].value = d.strftime(get_format('TIME_INPUT_FORMATS')[0]);
- DateTimeShortcuts.clockInputs[num].focus();
- DateTimeShortcuts.dismissClock(num);
+ var d;
+ if (val === -1) {
+ d = DateTimeShortcuts.now();
+ }
+ else {
+ d = new Date(1970, 1, 1, val, 0, 0, 0);
+ }
+ DateTimeShortcuts.clockInputs[num].value = d.strftime(get_format('TIME_INPUT_FORMATS')[0]);
+ DateTimeShortcuts.clockInputs[num].focus();
+ DateTimeShortcuts.dismissClock(num);
},
// Add calendar widget to a given field.
addCalendar: function(inp) {
@@ -274,7 +275,7 @@ var DateTimeShortcuts = {
cancel_p.className = 'calendar-cancel';
quickElement('a', cancel_p, gettext('Cancel'), 'href', 'javascript:DateTimeShortcuts.dismissCalendar(' + num + ');');
django.jQuery(document).bind('keyup', function(event) {
- if (event.which == 27) {
+ if (event.which === 27) {
// ESC key closes popup
DateTimeShortcuts.dismissCalendar(num);
event.preventDefault();
@@ -282,8 +283,8 @@ var DateTimeShortcuts = {
});
},
openCalendar: function(num) {
- var cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1+num)
- var cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName+num)
+ var cal_box = document.getElementById(DateTimeShortcuts.calendarDivName1+num);
+ var cal_link = document.getElementById(DateTimeShortcuts.calendarLinkName+num);
var inp = DateTimeShortcuts.calendarInputs[num];
// Determine if the current value in the input has a valid date.
@@ -293,7 +294,7 @@ var DateTimeShortcuts = {
var selected = inp.value.strptime(format);
var year = selected.getFullYear();
var month = selected.getMonth() + 1;
- var re = /\d{4}/
+ var re = /\d{4}/;
if (re.test(year.toString()) && month >= 1 && month <= 12) {
DateTimeShortcuts.calendars[num].drawDate(month, year, selected);
}
@@ -301,7 +302,7 @@ var DateTimeShortcuts = {
// Recalculate the clockbox position
// is it left-to-right or right-to-left layout ?
- if (getStyle(document.body,'direction')!='rtl') {
+ if (getStyle(document.body,'direction')!=='rtl') {
cal_box.style.left = findPosX(cal_link) + 17 + 'px';
}
else {
@@ -345,12 +346,12 @@ var DateTimeShortcuts = {
").style.display='none';}"].join('');
},
handleCalendarQuickLink: function(num, offset) {
- var d = DateTimeShortcuts.now();
- d.setDate(d.getDate() + offset)
- DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]);
- DateTimeShortcuts.calendarInputs[num].focus();
- DateTimeShortcuts.dismissCalendar(num);
+ var d = DateTimeShortcuts.now();
+ d.setDate(d.getDate() + offset);
+ DateTimeShortcuts.calendarInputs[num].value = d.strftime(get_format('DATE_INPUT_FORMATS')[0]);
+ DateTimeShortcuts.calendarInputs[num].focus();
+ DateTimeShortcuts.dismissCalendar(num);
}
-}
+};
addEvent(window, 'load', DateTimeShortcuts.init);
diff --git a/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js b/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js
index 4a577c4187..e8b8dd7890 100644
--- a/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js
+++ b/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js
@@ -1,3 +1,4 @@
+/*global SelectBox, interpolate*/
// Handles related-objects functionality: lookup link for raw_id_fields
// and Add Another links.
@@ -32,7 +33,7 @@ function showAdminPopup(triggeringLink, name_regexp, add_popup) {
name = id_to_windowname(name);
var href = triggeringLink.href;
if (add_popup) {
- if (href.indexOf('?') == -1) {
+ if (href.indexOf('?') === -1) {
href += '?_popup=1';
} else {
href += '&_popup=1';
@@ -50,7 +51,7 @@ function showRelatedObjectLookupPopup(triggeringLink) {
function dismissRelatedLookupPopup(win, chosenId) {
var name = windowname_to_id(win.name);
var elem = document.getElementById(name);
- if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) {
+ if (elem.className.indexOf('vManyToManyRawIdAdminField') !== -1 && elem.value) {
elem.value += ',' + chosenId;
} else {
document.getElementById(name).value = chosenId;
@@ -86,10 +87,10 @@ function dismissAddRelatedObjectPopup(win, newId, newRepr) {
var elem = document.getElementById(name);
if (elem) {
var elemName = elem.nodeName.toUpperCase();
- if (elemName == 'SELECT') {
+ if (elemName === 'SELECT') {
elem.options[elem.options.length] = new Option(newRepr, newId, true, true);
- } else if (elemName == 'INPUT') {
- if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) {
+ } else if (elemName === 'INPUT') {
+ if (elem.className.indexOf('vManyToManyRawIdAdminField') !== -1 && elem.value) {
elem.value += ',' + newId;
} else {
elem.value = newId;
@@ -113,13 +114,13 @@ function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) {
var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
var selects = django.jQuery(selectsSelector);
selects.find('option').each(function() {
- if (this.value == objId) {
+ if (this.value === objId) {
this.innerHTML = newRepr;
this.value = newId;
}
});
win.close();
-};
+}
function dismissDeleteRelatedObjectPopup(win, objId) {
objId = html_unescape(objId);
@@ -127,13 +128,13 @@ function dismissDeleteRelatedObjectPopup(win, objId) {
var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
var selects = django.jQuery(selectsSelector);
selects.find('option').each(function() {
- if (this.value == objId) {
+ if (this.value === objId) {
django.jQuery(this).remove();
}
}).trigger('change');
win.close();
-};
+}
// Kept for backward compatibility
-showAddAnotherPopup = showRelatedObjectPopup;
-dismissAddAnotherPopup = dismissAddRelatedObjectPopup;
+var showAddAnotherPopup = showRelatedObjectPopup;
+var dismissAddAnotherPopup = dismissAddRelatedObjectPopup;
diff --git a/django/contrib/admin/static/admin/js/calendar.js b/django/contrib/admin/static/admin/js/calendar.js
index 458eece92f..deaac8ec20 100644
--- a/django/contrib/admin/static/admin/js/calendar.js
+++ b/django/contrib/admin/static/admin/js/calendar.js
@@ -1,3 +1,4 @@
+/*global gettext, get_format, quickElement, removeChildren*/
/*
calendar.js - Calendar functions by Adrian Holovaty
depends on core.js for utility functions like removeChildren or quickElement
@@ -9,17 +10,17 @@ var CalendarNamespace = {
daysOfWeek: gettext('S M T W T F S').split(' '),
firstDayOfWeek: parseInt(get_format('FIRST_DAY_OF_WEEK')),
isLeapYear: function(year) {
- return (((year % 4)==0) && ((year % 100)!=0) || ((year % 400)==0));
+ return (((year % 4)===0) && ((year % 100)!==0) || ((year % 400)===0));
},
getDaysInMonth: function(month,year) {
var days;
- if (month==1 || month==3 || month==5 || month==7 || month==8 || month==10 || month==12) {
+ if (month===1 || month===3 || month===5 || month===7 || month===8 || month===10 || month===12) {
days = 31;
}
- else if (month==4 || month==6 || month==9 || month==11) {
+ else if (month===4 || month===6 || month===9 || month===11) {
days = 30;
}
- else if (month==2 && CalendarNamespace.isLeapYear(year)) {
+ else if (month===2 && CalendarNamespace.isLeapYear(year)) {
days = 29;
}
else {
@@ -46,8 +47,8 @@ var CalendarNamespace = {
// The day variable above will be 1 instead of 2 in, say, US Pacific time
// zone.
var isSelectedMonth = false;
- if (typeof selected != 'undefined') {
- isSelectedMonth = (selected.getUTCFullYear() == year && (selected.getUTCMonth()+1) == month);
+ if (typeof selected !== 'undefined') {
+ isSelectedMonth = (selected.getUTCFullYear() === year && (selected.getUTCMonth()+1) === month);
}
month = parseInt(month);
@@ -67,28 +68,30 @@ var CalendarNamespace = {
var startingPos = new Date(year, month-1, 1 - CalendarNamespace.firstDayOfWeek).getDay();
var days = CalendarNamespace.getDaysInMonth(month, year);
+ var _cell;
+
// Draw blanks before first of month
tableRow = quickElement('tr', tableBody);
- for (var i = 0; i < startingPos; i++) {
- var _cell = quickElement('td', tableRow, ' ');
+ for (i = 0; i < startingPos; i++) {
+ _cell = quickElement('td', tableRow, ' ');
_cell.className = "nonday";
}
// Draw days of month
var currentDay = 1;
- for (var i = startingPos; currentDay <= days; i++) {
- if (i%7 == 0 && currentDay != 1) {
+ for (i = startingPos; currentDay <= days; i++) {
+ if (i%7 === 0 && currentDay !== 1) {
tableRow = quickElement('tr', tableBody);
}
- if ((currentDay==todayDay) && (month==todayMonth) && (year==todayYear)) {
+ if ((currentDay===todayDay) && (month===todayMonth) && (year===todayYear)) {
todayClass='today';
} else {
todayClass='';
}
// use UTC function; see above for explanation.
- if (isSelectedMonth && currentDay == selected.getUTCDate()) {
- if (todayClass != '') todayClass += " ";
+ if (isSelectedMonth && currentDay === selected.getUTCDate()) {
+ if (todayClass !== '') todayClass += " ";
todayClass += "selected";
}
@@ -100,13 +103,13 @@ var CalendarNamespace = {
// Draw blanks after end of month (optional, but makes for valid code)
while (tableRow.childNodes.length < 7) {
- var _cell = quickElement('td', tableRow, ' ');
+ _cell = quickElement('td', tableRow, ' ');
_cell.className = "nonday";
}
calDiv.appendChild(calTable);
}
-}
+};
// Calendar -- A calendar instance
function Calendar(div_id, callback, selected) {
@@ -120,7 +123,7 @@ function Calendar(div_id, callback, selected) {
this.today = new Date();
this.currentMonth = this.today.getMonth() + 1;
this.currentYear = this.today.getFullYear();
- if (typeof selected != 'undefined') {
+ if (typeof selected !== 'undefined') {
this.selected = selected;
}
}
@@ -139,7 +142,7 @@ Calendar.prototype = {
this.drawCurrent();
},
drawPreviousMonth: function() {
- if (this.currentMonth == 1) {
+ if (this.currentMonth === 1) {
this.currentMonth = 12;
this.currentYear--;
}
@@ -149,7 +152,7 @@ Calendar.prototype = {
this.drawCurrent();
},
drawNextMonth: function() {
- if (this.currentMonth == 12) {
+ if (this.currentMonth === 12) {
this.currentMonth = 1;
this.currentYear++;
}
@@ -166,4 +169,4 @@ Calendar.prototype = {
this.currentYear++;
this.drawCurrent();
}
-}
+};
diff --git a/django/contrib/admin/static/admin/js/collapse.js b/django/contrib/admin/static/admin/js/collapse.js
index 3b1f31bd23..b11fcd68f3 100644
--- a/django/contrib/admin/static/admin/js/collapse.js
+++ b/django/contrib/admin/static/admin/js/collapse.js
@@ -1,24 +1,25 @@
+/*global gettext*/
(function($) {
- $(document).ready(function() {
- // Add anchor tag for Show/Hide link
- $("fieldset.collapse").each(function(i, elem) {
- // Don't hide if fields in this fieldset have errors
- if ($(elem).find("div.errors").length == 0) {
- $(elem).addClass("collapsed").find("h2").first().append(' (<a id="fieldsetcollapser' +
- i +'" class="collapse-toggle" href="#">' + gettext("Show") +
- '</a>)');
- }
- });
- // Add toggle to anchor tag
- $("fieldset.collapse a.collapse-toggle").click(function(ev) {
- if ($(this).closest("fieldset").hasClass("collapsed")) {
- // Show
- $(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset", [$(this).attr("id")]);
- } else {
- // Hide
- $(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset", [$(this).attr("id")]);
- }
- return false;
- });
- });
+ $(document).ready(function() {
+ // Add anchor tag for Show/Hide link
+ $("fieldset.collapse").each(function(i, elem) {
+ // Don't hide if fields in this fieldset have errors
+ if ($(elem).find("div.errors").length === 0) {
+ $(elem).addClass("collapsed").find("h2").first().append(' (<a id="fieldsetcollapser' +
+ i +'" class="collapse-toggle" href="#">' + gettext("Show") +
+ '</a>)');
+ }
+ });
+ // Add toggle to anchor tag
+ $("fieldset.collapse a.collapse-toggle").click(function(ev) {
+ if ($(this).closest("fieldset").hasClass("collapsed")) {
+ // Show
+ $(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset", [$(this).attr("id")]);
+ } else {
+ // Hide
+ $(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset", [$(this).attr("id")]);
+ }
+ return false;
+ });
+ });
})(django.jQuery);
diff --git a/django/contrib/admin/static/admin/js/collapse.min.js b/django/contrib/admin/static/admin/js/collapse.min.js
index 0a8c20ea44..6251d91666 100644
--- a/django/contrib/admin/static/admin/js/collapse.min.js
+++ b/django/contrib/admin/static/admin/js/collapse.min.js
@@ -1,2 +1,2 @@
-(function(a){a(document).ready(function(){a("fieldset.collapse").each(function(c,b){a(b).find("div.errors").length==0&&a(b).addClass("collapsed").find("h2").first().append(' (<a id="fieldsetcollapser'+c+'" class="collapse-toggle" href="#">'+gettext("Show")+"</a>)")});a("fieldset.collapse a.collapse-toggle").click(function(){a(this).closest("fieldset").hasClass("collapsed")?a(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset",[a(this).attr("id")]):a(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset",
-[a(this).attr("id")]);return false})})})(django.jQuery);
+(function(a){a(document).ready(function(){a("fieldset.collapse").each(function(b,c){0===a(c).find("div.errors").length&&a(c).addClass("collapsed").find("h2").first().append(' (<a id="fieldsetcollapser'+b+'" class="collapse-toggle" href="#">'+gettext("Show")+"</a>)")});a("fieldset.collapse a.collapse-toggle").click(function(b){a(this).closest("fieldset").hasClass("collapsed")?a(this).text(gettext("Hide")).closest("fieldset").removeClass("collapsed").trigger("show.fieldset",[a(this).attr("id")]):a(this).text(gettext("Show")).closest("fieldset").addClass("collapsed").trigger("hide.fieldset",
+[a(this).attr("id")]);return!1})})})(django.jQuery);
diff --git a/django/contrib/admin/static/admin/js/core.js b/django/contrib/admin/static/admin/js/core.js
index 2c096aac6d..7702c66194 100644
--- a/django/contrib/admin/static/admin/js/core.js
+++ b/django/contrib/admin/static/admin/js/core.js
@@ -74,8 +74,8 @@ var xmlhttp;
@else
xmlhttp = false;
@end @*/
-if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
- xmlhttp = new XMLHttpRequest();
+if (!xmlhttp && typeof XMLHttpRequest !== 'undefined') {
+ xmlhttp = new XMLHttpRequest();
}
// ----------------------------------------------------------------------------
@@ -90,7 +90,7 @@ function findPosX(obj) {
obj = obj.offsetParent;
}
// IE offsetParent does not include the top-level
- if (isIE && obj.parentElement){
+ if (isIE && obj.parentElement) {
curleft += obj.offsetLeft - obj.scrollLeft;
}
} else if (obj.x) {
@@ -107,7 +107,7 @@ function findPosY(obj) {
obj = obj.offsetParent;
}
// IE offsetParent does not include the top-level
- if (isIE && obj.parentElement){
+ if (isIE && obj.parentElement) {
curtop += obj.offsetTop - obj.scrollTop;
}
} else if (obj.y) {
@@ -121,46 +121,46 @@ function findPosY(obj) {
// ----------------------------------------------------------------------------
Date.prototype.getTwelveHours = function() {
- hours = this.getHours();
- if (hours == 0) {
+ var hours = this.getHours();
+ if (hours === 0) {
return 12;
}
else {
- return hours <= 12 ? hours : hours-12
+ return hours <= 12 ? hours : hours-12;
}
-}
+};
Date.prototype.getTwoDigitMonth = function() {
return (this.getMonth() < 9) ? '0' + (this.getMonth()+1) : (this.getMonth()+1);
-}
+};
Date.prototype.getTwoDigitDate = function() {
return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate();
-}
+};
Date.prototype.getTwoDigitTwelveHour = function() {
return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours();
-}
+};
Date.prototype.getTwoDigitHour = function() {
return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours();
-}
+};
Date.prototype.getTwoDigitMinute = function() {
return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes();
-}
+};
Date.prototype.getTwoDigitSecond = function() {
return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds();
-}
+};
Date.prototype.getHourMinute = function() {
return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute();
-}
+};
Date.prototype.getHourMinuteSecond = function() {
return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute() + ':' + this.getTwoDigitSecond();
-}
+};
Date.prototype.strftime = function(format) {
var fields = {
@@ -191,7 +191,7 @@ Date.prototype.strftime = function(format) {
++i;
}
return result;
-}
+};
// ----------------------------------------------------------------------------
// String object extensions
@@ -202,42 +202,43 @@ String.prototype.pad_left = function(pad_length, pad_string) {
new_string = pad_string + new_string;
}
return new_string;
-}
+};
String.prototype.strptime = function(format) {
var split_format = format.split(/[.\-/]/);
var date = this.split(/[.\-/]/);
var i = 0;
+ var day, month, year;
while (i < split_format.length) {
switch (split_format[i]) {
case "%d":
- var day = date[i];
+ day = date[i];
break;
case "%m":
- var month = date[i] - 1;
+ month = date[i] - 1;
break;
case "%Y":
- var year = date[i];
+ year = date[i];
break;
case "%y":
- var year = date[i];
+ year = date[i];
break;
}
++i;
- };
+ }
return new Date(year, month, day);
-}
+};
// ----------------------------------------------------------------------------
// Get the computed style for and element
// ----------------------------------------------------------------------------
-function getStyle(oElm, strCssRule){
+function getStyle(oElm, strCssRule) {
var strValue = "";
- if(document.defaultView && document.defaultView.getComputedStyle){
+ if(document.defaultView && document.defaultView.getComputedStyle) {
strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
}
- else if(oElm.currentStyle){
- strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
+ else if(oElm.currentStyle) {
+ strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1) {
return p1.toUpperCase();
});
strValue = oElm.currentStyle[strCssRule];
diff --git a/django/contrib/admin/static/admin/js/inlines.js b/django/contrib/admin/static/admin/js/inlines.js
index 6f127365e6..e977fc9fa5 100644
--- a/django/contrib/admin/static/admin/js/inlines.js
+++ b/django/contrib/admin/static/admin/js/inlines.js
@@ -1,3 +1,4 @@
+/*global DateTimeShortcuts, SelectFilter*/
/**
* Django admin inlines
*
@@ -15,258 +16,260 @@
* See: http://www.opensource.org/licenses/bsd-license.php
*/
(function($) {
- $.fn.formset = function(opts) {
- var options = $.extend({}, $.fn.formset.defaults, opts);
- var $this = $(this);
- var $parent = $this.parent();
- var updateElementIndex = function(el, prefix, ndx) {
- var id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))");
- var replacement = prefix + "-" + ndx;
- if ($(el).prop("for")) {
- $(el).prop("for", $(el).prop("for").replace(id_regex, replacement));
- }
- if (el.id) {
- el.id = el.id.replace(id_regex, replacement);
- }
- if (el.name) {
- el.name = el.name.replace(id_regex, replacement);
- }
- };
- var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").prop("autocomplete", "off");
- var nextIndex = parseInt(totalForms.val(), 10);
- var maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").prop("autocomplete", "off");
- // only show the add button if we are allowed to add more items,
+ $.fn.formset = function(opts) {
+ var options = $.extend({}, $.fn.formset.defaults, opts);
+ var $this = $(this);
+ var $parent = $this.parent();
+ var updateElementIndex = function(el, prefix, ndx) {
+ var id_regex = new RegExp("(" + prefix + "-(\\d+|__prefix__))");
+ var replacement = prefix + "-" + ndx;
+ if ($(el).prop("for")) {
+ $(el).prop("for", $(el).prop("for").replace(id_regex, replacement));
+ }
+ if (el.id) {
+ el.id = el.id.replace(id_regex, replacement);
+ }
+ if (el.name) {
+ el.name = el.name.replace(id_regex, replacement);
+ }
+ };
+ var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS").prop("autocomplete", "off");
+ var nextIndex = parseInt(totalForms.val(), 10);
+ var maxForms = $("#id_" + options.prefix + "-MAX_NUM_FORMS").prop("autocomplete", "off");
+ // only show the add button if we are allowed to add more items,
// note that max_num = None translates to a blank string.
- var showAddButton = maxForms.val() === '' || (maxForms.val()-totalForms.val()) > 0;
- $this.each(function(i) {
- $(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
- });
- if ($this.length && showAddButton) {
- var addButton;
- if ($this.prop("tagName") == "TR") {
- // If forms are laid out as table rows, insert the
- // "add" button in a new table row:
- var numCols = this.eq(-1).children().length;
- $parent.append('<tr class="' + options.addCssClass + '"><td colspan="' + numCols + '"><a href="javascript:void(0)">' + options.addText + "</a></tr>");
- addButton = $parent.find("tr:last a");
- } else {
- // Otherwise, insert it immediately after the last form:
- $this.filter(":last").after('<div class="' + options.addCssClass + '"><a href="javascript:void(0)">' + options.addText + "</a></div>");
- addButton = $this.filter(":last").next().find("a");
- }
- addButton.click(function(e) {
- e.preventDefault();
- var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS");
- var template = $("#" + options.prefix + "-empty");
- var row = template.clone(true);
- row.removeClass(options.emptyCssClass)
- .addClass(options.formCssClass)
- .attr("id", options.prefix + "-" + nextIndex);
- if (row.is("tr")) {
- // If the forms are laid out in table rows, insert
- // the remove button into the last table cell:
- row.children(":last").append('<div><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></div>");
- } else if (row.is("ul") || row.is("ol")) {
- // If they're laid out as an ordered/unordered list,
- // insert an <li> after the last list item:
- row.append('<li><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></li>");
- } else {
- // Otherwise, just insert the remove button as the
- // last child element of the form's container:
- row.children(":first").append('<span><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText + "</a></span>");
- }
- row.find("*").each(function() {
- updateElementIndex(this, options.prefix, totalForms.val());
+ var showAddButton = maxForms.val() === '' || (maxForms.val()-totalForms.val()) > 0;
+ $this.each(function(i) {
+ $(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
});
- // Insert the new form when it has been fully edited
- row.insertBefore($(template));
- // Update number of total forms
- $(totalForms).val(parseInt(totalForms.val(), 10) + 1);
- nextIndex += 1;
- // Hide add button in case we've hit the max, except we want to add infinitely
- if ((maxForms.val() !== '') && (maxForms.val()-totalForms.val()) <= 0) {
- addButton.parent().hide();
- }
- // The delete button of each row triggers a bunch of other things
- row.find("a." + options.deleteCssClass).click(function(e) {
- e.preventDefault();
- // Remove the parent form containing this button:
- var row = $(this).parents("." + options.formCssClass);
- row.remove();
- nextIndex -= 1;
- // If a post-delete callback was provided, call it with the deleted form:
- if (options.removed) {
- options.removed(row);
- }
- // Update the TOTAL_FORMS form count.
- var forms = $("." + options.formCssClass);
- $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
- // Show add button again once we drop below max
- if ((maxForms.val() === '') || (maxForms.val()-forms.length) > 0) {
- addButton.parent().show();
- }
- // Also, update names and ids for all remaining form controls
- // so they remain in sequence:
- for (var i=0, formCount=forms.length; i<formCount; i++)
- {
- updateElementIndex($(forms).get(i), options.prefix, i);
- $(forms.get(i)).find("*").each(function() {
- updateElementIndex(this, options.prefix, i);
+ if ($this.length && showAddButton) {
+ var addButton;
+ if ($this.prop("tagName") === "TR") {
+ // If forms are laid out as table rows, insert the
+ // "add" button in a new table row:
+ var numCols = this.eq(-1).children().length;
+ $parent.append('<tr class="' + options.addCssClass + '"><td colspan="' + numCols + '"><a href="javascript:void(0)">' + options.addText + "</a></tr>");
+ addButton = $parent.find("tr:last a");
+ } else {
+ // Otherwise, insert it immediately after the last form:
+ $this.filter(":last").after('<div class="' + options.addCssClass + '"><a href="javascript:void(0)">' + options.addText + "</a></div>");
+ addButton = $this.filter(":last").next().find("a");
+ }
+ addButton.click(function(e) {
+ e.preventDefault();
+ var totalForms = $("#id_" + options.prefix + "-TOTAL_FORMS");
+ var template = $("#" + options.prefix + "-empty");
+ var row = template.clone(true);
+ row.removeClass(options.emptyCssClass)
+ .addClass(options.formCssClass)
+ .attr("id", options.prefix + "-" + nextIndex);
+ if (row.is("tr")) {
+ // If the forms are laid out in table rows, insert
+ // the remove button into the last table cell:
+ row.children(":last").append('<div><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></div>");
+ } else if (row.is("ul") || row.is("ol")) {
+ // If they're laid out as an ordered/unordered list,
+ // insert an <li> after the last list item:
+ row.append('<li><a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + "</a></li>");
+ } else {
+ // Otherwise, just insert the remove button as the
+ // last child element of the form's container:
+ row.children(":first").append('<span><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText + "</a></span>");
+ }
+ row.find("*").each(function() {
+ updateElementIndex(this, options.prefix, totalForms.val());
+ });
+ // Insert the new form when it has been fully edited
+ row.insertBefore($(template));
+ // Update number of total forms
+ $(totalForms).val(parseInt(totalForms.val(), 10) + 1);
+ nextIndex += 1;
+ // Hide add button in case we've hit the max, except we want to add infinitely
+ if ((maxForms.val() !== '') && (maxForms.val()-totalForms.val()) <= 0) {
+ addButton.parent().hide();
+ }
+ // The delete button of each row triggers a bunch of other things
+ row.find("a." + options.deleteCssClass).click(function(e) {
+ e.preventDefault();
+ // Remove the parent form containing this button:
+ var row = $(this).parents("." + options.formCssClass);
+ row.remove();
+ nextIndex -= 1;
+ // If a post-delete callback was provided, call it with the deleted form:
+ if (options.removed) {
+ options.removed(row);
+ }
+ // Update the TOTAL_FORMS form count.
+ var forms = $("." + options.formCssClass);
+ $("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
+ // Show add button again once we drop below max
+ if ((maxForms.val() === '') || (maxForms.val()-forms.length) > 0) {
+ addButton.parent().show();
+ }
+ // Also, update names and ids for all remaining form controls
+ // so they remain in sequence:
+ var i, formCount;
+ var updateElementCallback = function() {
+ updateElementIndex(this, options.prefix, i);
+ };
+ for (i=0, formCount=forms.length; i<formCount; i++)
+ {
+ updateElementIndex($(forms).get(i), options.prefix, i);
+ $(forms.get(i)).find("*").each(updateElementCallback);
+ }
+ });
+ // If a post-add callback was supplied, call it with the added form:
+ if (options.added) {
+ options.added(row);
+ }
});
- }
- });
- // If a post-add callback was supplied, call it with the added form:
- if (options.added) {
- options.added(row);
}
- });
- }
- return this;
- };
+ return this;
+ };
- /* Setup plugin defaults */
- $.fn.formset.defaults = {
- prefix: "form", // The form prefix for your django formset
- addText: "add another", // Text for the add link
- deleteText: "remove", // Text for the delete link
- addCssClass: "add-row", // CSS class applied to the add link
- deleteCssClass: "delete-row", // CSS class applied to the delete link
- emptyCssClass: "empty-row", // CSS class applied to the empty row
- formCssClass: "dynamic-form", // CSS class applied to each form in a formset
- added: null, // Function called each time a new form is added
- removed: null // Function called each time a form is deleted
- };
+ /* Setup plugin defaults */
+ $.fn.formset.defaults = {
+ prefix: "form", // The form prefix for your django formset
+ addText: "add another", // Text for the add link
+ deleteText: "remove", // Text for the delete link
+ addCssClass: "add-row", // CSS class applied to the add link
+ deleteCssClass: "delete-row", // CSS class applied to the delete link
+ emptyCssClass: "empty-row", // CSS class applied to the empty row
+ formCssClass: "dynamic-form", // CSS class applied to each form in a formset
+ added: null, // Function called each time a new form is added
+ removed: null // Function called each time a form is deleted
+ };
- // Tabular inlines ---------------------------------------------------------
- $.fn.tabularFormset = function(options) {
- var $rows = $(this);
- var alternatingRows = function(row) {
- $($rows.selector).not(".add-row").removeClass("row1 row2")
- .filter(":even").addClass("row1").end()
- .filter(":odd").addClass("row2");
- };
+ // Tabular inlines ---------------------------------------------------------
+ $.fn.tabularFormset = function(options) {
+ var $rows = $(this);
+ var alternatingRows = function(row) {
+ $($rows.selector).not(".add-row").removeClass("row1 row2")
+ .filter(":even").addClass("row1").end()
+ .filter(":odd").addClass("row2");
+ };
- var reinitDateTimeShortCuts = function() {
- // Reinitialize the calendar and clock widgets by force
- if (typeof DateTimeShortcuts != "undefined") {
- $(".datetimeshortcuts").remove();
- DateTimeShortcuts.init();
- }
- };
+ var reinitDateTimeShortCuts = function() {
+ // Reinitialize the calendar and clock widgets by force
+ if (typeof DateTimeShortcuts !== "undefined") {
+ $(".datetimeshortcuts").remove();
+ DateTimeShortcuts.init();
+ }
+ };
- var updateSelectFilter = function() {
- // If any SelectFilter widgets are a part of the new form,
- // instantiate a new SelectFilter instance for it.
- if (typeof SelectFilter != 'undefined'){
- $('.selectfilter').each(function(index, value){
- var namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length-1], false);
- });
- $('.selectfilterstacked').each(function(index, value){
- var namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length-1], true);
- });
- }
- };
+ var updateSelectFilter = function() {
+ // If any SelectFilter widgets are a part of the new form,
+ // instantiate a new SelectFilter instance for it.
+ if (typeof SelectFilter !== 'undefined') {
+ $('.selectfilter').each(function(index, value) {
+ var namearr = value.name.split('-');
+ SelectFilter.init(value.id, namearr[namearr.length-1], false);
+ });
+ $('.selectfilterstacked').each(function(index, value) {
+ var namearr = value.name.split('-');
+ SelectFilter.init(value.id, namearr[namearr.length-1], true);
+ });
+ }
+ };
+
+ var initPrepopulatedFields = function(row) {
+ row.find('.prepopulated_field').each(function() {
+ var field = $(this),
+ input = field.find('input, select, textarea'),
+ dependency_list = input.data('dependency_list') || [],
+ dependencies = [];
+ $.each(dependency_list, function(i, field_name) {
+ dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id'));
+ });
+ if (dependencies.length) {
+ input.prepopulate(dependencies, input.attr('maxlength'));
+ }
+ });
+ };
- var initPrepopulatedFields = function(row) {
- row.find('.prepopulated_field').each(function() {
- var field = $(this),
- input = field.find('input, select, textarea'),
- dependency_list = input.data('dependency_list') || [],
- dependencies = [];
- $.each(dependency_list, function(i, field_name) {
- dependencies.push('#' + row.find('.field-' + field_name).find('input, select, textarea').attr('id'));
+ $rows.formset({
+ prefix: options.prefix,
+ addText: options.addText,
+ formCssClass: "dynamic-" + options.prefix,
+ deleteCssClass: "inline-deletelink",
+ deleteText: options.deleteText,
+ emptyCssClass: "empty-form",
+ removed: alternatingRows,
+ added: function(row) {
+ initPrepopulatedFields(row);
+ reinitDateTimeShortCuts();
+ updateSelectFilter();
+ alternatingRows(row);
+ }
});
- if (dependencies.length) {
- input.prepopulate(dependencies, input.attr('maxlength'));
- }
- });
+
+ return $rows;
};
- $rows.formset({
- prefix: options.prefix,
- addText: options.addText,
- formCssClass: "dynamic-" + options.prefix,
- deleteCssClass: "inline-deletelink",
- deleteText: options.deleteText,
- emptyCssClass: "empty-form",
- removed: alternatingRows,
- added: function(row) {
- initPrepopulatedFields(row);
- reinitDateTimeShortCuts();
- updateSelectFilter();
- alternatingRows(row);
- }
- });
+ // Stacked inlines ---------------------------------------------------------
+ $.fn.stackedFormset = function(options) {
+ var $rows = $(this);
+ var updateInlineLabel = function(row) {
+ $($rows.selector).find(".inline_label").each(function(i) {
+ var count = i + 1;
+ $(this).html($(this).html().replace(/(#\d+)/g, "#" + count));
+ });
+ };
- return $rows;
- };
+ var reinitDateTimeShortCuts = function() {
+ // Reinitialize the calendar and clock widgets by force, yuck.
+ if (typeof DateTimeShortcuts !== "undefined") {
+ $(".datetimeshortcuts").remove();
+ DateTimeShortcuts.init();
+ }
+ };
- // Stacked inlines ---------------------------------------------------------
- $.fn.stackedFormset = function(options) {
- var $rows = $(this);
- var updateInlineLabel = function(row) {
- $($rows.selector).find(".inline_label").each(function(i) {
- var count = i + 1;
- $(this).html($(this).html().replace(/(#\d+)/g, "#" + count));
- });
- };
+ var updateSelectFilter = function() {
+ // If any SelectFilter widgets were added, instantiate a new instance.
+ if (typeof SelectFilter !== "undefined") {
+ $(".selectfilter").each(function(index, value) {
+ var namearr = value.name.split('-');
+ SelectFilter.init(value.id, namearr[namearr.length-1], false);
+ });
+ $(".selectfilterstacked").each(function(index, value) {
+ var namearr = value.name.split('-');
+ SelectFilter.init(value.id, namearr[namearr.length-1], true);
+ });
+ }
+ };
- var reinitDateTimeShortCuts = function() {
- // Reinitialize the calendar and clock widgets by force, yuck.
- if (typeof DateTimeShortcuts != "undefined") {
- $(".datetimeshortcuts").remove();
- DateTimeShortcuts.init();
- }
- };
+ var initPrepopulatedFields = function(row) {
+ row.find('.prepopulated_field').each(function() {
+ var field = $(this),
+ input = field.find('input, select, textarea'),
+ dependency_list = input.data('dependency_list') || [],
+ dependencies = [];
+ $.each(dependency_list, function(i, field_name) {
+ dependencies.push('#' + row.find('.form-row .field-' + field_name).find('input, select, textarea').attr('id'));
+ });
+ if (dependencies.length) {
+ input.prepopulate(dependencies, input.attr('maxlength'));
+ }
+ });
+ };
- var updateSelectFilter = function() {
- // If any SelectFilter widgets were added, instantiate a new instance.
- if (typeof SelectFilter != "undefined"){
- $(".selectfilter").each(function(index, value){
- var namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length-1], false);
+ $rows.formset({
+ prefix: options.prefix,
+ addText: options.addText,
+ formCssClass: "dynamic-" + options.prefix,
+ deleteCssClass: "inline-deletelink",
+ deleteText: options.deleteText,
+ emptyCssClass: "empty-form",
+ removed: updateInlineLabel,
+ added: function(row) {
+ initPrepopulatedFields(row);
+ reinitDateTimeShortCuts();
+ updateSelectFilter();
+ updateInlineLabel(row);
+ }
});
- $(".selectfilterstacked").each(function(index, value){
- var namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length-1], true);
- });
- }
- };
- var initPrepopulatedFields = function(row) {
- row.find('.prepopulated_field').each(function() {
- var field = $(this),
- input = field.find('input, select, textarea'),
- dependency_list = input.data('dependency_list') || [],
- dependencies = [];
- $.each(dependency_list, function(i, field_name) {
- dependencies.push('#' + row.find('.form-row .field-' + field_name).find('input, select, textarea').attr('id'));
- });
- if (dependencies.length) {
- input.prepopulate(dependencies, input.attr('maxlength'));
- }
- });
+ return $rows;
};
-
- $rows.formset({
- prefix: options.prefix,
- addText: options.addText,
- formCssClass: "dynamic-" + options.prefix,
- deleteCssClass: "inline-deletelink",
- deleteText: options.deleteText,
- emptyCssClass: "empty-form",
- removed: updateInlineLabel,
- added: (function(row) {
- initPrepopulatedFields(row);
- reinitDateTimeShortCuts();
- updateSelectFilter();
- updateInlineLabel(row);
- })
- });
-
- return $rows;
- };
})(django.jQuery);
diff --git a/django/contrib/admin/static/admin/js/inlines.min.js b/django/contrib/admin/static/admin/js/inlines.min.js
index aa698cf4e1..64bcd0d8e7 100644
--- a/django/contrib/admin/static/admin/js/inlines.min.js
+++ b/django/contrib/admin/static/admin/js/inlines.min.js
@@ -1,9 +1,9 @@
-(function(c){c.fn.formset=function(b){var a=c.extend({},c.fn.formset.defaults,b),d=c(this);b=d.parent();var k=function(a,f,l){var h=new RegExp("("+f+"-(\\d+|__prefix__))");f=f+"-"+l;c(a).prop("for")&&c(a).prop("for",c(a).prop("for").replace(h,f));a.id&&(a.id=a.id.replace(h,f));a.name&&(a.name=a.name.replace(h,f))},e=c("#id_"+a.prefix+"-TOTAL_FORMS").prop("autocomplete","off"),l=parseInt(e.val(),10),f=c("#id_"+a.prefix+"-MAX_NUM_FORMS").prop("autocomplete","off"),e=""===f.val()||0<f.val()-e.val();
-d.each(function(f){c(this).not("."+a.emptyCssClass).addClass(a.formCssClass)});if(d.length&&e){var h;"TR"==d.prop("tagName")?(d=this.eq(-1).children().length,b.append('<tr class="'+a.addCssClass+'"><td colspan="'+d+'"><a href="javascript:void(0)">'+a.addText+"</a></tr>"),h=b.find("tr:last a")):(d.filter(":last").after('<div class="'+a.addCssClass+'"><a href="javascript:void(0)">'+a.addText+"</a></div>"),h=d.filter(":last").next().find("a"));h.click(function(b){b.preventDefault();var d=c("#id_"+a.prefix+
-"-TOTAL_FORMS");b=c("#"+a.prefix+"-empty");var g=b.clone(!0);g.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+l);g.is("tr")?g.children(":last").append('<div><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></div>"):g.is("ul")||g.is("ol")?g.append('<li><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></li>"):g.children(":first").append('<span><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+
-"</a></span>");g.find("*").each(function(){k(this,a.prefix,d.val())});g.insertBefore(c(b));c(d).val(parseInt(d.val(),10)+1);l+=1;""!==f.val()&&0>=f.val()-d.val()&&h.parent().hide();g.find("a."+a.deleteCssClass).click(function(b){b.preventDefault();b=c(this).parents("."+a.formCssClass);b.remove();--l;a.removed&&a.removed(b);b=c("."+a.formCssClass);c("#id_"+a.prefix+"-TOTAL_FORMS").val(b.length);(""===f.val()||0<f.val()-b.length)&&h.parent().show();for(var d=0,g=b.length;d<g;d++)k(c(b).get(d),a.prefix,
-d),c(b.get(d)).find("*").each(function(){k(this,a.prefix,d)})});a.added&&a.added(g)})}return this};c.fn.formset.defaults={prefix:"form",addText:"add another",deleteText:"remove",addCssClass:"add-row",deleteCssClass:"delete-row",emptyCssClass:"empty-row",formCssClass:"dynamic-form",added:null,removed:null};c.fn.tabularFormset=function(b){var a=c(this),d=function(b){c(a.selector).not(".add-row").removeClass("row1 row2").filter(":even").addClass("row1").end().filter(":odd").addClass("row2")},k=function(){"undefined"!=
-typeof SelectFilter&&(c(".selectfilter").each(function(a,c){var b=c.name.split("-");SelectFilter.init(c.id,b[b.length-1],!1)}),c(".selectfilterstacked").each(function(a,c){var b=c.name.split("-");SelectFilter.init(c.id,b[b.length-1],!0)}))},e=function(a){a.find(".prepopulated_field").each(function(){var b=c(this).find("input, select, textarea"),d=b.data("dependency_list")||[],e=[];c.each(d,function(c,b){e.push("#"+a.find(".field-"+b).find("input, select, textarea").attr("id"))});e.length&&b.prepopulate(e,
-b.attr("maxlength"))})};a.formset({prefix:b.prefix,addText:b.addText,formCssClass:"dynamic-"+b.prefix,deleteCssClass:"inline-deletelink",deleteText:b.deleteText,emptyCssClass:"empty-form",removed:d,added:function(a){e(a);"undefined"!=typeof DateTimeShortcuts&&(c(".datetimeshortcuts").remove(),DateTimeShortcuts.init());k();d(a)}});return a};c.fn.stackedFormset=function(b){var a=c(this),d=function(b){c(a.selector).find(".inline_label").each(function(a){a+=1;c(this).html(c(this).html().replace(/(#\d+)/g,
-"#"+a))})},k=function(){"undefined"!=typeof SelectFilter&&(c(".selectfilter").each(function(a,c){var b=c.name.split("-");SelectFilter.init(c.id,b[b.length-1],!1)}),c(".selectfilterstacked").each(function(a,c){var b=c.name.split("-");SelectFilter.init(c.id,b[b.length-1],!0)}))},e=function(a){a.find(".prepopulated_field").each(function(){var b=c(this).find("input, select, textarea"),d=b.data("dependency_list")||[],e=[];c.each(d,function(b,c){e.push("#"+a.find(".form-row .field-"+c).find("input, select, textarea").attr("id"))});
-e.length&&b.prepopulate(e,b.attr("maxlength"))})};a.formset({prefix:b.prefix,addText:b.addText,formCssClass:"dynamic-"+b.prefix,deleteCssClass:"inline-deletelink",deleteText:b.deleteText,emptyCssClass:"empty-form",removed:d,added:function(a){e(a);"undefined"!=typeof DateTimeShortcuts&&(c(".datetimeshortcuts").remove(),DateTimeShortcuts.init());k();d(a)}});return a}})(django.jQuery);
+(function(c){c.fn.formset=function(b){var a=c.extend({},c.fn.formset.defaults,b),d=c(this);b=d.parent();var k=function(a,g,l){var h=new RegExp("("+g+"-(\\d+|__prefix__))");g=g+"-"+l;c(a).prop("for")&&c(a).prop("for",c(a).prop("for").replace(h,g));a.id&&(a.id=a.id.replace(h,g));a.name&&(a.name=a.name.replace(h,g))},f=c("#id_"+a.prefix+"-TOTAL_FORMS").prop("autocomplete","off"),l=parseInt(f.val(),10),g=c("#id_"+a.prefix+"-MAX_NUM_FORMS").prop("autocomplete","off"),f=""===g.val()||0<g.val()-f.val();
+d.each(function(g){c(this).not("."+a.emptyCssClass).addClass(a.formCssClass)});if(d.length&&f){var h;"TR"==d.prop("tagName")?(d=this.eq(-1).children().length,b.append('<tr class="'+a.addCssClass+'"><td colspan="'+d+'"><a href="javascript:void(0)">'+a.addText+"</a></tr>"),h=b.find("tr:last a")):(d.filter(":last").after('<div class="'+a.addCssClass+'"><a href="javascript:void(0)">'+a.addText+"</a></div>"),h=d.filter(":last").next().find("a"));h.click(function(b){b.preventDefault();var d=c("#id_"+a.prefix+
+"-TOTAL_FORMS");b=c("#"+a.prefix+"-empty");var e=b.clone(!0);e.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+l);e.is("tr")?e.children(":last").append('<div><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></div>"):e.is("ul")||e.is("ol")?e.append('<li><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+"</a></li>"):e.children(":first").append('<span><a class="'+a.deleteCssClass+'" href="javascript:void(0)">'+a.deleteText+
+"</a></span>");e.find("*").each(function(){k(this,a.prefix,d.val())});e.insertBefore(c(b));c(d).val(parseInt(d.val(),10)+1);l+=1;""!==g.val()&&0>=g.val()-d.val()&&h.parent().hide();e.find("a."+a.deleteCssClass).click(function(b){b.preventDefault();b=c(this).parents("."+a.formCssClass);b.remove();--l;a.removed&&a.removed(b);b=c("."+a.formCssClass);c("#id_"+a.prefix+"-TOTAL_FORMS").val(b.length);(""===g.val()||0<g.val()-b.length)&&h.parent().show();for(var d=function(){k(this,a.prefix,e)},e=0,f=b.length;e<
+f;e++)k(c(b).get(e),a.prefix,e),c(b.get(e)).find("*").each(d)});a.added&&a.added(e)})}return this};c.fn.formset.defaults={prefix:"form",addText:"add another",deleteText:"remove",addCssClass:"add-row",deleteCssClass:"delete-row",emptyCssClass:"empty-row",formCssClass:"dynamic-form",added:null,removed:null};c.fn.tabularFormset=function(b){var a=c(this),d=function(b){c(a.selector).not(".add-row").removeClass("row1 row2").filter(":even").addClass("row1").end().filter(":odd").addClass("row2")},k=function(){"undefined"!=
+typeof SelectFilter&&(c(".selectfilter").each(function(a,c){var b=c.name.split("-");SelectFilter.init(c.id,b[b.length-1],!1)}),c(".selectfilterstacked").each(function(a,c){var b=c.name.split("-");SelectFilter.init(c.id,b[b.length-1],!0)}))},f=function(a){a.find(".prepopulated_field").each(function(){var b=c(this).find("input, select, textarea"),d=b.data("dependency_list")||[],f=[];c.each(d,function(c,b){f.push("#"+a.find(".field-"+b).find("input, select, textarea").attr("id"))});f.length&&b.prepopulate(f,
+b.attr("maxlength"))})};a.formset({prefix:b.prefix,addText:b.addText,formCssClass:"dynamic-"+b.prefix,deleteCssClass:"inline-deletelink",deleteText:b.deleteText,emptyCssClass:"empty-form",removed:d,added:function(a){f(a);"undefined"!=typeof DateTimeShortcuts&&(c(".datetimeshortcuts").remove(),DateTimeShortcuts.init());k();d(a)}});return a};c.fn.stackedFormset=function(b){var a=c(this),d=function(b){c(a.selector).find(".inline_label").each(function(a){a+=1;c(this).html(c(this).html().replace(/(#\d+)/g,
+"#"+a))})},k=function(){"undefined"!=typeof SelectFilter&&(c(".selectfilter").each(function(a,c){var b=c.name.split("-");SelectFilter.init(c.id,b[b.length-1],!1)}),c(".selectfilterstacked").each(function(a,c){var b=c.name.split("-");SelectFilter.init(c.id,b[b.length-1],!0)}))},f=function(a){a.find(".prepopulated_field").each(function(){var b=c(this).find("input, select, textarea"),d=b.data("dependency_list")||[],f=[];c.each(d,function(b,c){f.push("#"+a.find(".form-row .field-"+c).find("input, select, textarea").attr("id"))});
+f.length&&b.prepopulate(f,b.attr("maxlength"))})};a.formset({prefix:b.prefix,addText:b.addText,formCssClass:"dynamic-"+b.prefix,deleteCssClass:"inline-deletelink",deleteText:b.deleteText,emptyCssClass:"empty-form",removed:d,added:function(a){f(a);"undefined"!=typeof DateTimeShortcuts&&(c(".datetimeshortcuts").remove(),DateTimeShortcuts.init());k();d(a)}});return a}})(django.jQuery);
diff --git a/django/contrib/admin/static/admin/js/jquery.init.js b/django/contrib/admin/static/admin/js/jquery.init.js
index 22a4c8bfd3..f3ac162514 100644
--- a/django/contrib/admin/static/admin/js/jquery.init.js
+++ b/django/contrib/admin/static/admin/js/jquery.init.js
@@ -1,3 +1,4 @@
+/*global django:true, jQuery:false*/
/* Puts the included jQuery into our own namespace using noConflict and passing
* it 'true'. This ensures that the included jQuery doesn't pollute the global
* namespace (i.e. this preserves pre-existing values for both window.$ and
diff --git a/django/contrib/admin/static/admin/js/prepopulate.js b/django/contrib/admin/static/admin/js/prepopulate.js
index db7903a5ef..1b268999f3 100644
--- a/django/contrib/admin/static/admin/js/prepopulate.js
+++ b/django/contrib/admin/static/admin/js/prepopulate.js
@@ -1,3 +1,4 @@
+/*global URLify*/
(function($) {
$.fn.prepopulate = function(dependencies, maxLength) {
/*
diff --git a/django/contrib/admin/static/admin/js/prepopulate.min.js b/django/contrib/admin/static/admin/js/prepopulate.min.js
index 4a75827c97..dfac041b40 100644
--- a/django/contrib/admin/static/admin/js/prepopulate.min.js
+++ b/django/contrib/admin/static/admin/js/prepopulate.min.js
@@ -1 +1 @@
-(function(b){b.fn.prepopulate=function(e,g){return this.each(function(){var a=b(this),d=function(){if(!a.data("_changed")){var f=[];b.each(e,function(h,c){c=b(c);c.val().length>0&&f.push(c.val())});a.val(URLify(f.join(" "),g))}};a.data("_changed",false);a.change(function(){a.data("_changed",true)});a.val()||b(e.join(",")).keyup(d).change(d).focus(d)})}})(django.jQuery);
+(function(c){c.fn.prepopulate=function(e,f){return this.each(function(){var a=c(this),b=function(){if(!a.data("_changed")){var b=[];c.each(e,function(a,d){d=c(d);0<d.val().length&&b.push(d.val())});a.val(URLify(b.join(" "),f))}};a.data("_changed",!1);a.change(function(){a.data("_changed",!0)});a.val()||c(e.join(",")).keyup(b).change(b).focus(b)})}})(django.jQuery);
diff --git a/django/contrib/admin/static/admin/js/timeparse.js b/django/contrib/admin/static/admin/js/timeparse.js
index 882f41d56e..50747c8199 100644
--- a/django/contrib/admin/static/admin/js/timeparse.js
+++ b/django/contrib/admin/static/admin/js/timeparse.js
@@ -2,7 +2,7 @@ var timeParsePatterns = [
// 9
{ re: /^\d{1,2}$/i,
handler: function(bits) {
- if (bits[0].length == 1) {
+ if (bits[0].length === 1) {
return '0' + bits[0] + ':00';
} else {
return bits[0] + ':00';
@@ -25,11 +25,11 @@ var timeParsePatterns = [
{ re: /^(\d+)\s*([ap])(?:.?m.?)?$/i,
handler: function(bits) {
var hour = parseInt(bits[1]);
- if (hour == 12) {
+ if (hour === 12) {
hour = 0;
}
- if (bits[2].toLowerCase() == 'p') {
- if (hour == 12) {
+ if (bits[2].toLowerCase() === 'p') {
+ if (hour === 12) {
hour = 0;
}
return (hour + 12) + ':00';
@@ -50,11 +50,11 @@ var timeParsePatterns = [
if (mins < 10) {
mins = '0' + mins;
}
- if (hour == 12) {
+ if (hour === 12) {
hour = 0;
}
- if (bits[3].toLowerCase() == 'p') {
- if (hour == 12) {
+ if (bits[3].toLowerCase() === 'p') {
+ if (hour === 12) {
hour = 0;
}
return (hour + 12) + ':' + mins;
diff --git a/django/contrib/gis/static/gis/js/OLMapWidget.js b/django/contrib/gis/static/gis/js/OLMapWidget.js
index e743310632..fde1f3cf23 100644
--- a/django/contrib/gis/static/gis/js/OLMapWidget.js
+++ b/django/contrib/gis/static/gis/js/OLMapWidget.js
@@ -1,10 +1,12 @@
+/*global OpenLayers*/
+/*eslint indent:1*/
(function() {
-/**
- * Transforms an array of features to a single feature with the merged
- * geometry of geom_type
- */
+ /**
+ * Transforms an array of features to a single feature with the merged
+ * geometry of geom_type
+ */
OpenLayers.Util.properFeatures = function(features, geom_type) {
- if (features.constructor == Array) {
+ if (features.constructor === Array) {
var geoms = [];
for (var i=0; i<features.length; i++) {
geoms.push(features[i].geometry);
@@ -13,7 +15,7 @@ OpenLayers.Util.properFeatures = function(features, geom_type) {
features = new OpenLayers.Feature.Vector(geom);
}
return features;
-}
+};
/**
* @requires OpenLayers/Format/WKT.js
@@ -128,7 +130,7 @@ OpenLayers.Format.DjangoWKT = OpenLayers.Class(OpenLayers.Format.WKT, {
geometry = geometry.clone();
geometry.transform(this.internalProjection, this.externalProjection);
}
- var wktType = type == 'collection' ? 'GEOMETRYCOLLECTION' : type.toUpperCase();
+ var wktType = type === 'collection' ? 'GEOMETRYCOLLECTION' : type.toUpperCase();
var data = wktType + '(' + this.extract[type].apply(this, [geometry]) + ')';
return data;
},
@@ -138,8 +140,8 @@ OpenLayers.Format.DjangoWKT = OpenLayers.Class(OpenLayers.Format.WKT, {
* geometrycollections.
*/
write: function(features) {
- var collection, geometry, type, data, isCollection;
- isCollection = features.geometry.CLASS_NAME == "OpenLayers.Geometry.Collection";
+ var collection, isCollection;
+ isCollection = features.geometry.CLASS_NAME === "OpenLayers.Geometry.Collection";
var pieces = [];
if (isCollection) {
collection = features.geometry.components;
@@ -168,8 +170,8 @@ function MapWidget(options) {
this.wkt_f = new OpenLayers.Format.DjangoWKT();
// Mapping from OGRGeomType name to OpenLayers.Geometry name
- if (options['geom_name'] == 'Unknown') options['geom_type'] = OpenLayers.Geometry;
- else if (options['geom_name'] == 'GeometryCollection') options['geom_type'] = OpenLayers.Geometry.Collection;
+ if (options['geom_name'] === 'Unknown') options['geom_type'] = OpenLayers.Geometry;
+ else if (options['geom_name'] === 'GeometryCollection') options['geom_type'] = OpenLayers.Geometry.Collection;
else options['geom_type'] = eval('OpenLayers.Geometry.' + options['geom_name']);
// Default options
@@ -204,7 +206,7 @@ function MapWidget(options) {
'fillOpacity': this.options.opacity,
'strokeColor': '#' + this.options.color
};
- if (this.options.geom_name == 'LineString') {
+ if (this.options.geom_name === 'LineString') {
defaults_style['strokeWidth'] = 3;
}
var styleMap = new OpenLayers.StyleMap({'default': OpenLayers.Util.applyDefaults(defaults_style, OpenLayers.Feature.Vector.style['default'])});
@@ -222,7 +224,7 @@ function MapWidget(options) {
this.layers.vector.addFeatures([feat]);
}
this.map.zoomToExtent(feat.geometry.getBounds());
- if (this.options.geom_name == 'Point') {
+ if (this.options.geom_name === 'Point') {
this.map.zoomTo(this.options.point_zoom);
}
} else {
@@ -262,7 +264,7 @@ MapWidget.prototype.create_map = function() {
if (this.options.base_layer) this.layers.base = this.options.base_layer;
else this.layers.base = new OpenLayers.Layer.WMS('OpenLayers WMS', 'http://vmap0.tiles.osgeo.org/wms/vmap0', {layers: 'basic'});
map.addLayer(this.layers.base);
- return map
+ return map;
};
MapWidget.prototype.get_ewkt = function(feat) {
@@ -270,7 +272,7 @@ MapWidget.prototype.get_ewkt = function(feat) {
};
MapWidget.prototype.read_wkt = function(wkt) {
- var prefix = 'SRID=' + this.options.map_srid + ';'
+ var prefix = 'SRID=' + this.options.map_srid + ';';
if (wkt.indexOf(prefix) === 0) {
wkt = wkt.slice(prefix.length);
}
@@ -296,7 +298,7 @@ MapWidget.prototype.add_wkt = function(event) {
this.write_wkt(feat);
} else {
if (this.layers.vector.features.length > 1) {
- old_feats = [this.layers.vector.features[0]];
+ var old_feats = [this.layers.vector.features[0]];
this.layers.vector.removeFeatures(old_feats);
this.layers.vector.destroyFeatures(old_feats);
}
@@ -306,7 +308,7 @@ MapWidget.prototype.add_wkt = function(event) {
MapWidget.prototype.modify_wkt = function(event) {
if (this.options.is_collection) {
- if (this.options.geom_name == 'MultiPoint') {
+ if (this.options.geom_name === 'MultiPoint') {
this.add_wkt(event);
return;
} else {
@@ -359,13 +361,13 @@ MapWidget.prototype.getControls = function(layer) {
this.controls = [new OpenLayers.Control.Navigation()];
if (!this.options.modifiable && layer.features.length)
return;
- if (this.options.geom_name.indexOf('LineString') >= 0 || this.options.geom_name == 'GeometryCollection' || this.options.geom_name == 'Unknown') {
+ if (this.options.geom_name.indexOf('LineString') >= 0 || this.options.geom_name === 'GeometryCollection' || this.options.geom_name === 'Unknown') {
this.controls.push(new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Path, {'displayClass': 'olControlDrawFeaturePath'}));
}
- if (this.options.geom_name.indexOf('Polygon') >= 0 || this.options.geom_name == 'GeometryCollection' || this.options.geom_name == 'Unknown') {
+ if (this.options.geom_name.indexOf('Polygon') >= 0 || this.options.geom_name === 'GeometryCollection' || this.options.geom_name === 'Unknown') {
this.controls.push(new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Polygon, {'displayClass': 'olControlDrawFeaturePolygon'}));
}
- if (this.options.geom_name.indexOf('Point') >= 0 || this.options.geom_name == 'GeometryCollection' || this.options.geom_name == 'Unknown') {
+ if (this.options.geom_name.indexOf('Point') >= 0 || this.options.geom_name === 'GeometryCollection' || this.options.geom_name === 'Unknown') {
this.controls.push(new OpenLayers.Control.DrawFeature(layer, OpenLayers.Handler.Point, {'displayClass': 'olControlDrawFeaturePoint'}));
}
if (this.options.modifiable) {
diff --git a/django/contrib/gis/templates/gis/admin/openlayers.js b/django/contrib/gis/templates/gis/admin/openlayers.js
index 4425fee27e..dd00bfd70a 100644
--- a/django/contrib/gis/templates/gis/admin/openlayers.js
+++ b/django/contrib/gis/templates/gis/admin/openlayers.js
@@ -12,98 +12,98 @@ OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:3857", OpenLayers.Layer.Sp
{{ module }}.is_point = {{ is_point|yesno:"true,false" }};
{% endblock %}
{{ module }}.get_ewkt = function(feat){
- return 'SRID={{ srid|unlocalize }};' + {{ module }}.wkt_f.write(feat);
+ return 'SRID={{ srid|unlocalize }};' + {{ module }}.wkt_f.write(feat);
};
{{ module }}.read_wkt = function(wkt){
- // OpenLayers cannot handle EWKT -- we make sure to strip it out.
- // EWKT is only exposed to OL if there's a validation error in the admin.
- var match = {{ module }}.re.exec(wkt);
- if (match){wkt = match[1];}
- return {{ module }}.wkt_f.read(wkt);
+ // OpenLayers cannot handle EWKT -- we make sure to strip it out.
+ // EWKT is only exposed to OL if there's a validation error in the admin.
+ var match = {{ module }}.re.exec(wkt);
+ if (match){wkt = match[1];}
+ return {{ module }}.wkt_f.read(wkt);
};
{{ module }}.write_wkt = function(feat){
- if ({{ module }}.is_collection){ {{ module }}.num_geom = feat.geometry.components.length;}
- else { {{ module }}.num_geom = 1;}
- document.getElementById('{{ id }}').value = {{ module }}.get_ewkt(feat);
+ if ({{ module }}.is_collection){ {{ module }}.num_geom = feat.geometry.components.length;}
+ else { {{ module }}.num_geom = 1;}
+ document.getElementById('{{ id }}').value = {{ module }}.get_ewkt(feat);
};
{{ module }}.add_wkt = function(event){
- // This function will sync the contents of the `vector` layer with the
- // WKT in the text field.
- if ({{ module }}.is_collection){
- var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.{{ geom_type }}());
- for (var i = 0; i < {{ module }}.layers.vector.features.length; i++){
- feat.geometry.addComponents([{{ module }}.layers.vector.features[i].geometry]);
- }
- {{ module }}.write_wkt(feat);
- } else {
- // Make sure to remove any previously added features.
- if ({{ module }}.layers.vector.features.length > 1){
- old_feats = [{{ module }}.layers.vector.features[0]];
- {{ module }}.layers.vector.removeFeatures(old_feats);
- {{ module }}.layers.vector.destroyFeatures(old_feats);
+ // This function will sync the contents of the `vector` layer with the
+ // WKT in the text field.
+ if ({{ module }}.is_collection){
+ var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.{{ geom_type }}());
+ for (var i = 0; i < {{ module }}.layers.vector.features.length; i++){
+ feat.geometry.addComponents([{{ module }}.layers.vector.features[i].geometry]);
+ }
+ {{ module }}.write_wkt(feat);
+ } else {
+ // Make sure to remove any previously added features.
+ if ({{ module }}.layers.vector.features.length > 1){
+ old_feats = [{{ module }}.layers.vector.features[0]];
+ {{ module }}.layers.vector.removeFeatures(old_feats);
+ {{ module }}.layers.vector.destroyFeatures(old_feats);
+ }
+ {{ module }}.write_wkt(event.feature);
}
- {{ module }}.write_wkt(event.feature);
- }
};
{{ module }}.modify_wkt = function(event){
- if ({{ module }}.is_collection){
- if ({{ module }}.is_point){
- {{ module }}.add_wkt(event);
- return;
+ if ({{ module }}.is_collection){
+ if ({{ module }}.is_point){
+ {{ module }}.add_wkt(event);
+ return;
+ } else {
+ // When modifying the selected components are added to the
+ // vector layer so we only increment to the `num_geom` value.
+ var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.{{ geom_type }}());
+ for (var i = 0; i < {{ module }}.num_geom; i++){
+ feat.geometry.addComponents([{{ module }}.layers.vector.features[i].geometry]);
+ }
+ {{ module }}.write_wkt(feat);
+ }
} else {
- // When modifying the selected components are added to the
- // vector layer so we only increment to the `num_geom` value.
- var feat = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.{{ geom_type }}());
- for (var i = 0; i < {{ module }}.num_geom; i++){
- feat.geometry.addComponents([{{ module }}.layers.vector.features[i].geometry]);
- }
- {{ module }}.write_wkt(feat);
+ {{ module }}.write_wkt(event.feature);
}
- } else {
- {{ module }}.write_wkt(event.feature);
- }
};
// Function to clear vector features and purge wkt from div
{{ module }}.deleteFeatures = function(){
- {{ module }}.layers.vector.removeFeatures({{ module }}.layers.vector.features);
- {{ module }}.layers.vector.destroyFeatures();
+ {{ module }}.layers.vector.removeFeatures({{ module }}.layers.vector.features);
+ {{ module }}.layers.vector.destroyFeatures();
};
{{ module }}.clearFeatures = function (){
- {{ module }}.deleteFeatures();
- document.getElementById('{{ id }}').value = '';
- {% localize off %}
- {{ module }}.map.setCenter(new OpenLayers.LonLat({{ default_lon }}, {{ default_lat }}), {{ default_zoom }});
- {% endlocalize %}
+ {{ module }}.deleteFeatures();
+ document.getElementById('{{ id }}').value = '';
+ {% localize off %}
+ {{ module }}.map.setCenter(new OpenLayers.LonLat({{ default_lon }}, {{ default_lat }}), {{ default_zoom }});
+ {% endlocalize %}
};
// Add Select control
{{ module }}.addSelectControl = function(){
- var select = new OpenLayers.Control.SelectFeature({{ module }}.layers.vector, {'toggle' : true, 'clickout' : true});
- {{ module }}.map.addControl(select);
- select.activate();
+ var select = new OpenLayers.Control.SelectFeature({{ module }}.layers.vector, {'toggle' : true, 'clickout' : true});
+ {{ module }}.map.addControl(select);
+ select.activate();
};
{{ module }}.enableDrawing = function(){
- {{ module }}.map.getControlsByClass('OpenLayers.Control.DrawFeature')[0].activate();
+ {{ module }}.map.getControlsByClass('OpenLayers.Control.DrawFeature')[0].activate();
};
{{ module }}.enableEditing = function(){
- {{ module }}.map.getControlsByClass('OpenLayers.Control.ModifyFeature')[0].activate();
+ {{ module }}.map.getControlsByClass('OpenLayers.Control.ModifyFeature')[0].activate();
};
// Create an array of controls based on geometry type
{{ module }}.getControls = function(lyr){
- {{ module }}.panel = new OpenLayers.Control.Panel({'displayClass': 'olControlEditingToolbar'});
- {{ module }}.controls = [new OpenLayers.Control.Navigation()];
- if (!{{ module }}.modifiable && lyr.features.length) return;
- if ({{ module }}.is_linestring || {{ module }}.is_generic){
- {{ module }}.controls.push(new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Path, {'displayClass': 'olControlDrawFeaturePath'}));
- }
- if ({{ module }}.is_polygon || {{ module }}.is_generic){
- {{ module }}.controls.push(new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Polygon, {'displayClass': 'olControlDrawFeaturePolygon'}));
- }
- if ({{ module }}.is_point || {{ module }}.is_generic){
- {{ module }}.controls.push(new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Point, {'displayClass': 'olControlDrawFeaturePoint'}));
- }
- if ({{ module }}.modifiable){
- {{ module }}.controls.push(new OpenLayers.Control.ModifyFeature(lyr, {'displayClass': 'olControlModifyFeature'}));
- }
+ {{ module }}.panel = new OpenLayers.Control.Panel({'displayClass': 'olControlEditingToolbar'});
+ {{ module }}.controls = [new OpenLayers.Control.Navigation()];
+ if (!{{ module }}.modifiable && lyr.features.length) return;
+ if ({{ module }}.is_linestring || {{ module }}.is_generic){
+ {{ module }}.controls.push(new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Path, {'displayClass': 'olControlDrawFeaturePath'}));
+ }
+ if ({{ module }}.is_polygon || {{ module }}.is_generic){
+ {{ module }}.controls.push(new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Polygon, {'displayClass': 'olControlDrawFeaturePolygon'}));
+ }
+ if ({{ module }}.is_point || {{ module }}.is_generic){
+ {{ module }}.controls.push(new OpenLayers.Control.DrawFeature(lyr, OpenLayers.Handler.Point, {'displayClass': 'olControlDrawFeaturePoint'}));
+ }
+ if ({{ module }}.modifiable){
+ {{ module }}.controls.push(new OpenLayers.Control.ModifyFeature(lyr, {'displayClass': 'olControlModifyFeature'}));
+ }
};
{{ module }}.init = function(){
{% block map_options %}// The options hash, w/ zoom, resolution, and projection settings.
@@ -124,28 +124,28 @@ OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:3857", OpenLayers.Layer.Sp
// Read WKT from the text field.
var wkt = document.getElementById('{{ id }}').value;
if (wkt){
- // After reading into geometry, immediately write back to
- // WKT <textarea> as EWKT (so that SRID is included).
- var admin_geom = {{ module }}.read_wkt(wkt);
- {{ module }}.write_wkt(admin_geom);
- if ({{ module }}.is_collection){
- // If geometry collection, add each component individually so they may be
- // edited individually.
- for (var i = 0; i < {{ module }}.num_geom; i++){
- {{ module }}.layers.vector.addFeatures([new OpenLayers.Feature.Vector(admin_geom.geometry.components[i].clone())]);
+ // After reading into geometry, immediately write back to
+ // WKT <textarea> as EWKT (so that SRID is included).
+ var admin_geom = {{ module }}.read_wkt(wkt);
+ {{ module }}.write_wkt(admin_geom);
+ if ({{ module }}.is_collection){
+ // If geometry collection, add each component individually so they may be
+ // edited individually.
+ for (var i = 0; i < {{ module }}.num_geom; i++){
+ {{ module }}.layers.vector.addFeatures([new OpenLayers.Feature.Vector(admin_geom.geometry.components[i].clone())]);
+ }
+ } else {
+ {{ module }}.layers.vector.addFeatures([admin_geom]);
+ }
+ // Zooming to the bounds.
+ {{ module }}.map.zoomToExtent(admin_geom.geometry.getBounds());
+ if ({{ module }}.is_point){
+ {{ module }}.map.zoomTo({{ point_zoom }});
}
- } else {
- {{ module }}.layers.vector.addFeatures([admin_geom]);
- }
- // Zooming to the bounds.
- {{ module }}.map.zoomToExtent(admin_geom.geometry.getBounds());
- if ({{ module }}.is_point){
- {{ module }}.map.zoomTo({{ point_zoom }});
- }
} else {
- {% localize off %}
- {{ module }}.map.setCenter(new OpenLayers.LonLat({{ default_lon }}, {{ default_lat }}), {{ default_zoom }});
- {% endlocalize %}
+ {% localize off %}
+ {{ module }}.map.setCenter(new OpenLayers.LonLat({{ default_lon }}, {{ default_lat }}), {{ default_zoom }});
+ {% endlocalize %}
}
// This allows editing of the geographic fields -- the modified WKT is
// written back to the content field (as EWKT, so that the ORM will know
@@ -167,10 +167,10 @@ OpenLayers.Projection.addTransform("EPSG:4326", "EPSG:3857", OpenLayers.Layer.Sp
{% if not scrollable %}{{ module }}.map.getControlsByClass('OpenLayers.Control.Navigation')[0].disableZoomWheel();{% endif %}
{% endblock %}
if (wkt){
- if ({{ module }}.modifiable){
- {{ module }}.enableEditing();
- }
+ if ({{ module }}.modifiable){
+ {{ module }}.enableEditing();
+ }
} else {
- {{ module }}.enableDrawing();
+ {{ module }}.enableDrawing();
}
};
diff --git a/docs/internals/contributing/writing-code/coding-style.txt b/docs/internals/contributing/writing-code/coding-style.txt
index 2aa967c88d..54c2bd47e2 100644
--- a/docs/internals/contributing/writing-code/coding-style.txt
+++ b/docs/internals/contributing/writing-code/coding-style.txt
@@ -7,6 +7,11 @@ Please follow these coding standards when writing code for inclusion in Django.
Python style
------------
+* Please conform to the indentation style dictated in the ``.editorconfig``
+ file. We recommend using a text editor with `EditorConfig`_ support to avoid
+ indentation and whitespace issues. The Python files use 4 spaces for
+ indentation and the HTML files use 2 spaces.
+
* Unless otherwise specified, follow :pep:`8`.
Use `flake8`_ to check for problems in this area. Note that our ``setup.cfg``
@@ -286,4 +291,11 @@ Miscellaneous
change to the ``AUTHORS`` file in your patch if you make more than a
single trivial change.
+JavaScript style
+----------------
+
+For details about the JavaScript code style used by Django, see
+:doc:`javascript`.
+
+.. _editorconfig: http://editorconfig.org/
.. _flake8: https://pypi.python.org/pypi/flake8
diff --git a/docs/internals/contributing/writing-code/index.txt b/docs/internals/contributing/writing-code/index.txt
index fe9c3cc933..98e2b8dfa2 100644
--- a/docs/internals/contributing/writing-code/index.txt
+++ b/docs/internals/contributing/writing-code/index.txt
@@ -13,3 +13,4 @@ chances to be included in Django core:
unit-tests
submitting-patches
working-with-git
+ javascript
diff --git a/docs/internals/contributing/writing-code/javascript.txt b/docs/internals/contributing/writing-code/javascript.txt
new file mode 100644
index 0000000000..fa3685720e
--- /dev/null
+++ b/docs/internals/contributing/writing-code/javascript.txt
@@ -0,0 +1,64 @@
+==========
+JavaScript
+==========
+
+While most of Django core is Python, the ``admin`` and ``gis`` contrib apps
+contain JavaScript code.
+
+Please follow these coding standards when writing JavaScript code for inclusion
+in Django.
+
+Code style
+----------
+
+* Please conform to the indentation style dictated in the ``.editorconfig``
+ file. We recommend using a text editor with `EditorConfig`_ support to avoid
+ indentation and whitespace issues. Most of the JavaScript files use 4 spaces
+ for indentation, but there are some exceptions.
+
+* When naming variables, use ``camelCase`` instead of ``underscore_case``.
+ Different JavaScript files sometimes use a different code style. Please try to
+ conform to the code style of each file.
+
+* Use the `JSHint`_ code linter to check your code for bugs and style errors.
+ JSHint will be run when you run the JavaScript tests. We also recommended
+ installing a JSHint plugin in your text editor.
+
+.. _javascript-patches:
+
+JavaScript patches
+------------------
+
+Django's admin system leverages the jQuery framework to increase the
+capabilities of the admin interface. In conjunction, there is an emphasis on
+admin JavaScript performance and minimizing overall admin media file size.
+Serving compressed or "minified" versions of JavaScript files is considered
+best practice in this regard.
+
+To that end, patches for JavaScript files should include both the original
+code for future development (e.g. ``foo.js``), and a compressed version for
+production use (e.g. ``foo.min.js``). Any links to the file in the codebase
+should point to the compressed version.
+
+Compressing JavaScript
+~~~~~~~~~~~~~~~~~~~~~~
+
+To simplify the process of providing optimized JavaScript code, Django
+includes a handy Python script which should be used to create a "minified"
+version. To run it::
+
+ python django/contrib/admin/bin/compress.py
+
+Behind the scenes, ``compress.py`` is a front-end for Google's
+`Closure Compiler`_ which is written in Java. However, the Closure Compiler
+library is not bundled with Django directly, so those wishing to contribute
+complete JavaScript patches will need to download and install the library
+independently. The Closure Compiler library requires `Java`_ 7 or higher.
+
+Please don't forget to run ``compress.py`` and include the ``diff`` of the
+minified scripts when submitting patches for Django's JavaScript.
+
+.. _Closure Compiler: https://developers.google.com/closure/compiler/
+.. _EditorConfig: http://editorconfig.org/
+.. _Java: https://www.java.com
+.. _jshint: http://jshint.com/
diff --git a/docs/internals/contributing/writing-code/submitting-patches.txt b/docs/internals/contributing/writing-code/submitting-patches.txt
index d9302169b6..bc7503518f 100644
--- a/docs/internals/contributing/writing-code/submitting-patches.txt
+++ b/docs/internals/contributing/writing-code/submitting-patches.txt
@@ -145,6 +145,8 @@ Regardless of the way you submit your work, follow these steps.
obvious that the ticket includes a patch, and it will add the ticket to
the `list of tickets with patches`_.
+.. _list of tickets with patches: https://code.djangoproject.com/query?status=new&status=assigned&status=reopened&has_patch=1&order=priority
+.. _ticket tracker: https://code.djangoproject.com/newticket
Non-trivial patches
-------------------
@@ -245,39 +247,8 @@ the new version are removed.
JavaScript patches
------------------
-Django's admin system leverages the jQuery framework to increase the
-capabilities of the admin interface. In conjunction, there is an emphasis on
-admin JavaScript performance and minimizing overall admin media file size.
-Serving compressed or "minified" versions of JavaScript files is considered
-best practice in this regard.
-
-To that end, patches for JavaScript files should include both the original
-code for future development (e.g. ``foo.js``), and a compressed version for
-production use (e.g. ``foo.min.js``). Any links to the file in the codebase
-should point to the compressed version.
-
-Compressing JavaScript
-~~~~~~~~~~~~~~~~~~~~~~
-
-To simplify the process of providing optimized JavaScript code, Django
-includes a handy Python script which should be used to create a "minified"
-version. To run it::
-
- python django/contrib/admin/bin/compress.py
-
-Behind the scenes, ``compress.py`` is a front-end for Google's
-`Closure Compiler`_ which is written in Java. However, the Closure Compiler
-library is not bundled with Django directly, so those wishing to contribute
-complete JavaScript patches will need to download and install the library
-independently. The Closure Compiler library requires `Java`_ 7 or higher.
-
-Please don't forget to run ``compress.py`` and include the ``diff`` of the
-minified scripts when submitting patches for Django's JavaScript.
-
-.. _Closure Compiler: https://developers.google.com/closure/compiler/
-.. _list of tickets with patches: https://code.djangoproject.com/query?status=new&status=assigned&status=reopened&has_patch=1&order=priority
-.. _ticket tracker: https://code.djangoproject.com/newticket
-.. _Java: https://www.java.com
+For information on JavaScript patches, see the :ref:`javascript-patches`
+documentation.
.. _patch-review-checklist:
diff --git a/package.json b/package.json
new file mode 100644
index 0000000000..3370c8c04e
--- /dev/null
+++ b/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "Django",
+ "private": true,
+ "scripts": {
+ "pretest": "eslint django/"
+ },
+ "devDependencies": {
+ "eslint": "^0.22.1"
+ }
+}