Merge branch 'master' of https://github.com/jgoodman/Freeside
[freeside.git] / rt / share / html / NoAuth / js / util.js
index a0d3579..cc6e275 100644 (file)
@@ -1,40 +1,40 @@
 %# BEGIN BPS TAGGED BLOCK {{{
-%# 
+%#
 %# COPYRIGHT:
-%# 
-%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC
-%#                                          <jesse@bestpractical.com>
-%# 
+%#
+%# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC
+%#                                          <sales@bestpractical.com>
+%#
 %# (Except where explicitly superseded by other copyright notices)
-%# 
-%# 
+%#
+%#
 %# LICENSE:
-%# 
+%#
 %# This work is made available to you under the terms of Version 2 of
 %# the GNU General Public License. A copy of that license should have
 %# been provided with this software, but in any event can be snarfed
 %# from www.gnu.org.
-%# 
+%#
 %# This work is distributed in the hope that it will be useful, but
 %# WITHOUT ANY WARRANTY; without even the implied warranty of
 %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 %# General Public License for more details.
-%# 
+%#
 %# You should have received a copy of the GNU General Public License
 %# along with this program; if not, write to the Free Software
 %# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 %# 02110-1301 or visit their web page on the internet at
 %# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
-%# 
-%# 
+%#
+%#
 %# CONTRIBUTION SUBMISSION POLICY:
-%# 
+%#
 %# (The following paragraph is not intended to limit the rights granted
 %# to you to modify and distribute this software under the terms of
 %# the GNU General Public License and is only of importance to you if
 %# you choose to contribute your changes and enhancements to the
 %# community by submitting them to Best Practical Solutions, LLC.)
-%# 
+%#
 %# By intentionally submitting any modifications, corrections or
 %# derivatives to this work, or any other work intended for use with
 %# Request Tracker, to Best Practical Solutions, LLC, you confirm that
 %# royalty-free, perpetual, license to use, copy, create derivative
 %# works based on those contributions, and sublicense and distribute
 %# those contributions and any derivatives thereof.
-%# 
+%#
 %# END BPS TAGGED BLOCK }}}
-/* $(...)
-    Returns DOM node or array of nodes (if more then one argument passed).
-    If argument is node object allready then do nothing.
-    // Stolen from Prototype
-*/
-function $() {
-    var elements = new Array();
-
-    for (var i = 0; i < arguments.length; i++) {
-        var element = arguments[i];
-        if (typeof element == 'string')
-            element = document.getElementById(element);
-
-        if (arguments.length == 1)
-            return element;
-
-        elements.push(element);
-    }
-
-    return elements;
-}
-
 /* Visibility */
 
 function show(id) { delClass( id, 'hidden' ) }
@@ -74,12 +52,14 @@ function hide(id) { addClass( id, 'hidden' ) }
 
 function hideshow(id) { return toggleVisibility( id ) }
 function toggleVisibility(id) {
-    var e = $(id);
+    var e = jQuery('#' + id);
 
-    if ( e.className.match( /\bhidden\b/ ) )
-        show(e);
-    else
-        hide(e);
+    if ( e.hasClass('hidden') ) {
+        e.removeClass('hidden');
+    }
+    else {
+        e.addClass('hidden');
+    }
 
     return false;
 }
@@ -98,26 +78,25 @@ function switchVisibility(id1, id2) {
 }
 
 /* Classes */
