rt 4.0.23
[freeside.git] / rt / share / html / NoAuth / js / util.js
1 %# BEGIN BPS TAGGED BLOCK {{{
2 %#
3 %# COPYRIGHT:
4 %#
5 %# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
6 %#                                          <sales@bestpractical.com>
7 %#
8 %# (Except where explicitly superseded by other copyright notices)
9 %#
10 %#
11 %# LICENSE:
12 %#
13 %# This work is made available to you under the terms of Version 2 of
14 %# the GNU General Public License. A copy of that license should have
15 %# been provided with this software, but in any event can be snarfed
16 %# from www.gnu.org.
17 %#
18 %# This work is distributed in the hope that it will be useful, but
19 %# WITHOUT ANY WARRANTY; without even the implied warranty of
20 %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 %# General Public License for more details.
22 %#
23 %# You should have received a copy of the GNU General Public License
24 %# along with this program; if not, write to the Free Software
25 %# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 %# 02110-1301 or visit their web page on the internet at
27 %# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28 %#
29 %#
30 %# CONTRIBUTION SUBMISSION POLICY:
31 %#
32 %# (The following paragraph is not intended to limit the rights granted
33 %# to you to modify and distribute this software under the terms of
34 %# the GNU General Public License and is only of importance to you if
35 %# you choose to contribute your changes and enhancements to the
36 %# community by submitting them to Best Practical Solutions, LLC.)
37 %#
38 %# By intentionally submitting any modifications, corrections or
39 %# derivatives to this work, or any other work intended for use with
40 %# Request Tracker, to Best Practical Solutions, LLC, you confirm that
41 %# you are the copyright holder for those contributions and you grant
42 %# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
43 %# royalty-free, perpetual, license to use, copy, create derivative
44 %# works based on those contributions, and sublicense and distribute
45 %# those contributions and any derivatives thereof.
46 %#
47 %# END BPS TAGGED BLOCK }}}
48 /* Visibility */
49
50 function show(id) { delClass( id, 'hidden' ) }
51 function hide(id) { addClass( id, 'hidden' ) }
52
53 function hideshow(id) { return toggleVisibility( id ) }
54 function toggleVisibility(id) {
55     var e = jQuery('#' + id);
56
57     if ( e.hasClass('hidden') ) {
58         e.removeClass('hidden');
59     }
60     else {
61         e.addClass('hidden');
62     }
63
64     return false;
65 }
66
67 function setVisibility(id, visibility) {
68     if ( visibility ) show(id);
69     else hide(id);
70 }
71
72 function switchVisibility(id1, id2) {
73     // Show both and then hide the one we want
74     show(id1);
75     show(id2);
76     hide(id2);
77     return false;
78 }
79
80 /* Classes */
81 function jQueryWrap( id ) {
82     return typeof id == 'object' ? jQuery(id) : jQuery('#'+id);
83 }
84
85 function addClass(id, value) {
86     jQueryWrap(id).addClass(value);
87 }
88
89 function delClass(id, value) {
90     jQueryWrap(id).removeClass(value);
91 }
92
93 /* Rollups */
94
95 function rollup(id) {
96     var e = jQueryWrap(id);
97     var e2  = e.parent();
98     
99     if (e.hasClass('hidden')) {
100         set_rollup_state(e,e2,'shown');
101         createCookie(id,1,365);
102     }
103     else {
104         set_rollup_state(e,e2,'hidden');
105         createCookie(id,0,365);
106     }
107     return false;
108 }
109
110 function set_rollup_state(e,e2,state) {
111     if (e && e2) {
112         if (state == 'shown') {
113             show(e);
114             delClass( e2, 'rolled-up' );
115         }
116         else if (state == 'hidden') {
117             hide(e);
118             addClass( e2, 'rolled-up' );
119         }
120     }
121 }
122
123 /* other utils */
124
125 function focusElementById(id) {
126     var e = jQuery('#'+id);
127     if (e) e.focus();
128 }
129
130 function setCheckbox(form, name, val) {
131     var myfield = form.getElementsByTagName('input');
132     for ( var i = 0; i < myfield.length; i++ ) {
133         if ( myfield[i].type != 'checkbox' ) continue;
134         if ( name ) {
135             if ( name instanceof RegExp ) {
136                 if ( ! myfield[i].name.match( name ) ) continue;
137             }
138             else {
139                 if ( myfield[i].name != name ) continue;
140             }
141
142         }
143
144         myfield[i].checked = val;
145     }
146 }
147
148 /* apply callback to nodes or elements */
149
150 function walkChildNodes(parent, callback)
151 {
152     if( !parent || !parent.childNodes ) return;
153     var list = parent.childNodes;
154     for( var i = 0; i < list.length; i++ ) {
155         callback( list[i] );
156     }
157 }
158
159 function walkChildElements(parent, callback)
160 {
161     walkChildNodes( parent, function(node) {
162         if( node.nodeType != 1 ) return;
163         return callback( node );
164     } );
165 }
166
167 /* shredder things */
168
169 function showShredderPluginTab( plugin )
170 {
171     var plugin_tab_id = 'shredder-plugin-'+ plugin +'-tab';
172     var root = jQuery('#shredder-plugin-tabs');
173     
174     root.children(':not(.hidden)').addClass('hidden');
175     root.children('#' + plugin_tab_id).removeClass('hidden');
176
177     if( plugin ) {
178         show('shredder-submit-button');
179     } else {
180         hide('shredder-submit-button');
181     }
182 }
183
184 function checkAllObjects()
185 {
186     var check = jQuery('#shredder-select-all-objects-checkbox').attr('checked');
187     var elements = jQuery('#shredder-search-form :checkbox[name=WipeoutObject]');
188
189     if( check ) {
190         elements.attr('checked', true);
191     } else {
192         elements.attr('checked', false);
193     }
194 }
195
196 function checkboxToInput(target,checkbox,val){    
197     var tar = jQuery('#' + escapeCssSelector(target));
198     var box = jQuery('#' + escapeCssSelector(checkbox));
199     if(box.attr('checked')){
200         if (tar.val()==''){
201             tar.val(val);
202         }
203         else{
204             tar.val( val+', '+ tar.val() );        
205         }
206     }
207     else{
208         tar.val(tar.val().replace(val+', ',''));
209         tar.val(tar.val().replace(val,''));
210     }
211     jQuery('#UpdateIgnoreAddressCheckboxes').val(true);
212 }
213
214 // ahah for back compatibility as plugins may still use it
215 function ahah( url, id ) {
216     jQuery('#'+id).load(url);
217 }
218
219 // only for back compatibility, please JQuery() instead
220 function doOnLoad( js ) {
221     jQuery(js);
222 }
223
224 jQuery(function() {
225     var opts = {
226         dateFormat: 'yy-mm-dd',
227         constrainInput: false,
228         showButtonPanel: true,
229         changeMonth: true,
230         changeYear: true,
231         showOtherMonths: true,
232         selectOtherMonths: true
233     };
234     jQuery(".ui-datepicker:not(.withtime)").datepicker(opts);
235     jQuery(".ui-datepicker.withtime").datetimepicker( jQuery.extend({}, opts, {
236         stepHour: 1,
237         // We fake this by snapping below for the minute slider
238         //stepMinute: 5,
239         hourGrid: 6,
240         minuteGrid: 15,
241         showSecond: false,
242         timeFormat: 'hh:mm:ss'
243     }) ).each(function(index, el) {
244         var tp = jQuery.datepicker._get( jQuery.datepicker._getInst(el), 'timepicker');
245         if (!tp) return;
246
247         // Hook after _injectTimePicker so we can modify the minute_slider
248         // right after it's first created
249         tp._base_injectTimePicker = tp._injectTimePicker;
250         tp._injectTimePicker = function() {
251             this._base_injectTimePicker.apply(this, arguments);
252
253             // Now that we have minute_slider, modify it to be stepped for mouse movements
254             var slider = jQuery.data(this.minute_slider[0], "slider");
255             slider._base_normValueFromMouse = slider._normValueFromMouse;
256             slider._normValueFromMouse = function() {
257                 var value           = this._base_normValueFromMouse.apply(this, arguments);
258                 var old_step        = this.options.step;
259                 this.options.step   = 5;
260                 var aligned         = this._trimAlignValue( value );
261                 this.options.step   = old_step;
262                 return aligned;
263             };
264         };
265     });
266 });
267
268 function textToHTML(value) {
269     return value.replace(/&/g,    "&amp;")
270                 .replace(/</g,    "&lt;")
271                 .replace(/>/g,    "&gt;")
272                 .replace(/-- \n/g,"--&nbsp;\n")
273                 .replace(/\n/g,   "\n<br />");
274 };
275
276 function ReplaceAllTextareas() {
277     var sAgent = navigator.userAgent.toLowerCase();
278     if (!CKEDITOR.env.isCompatible ||
279         sAgent.indexOf('iphone') != -1 ||
280         sAgent.indexOf('ipad') != -1 ||
281         sAgent.indexOf('android') != -1 )
282         return false;
283
284     // replace all content and signature message boxes
285     var allTextAreas = document.getElementsByTagName("textarea");
286
287     for (var i=0; i < allTextAreas.length; i++) {
288         var textArea = allTextAreas[i];
289         if (jQuery(textArea).hasClass("messagebox")) {
290             // Turn the original plain text content into HTML
291             var type = jQuery("#"+textArea.name+"Type");
292             if (type.val() != "text/html")
293                 textArea.value = textToHTML(textArea.value);
294
295             // Set the type
296             type.val("text/html");
297
298             CKEDITOR.replace(textArea.name,{width:'100%',height:<% RT->Config->Get('MessageBoxRichTextHeight') |n,j%>});
299             CKEDITOR.basePath = <%RT->Config->Get('WebPath')|n,j%>+"/NoAuth/RichText/";
300
301             jQuery("#" + textArea.name + "___Frame").addClass("richtext-editor");
302         }
303     }
304 };
305
306 function toggle_addprincipal_validity(input, good, title) {
307     if (good) {
308         jQuery(input).nextAll(".warning").hide();
309         jQuery("#acl-AddPrincipal input[type=checkbox]").removeAttr("disabled");
310     } else {
311         jQuery(input).nextAll(".warning").css("display", "block");
312         jQuery("#acl-AddPrincipal input[type=checkbox]").attr("disabled", "disabled");
313     }
314
315     if (title == null)
316         title = jQuery(input).val();
317
318     update_addprincipal_title( title );
319 }
320
321 function update_addprincipal_title(title) {
322     var h3 = jQuery("#acl-AddPrincipal h3");
323     h3.html( h3.text().replace(/: .*$/,'') + ": " + title );
324 }
325
326 // when a value is selected from the autocompleter
327 function addprincipal_onselect(ev, ui) {
328
329     // if principal link exists, we shall go there instead
330     var principal_link = jQuery(ev.target).closest('form').find('ul.ui-tabs-nav a[href="#acl-' + ui.item.id + '"]:first');
331     if (principal_link.size()) {
332         jQuery(this).val('').blur();
333         update_addprincipal_title( '' ); // reset title to blank for #acl-AddPrincipal
334         principal_link.click();
335         return false;
336     }
337
338     // pass the item's value along as the title since the input's value
339     // isn't actually updated yet
340     toggle_addprincipal_validity(this, true, ui.item.value);
341 }
342
343 // when the input is actually changed, through typing or autocomplete
344 function addprincipal_onchange(ev, ui) {
345     // if we have a ui.item, then they selected from autocomplete and it's good
346     if (!ui.item) {
347         var input = jQuery(this);
348         // Check using the same autocomplete source if the value typed would
349         // have been autocompleted and is therefore valid
350         jQuery.ajax({
351             url: input.autocomplete("option", "source"),
352             data: {
353                 op: "=",
354                 term: input.val()
355             },
356             dataType: "json",
357             success: function(data) {
358                 if (data)
359                     toggle_addprincipal_validity(input, data.length ? true : false );
360                 else
361                     toggle_addprincipal_validity(input, true);
362             }
363         });
364     } else {
365         toggle_addprincipal_validity(this, true);
366     }
367 }
368
369
370 function escapeCssSelector(str) {
371     return str.replace(/([^A-Za-z0-9_-])/g,'\\$1');
372 }