| '+a.addText+""),l=d.find("tr:last a")):(c.filter(":last").after('"),l=c.filter(":last").next().find("a")));l.on("click",function(d){d.preventDefault();d=b("#"+a.prefix+"-empty");
6 | var c=d.clone(!0);c.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+h);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(){f(this,a.prefix,g.val())});c.insertBefore(b(d));
7 | b(g).val(parseInt(g.val(),10)+1);h+=1;""!==e.val()&&0>=e.val()-g.val()&&l.parent().hide();c.find("a."+a.deleteCssClass).on("click",function(d){d.preventDefault();c.remove();--h;a.removed&&a.removed(c);b(document).trigger("formset:removed",[c,a.prefix]);d=b("."+a.formCssClass);b("#id_"+a.prefix+"-TOTAL_FORMS").val(d.length);(""===e.val()||0 tr",b(d).tabularFormset(d,a.options)}})})})(django.jQuery);
14 |
--------------------------------------------------------------------------------
/resources/spf13-script.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright 2014 Steve Francia
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | ############################ SETUP PARAMETERS
18 | app_name='spf13-vim'
19 | [ -z "$APP_PATH" ] && APP_PATH="$HOME/.spf13-vim-3"
20 | [ -z "$REPO_URI" ] && REPO_URI='https://github.com/spf13/spf13-vim.git'
21 | [ -z "$REPO_BRANCH" ] && REPO_BRANCH='3.0'
22 | debug_mode='0'
23 | fork_maintainer='0'
24 | [ -z "$VUNDLE_URI" ] && VUNDLE_URI="https://github.com/gmarik/vundle.git"
25 |
26 | ############################ BASIC SETUP TOOLS
27 | msg() {
28 | printf '%b\n' "$1" >&2
29 | }
30 |
31 | success() {
32 | if [ "$ret" -eq '0' ]; then
33 | msg "\33[32m[✔]\33[0m ${1}${2}"
34 | fi
35 | }
36 |
37 | error() {
38 | msg "\33[31m[✘]\33[0m ${1}${2}"
39 | exit 1
40 | }
41 |
42 | debug() {
43 | if [ "$debug_mode" -eq '1' ] && [ "$ret" -gt '1' ]; then
44 | msg "An error occurred in function \"${FUNCNAME[$i+1]}\" on line ${BASH_LINENO[$i+1]}, we're sorry for that."
45 | fi
46 | }
47 |
48 | program_exists() {
49 | local ret='0'
50 | type $1 >/dev/null 2>&1 || { local ret='1'; }
51 |
52 | # throw error on non-zero return value
53 | if [ ! "$ret" -eq '0' ]; then
54 | error "You must have '$1' installed to continue."
55 | fi
56 | }
57 |
58 | variable_set() {
59 | if [ -z "$1" ]; then
60 | error "You must have your HOME environmental variable set to continue."
61 | fi
62 | }
63 |
64 | lnif() {
65 | if [ -e "$1" ]; then
66 | ln -sf "$1" "$2"
67 | fi
68 | ret="$?"
69 | debug
70 | }
71 |
72 | ############################ SETUP FUNCTIONS
73 |
74 | do_backup() {
75 | if [ -e "$1" ] || [ -e "$2" ] || [ -e "$3" ]; then
76 | msg "Attempting to back up your original vim configuration."
77 | today=`date +%Y%m%d_%s`
78 | for i in "$1" "$2" "$3"; do
79 | [ -e "$i" ] && [ ! -L "$i" ] && mv -v "$i" "$i.$today";
80 | done
81 | ret="$?"
82 | success "Your original vim configuration has been backed up."
83 | debug
84 | fi
85 | }
86 |
87 | sync_repo() {
88 | local repo_path="$1"
89 | local repo_uri="$2"
90 | local repo_branch="$3"
91 | local repo_name="$4"
92 |
93 | msg "Trying to update $repo_name"
94 |
95 | if [ ! -e "$repo_path" ]; then
96 | mkdir -p "$repo_path"
97 | git clone -b "$repo_branch" "$repo_uri" "$repo_path"
98 | ret="$?"
99 | success "Successfully cloned $repo_name."
100 | else
101 | cd "$repo_path" && git pull origin "$repo_branch"
102 | ret="$?"
103 | success "Successfully updated $repo_name"
104 | fi
105 |
106 | debug
107 | }
108 |
109 | create_symlinks() {
110 | local source_path="$1"
111 | local target_path="$2"
112 |
113 | lnif "$source_path/.vimrc" "$target_path/.vimrc"
114 | lnif "$source_path/.vimrc.bundles" "$target_path/.vimrc.bundles"
115 | lnif "$source_path/.vimrc.before" "$target_path/.vimrc.before"
116 | lnif "$source_path/.vim" "$target_path/.vim"
117 |
118 | touch "$target_path/.vimrc.local"
119 |
120 | ret="$?"
121 | success "Setting up vim symlinks."
122 | debug
123 | }
124 |
125 | setup_fork_mode() {
126 | local source_path="$2"
127 | local target_path="$3"
128 |
129 | if [ "$1" -eq '1' ]; then
130 | touch "$target_path/.vimrc.fork"
131 | touch "$target_path/.vimrc.bundles.fork"
132 | touch "$target_path/.vimrc.before.fork"
133 |
134 | lnif "$source_path/.vimrc.fork" "$target_path/.vimrc.fork"
135 | lnif "$source_path/.vimrc.bundles.fork" "$target_path/.vimrc.bundles.fork"
136 | lnif "$source_path/.vimrc.before.fork" "$target_path/.vimrc.before.fork"
137 |
138 | ret="$?"
139 | success "Created fork maintainer files."
140 | debug
141 | fi
142 | }
143 |
144 | setup_vundle() {
145 | local system_shell="$SHELL"
146 | export SHELL='/bin/sh'
147 |
148 | vim \
149 | -u "$1" \
150 | "+set nomore" \
151 | "+BundleInstall!" \
152 | "+BundleClean" \
153 | "+qall"
154 |
155 | export SHELL="$system_shell"
156 |
157 | success "Now updating/installing plugins using Vundle"
158 | debug
159 | }
160 |
161 | ############################ MAIN()
162 | variable_set "$HOME"
163 | program_exists "vim"
164 | program_exists "git"
165 |
166 | do_backup "$HOME/.vim" \
167 | "$HOME/.vimrc" \
168 | "$HOME/.gvimrc"
169 |
170 | sync_repo "$APP_PATH" \
171 | "$REPO_URI" \
172 | "$REPO_BRANCH" \
173 | "$app_name"
174 |
175 | create_symlinks "$APP_PATH" \
176 | "$HOME"
177 |
178 | setup_fork_mode "$fork_maintainer" \
179 | "$APP_PATH" \
180 | "$HOME"
181 |
182 | sync_repo "$HOME/.vim/bundle/vundle" \
183 | "$VUNDLE_URI" \
184 | "master" \
185 | "vundle"
186 |
187 | setup_vundle "$APP_PATH/.vimrc.bundles.default"
188 |
189 | msg "\nThanks for installing $app_name."
190 | msg "© `date +%Y` http://vim.spf13.com/"
191 |
--------------------------------------------------------------------------------
/ballista/static/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 |
--------------------------------------------------------------------------------
/ballista/static/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 |
--------------------------------------------------------------------------------
/ballista/static/admin/js/admin/RelatedObjectLookups.js:
--------------------------------------------------------------------------------
1 | /*global SelectBox, interpolate*/
2 | // Handles related-objects functionality: lookup link for raw_id_fields
3 | // and Add Another links.
4 |
5 | (function($) {
6 | 'use strict';
7 |
8 | // IE doesn't accept periods or dashes in the window name, but the element IDs
9 | // we use to generate popup window names may contain them, therefore we map them
10 | // to allowed characters in a reversible way so that we can locate the correct
11 | // element when the popup window is dismissed.
12 | function id_to_windowname(text) {
13 | text = text.replace(/\./g, '__dot__');
14 | text = text.replace(/\-/g, '__dash__');
15 | return text;
16 | }
17 |
18 | function windowname_to_id(text) {
19 | text = text.replace(/__dot__/g, '.');
20 | text = text.replace(/__dash__/g, '-');
21 | return text;
22 | }
23 |
24 | function showAdminPopup(triggeringLink, name_regexp, add_popup) {
25 | var name = triggeringLink.id.replace(name_regexp, '');
26 | name = id_to_windowname(name);
27 | var href = triggeringLink.href;
28 | if (add_popup) {
29 | if (href.indexOf('?') === -1) {
30 | href += '?_popup=1';
31 | } else {
32 | href += '&_popup=1';
33 | }
34 | }
35 | var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
36 | win.focus();
37 | return false;
38 | }
39 |
40 | function showRelatedObjectLookupPopup(triggeringLink) {
41 | return showAdminPopup(triggeringLink, /^lookup_/, true);
42 | }
43 |
44 | function dismissRelatedLookupPopup(win, chosenId) {
45 | var name = windowname_to_id(win.name);
46 | var elem = document.getElementById(name);
47 | if (elem.className.indexOf('vManyToManyRawIdAdminField') !== -1 && elem.value) {
48 | elem.value += ',' + chosenId;
49 | } else {
50 | document.getElementById(name).value = chosenId;
51 | }
52 | win.close();
53 | }
54 |
55 | function showRelatedObjectPopup(triggeringLink) {
56 | return showAdminPopup(triggeringLink, /^(change|add|delete)_/, false);
57 | }
58 |
59 | function updateRelatedObjectLinks(triggeringLink) {
60 | var $this = $(triggeringLink);
61 | var siblings = $this.nextAll('.view-related, .change-related, .delete-related');
62 | if (!siblings.length) {
63 | return;
64 | }
65 | var value = $this.val();
66 | if (value) {
67 | siblings.each(function() {
68 | var elm = $(this);
69 | elm.attr('href', elm.attr('data-href-template').replace('__fk__', value));
70 | });
71 | } else {
72 | siblings.removeAttr('href');
73 | }
74 | }
75 |
76 | function dismissAddRelatedObjectPopup(win, newId, newRepr) {
77 | var name = windowname_to_id(win.name);
78 | var elem = document.getElementById(name);
79 | if (elem) {
80 | var elemName = elem.nodeName.toUpperCase();
81 | if (elemName === 'SELECT') {
82 | elem.options[elem.options.length] = new Option(newRepr, newId, true, true);
83 | } else if (elemName === 'INPUT') {
84 | if (elem.className.indexOf('vManyToManyRawIdAdminField') !== -1 && elem.value) {
85 | elem.value += ',' + newId;
86 | } else {
87 | elem.value = newId;
88 | }
89 | }
90 | // Trigger a change event to update related links if required.
91 | $(elem).trigger('change');
92 | } else {
93 | var toId = name + "_to";
94 | var o = new Option(newRepr, newId);
95 | SelectBox.add_to_cache(toId, o);
96 | SelectBox.redisplay(toId);
97 | }
98 | win.close();
99 | }
100 |
101 | function dismissChangeRelatedObjectPopup(win, objId, newRepr, newId) {
102 | var id = windowname_to_id(win.name).replace(/^edit_/, '');
103 | var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
104 | var selects = $(selectsSelector);
105 | selects.find('option').each(function() {
106 | if (this.value === objId) {
107 | this.textContent = newRepr;
108 | this.value = newId;
109 | }
110 | });
111 | selects.next().find('.select2-selection__rendered').each(function() {
112 | // The element can have a clear button as a child.
113 | // Use the lastChild to modify only the displayed value.
114 | this.lastChild.textContent = newRepr;
115 | this.title = newRepr;
116 | });
117 | win.close();
118 | }
119 |
120 | function dismissDeleteRelatedObjectPopup(win, objId) {
121 | var id = windowname_to_id(win.name).replace(/^delete_/, '');
122 | var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
123 | var selects = $(selectsSelector);
124 | selects.find('option').each(function() {
125 | if (this.value === objId) {
126 | $(this).remove();
127 | }
128 | }).trigger('change');
129 | win.close();
130 | }
131 |
132 | // Global for testing purposes
133 | window.id_to_windowname = id_to_windowname;
134 | window.windowname_to_id = windowname_to_id;
135 |
136 | window.showRelatedObjectLookupPopup = showRelatedObjectLookupPopup;
137 | window.dismissRelatedLookupPopup = dismissRelatedLookupPopup;
138 | window.showRelatedObjectPopup = showRelatedObjectPopup;
139 | window.updateRelatedObjectLinks = updateRelatedObjectLinks;
140 | window.dismissAddRelatedObjectPopup = dismissAddRelatedObjectPopup;
141 | window.dismissChangeRelatedObjectPopup = dismissChangeRelatedObjectPopup;
142 | window.dismissDeleteRelatedObjectPopup = dismissDeleteRelatedObjectPopup;
143 |
144 | // Kept for backward compatibility
145 | window.showAddAnotherPopup = showRelatedObjectPopup;
146 | window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup;
147 |
148 | $(document).ready(function() {
149 | $("a[data-popup-opener]").on('click', function(event) {
150 | event.preventDefault();
151 | opener.dismissRelatedLookupPopup(window, $(this).data("popup-opener"));
152 | });
153 | $('body').on('click', '.related-widget-wrapper-link', function(e) {
154 | e.preventDefault();
155 | if (this.href) {
156 | var event = $.Event('django:show-related', {href: this.href});
157 | $(this).trigger(event);
158 | if (!event.isDefaultPrevented()) {
159 | showRelatedObjectPopup(this);
160 | }
161 | }
162 | });
163 | $('body').on('change', '.related-widget-wrapper select', function(e) {
164 | var event = $.Event('django:update-related');
165 | $(this).trigger(event);
166 | if (!event.isDefaultPrevented()) {
167 | updateRelatedObjectLinks(this);
168 | }
169 | });
170 | $('.related-widget-wrapper select').trigger('change');
171 | $('body').on('click', '.related-lookup', function(e) {
172 | e.preventDefault();
173 | var event = $.Event('django:lookup-related');
174 | $(this).trigger(event);
175 | if (!event.isDefaultPrevented()) {
176 | showRelatedObjectLookupPopup(this);
177 | }
178 | });
179 | });
180 |
181 | })(django.jQuery);
182 |
--------------------------------------------------------------------------------
/ballista/static/admin/css/changelists.css:
--------------------------------------------------------------------------------
1 | /* CHANGELISTS */
2 |
3 | #changelist {
4 | position: relative;
5 | width: 100%;
6 | }
7 |
8 | #changelist table {
9 | width: 100%;
10 | }
11 |
12 | .change-list .hiddenfields { display:none; }
13 |
14 | .change-list .filtered table {
15 | border-right: none;
16 | }
17 |
18 | .change-list .filtered {
19 | min-height: 400px;
20 | }
21 |
22 | .change-list .filtered .results, .change-list .filtered .paginator,
23 | .filtered #toolbar, .filtered div.xfull {
24 | margin-right: 280px;
25 | width: auto;
26 | }
27 |
28 | .change-list .filtered table tbody th {
29 | padding-right: 1em;
30 | }
31 |
32 | #changelist-form .results {
33 | overflow-x: auto;
34 | }
35 |
36 | #changelist .toplinks {
37 | border-bottom: 1px solid #ddd;
38 | }
39 |
40 | #changelist .paginator {
41 | color: #666;
42 | border-bottom: 1px solid #eee;
43 | background: #fff;
44 | overflow: hidden;
45 | }
46 |
47 | /* CHANGELIST TABLES */
48 |
49 | #changelist table thead th {
50 | padding: 0;
51 | white-space: nowrap;
52 | vertical-align: middle;
53 | }
54 |
55 | #changelist table thead th.action-checkbox-column {
56 | width: 1.5em;
57 | text-align: center;
58 | }
59 |
60 | #changelist table tbody td.action-checkbox {
61 | text-align: center;
62 | }
63 |
64 | #changelist table tfoot {
65 | color: #666;
66 | }
67 |
68 | /* TOOLBAR */
69 |
70 | #changelist #toolbar {
71 | padding: 8px 10px;
72 | margin-bottom: 15px;
73 | border-top: 1px solid #eee;
74 | border-bottom: 1px solid #eee;
75 | background: #f8f8f8;
76 | color: #666;
77 | }
78 |
79 | #changelist #toolbar form input {
80 | border-radius: 4px;
81 | font-size: 14px;
82 | padding: 5px;
83 | color: #333;
84 | }
85 |
86 | #changelist #toolbar form #searchbar {
87 | height: 19px;
88 | border: 1px solid #ccc;
89 | padding: 2px 5px;
90 | margin: 0;
91 | vertical-align: top;
92 | font-size: 13px;
93 | }
94 |
95 | #changelist #toolbar form #searchbar:focus {
96 | border-color: #999;
97 | }
98 |
99 | #changelist #toolbar form input[type="submit"] {
100 | border: 1px solid #ccc;
101 | padding: 2px 10px;
102 | margin: 0;
103 | vertical-align: middle;
104 | background: #fff;
105 | box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset;
106 | cursor: pointer;
107 | color: #333;
108 | }
109 |
110 | #changelist #toolbar form input[type="submit"]:focus,
111 | #changelist #toolbar form input[type="submit"]:hover {
112 | border-color: #999;
113 | }
114 |
115 | #changelist #changelist-search img {
116 | vertical-align: middle;
117 | margin-right: 4px;
118 | }
119 |
120 | /* FILTER COLUMN */
121 |
122 | #changelist-filter {
123 | position: absolute;
124 | top: 0;
125 | right: 0;
126 | z-index: 1000;
127 | width: 240px;
128 | background: #f8f8f8;
129 | border-left: none;
130 | margin: 0;
131 | }
132 |
133 | #changelist-filter h2 {
134 | font-size: 14px;
135 | text-transform: uppercase;
136 | letter-spacing: 0.5px;
137 | padding: 5px 15px;
138 | margin-bottom: 12px;
139 | border-bottom: none;
140 | }
141 |
142 | #changelist-filter h3 {
143 | font-weight: 400;
144 | font-size: 14px;
145 | padding: 0 15px;
146 | margin-bottom: 10px;
147 | }
148 |
149 | #changelist-filter ul {
150 | margin: 5px 0;
151 | padding: 0 15px 15px;
152 | border-bottom: 1px solid #eaeaea;
153 | }
154 |
155 | #changelist-filter ul:last-child {
156 | border-bottom: none;
157 | padding-bottom: none;
158 | }
159 |
160 | #changelist-filter li {
161 | list-style-type: none;
162 | margin-left: 0;
163 | padding-left: 0;
164 | }
165 |
166 | #changelist-filter a {
167 | display: block;
168 | color: #999;
169 | text-overflow: ellipsis;
170 | overflow-x: hidden;
171 | }
172 |
173 | #changelist-filter li.selected {
174 | border-left: 5px solid #eaeaea;
175 | padding-left: 10px;
176 | margin-left: -15px;
177 | }
178 |
179 | #changelist-filter li.selected a {
180 | color: #5b80b2;
181 | }
182 |
183 | #changelist-filter a:focus, #changelist-filter a:hover,
184 | #changelist-filter li.selected a:focus,
185 | #changelist-filter li.selected a:hover {
186 | color: #036;
187 | }
188 |
189 | /* DATE DRILLDOWN */
190 |
191 | .change-list ul.toplinks {
192 | display: block;
193 | float: left;
194 | padding: 0;
195 | margin: 0;
196 | width: 100%;
197 | }
198 |
199 | .change-list ul.toplinks li {
200 | padding: 3px 6px;
201 | font-weight: bold;
202 | list-style-type: none;
203 | display: inline-block;
204 | }
205 |
206 | .change-list ul.toplinks .date-back a {
207 | color: #999;
208 | }
209 |
210 | .change-list ul.toplinks .date-back a:focus,
211 | .change-list ul.toplinks .date-back a:hover {
212 | color: #036;
213 | }
214 |
215 | /* PAGINATOR */
216 |
217 | .paginator {
218 | font-size: 13px;
219 | padding-top: 10px;
220 | padding-bottom: 10px;
221 | line-height: 22px;
222 | margin: 0;
223 | border-top: 1px solid #ddd;
224 | }
225 |
226 | .paginator a:link, .paginator a:visited {
227 | padding: 2px 6px;
228 | background: #79aec8;
229 | text-decoration: none;
230 | color: #fff;
231 | }
232 |
233 | .paginator a.showall {
234 | padding: 0;
235 | border: none;
236 | background: none;
237 | color: #5b80b2;
238 | }
239 |
240 | .paginator a.showall:focus, .paginator a.showall:hover {
241 | background: none;
242 | color: #036;
243 | }
244 |
245 | .paginator .end {
246 | margin-right: 6px;
247 | }
248 |
249 | .paginator .this-page {
250 | padding: 2px 6px;
251 | font-weight: bold;
252 | font-size: 13px;
253 | vertical-align: top;
254 | }
255 |
256 | .paginator a:focus, .paginator a:hover {
257 | color: white;
258 | background: #036;
259 | }
260 |
261 | /* ACTIONS */
262 |
263 | .filtered .actions {
264 | margin-right: 280px;
265 | border-right: none;
266 | }
267 |
268 | #changelist table input {
269 | margin: 0;
270 | vertical-align: baseline;
271 | }
272 |
273 | #changelist table tbody tr.selected {
274 | background-color: #FFFFCC;
275 | }
276 |
277 | #changelist .actions {
278 | padding: 10px;
279 | background: #fff;
280 | border-top: none;
281 | border-bottom: none;
282 | line-height: 24px;
283 | color: #999;
284 | }
285 |
286 | #changelist .actions.selected {
287 | background: #fffccf;
288 | border-top: 1px solid #fffee8;
289 | border-bottom: 1px solid #edecd6;
290 | }
291 |
292 | #changelist .actions span.all,
293 | #changelist .actions span.action-counter,
294 | #changelist .actions span.clear,
295 | #changelist .actions span.question {
296 | font-size: 13px;
297 | margin: 0 0.5em;
298 | display: none;
299 | }
300 |
301 | #changelist .actions:last-child {
302 | border-bottom: none;
303 | }
304 |
305 | #changelist .actions select {
306 | vertical-align: top;
307 | height: 24px;
308 | background: none;
309 | color: #000;
310 | border: 1px solid #ccc;
311 | border-radius: 4px;
312 | font-size: 14px;
313 | padding: 0 0 0 4px;
314 | margin: 0;
315 | margin-left: 10px;
316 | }
317 |
318 | #changelist .actions select:focus {
319 | border-color: #999;
320 | }
321 |
322 | #changelist .actions label {
323 | display: inline-block;
324 | vertical-align: middle;
325 | font-size: 13px;
326 | }
327 |
328 | #changelist .actions .button {
329 | font-size: 13px;
330 | border: 1px solid #ccc;
331 | border-radius: 4px;
332 | background: #fff;
333 | box-shadow: 0 -15px 20px -10px rgba(0, 0, 0, 0.15) inset;
334 | cursor: pointer;
335 | height: 24px;
336 | line-height: 1;
337 | padding: 4px 8px;
338 | margin: 0;
339 | color: #333;
340 | }
341 |
342 | #changelist .actions .button:focus, #changelist .actions .button:hover {
343 | border-color: #999;
344 | }
345 |
--------------------------------------------------------------------------------
/ballista/static/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 | var hours = this.getHours();
78 | if (hours === 0) {
79 | return 12;
80 | }
81 | else {
82 | return hours <= 12 ? hours : hours - 12;
83 | }
84 | };
85 |
86 | Date.prototype.getTwoDigitMonth = function() {
87 | return (this.getMonth() < 9) ? '0' + (this.getMonth() + 1) : (this.getMonth() + 1);
88 | };
89 |
90 | Date.prototype.getTwoDigitDate = function() {
91 | return (this.getDate() < 10) ? '0' + this.getDate() : this.getDate();
92 | };
93 |
94 | Date.prototype.getTwoDigitTwelveHour = function() {
95 | return (this.getTwelveHours() < 10) ? '0' + this.getTwelveHours() : this.getTwelveHours();
96 | };
97 |
98 | Date.prototype.getTwoDigitHour = function() {
99 | return (this.getHours() < 10) ? '0' + this.getHours() : this.getHours();
100 | };
101 |
102 | Date.prototype.getTwoDigitMinute = function() {
103 | return (this.getMinutes() < 10) ? '0' + this.getMinutes() : this.getMinutes();
104 | };
105 |
106 | Date.prototype.getTwoDigitSecond = function() {
107 | return (this.getSeconds() < 10) ? '0' + this.getSeconds() : this.getSeconds();
108 | };
109 |
110 | Date.prototype.getHourMinute = function() {
111 | return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute();
112 | };
113 |
114 | Date.prototype.getHourMinuteSecond = function() {
115 | return this.getTwoDigitHour() + ':' + this.getTwoDigitMinute() + ':' + this.getTwoDigitSecond();
116 | };
117 |
118 | Date.prototype.getFullMonthName = function() {
119 | return typeof window.CalendarNamespace === "undefined"
120 | ? this.getTwoDigitMonth()
121 | : window.CalendarNamespace.monthsOfYear[this.getMonth()];
122 | };
123 |
124 | Date.prototype.strftime = function(format) {
125 | var fields = {
126 | B: this.getFullMonthName(),
127 | c: this.toString(),
128 | d: this.getTwoDigitDate(),
129 | H: this.getTwoDigitHour(),
130 | I: this.getTwoDigitTwelveHour(),
131 | m: this.getTwoDigitMonth(),
132 | M: this.getTwoDigitMinute(),
133 | p: (this.getHours() >= 12) ? 'PM' : 'AM',
134 | S: this.getTwoDigitSecond(),
135 | w: '0' + this.getDay(),
136 | x: this.toLocaleDateString(),
137 | X: this.toLocaleTimeString(),
138 | y: ('' + this.getFullYear()).substr(2, 4),
139 | Y: '' + this.getFullYear(),
140 | '%': '%'
141 | };
142 | var result = '', i = 0;
143 | while (i < format.length) {
144 | if (format.charAt(i) === '%') {
145 | result = result + fields[format.charAt(i + 1)];
146 | ++i;
147 | }
148 | else {
149 | result = result + format.charAt(i);
150 | }
151 | ++i;
152 | }
153 | return result;
154 | };
155 |
156 | // ----------------------------------------------------------------------------
157 | // String object extensions
158 | // ----------------------------------------------------------------------------
159 | String.prototype.pad_left = function(pad_length, pad_string) {
160 | var new_string = this;
161 | for (var i = 0; new_string.length < pad_length; i++) {
162 | new_string = pad_string + new_string;
163 | }
164 | return new_string;
165 | };
166 |
167 | String.prototype.strptime = function(format) {
168 | var split_format = format.split(/[.\-/]/);
169 | var date = this.split(/[.\-/]/);
170 | var i = 0;
171 | var day, month, year;
172 | while (i < split_format.length) {
173 | switch (split_format[i]) {
174 | case "%d":
175 | day = date[i];
176 | break;
177 | case "%m":
178 | month = date[i] - 1;
179 | break;
180 | case "%Y":
181 | year = date[i];
182 | break;
183 | case "%y":
184 | year = date[i];
185 | break;
186 | }
187 | ++i;
188 | }
189 | // Create Date object from UTC since the parsed value is supposed to be
190 | // in UTC, not local time. Also, the calendar uses UTC functions for
191 | // date extraction.
192 | return new Date(Date.UTC(year, month, day));
193 | };
194 |
195 | })();
196 | // ----------------------------------------------------------------------------
197 | // Get the computed style for and element
198 | // ----------------------------------------------------------------------------
199 | function getStyle(oElm, strCssRule) {
200 | 'use strict';
201 | var strValue = "";
202 | if(document.defaultView && document.defaultView.getComputedStyle) {
203 | strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
204 | }
205 | else if(oElm.currentStyle) {
206 | strCssRule = strCssRule.replace(/\-(\w)/g, function(strMatch, p1) {
207 | return p1.toUpperCase();
208 | });
209 | strValue = oElm.currentStyle[strCssRule];
210 | }
211 | return strValue;
212 | }
213 |
--------------------------------------------------------------------------------
|