RT# 83091 - fixed selfserivce to insert payment account if one does not exits
[freeside.git] / rt / share / static / js / util.js
1 /* Visibility */
2
3 function show(id) { delClass( id, 'hidden' ) }
4 function hide(id) { addClass( id, 'hidden' ) }
5
6 function hideshow(id) { return toggleVisibility( id ) }
7 function toggleVisibility(id) {
8     var e = jQuery('#' + id);
9
10     if ( e.hasClass('hidden') ) {
11         e.removeClass('hidden');
12     }
13     else {
14         e.addClass('hidden');
15     }
16
17     return false;
18 }
19
20 function setVisibility(id, visibility) {
21     if ( visibility ) show(id);
22     else hide(id);
23 }
24
25 function switchVisibility(id1, id2) {
26     // Show both and then hide the one we want
27     show(id1);
28     show(id2);
29     hide(id2);
30     return false;
31 }
32
33 function toggle_upgrade_history(widget, selector) {
34     jQuery(selector).toggle();
35     jQuery(widget).toggleClass("rolled-up");
36 }
37
38 /* Classes */
39 function jQueryWrap( id ) {
40     return typeof id == 'object' ? jQuery(id) : jQuery('#'+id);
41 }
42
43 function addClass(id, value) {
44     jQueryWrap(id).addClass(value);
45 }
46
47 function delClass(id, value) {
48     jQueryWrap(id).removeClass(value);
49 }
50
51 /* Rollups */
52
53 function rollup(id) {
54     var e = jQueryWrap(id);
55     var e2  = e.parent();
56     
57     if (e.hasClass('hidden')) {
58         set_rollup_state(e,e2,'shown');
59         createCookie(id,1,365);
60     }
61     else {
62         set_rollup_state(e,e2,'hidden');
63         createCookie(id,0,365);
64     }
65     return false;
66 }
67
68 function set_rollup_state(e,e2,state) {
69     if (e && e2) {
70         if (state == 'shown') {
71             show(e);
72             delClass( e2, 'rolled-up' );
73         }
74         else if (state == 'hidden') {
75             hide(e);
76             addClass( e2, 'rolled-up' );
77         }
78     }
79 }
80
81 /* other utils */
82
83 function setCheckbox(input, name, val) {
84     if (val == null) val = input.checked;
85
86     // Find inputs within the current form or collection list, whichever is closest.
87     var container = jQuery(input).closest("form, table.collection-as-table").get(0);
88     var myfield   = container.getElementsByTagName('input');
89     for ( var i = 0; i < myfield.length; i++ ) {
90         if ( myfield[i].type != 'checkbox' ) continue;
91         if ( name ) {
92             if ( name instanceof RegExp ) {
93                 if ( ! myfield[i].name.match( name ) ) continue;
94             }
95             else {
96                 if ( myfield[i].name != name ) continue;
97             }
98
99         }
100
101         myfield[i].checked = val;
102     }
103 }
104
105 /* apply callback to nodes or elements */
106
107 function walkChildNodes(parent, callback)
108 {
109     if( !parent || !parent.childNodes ) return;
110     var list = parent.childNodes;
111     for( var i = 0; i < list.length; i++ ) {
112         callback( list[i] );
113     }
114 }
115
116 function walkChildElements(parent, callback)
117 {
118     walkChildNodes( parent, function(node) {
119         if( node.nodeType != 1 ) return;
120         return callback( node );
121     } );
122 }
123
124 /* shredder things */
125
126 function showShredderPluginTab( plugin )
127 {
128     var plugin_tab_id = 'shredder-plugin-'+ plugin +'-tab';
129     var root = jQuery('#shredder-plugin-tabs');
130     
131     root.children(':not(.hidden)').addClass('hidden');
132     root.children('#' + plugin_tab_id).removeClass('hidden');
133
134     if( plugin ) {
135         show('shredder-submit-button');
136     } else {
137         hide('shredder-submit-button');
138     }
139 }
140
141 function checkAllObjects()
142 {
143     var check = jQuery('#shredder-select-all-objects-checkbox').prop('checked');
144     var elements = jQuery('#shredder-search-form :checkbox[name=WipeoutObject]');
145
146     if( check ) {
147         elements.prop('checked', true);
148     } else {
149         elements.prop('checked', false);
150     }
151 }
152
153 function checkboxToInput(target,checkbox,val){    
154     var tar = jQuery('#' + escapeCssSelector(target));
155     var box = jQuery('#' + escapeCssSelector(checkbox));
156     if(box.prop('checked')){
157         if (tar.val()==''){
158             tar.val(val);
159         }
160         else{
161             tar.val( val+', '+ tar.val() );        
162         }
163     }
164     else{
165         tar.val(tar.val().replace(val+', ',''));
166         tar.val(tar.val().replace(val,''));
167     }
168     jQuery('#UpdateIgnoreAddressCheckboxes').val(true);
169 }
170
171 // ahah for back compatibility as plugins may still use it
172 function ahah( url, id ) {
173     jQuery('#'+id).load(url);
174 }
175
176 // only for back compatibility, please JQuery() instead
177 function doOnLoad( js ) {
178     jQuery(js);
179 }
180
181 jQuery(function() {
182     var opts = {
183         dateFormat: 'yy-mm-dd',
184         constrainInput: false,
185         showButtonPanel: true,
186         changeMonth: true,
187         changeYear: true,
188         showOtherMonths: true,
189         selectOtherMonths: true
190     };
191     jQuery(".datepicker:not(.withtime)").datepicker(opts);
192     jQuery(".datepicker.withtime").datetimepicker( jQuery.extend({}, opts, {
193         stepHour: 1,
194         // We fake this by snapping below for the minute slider
195         //stepMinute: 5,
196         hourGrid: 6,
197         minuteGrid: 15,
198         showSecond: false,
199         timeFormat: 'HH:mm:ss'
200     }) ).each(function(index, el) {
201         var tp = jQuery.datepicker._get( jQuery.datepicker._getInst(el), 'timepicker');
202         if (!tp) return;
203
204         // Hook after _injectTimePicker so we can modify the minute_slider
205         // right after it's first created
206         tp._base_injectTimePicker = tp._injectTimePicker;
207         tp._injectTimePicker = function() {
208             this._base_injectTimePicker.apply(this, arguments);
209
210             // Now that we have minute_slider, modify it to be stepped for mouse movements
211             var slider = jQuery.data(this.minute_slider[0], "ui-slider");
212             slider._base_normValueFromMouse = slider._normValueFromMouse;
213             slider._normValueFromMouse = function() {
214                 var value           = this._base_normValueFromMouse.apply(this, arguments);
215                 var old_step        = this.options.step;
216                 this.options.step   = 5;
217                 var aligned         = this._trimAlignValue( value );
218                 this.options.step   = old_step;
219                 return aligned;
220             };
221         };
222     });
223 });
224
225 function textToHTML(value) {
226     return value.replace(/&/g,    "&amp;")
227                 .replace(/</g,    "&lt;")
228                 .replace(/>/g,    "&gt;")
229                 .replace(/-- \n/g,"--&nbsp;\n")
230                 .replace(/\n/g,   "\n<br />");
231 };
232
233 CKEDITOR_BASEPATH=RT.Config.WebPath + "/static/RichText/";
234 function ReplaceAllTextareas() {
235     var sAgent = navigator.userAgent.toLowerCase();
236     if (!CKEDITOR.env.isCompatible ||
237         sAgent.indexOf('iphone') != -1 ||
238         sAgent.indexOf('ipad') != -1 ||
239         sAgent.indexOf('android') != -1 )
240         return false;
241
242     // replace all content and signature message boxes
243     var allTextAreas = document.getElementsByTagName("textarea");
244
245     for (var i=0; i < allTextAreas.length; i++) {
246         var textArea = allTextAreas[i];
247         if (jQuery(textArea).hasClass("messagebox richtext")) {
248             // Turn the original plain text content into HTML
249             var type = jQuery("#"+textArea.name+"Type");
250             if (type.val() != "text/html")
251                 textArea.value = textToHTML(textArea.value);
252
253             // Set the type
254             type.val("text/html");
255
256             CKEDITOR.replace(textArea.name,{ width: '100%', height: RT.Config.MessageBoxRichTextHeight });
257
258             jQuery("#" + textArea.name + "___Frame").addClass("richtext-editor");
259         }
260     }
261 };
262
263 function toggle_addprincipal_validity(input, good, title) {
264     if (good) {
265         jQuery(input).nextAll(".warning").hide();
266         jQuery("#acl-AddPrincipal input[type=checkbox]").removeAttr("disabled");
267     } else {
268         jQuery(input).nextAll(".warning").css("display", "block");
269         jQuery("#acl-AddPrincipal input[type=checkbox]").attr("disabled", "disabled");
270     }
271
272     if (title == null)
273         title = jQuery(input).val();
274
275     update_addprincipal_title( title );
276 }
277
278 function update_addprincipal_title(title) {
279     var h3 = jQuery("#acl-AddPrincipal h3");
280     h3.text( h3.text().replace(/: .*$/,'') + ": " + title );
281 }
282
283 // when a value is selected from the autocompleter
284 function addprincipal_onselect(ev, ui) {
285
286     // if principal link exists, we shall go there instead
287     var principal_link = jQuery(ev.target).closest('form').find('ul.ui-tabs-nav a[href="#acl-' + ui.item.id + '"]:first');
288     if (principal_link.size()) {
289         jQuery(this).val('').blur();
290         update_addprincipal_title( '' ); // reset title to blank for #acl-AddPrincipal
291         principal_link.click();
292         return false;
293     }
294
295     // pass the item's value along as the title since the input's value
296     // isn't actually updated yet
297     toggle_addprincipal_validity(this, true, ui.item.value);
298 }
299
300 // when the input is actually changed, through typing or autocomplete
301 function addprincipal_onchange(ev, ui) {
302     // if we have a ui.item, then they selected from autocomplete and it's good
303     if (!ui.item) {
304         var input = jQuery(this);
305         // Check using the same autocomplete source if the value typed would
306         // have been autocompleted and is therefore valid
307         jQuery.ajax({
308             url: input.autocomplete("option", "source"),
309             data: {
310                 op: "=",
311                 term: input.val()
312             },
313             dataType: "json",
314             success: function(data) {
315                 if (data)
316                     toggle_addprincipal_validity(input, data.length ? true : false );
317                 else
318                     toggle_addprincipal_validity(input, true);
319             }
320         });
321     } else {
322         toggle_addprincipal_validity(this, true);
323     }
324 }
325
326
327 function escapeCssSelector(str) {
328     return str.replace(/([^A-Za-z0-9_-])/g,'\\$1');
329 }
330
331
332 jQuery(function() {
333     jQuery(".user-accordion").each(function(){
334         jQuery(this).accordion({
335             active: (jQuery(this).find("h3").length == 1 ? 0 : false),
336             collapsible: true,
337             heightStyle: "content",
338             header: "h3"
339         }).find("h3 a.user-summary").click(function(ev){
340             ev.stopPropagation();
341             return true;
342         });
343     });
344     ReplaceAllTextareas();
345 });