1 %# BEGIN BPS TAGGED BLOCK {{{
5 %# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
6 %# <sales@bestpractical.com>
8 %# (Except where explicitly superseded by other copyright notices)
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
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.
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.
30 %# CONTRIBUTION SUBMISSION POLICY:
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.)
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.
47 %# END BPS TAGGED BLOCK }}}
50 function show(id) { delClass( id, 'hidden' ) }
51 function hide(id) { addClass( id, 'hidden' ) }
53 function hideshow(id) { return toggleVisibility( id ) }
54 function toggleVisibility(id) {
55 var e = jQuery('#' + id);
57 if ( e.hasClass('hidden') ) {
58 e.removeClass('hidden');
67 function setVisibility(id, visibility) {
68 if ( visibility ) show(id);
72 function switchVisibility(id1, id2) {
73 // Show both and then hide the one we want
81 function jQueryWrap( id ) {
82 return typeof id == 'object' ? jQuery(id) : jQuery('#'+id);
85 function addClass(id, value) {
86 jQueryWrap(id).addClass(value);
89 function delClass(id, value) {
90 jQueryWrap(id).removeClass(value);
96 var e = jQueryWrap(id);
99 if (e.hasClass('hidden')) {
100 set_rollup_state(e,e2,'shown');
101 createCookie(id,1,365);
104 set_rollup_state(e,e2,'hidden');
105 createCookie(id,0,365);
110 function set_rollup_state(e,e2,state) {
112 if (state == 'shown') {
114 delClass( e2, 'rolled-up' );
116 else if (state == 'hidden') {
118 addClass( e2, 'rolled-up' );
125 function focusElementById(id) {
126 var e = jQuery('#'+id);
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;
135 if ( name instanceof RegExp ) {
136 if ( ! myfield[i].name.match( name ) ) continue;
139 if ( myfield[i].name != name ) continue;
144 myfield[i].checked = val;
148 /* apply callback to nodes or elements */
150 function walkChildNodes(parent, callback)
152 if( !parent || !parent.childNodes ) return;
153 var list = parent.childNodes;
154 for( var i = 0; i < list.length; i++ ) {
159 function walkChildElements(parent, callback)
161 walkChildNodes( parent, function(node) {
162 if( node.nodeType != 1 ) return;
163 return callback( node );
167 /* shredder things */
169 function showShredderPluginTab( plugin )
171 var plugin_tab_id = 'shredder-plugin-'+ plugin +'-tab';
172 var root = jQuery('#shredder-plugin-tabs');
174 root.children(':not(.hidden)').addClass('hidden');
175 root.children('#' + plugin_tab_id).removeClass('hidden');
178 show('shredder-submit-button');
180 hide('shredder-submit-button');
184 function checkAllObjects()
186 var check = jQuery('#shredder-select-all-objects-checkbox').attr('checked');
187 var elements = jQuery('#shredder-search-form :checkbox[name=WipeoutObject]');
190 elements.attr('checked', true);
192 elements.attr('checked', false);
196 function checkboxToInput(target,checkbox,val){
197 var tar = jQuery('#' + escapeCssSelector(target));
198 var box = jQuery('#' + escapeCssSelector(checkbox));
199 if(box.attr('checked')){
204 tar.val( val+', '+ tar.val() );
208 tar.val(tar.val().replace(val+', ',''));
209 tar.val(tar.val().replace(val,''));
211 jQuery('#UpdateIgnoreAddressCheckboxes').val(true);
214 // ahah for back compatibility as plugins may still use it
215 function ahah( url, id ) {
216 jQuery('#'+id).load(url);
219 // only for back compatibility, please JQuery() instead
220 function doOnLoad( js ) {
226 dateFormat: 'yy-mm-dd',
227 constrainInput: false,
228 showButtonPanel: true,
231 showOtherMonths: true,
232 selectOtherMonths: true
234 jQuery(".ui-datepicker:not(.withtime)").datepicker(opts);
235 jQuery(".ui-datepicker.withtime").datetimepicker( jQuery.extend({}, opts, {
237 // We fake this by snapping below for the minute slider
242 timeFormat: 'hh:mm:ss'
243 }) ).each(function(index, el) {
244 var tp = jQuery.datepicker._get( jQuery.datepicker._getInst(el), 'timepicker');
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);
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;
268 function textToHTML(value) {
269 return value.replace(/&/g, "&")
270 .replace(/</g, "<")
271 .replace(/>/g, ">")
272 .replace(/-- \n/g,"-- \n")
273 .replace(/\n/g, "\n<br />");
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 )
284 // replace all content and signature message boxes
285 var allTextAreas = document.getElementsByTagName("textarea");
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);
296 type.val("text/html");
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/";
301 jQuery("#" + textArea.name + "___Frame").addClass("richtext-editor");
306 function toggle_addprincipal_validity(input, good, title) {
308 jQuery(input).nextAll(".warning").hide();
309 jQuery("#acl-AddPrincipal input[type=checkbox]").removeAttr("disabled");
311 jQuery(input).nextAll(".warning").css("display", "block");
312 jQuery("#acl-AddPrincipal input[type=checkbox]").attr("disabled", "disabled");
316 title = jQuery(input).val();
318 update_addprincipal_title( title );
321 function update_addprincipal_title(title) {
322 var h3 = jQuery("#acl-AddPrincipal h3");
323 h3.html( h3.text().replace(/: .*$/,'') + ": " + title );
326 // when a value is selected from the autocompleter
327 function addprincipal_onselect(ev, ui) {
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();
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);
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
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
351 url: input.autocomplete("option", "source"),
357 success: function(data) {
359 toggle_addprincipal_validity(input, data.length ? true : false );
361 toggle_addprincipal_validity(input, true);
365 toggle_addprincipal_validity(this, true);
370 function escapeCssSelector(str) {
371 return str.replace(/([^A-Za-z0-9_-])/g,'\\$1');