initial commit
[emels.git] / emels / 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('.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         win.close();
112     }
113
114     function dismissDeleteRelatedObjectPopup(win, objId) {
115         var id = windowname_to_id(win.name).replace(/^delete_/, '');
116         var selectsSelector = interpolate('#%s, #%s_from, #%s_to', [id, id, id]);
117         var selects = $(selectsSelector);
118         selects.find('option').each(function() {
119             if (this.value === objId) {
120                 $(this).remove();
121             }
122         }).trigger('change');
123         win.close();
124     }
125
126     // Global for testing purposes
127     window.id_to_windowname = id_to_windowname;
128     window.windowname_to_id = windowname_to_id;
129
130     window.showRelatedObjectLookupPopup = showRelatedObjectLookupPopup;
131     window.dismissRelatedLookupPopup = dismissRelatedLookupPopup;
132     window.showRelatedObjectPopup = showRelatedObjectPopup;
133     window.updateRelatedObjectLinks = updateRelatedObjectLinks;
134     window.dismissAddRelatedObjectPopup = dismissAddRelatedObjectPopup;
135     window.dismissChangeRelatedObjectPopup = dismissChangeRelatedObjectPopup;
136     window.dismissDeleteRelatedObjectPopup = dismissDeleteRelatedObjectPopup;
137
138     // Kept for backward compatibility
139     window.showAddAnotherPopup = showRelatedObjectPopup;
140     window.dismissAddAnotherPopup = dismissAddRelatedObjectPopup;
141
142     $(document).ready(function() {
143         $("a[data-popup-opener]").click(function(event) {
144             event.preventDefault();
145             opener.dismissRelatedLookupPopup(window, $(this).data("popup-opener"));
146         });
147         $('body').on('click', '.related-widget-wrapper-link', function(e) {
148             e.preventDefault();
149             if (this.href) {
150                 var event = $.Event('django:show-related', {href: this.href});
151                 $(this).trigger(event);
152                 if (!event.isDefaultPrevented()) {
153                     showRelatedObjectPopup(this);
154                 }
155             }
156         });
157         $('body').on('change', '.related-widget-wrapper select', function(e) {
158             var event = $.Event('django:update-related');
159             $(this).trigger(event);
160             if (!event.isDefaultPrevented()) {
161                 updateRelatedObjectLinks(this);
162             }
163         });
164         $('.related-widget-wrapper select').trigger('change');
165         $('.related-lookup').click(function(e) {
166             e.preventDefault();
167             var event = $.Event('django:lookup-related');
168             $(this).trigger(event);
169             if (!event.isDefaultPrevented()) {
170                 showRelatedObjectLookupPopup(this);
171             }
172         });
173     });
174
175 })(django.jQuery);