| '+a.addText+""),m=c.find("tr:last a")):(d.filter(":last").after('"),m=d.filter(":last").next().find("a")));m.on("click",function(f){f.preventDefault();f=b("#"+a.prefix+"-empty");
3 | var c=f.clone(!0);c.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+k);c.is("tr")?c.children(":last").append('"):c.is("ul")||c.is("ol")?c.append(''+a.deleteText+""):c.children(":first").append(''+a.deleteText+"");c.find("*").each(function(){h(this,a.prefix,g.val())});c.insertBefore(b(f));
4 | b(g).val(parseInt(g.val(),10)+1);k+=1;""!==e.val()&&0>=e.val()-g.val()&&m.parent().hide();c.find("a."+a.deleteCssClass).on("click",function(f){f.preventDefault();c.remove();--k;a.removed&&a.removed(c);b(document).trigger("formset:removed",[c,a.prefix]);f=b("."+a.formCssClass);b("#id_"+a.prefix+"-TOTAL_FORMS").val(f.length);(""===e.val()||0 tr",b(c).tabularFormset(c,a.options)}})})})(django.jQuery);
11 |
--------------------------------------------------------------------------------
/assets/admin/css/rtl.css:
--------------------------------------------------------------------------------
1 | body {
2 | direction: rtl;
3 | }
4 |
5 | /* LOGIN */
6 |
7 | .login .form-row {
8 | float: right;
9 | }
10 |
11 | .login .form-row label {
12 | float: right;
13 | padding-left: 0.5em;
14 | padding-right: 0;
15 | text-align: left;
16 | }
17 |
18 | .login .submit-row {
19 | clear: both;
20 | padding: 1em 9.4em 0 0;
21 | }
22 |
23 | /* GLOBAL */
24 |
25 | th {
26 | text-align: right;
27 | }
28 |
29 | .module h2, .module caption {
30 | text-align: right;
31 | }
32 |
33 | .module ul, .module ol {
34 | margin-left: 0;
35 | margin-right: 1.5em;
36 | }
37 |
38 | .viewlink, .addlink, .changelink {
39 | padding-left: 0;
40 | padding-right: 16px;
41 | background-position: 100% 1px;
42 | }
43 |
44 | .deletelink {
45 | padding-left: 0;
46 | padding-right: 16px;
47 | background-position: 100% 1px;
48 | }
49 |
50 | .object-tools {
51 | float: left;
52 | }
53 |
54 | thead th:first-child,
55 | tfoot td:first-child {
56 | border-left: none;
57 | }
58 |
59 | /* LAYOUT */
60 |
61 | #user-tools {
62 | right: auto;
63 | left: 0;
64 | text-align: left;
65 | }
66 |
67 | div.breadcrumbs {
68 | text-align: right;
69 | }
70 |
71 | #content-main {
72 | float: right;
73 | }
74 |
75 | #content-related {
76 | float: left;
77 | margin-left: -300px;
78 | margin-right: auto;
79 | }
80 |
81 | .colMS {
82 | margin-left: 300px;
83 | margin-right: 0;
84 | }
85 |
86 | /* SORTABLE TABLES */
87 |
88 | table thead th.sorted .sortoptions {
89 | float: left;
90 | }
91 |
92 | thead th.sorted .text {
93 | padding-right: 0;
94 | padding-left: 42px;
95 | }
96 |
97 | /* dashboard styles */
98 |
99 | .dashboard .module table td a {
100 | padding-left: .6em;
101 | padding-right: 16px;
102 | }
103 |
104 | /* changelists styles */
105 |
106 | .change-list .filtered table {
107 | border-left: none;
108 | border-right: 0px none;
109 | }
110 |
111 | #changelist-filter {
112 | right: auto;
113 | left: 0;
114 | border-left: none;
115 | border-right: none;
116 | }
117 |
118 | .change-list .filtered .results, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull {
119 | margin-right: 0;
120 | margin-left: 280px;
121 | }
122 |
123 | #changelist-filter li.selected {
124 | border-left: none;
125 | padding-left: 10px;
126 | margin-left: 0;
127 | border-right: 5px solid #eaeaea;
128 | padding-right: 10px;
129 | margin-right: -15px;
130 | }
131 |
132 | .filtered .actions {
133 | margin-left: 280px;
134 | margin-right: 0;
135 | }
136 |
137 | #changelist table tbody td:first-child, #changelist table tbody th:first-child {
138 | border-right: none;
139 | border-left: none;
140 | }
141 |
142 | /* FORMS */
143 |
144 | .aligned label {
145 | padding: 0 0 3px 1em;
146 | float: right;
147 | }
148 |
149 | .submit-row {
150 | text-align: left
151 | }
152 |
153 | .submit-row p.deletelink-box {
154 | float: right;
155 | }
156 |
157 | .submit-row input.default {
158 | margin-left: 0;
159 | }
160 |
161 | .vDateField, .vTimeField {
162 | margin-left: 2px;
163 | }
164 |
165 | .aligned .form-row input {
166 | margin-left: 5px;
167 | }
168 |
169 | form .aligned p.help, form .aligned div.help {
170 | clear: right;
171 | }
172 |
173 | form .aligned ul {
174 | margin-right: 163px;
175 | margin-left: 0;
176 | }
177 |
178 | form ul.inline li {
179 | float: right;
180 | padding-right: 0;
181 | padding-left: 7px;
182 | }
183 |
184 | input[type=submit].default, .submit-row input.default {
185 | float: left;
186 | }
187 |
188 | fieldset .fieldBox {
189 | float: right;
190 | margin-left: 20px;
191 | margin-right: 0;
192 | }
193 |
194 | .errorlist li {
195 | background-position: 100% 12px;
196 | padding: 0;
197 | }
198 |
199 | .errornote {
200 | background-position: 100% 12px;
201 | padding: 10px 12px;
202 | }
203 |
204 | /* WIDGETS */
205 |
206 | .calendarnav-previous {
207 | top: 0;
208 | left: auto;
209 | right: 10px;
210 | }
211 |
212 | .calendarnav-next {
213 | top: 0;
214 | right: auto;
215 | left: 10px;
216 | }
217 |
218 | .calendar caption, .calendarbox h2 {
219 | text-align: center;
220 | }
221 |
222 | .selector {
223 | float: right;
224 | }
225 |
226 | .selector .selector-filter {
227 | text-align: right;
228 | }
229 |
230 | .inline-deletelink {
231 | float: left;
232 | }
233 |
234 | form .form-row p.datetime {
235 | overflow: hidden;
236 | }
237 |
238 | .related-widget-wrapper {
239 | float: right;
240 | }
241 |
242 | /* MISC */
243 |
244 | .inline-related h2, .inline-group h2 {
245 | text-align: right
246 | }
247 |
248 | .inline-related h3 span.delete {
249 | padding-right: 20px;
250 | padding-left: inherit;
251 | left: 10px;
252 | right: inherit;
253 | float:left;
254 | }
255 |
256 | .inline-related h3 span.delete label {
257 | margin-left: inherit;
258 | margin-right: 2px;
259 | }
260 |
261 | /* IE7 specific bug fixes */
262 |
263 | div.colM {
264 | position: relative;
265 | }
266 |
267 | .submit-row input {
268 | float: left;
269 | }
270 |
--------------------------------------------------------------------------------
/assets/admin/js/SelectBox.js:
--------------------------------------------------------------------------------
1 | (function($) {
2 | 'use strict';
3 | var SelectBox = {
4 | cache: {},
5 | init: function(id) {
6 | var box = document.getElementById(id);
7 | var node;
8 | SelectBox.cache[id] = [];
9 | var cache = SelectBox.cache[id];
10 | var boxOptions = box.options;
11 | var boxOptionsLength = boxOptions.length;
12 | for (var i = 0, j = boxOptionsLength; i < j; i++) {
13 | node = boxOptions[i];
14 | cache.push({value: node.value, text: node.text, displayed: 1});
15 | }
16 | },
17 | redisplay: function(id) {
18 | // Repopulate HTML select box from cache
19 | var box = document.getElementById(id);
20 | var node;
21 | $(box).empty(); // clear all options
22 | var new_options = box.outerHTML.slice(0, -9); // grab just the opening tag
23 | var cache = SelectBox.cache[id];
24 | for (var i = 0, j = cache.length; i < j; i++) {
25 | node = cache[i];
26 | if (node.displayed) {
27 | var new_option = new Option(node.text, node.value, false, false);
28 | // Shows a tooltip when hovering over the option
29 | new_option.setAttribute("title", node.text);
30 | new_options += new_option.outerHTML;
31 | }
32 | }
33 | new_options += '';
34 | box.outerHTML = new_options;
35 | },
36 | filter: function(id, text) {
37 | // Redisplay the HTML select box, displaying only the choices containing ALL
38 | // the words in text. (It's an AND search.)
39 | var tokens = text.toLowerCase().split(/\s+/);
40 | var node, token;
41 | var cache = SelectBox.cache[id];
42 | for (var i = 0, j = cache.length; i < j; i++) {
43 | node = cache[i];
44 | node.displayed = 1;
45 | var node_text = node.text.toLowerCase();
46 | var numTokens = tokens.length;
47 | for (var k = 0; k < numTokens; k++) {
48 | token = tokens[k];
49 | if (node_text.indexOf(token) === -1) {
50 | node.displayed = 0;
51 | break; // Once the first token isn't found we're done
52 | }
53 | }
54 | }
55 | SelectBox.redisplay(id);
56 | },
57 | delete_from_cache: function(id, value) {
58 | var node, delete_index = null;
59 | var cache = SelectBox.cache[id];
60 | for (var i = 0, j = cache.length; i < j; i++) {
61 | node = cache[i];
62 | if (node.value === value) {
63 | delete_index = i;
64 | break;
65 | }
66 | }
67 | cache.splice(delete_index, 1);
68 | },
69 | add_to_cache: function(id, option) {
70 | SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1});
71 | },
72 | cache_contains: function(id, value) {
73 | // Check if an item is contained in the cache
74 | var node;
75 | var cache = SelectBox.cache[id];
76 | for (var i = 0, j = cache.length; i < j; i++) {
77 | node = cache[i];
78 | if (node.value === value) {
79 | return true;
80 | }
81 | }
82 | return false;
83 | },
84 | move: function(from, to) {
85 | var from_box = document.getElementById(from);
86 | var option;
87 | var boxOptions = from_box.options;
88 | var boxOptionsLength = boxOptions.length;
89 | for (var i = 0, j = boxOptionsLength; i < j; i++) {
90 | option = boxOptions[i];
91 | var option_value = option.value;
92 | if (option.selected && SelectBox.cache_contains(from, option_value)) {
93 | SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1});
94 | SelectBox.delete_from_cache(from, option_value);
95 | }
96 | }
97 | SelectBox.redisplay(from);
98 | SelectBox.redisplay(to);
99 | },
100 | move_all: function(from, to) {
101 | var from_box = document.getElementById(from);
102 | var option;
103 | var boxOptions = from_box.options;
104 | var boxOptionsLength = boxOptions.length;
105 | for (var i = 0, j = boxOptionsLength; i < j; i++) {
106 | option = boxOptions[i];
107 | var option_value = option.value;
108 | if (SelectBox.cache_contains(from, option_value)) {
109 | SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1});
110 | SelectBox.delete_from_cache(from, option_value);
111 | }
112 | }
113 | SelectBox.redisplay(from);
114 | SelectBox.redisplay(to);
115 | },
116 | sort: function(id) {
117 | SelectBox.cache[id].sort(function(a, b) {
118 | a = a.text.toLowerCase();
119 | b = b.text.toLowerCase();
120 | try {
121 | if (a > b) {
122 | return 1;
123 | }
124 | if (a < b) {
125 | return -1;
126 | }
127 | }
128 | catch (e) {
129 | // silently fail on IE 'unknown' exception
130 | }
131 | return 0;
132 | } );
133 | },
134 | select_all: function(id) {
135 | var box = document.getElementById(id);
136 | var boxOptions = box.options;
137 | var boxOptionsLength = boxOptions.length;
138 | for (var i = 0; i < boxOptionsLength; i++) {
139 | boxOptions[i].selected = 'selected';
140 | }
141 | }
142 | };
143 | window.SelectBox = SelectBox;
144 | })(django.jQuery);
145 |
--------------------------------------------------------------------------------
/assets/admin/js/core.js:
--------------------------------------------------------------------------------
1 | // Core javascript helper functions
2 |
3 | // basic browser identification & version
4 | var isOpera = (navigator.userAgent.indexOf("Opera") >= 0) && parseFloat(navigator.appVersion);
5 | var isIE = ((document.all) && (!isOpera)) && parseFloat(navigator.appVersion.split("MSIE ")[1].split(";")[0]);
6 |
7 | // quickElement(tagType, parentReference [, textInChildNode, attribute, attributeValue ...]);
8 | function quickElement() {
9 | 'use strict';
10 | var obj = document.createElement(arguments[0]);
11 | if (arguments[2]) {
12 | var textNode = document.createTextNode(arguments[2]);
13 | obj.appendChild(textNode);
14 | }
15 | var len = arguments.length;
16 | for (var i = 3; i < len; i += 2) {
17 | obj.setAttribute(arguments[i], arguments[i + 1]);
18 | }
19 | arguments[1].appendChild(obj);
20 | return obj;
21 | }
22 |
23 | // "a" is reference to an object
24 | function removeChildren(a) {
25 | 'use strict';
26 | while (a.hasChildNodes()) {
27 | a.removeChild(a.lastChild);
28 | }
29 | }
30 |
31 | // ----------------------------------------------------------------------------
32 | // Find-position functions by PPK
33 | // See https://www.quirksmode.org/js/findpos.html
34 | // ----------------------------------------------------------------------------
35 | function findPosX(obj) {
36 | 'use strict';
37 | var curleft = 0;
38 | if (obj.offsetParent) {
39 | while (obj.offsetParent) {
40 | curleft += obj.offsetLeft - ((isOpera) ? 0 : obj.scrollLeft);
41 | obj = obj.offsetParent;
42 | }
43 | // IE offsetParent does not include the top-level
44 | if (isIE && obj.parentElement) {
45 | curleft += obj.offsetLeft - obj.scrollLeft;
46 | }
47 | } else if (obj.x) {
48 | curleft += obj.x;
49 | }
50 | return curleft;
51 | }
52 |
53 | function findPosY(obj) {
54 | 'use strict';
55 | var curtop = 0;
56 | if (obj.offsetParent) {
57 | while (obj.offsetParent) {
58 | curtop += obj.offsetTop - ((isOpera) ? 0 : obj.scrollTop);
59 | obj = obj.offsetParent;
60 | }
61 | // IE offsetParent does not include the top-level
62 | if (isIE && obj.parentElement) {
63 | curtop += obj.offsetTop - obj.scrollTop;
64 | }
65 | } else if (obj.y) {
66 | curtop += obj.y;
67 | }
68 | return curtop;
69 | }
70 |
71 | //-----------------------------------------------------------------------------
72 | // Date object extensions
73 | // ----------------------------------------------------------------------------
74 | (function() {
75 | 'use strict';
76 | Date.prototype.getTwelveHours = function() {
77 | return this.getHours() % 12 || 12;
78 | };
79 |
80 | Date.prototype.getTwoDigitMonth = function() {
81 | return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1);
82 | };
83 |
84 | Date.prototype.getTwoDigitDate = function() {
85 | return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate();
86 | };
87 |
88 | Date.prototype.getTwoDigitTwelveHour = function() {
89 | return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours();
90 | };
91 |
92 | Date.prototype.getTwoDigitHour = function() {
93 | return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours();
94 | };
95 |
96 | Date.prototype.getTwoDigitMinute = function() {
97 | return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes();
98 | };
99 |
100 | Date.prototype.getTwoDigitSecond = function() {
101 | return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds();
102 | };
103 |
104 | Date.prototype.getFullMonthName = function() {
105 | return typeof window.CalendarNamespace === "undefined"
106 | ? this.getTwoDigitMonth()
107 | : window.CalendarNamespace.monthsOfYear[this.getMonth()];
108 | };
109 |
110 | Date.prototype.strftime = function(format) {
111 | var fields = {
112 | B: this.getFullMonthName(),
113 | c: this.toString(),
114 | d: this.getTwoDigitDate(),
115 | H: this.getTwoDigitHour(),
116 | I: this.getTwoDigitTwelveHour(),
117 | m: this.getTwoDigitMonth(),
118 | M: this.getTwoDigitMinute(),
119 | p: (this.getHours() >= 12) ? 'PM' : 'AM',
120 | S: this.getTwoDigitSecond(),
121 | w: '0' + this.getDay(),
122 | x: this.toLocaleDateString(),
123 | X: this.toLocaleTimeString(),
124 | y: ('' + this.getFullYear()).substr(2, 4),
125 | Y: '' + this.getFullYear(),
126 | '%': '%'
127 | };
128 | var result = '', i = 0;
129 | while (i < format.length) {
130 | if (format.charAt(i) === '%') {
131 | result = result + fields[format.charAt(i + 1)];
132 | ++i;
133 | }
134 | else {
135 | result = result + format.charAt(i);
136 | }
137 | ++i;
138 | }
139 | return result;
140 | };
141 |
142 | // ----------------------------------------------------------------------------
143 | // String object extensions
144 | // ----------------------------------------------------------------------------
145 | String.prototype.strptime = function(format) {
146 | var split_format = format.split(/[.\-/]/);
147 | var date = this.split(/[.\-/]/);
148 | var i = 0;
149 | var day, month, year;
150 | while (i < split_format.length) {
151 | switch (split_format[i]) {
152 | case "%d":
153 | day = date[i];
154 | break;
155 | case "%m":
156 | month = date[i] - 1;
157 | break;
158 | case "%Y":
159 | year = date[i];
160 | break;
161 | case "%y":
162 | year = date[i];
163 | break;
164 | }
165 | ++i;
166 | }
167 | // Create Date object from UTC since the parsed value is supposed to be
168 | // in UTC, not local time. Also, the calendar uses UTC functions for
169 | // date extraction.
170 | return new Date(Date.UTC(year, month, day));
171 | };
172 |
173 | })();
174 |
--------------------------------------------------------------------------------
/assets/admin/js/actions.js:
--------------------------------------------------------------------------------
1 | /*global gettext, interpolate, ngettext*/
2 | (function($) {
3 | 'use strict';
4 | var lastChecked;
5 |
6 | $.fn.actions = function(opts) {
7 | var options = $.extend({}, $.fn.actions.defaults, opts);
8 | var actionCheckboxes = $(this);
9 | var list_editable_changed = false;
10 | var showQuestion = function() {
11 | $(options.acrossClears).hide();
12 | $(options.acrossQuestions).show();
13 | $(options.allContainer).hide();
14 | },
15 | showClear = function() {
16 | $(options.acrossClears).show();
17 | $(options.acrossQuestions).hide();
18 | $(options.actionContainer).toggleClass(options.selectedClass);
19 | $(options.allContainer).show();
20 | $(options.counterContainer).hide();
21 | },
22 | reset = function() {
23 | $(options.acrossClears).hide();
24 | $(options.acrossQuestions).hide();
25 | $(options.allContainer).hide();
26 | $(options.counterContainer).show();
27 | },
28 | clearAcross = function() {
29 | reset();
30 | $(options.acrossInput).val(0);
31 | $(options.actionContainer).removeClass(options.selectedClass);
32 | },
33 | checker = function(checked) {
34 | if (checked) {
35 | showQuestion();
36 | } else {
37 | reset();
38 | }
39 | $(actionCheckboxes).prop("checked", checked)
40 | .parent().parent().toggleClass(options.selectedClass, checked);
41 | },
42 | updateCounter = function() {
43 | var sel = $(actionCheckboxes).filter(":checked").length;
44 | // data-actions-icnt is defined in the generated HTML
45 | // and contains the total amount of objects in the queryset
46 | var actions_icnt = $('.action-counter').data('actionsIcnt');
47 | $(options.counterContainer).html(interpolate(
48 | ngettext('%(sel)s of %(cnt)s selected', '%(sel)s of %(cnt)s selected', sel), {
49 | sel: sel,
50 | cnt: actions_icnt
51 | }, true));
52 | $(options.allToggle).prop("checked", function() {
53 | var value;
54 | if (sel === actionCheckboxes.length) {
55 | value = true;
56 | showQuestion();
57 | } else {
58 | value = false;
59 | clearAcross();
60 | }
61 | return value;
62 | });
63 | };
64 | // Show counter by default
65 | $(options.counterContainer).show();
66 | // Check state of checkboxes and reinit state if needed
67 | $(this).filter(":checked").each(function(i) {
68 | $(this).parent().parent().toggleClass(options.selectedClass);
69 | updateCounter();
70 | if ($(options.acrossInput).val() === 1) {
71 | showClear();
72 | }
73 | });
74 | $(options.allToggle).show().on('click', function() {
75 | checker($(this).prop("checked"));
76 | updateCounter();
77 | });
78 | $("a", options.acrossQuestions).on('click', function(event) {
79 | event.preventDefault();
80 | $(options.acrossInput).val(1);
81 | showClear();
82 | });
83 | $("a", options.acrossClears).on('click', function(event) {
84 | event.preventDefault();
85 | $(options.allToggle).prop("checked", false);
86 | clearAcross();
87 | checker(0);
88 | updateCounter();
89 | });
90 | lastChecked = null;
91 | $(actionCheckboxes).on('click', function(event) {
92 | if (!event) { event = window.event; }
93 | var target = event.target ? event.target : event.srcElement;
94 | if (lastChecked && $.data(lastChecked) !== $.data(target) && event.shiftKey === true) {
95 | var inrange = false;
96 | $(lastChecked).prop("checked", target.checked)
97 | .parent().parent().toggleClass(options.selectedClass, target.checked);
98 | $(actionCheckboxes).each(function() {
99 | if ($.data(this) === $.data(lastChecked) || $.data(this) === $.data(target)) {
100 | inrange = (inrange) ? false : true;
101 | }
102 | if (inrange) {
103 | $(this).prop("checked", target.checked)
104 | .parent().parent().toggleClass(options.selectedClass, target.checked);
105 | }
106 | });
107 | }
108 | $(target).parent().parent().toggleClass(options.selectedClass, target.checked);
109 | lastChecked = target;
110 | updateCounter();
111 | });
112 | $('form#changelist-form table#result_list tr').on('change', 'td:gt(0) :input', function() {
113 | list_editable_changed = true;
114 | });
115 | $('form#changelist-form button[name="index"]').on('click', function(event) {
116 | if (list_editable_changed) {
117 | return confirm(gettext("You have unsaved changes on individual editable fields. If you run an action, your unsaved changes will be lost."));
118 | }
119 | });
120 | $('form#changelist-form input[name="_save"]').on('click', function(event) {
121 | var action_changed = false;
122 | $('select option:selected', options.actionContainer).each(function() {
123 | if ($(this).val()) {
124 | action_changed = true;
125 | }
126 | });
127 | if (action_changed) {
128 | if (list_editable_changed) {
129 | 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."));
130 | } else {
131 | 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."));
132 | }
133 | }
134 | });
135 | };
136 | /* Setup plugin defaults */
137 | $.fn.actions.defaults = {
138 | actionContainer: "div.actions",
139 | counterContainer: "span.action-counter",
140 | allContainer: "div.actions span.all",
141 | acrossInput: "div.actions input.select-across",
142 | acrossQuestions: "div.actions span.question",
143 | acrossClears: "div.actions span.clear",
144 | allToggle: "#action-toggle",
145 | selectedClass: "selected"
146 | };
147 | $(document).ready(function() {
148 | var $actionsEls = $('tr input.action-select');
149 | if ($actionsEls.length > 0) {
150 | $actionsEls.actions();
151 | }
152 | });
153 | })(django.jQuery);
154 |
--------------------------------------------------------------------------------
|