+function jQueryWrap( id ) {
+    return typeof id == 'object' ? jQuery(id) : jQuery('#'+id);
+}
 
 function addClass(id, value) {
-    var e = $(id);
-    if ( e.className.match( new RegExp('\b'+ value +'\b') ) )
-        return;
-    e.className += e.className? ' '+value : value;
+    jQueryWrap(id).addClass(value);
 }
 
 function delClass(id, value) {
-    var e = $(id);
-    e.className = e.className.replace( new RegExp('\\s?\\b'+ value +'\\b', 'g'), '' );
+    jQueryWrap(id).removeClass(value);
 }
 
 /* Rollups */
 
 function rollup(id) {
-    var e   = $(id);
-    var e2  = e.parentNode;
+    var e = jQueryWrap(id);
+    var e2  = e.parent();
     
-    if (e.className.match(/\bhidden\b/)) {
+    if (e.hasClass('hidden')) {
         set_rollup_state(e,e2,'shown');
         createCookie(id,1,365);
     }
@@ -141,103 +120,26 @@ function set_rollup_state(e,e2,state) {
     }
 }
 
-
-/* onload handlers */
-/* New code should be using doOnLoad which makes use of prototype
-   instead. See HeaderJavascript.  It works better than clobbering
-   window.onload.  Left around in case other code is using them */
-
-var onLoadStack     = new Array();
-var onLoadLastStack = new Array();
-var onLoadExecuted  = 0;
-
-function onLoadHook(commandStr) {
-    if(typeof(commandStr) == "string") {
-        onLoadStack[ onLoadStack.length ] = commandStr;
-        return true;
-    }
-    return false;
-}
-
-// some things *really* need to be done after everything else
-function onLoadLastHook(commandStr) {
-    if(typeof(commandStr) == "string"){
-        onLoadLastStack[onLoadLastStack.length] = commandStr;
-        return true;
-    }
-    return false;
-}
-
-function doOnLoadHooks() {
-    if(onLoadExecuted) return;
-
-    var i;
-    for ( i in onLoadStack ) { 
-        eval( onLoadStack[i] );
-    }
-    for ( i in onLoadLastStack ) { 
-        eval( onLoadLastStack[i] );
-    }
-    onLoadExecuted = 1;
-}
-
-window.onload = doOnLoadHooks;
-
-/* new onLoad code */
-
-function doOnLoad(handler) {
-    Event.observe(window, 'load', handler);
-}
-
-/* calendar functions */
-
-function openCalWindow(field) {
-    var objWindow = window.open('<%RT->Config->Get('WebPath')%>/Helpers/CalPopup.html?field='+field, 
-                                'RT_Calendar', 
-                                'height=235,width=285,scrollbars=1');
-    objWindow.focus();
-}
-
-function createCalendarLink(input) {
-    var e = $(input);
-    if (e) {
-        var link = document.createElement('a');
-        link.setAttribute('href', '#');
-        $(link).observe('click', function(ev) { openCalWindow(input); ev.stop(); });
-        //link.setAttribute('onclick', "openCalWindow('"+input+"'); return false;");
-
-        var text = document.createTextNode('<% loc("Calendar") %>');
-        link.appendChild(text);
-
-        var space = document.createTextNode(' ');
-        
-        e.parentNode.insertBefore(link, e.nextSibling);
-        e.parentNode.insertBefore(space, e.nextSibling);
-
-        return true;
-    }
-    return false;
-}
-
 /* other utils */
 
 function focusElementById(id) {
-    var e = $(id);
+    var e = jQuery('#'+id);
     if (e) e.focus();
 }
 
-function updateParentField(field, value) {
-    if (window.opener) {
-        window.opener.$(field).value = value;
-        window.close();
-    }
-}
-
 function setCheckbox(form, name, val) {
     var myfield = form.getElementsByTagName('input');
     for ( var i = 0; i < myfield.length; i++ ) {
-        if ( name && myfield[i].name != name ) continue;
         if ( myfield[i].type != 'checkbox' ) continue;
+        if ( name ) {
+            if ( name instanceof RegExp ) {
+                if ( ! myfield[i].name.match( name ) ) continue;
+            }
+            else {
+                if ( myfield[i].name != name ) continue;
+            }
+
+        }
 
         myfield[i].checked = val;
     }
@@ -247,71 +149,224 @@ function setCheckbox(form, name, val) {
 
 function walkChildNodes(parent, callback)
 {
-       if( !parent || !parent.childNodes ) return;
-       var list = parent.childNodes;
-       for( var i = 0; i < list.length; i++ ) {
-               callback( list[i] );
-       }
+    if( !parent || !parent.childNodes ) return;
+    var list = parent.childNodes;
+    for( var i = 0; i < list.length; i++ ) {
+        callback( list[i] );
+    }
 }
 
 function walkChildElements(parent, callback)
 {
-       walkChildNodes( parent, function(node) {
-               if( node.nodeType != 1 ) return;
-               return callback( node );
-       } );
+    walkChildNodes( parent, function(node) {
+        if( node.nodeType != 1 ) return;
+        return callback( node );
+    } );
 }
 
 /* shredder things */
 
 function showShredderPluginTab( plugin )
 {
-       var plugin_tab_id = 'shredder-plugin-'+ plugin +'-tab';
-       var root = $('shredder-plugin-tabs');
-       walkChildElements( root, function(node) {
-               if( node.id == plugin_tab_id ) {
-                       show( node );
-               } else {
-                       hide( node );
-               }
-       } );
-       if( plugin ) {
-               show('shredder-submit-button');
-       } else {
-               hide('shredder-submit-button');
-       }
+    var plugin_tab_id = 'shredder-plugin-'+ plugin +'-tab';
+    var root = jQuery('#shredder-plugin-tabs');
+    
+    root.children(':not(.hidden)').addClass('hidden');
+    root.children('#' + plugin_tab_id).removeClass('hidden');
+
+    if( plugin ) {
+        show('shredder-submit-button');
+    } else {
+        hide('shredder-submit-button');
+    }
 }
 
 function checkAllObjects()
 {
-       var check = $('shredder-select-all-objects-checkbox').checked;
-       var elements = $('shredder-search-form').elements;
-       for( var i = 0; i < elements.length; i++ ) {
-               if( elements[i].name != 'WipeoutObject' ) {
-                       continue;
-               }
-               if( elements[i].type != 'checkbox' ) {
-                       continue;
-               }
-               if( check ) {
-                       elements[i].checked = true;
-               } else {
-                       elements[i].checked = false;
-               }
-       }
+    var check = jQuery('#shredder-select-all-objects-checkbox').attr('checked');
+    var elements = jQuery('#shredder-search-form :checkbox[name=WipeoutObject]');
+
+    if( check ) {
+        elements.attr('checked', true);
+    } else {
+        elements.attr('checked', false);
+    }
 }
 
 function checkboxToInput(target,checkbox,val){    
-    var tar=$(target);
-    var box = $(checkbox);
-    if(box.checked){
-        if (tar.value==''){
-            tar.value=val;
-        }else{
-            tar.value=val+', '+tar.value;        }
-    }else{
-        tar.value=tar.value.replace(val+', ','');
-        tar.value=tar.value.replace(val,'');
+    var tar = jQuery('#' + escapeCssSelector(target));
+    var box = jQuery('#' + escapeCssSelector(checkbox));
+    if(box.attr('checked')){
+        if (tar.val()==''){
+            tar.val(val);
+        }
+        else{
+            tar.val( val+', '+ tar.val() );        
+        }
     }
+    else{
+        tar.val(tar.val().replace(val+', ',''));
+        tar.val(tar.val().replace(val,''));
+    }
+    jQuery('#UpdateIgnoreAddressCheckboxes').val(true);
 }
 
+// ahah for back compatibility as plugins may still use it
+function ahah( url, id ) {
+    jQuery('#'+id).load(url);
+}
+
+// only for back compatibility, please JQuery() instead
+function doOnLoad( js ) {
+    jQuery(js);
+}
+
+jQuery(function() {
+    var opts = {
+        dateFormat: 'yy-mm-dd',
+        constrainInput: false,
+        showButtonPanel: true,
+        changeMonth: true,
+        changeYear: true,
+        showOtherMonths: true,
+        selectOtherMonths: true
+    };
+    jQuery(".ui-datepicker:not(.withtime)").datepicker(opts);
+    jQuery(".ui-datepicker.withtime").datetimepicker( jQuery.extend({}, opts, {
+        stepHour: 1,
+        // We fake this by snapping below for the minute slider
+        //stepMinute: 5,
+        hourGrid: 6,
+        minuteGrid: 15,
+        showSecond: false,
+        timeFormat: 'hh:mm:ss'
+    }) ).each(function(index, el) {
+        var tp = jQuery.datepicker._get( jQuery.datepicker._getInst(el), 'timepicker');
+        if (!tp) return;
+
+        // Hook after _injectTimePicker so we can modify the minute_slider
+        // right after it's first created
+        tp._base_injectTimePicker = tp._injectTimePicker;
+        tp._injectTimePicker = function() {
+            this._base_injectTimePicker.apply(this, arguments);
+
+            // Now that we have minute_slider, modify it to be stepped for mouse movements
+            var slider = jQuery.data(this.minute_slider[0], "slider");
+            slider._base_normValueFromMouse = slider._normValueFromMouse;
+            slider._normValueFromMouse = function() {
+                var value           = this._base_normValueFromMouse.apply(this, arguments);
+                var old_step        = this.options.step;
+                this.options.step   = 5;
+                var aligned         = this._trimAlignValue( value );
+                this.options.step   = old_step;
+                return aligned;
+            };
+        };
+    });
+});
+
+function textToHTML(value) {
+    return value.replace(/&/g,    "&amp;")
+                .replace(/</g,    "&lt;")
+                .replace(/>/g,    "&gt;")
+                .replace(/-- \n/g,"--&nbsp;\n")
+                .replace(/\n/g,   "\n<br />");
+};
+
+function ReplaceAllTextareas() {
+    var sAgent = navigator.userAgent.toLowerCase();
+    if (!CKEDITOR.env.isCompatible ||
+        sAgent.indexOf('iphone') != -1 ||
+        sAgent.indexOf('ipad') != -1 ||
+        sAgent.indexOf('android') != -1 )
+        return false;
+
+    // replace all content and signature message boxes
+    var allTextAreas = document.getElementsByTagName("textarea");
+
+    for (var i=0; i < allTextAreas.length; i++) {
+        var textArea = allTextAreas[i];
+        if (jQuery(textArea).hasClass("messagebox")) {
+            // Turn the original plain text content into HTML
+            var type = jQuery("#"+textArea.name+"Type");
+            if (type.val() != "text/html")
+                textArea.value = textToHTML(textArea.value);
+
+            // Set the type
+            type.val("text/html");
+
+            CKEDITOR.replace(textArea.name,{width:'100%',height:<% RT->Config->Get('MessageBoxRichTextHeight') |n,j%>});
+            CKEDITOR.basePath = <%RT->Config->Get('WebPath')|n,j%>+"/NoAuth/RichText/";
+
+            jQuery("#" + textArea.name + "___Frame").addClass("richtext-editor");
+        }
+    }
+};
+
+function toggle_addprincipal_validity(input, good, title) {
+    if (good) {
+        jQuery(input).nextAll(".warning").hide();
+        jQuery("#acl-AddPrincipal input[type=checkbox]").removeAttr("disabled");
+    } else {
+        jQuery(input).nextAll(".warning").css("display", "block");
+        jQuery("#acl-AddPrincipal input[type=checkbox]").attr("disabled", "disabled");
+    }
+
+    if (title == null)
+        title = jQuery(input).val();
+
+    update_addprincipal_title( title );
+}
+
+function update_addprincipal_title(title) {
+    var h3 = jQuery("#acl-AddPrincipal h3");
+    h3.html( h3.text().replace(/: .*$/,'') + ": " + title );
+}
+
+// when a value is selected from the autocompleter
+function addprincipal_onselect(ev, ui) {
+
+    // if principal link exists, we shall go there instead
+    var principal_link = jQuery(ev.target).closest('form').find('ul.ui-tabs-nav a[href="#acl-' + ui.item.id + '"]:first');
+    if (principal_link.size()) {
+        jQuery(this).val('').blur();
+        update_addprincipal_title( '' ); // reset title to blank for #acl-AddPrincipal
+        principal_link.click();
+        return false;
+    }
+
+    // pass the item's value along as the title since the input's value
+    // isn't actually updated yet
+    toggle_addprincipal_validity(this, true, ui.item.value);
+}
+
+// when the input is actually changed, through typing or autocomplete
+function addprincipal_onchange(ev, ui) {
+    // if we have a ui.item, then they selected from autocomplete and it's good
+    if (!ui.item) {
+        var input = jQuery(this);
+        // Check using the same autocomplete source if the value typed would
+        // have been autocompleted and is therefore valid
+        jQuery.ajax({
+            url: input.autocomplete("option", "source"),
+            data: {
+                op: "=",
+                term: input.val()
+            },
+            dataType: "json",
+            success: function(data) {
+                if (data)
+                    toggle_addprincipal_validity(input, data.length ? true : false );
+                else
+                    toggle_addprincipal_validity(input, true);
+            }
+        });
+    } else {
+        toggle_addprincipal_validity(this, true);
+    }
+}
+
+
+function escapeCssSelector(str) {
+    return str.replace(/([^A-Za-z0-9_-])/g,'\\$1');
+}