Skip to content
Snippets Groups Projects
scp.js 39.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jared Hancock's avatar
    Jared Hancock committed
       scp.js
    
       osTicket SCP
       Copyright (c) osTicket.com
    
    function checkbox_checker(formObj, min, max) {
    
        var max = max || 0;
        var min = min || 1;
        var checked=$('input:checkbox:checked', formObj).length;
    
    Jared Hancock's avatar
    Jared Hancock committed
        var action= action?action:"process";
        if (max>0 && checked > max ){
    
            msg=__("You're limited to only {0} selections.\n") .replace('{0}', max);
            msg=msg + __("You have made {0} selections.\n").replace('{0}', checked);
            msg=msg + __("Please remove {0} selection(s).").replace('{0}', checked-max);
    
            $.sysAlert(__('Alert'), msg);
    
    
    Jared Hancock's avatar
    Jared Hancock committed
            return (false);
        }
    
        if (checked< min ){
    
            $.sysAlert( __('Alert'),
                    __("Please make at least {0} selections. {1} checked so far.")
                    .replace('{0}', min)
                    .replace('{1}', checked)
                    );
    
    
    Jared Hancock's avatar
    Jared Hancock committed
            return (false);
        }
    
    
        return checked;
    
    var scp_prep = function() {
    
        $("input[autofocus]:visible:enabled:first").each(function() {
          if ($(this).val())
            $(this).blur();
        });
    
        $('table.list input:checkbox').bind('click, change', function() {
            $(this)
                .parents("tr:first")
                .toggleClass("highlight", this.checked);
         });
    
    
        $('table.list input:checkbox:checked').trigger('change');
    
    
        $('#selectAll').click(function(e) {
            e.preventDefault();
            var target = $(this).attr('href').substr(1, $(this).attr('href').length);
            $(this).closest('form')
    
                .find('input:enabled:checkbox.'+target)
    
                .prop('checked', true)
                .trigger('change');
    
            return false;
         });
    
    
        $('#selectNone').click(function(e) {
            e.preventDefault();
            var target = $(this).attr('href').substr(1, $(this).attr('href').length);
            $(this).closest('form')
    
                .find('input:enabled:checkbox.'+target)
    
                .prop('checked', false)
                .trigger('change');
            return false;
         });
    
        $('#selectToggle').click(function(e) {
            e.preventDefault();
            var target = $(this).attr('href').substr(1, $(this).attr('href').length);
            $(this).closest('form')
    
                .find('input:enabled:checkbox.'+target)
    
                .each(function() {
                    $(this)
                        .prop('checked', !$(this).is(':checked'))
                        .trigger('change');
                 });
            return false;
         });
    
    
        $('#actions:submit, #actions :submit.button:not(.no-confirm), #actions .confirm').bind('click', function(e) {
    
                name = this.name || $(this).data('name');
    
            if ($(this).data('formId'))
                formObj = $('#' + $(this).data('formId'));
            else
                formObj = $(this).closest('form');
            if($('.dialog#confirm-action p#'+name+'-confirm').length === 0) {
    
                alert('Unknown action '+name+' - get technical help.');
    
            } else if(checkbox_checker(formObj, 1)) {
    
                var action = name;
    
                $('.dialog#confirm-action').undelegate('.confirm');
                $('.dialog#confirm-action').delegate('input.confirm', 'click.confirm', function(e) {
                    e.preventDefault();
                    $('.dialog#confirm-action').hide();
    
                    $.toggleOverlay(false);
    
                    $('input#action', formObj).val(action);
                    formObj.submit();
                    return false;
                 });
    
                $.toggleOverlay(true);
    
                $('.dialog#confirm-action .confirm-action').hide();
    
                $('.dialog#confirm-action p#'+name+'-confirm')
    
                .show()
                .parent('div').show().trigger('click');
    
            e.preventDefault();
    
            return false;
         });
    
        $('a.confirm-action').click(function(e) {
            $dialog = $('.dialog#confirm-action');
            if ($($(this).attr('href')+'-confirm', $dialog).length) {
                e.preventDefault();
                var action = $(this).attr('href').substr(1, $(this).attr('href').length);
    
                $('input#action', $dialog).val(action);
    
                $.toggleOverlay(true);
    
                $('.confirm-action', $dialog).hide();
                $('p'+$(this).attr('href')+'-confirm', $dialog)
                .show()
                .parent('div').show().trigger('click');
    
                return false;
            }
         });
    
    
        var warnOnLeave = function (el) {
            var fObj = el.closest('form');
    
    Jared Hancock's avatar
    Jared Hancock committed
            if(!fObj.data('changed')){
                fObj.data('changed', true);
    
                $('input[type=submit], button[type=submit]', fObj).addClass('save pending');
    
                $(window).bind('beforeunload', function(e) {
    
                    return __('Are you sure you want to leave? Any changes or info you\'ve entered will be discarded!');
    
                });
                $(document).on('pjax:beforeSend.changed', function(e) {
    
                    return confirm(__('Are you sure you want to leave? Any changes or info you\'ve entered will be discarded!'));
    
        $("form#save").on('change', ':input[name], :button[name]', function() {
    
            if (!$(this).is('.nowarn')) warnOnLeave($(this));
    
        $("form#save").on('click', ':input[type=reset], :button[type=reset]', function() {
    
    Jared Hancock's avatar
    Jared Hancock committed
            var fObj = $(this).closest('form');
            if(fObj.data('changed')){
    
                $('input[type=submit], button[type=submit]', fObj).removeClass('save pending');
    
    Jared Hancock's avatar
    Jared Hancock committed
                $('label', fObj).removeAttr('style');
                $('label', fObj).removeClass('strike');
                fObj.data('changed', false);
    
                $(window).unbind('beforeunload');
    
        $('form#save, form:has(table.list)').submit(function() {
    
            $(window).unbind('beforeunload');
    
            $('#overlay, #loading').show();
    
        $('select#tpl_options').change(function() {
    
            var $this = $(this), form = $this.closest('form');
            if ($this.val() % 1 !== 0) {
                $('[name="a"]', form).val('implement');
                $this.attr('name', 'code_name');
            }
            form.submit();
    
        $(document).on('click', ".clearrule",function() {
    
    Jared Hancock's avatar
    Jared Hancock committed
            $(this).closest("tr").find(":input").val('');
            return false;
         });
    
    
        //Canned attachments.
    
        $('.canned_attachments, .faq_attachments').delegate('input:checkbox', 'click', function(e) {
    
    Jared Hancock's avatar
    Jared Hancock committed
            var elem = $(this);
    
            if(!$(this).is(':checked') && confirm(__("Are you sure you want to remove this attachment?"))==true) {
    
    Jared Hancock's avatar
    Jared Hancock committed
                elem.parent().addClass('strike');
            } else {
                elem.attr('checked', 'checked');
                elem.parent().removeClass('strike');
            }
         });
    
        $('form select#cannedResp').change(function() {
    
    
            var fObj = $(this).closest('form');
            var cid = $(this).val();
            var tid = $(':input[name=id]',fObj).val();
    
    Jared Hancock's avatar
    Jared Hancock committed
            $(this).find('option:first').attr('selected', 'selected').parent('select');
    
    
            var $url = 'ajax.php/kb/canned-response/'+cid+'.json';
            if (tid)
                $url =  'ajax.php/tickets/'+tid+'/canned-resp/'+cid+'.json';
    
    
    Jared Hancock's avatar
    Jared Hancock committed
            $.ajax({
                    type: "GET",
    
    Jared Hancock's avatar
    Jared Hancock committed
                    dataType: 'json',
                    cache: false,
                    success: function(canned){
                        //Canned response.
    
                        var box = $('#response',fObj),
                            redactor = box.data('redactor');
    
    Jared Hancock's avatar
    Jared Hancock committed
                        if(canned.response) {
    
                                redactor.insert.html(canned.response);
    
                            else
                                box.val(box.val() + canned.response);
    
    
                                redactor.observe.load();
    
    Jared Hancock's avatar
    Jared Hancock committed
                        }
                        //Canned attachments.
    
                        var ca = $('.attachments', fObj);
    
                        if(canned.files && ca.length) {
    
                            var fdb = ca.find('.dropzone').data('dropbox');
    
    Jared Hancock's avatar
    Jared Hancock committed
                            $.each(canned.files,function(i, j) {
    
    Jared Hancock's avatar
    Jared Hancock committed
                        }
                    }
                })
                .done(function() { })
                .fail(function() { });
    
        /* Get config settings from the backend */
    
        getConfig().then(function(c) {
    
            // Datepicker
    
            $('.dp').datepicker({
                numberOfMonths: 2,
                showButtonPanel: true,
                buttonImage: './images/cal.png',
                showOn:'both',
    
                dateFormat: $.translate_format(c.date_format||'m/d/Y')
    
        /* Typeahead tickets lookup */
    
        var last_req;
    
    Peter Rotich's avatar
    Peter Rotich committed
        $('input.basic-search').typeahead({
    
            source: function (typeahead, query) {
    
                if (last_req) last_req.abort();
    
    Peter Rotich's avatar
    Peter Rotich committed
                var $el = this.$element;
    
                var url = $el.data('url')+'?q='+encodeURIComponent(query);
    
                last_req = $.ajax({
    
    Peter Rotich's avatar
    Peter Rotich committed
                    url: url,
    
                    dataType: 'json',
                    success: function (data) {
                        typeahead.process(data);
                    }
                });
            },
            onselect: function (obj) {
    
    Peter Rotich's avatar
    Peter Rotich committed
                var $el = this.$element;
                var form = $el.closest('form');
    
                form.find('input[name=search-type]').val('typeahead');
    
    Peter Rotich's avatar
    Peter Rotich committed
                $el.val(obj.value);
    
                if (obj.id) {
                    form.append($('<input type="hidden" name="number">').val(obj.id))
                }
    
            property: "matches"
    
        /* Typeahead user lookup */
    
        $('.email.typeahead').typeahead({
    
            source: function (typeahead, query) {
                if(query.length > 2) {
    
                    if (last_req) last_req.abort();
                    last_req = $.ajax({
    
                        url: "ajax.php/users?q="+query,
                        dataType: 'json',
                        success: function (data) {
                            typeahead.process(data);
                        }
                    });
                }
            },
            onselect: function (obj) {
    
                var fObj=$('.email.typeahead').closest('form');
    
                if(obj.name)
    
                    $('.auto.name', fObj).val(obj.name);
    
            },
            property: "email"
        });
    
    Jared Hancock's avatar
    Jared Hancock committed
        $('.staff-username.typeahead').typeahead({
            source: function (typeahead, query) {
                if(query.length > 2) {
    
                    if (last_req) last_req.abort();
                    last_req = $.ajax({
    
    Jared Hancock's avatar
    Jared Hancock committed
                        url: "ajax.php/users/staff?q="+query,
                        dataType: 'json',
                        success: function (data) {
                            typeahead.process(data);
                        }
                    });
                }
            },
            onselect: function (obj) {
                var fObj=$('.staff-username.typeahead').closest('form');
                $.each(['first','last','email','phone','mobile'], function(i,k) {
                    if (obj[k]) $('.auto.'+k, fObj).val(obj[k]);
                });
            },
            property: "username"
        });
    
        $('.dialog').resize(function() {
    
            var w = $(window), $this=$(this);
            $this.css({
    
    Jared Hancock's avatar
    Jared Hancock committed
                top : (w.innerHeight() / 7),
    
                left : (w.width() - $this.outerWidth()) / 2
            });
    
            $this.hasClass('draggable') && $this.draggable({handle:'.drag-handle'});
    
    
        $('.dialog').each(function() {
            $this=$(this);
            $this.resize();
    
            $this.hasClass('draggable') && $this.draggable({handle:'.drag-handle'});
    
        $('.dialog').delegate('input.close, a.close', 'click', function(e) {
    
    Peter Rotich's avatar
    Peter Rotich committed
            var $dialog = $(this).parents('div.dialog');
            $dialog.off('blur.redactor');
            $dialog
    
            .hide()
            .removeAttr('style');
    
            $.toggleOverlay(false);
    
        /* loading ... */
    
        $("#loading").css({
            top  : ($(window).height() / 3),
    
            left : ($(window).width() - $("#loading").outerWidth()) / 2
        });
    
    Jared Hancock's avatar
    Jared Hancock committed
       // Return a helper with preserved width of cells
       var fixHelper = function(e, ui) {
          ui.children().each(function() {
              $(this).width($(this).width());
          });
          return ui;
       };
    
    Jared Hancock's avatar
    Jared Hancock committed
       // Sortable tables for dynamic forms objects
       $('.sortable-rows').sortable({
           'helper': fixHelper,
    
           'cursor': 'move',
    
    Jared Hancock's avatar
    Jared Hancock committed
           'stop': function(e, ui) {
    
               var attr = ui.item.parent('tbody').data('sort'),
                   offset = parseInt($('#sort-offset').val(), 10) || 0;
    
               warnOnLeave(ui.item);
    
    Jared Hancock's avatar
    Jared Hancock committed
               $('input[name^='+attr+']', ui.item.parent('tbody')).each(function(i, el) {
    
                   $(el).val(i + 1 + offset);
    
        // Scroll to a stop or top on scroll-up click
         $(document).off('click.scroll-up');
         $(document).on('click.scroll-up', 'a.scroll-up', function() {
            $stop = $(this).data('stop');
            $('html, body').animate({scrollTop: ($stop ? $stop : 0)}, 'fast');
            return false;
          });
    
    
    
       // Make translatable fields translatable
    
       $('input[data-translate-tag]').translatable();
    
    Jared Hancock's avatar
    Jared Hancock committed
    
       if (window.location.hash) {
         $('ul.tabs li a[href="' + window.location.hash + '"]').trigger('click');
       }
    
    
       // Make sticky bars float on scroll
       // Thanks, https://stackoverflow.com/a/17166225/1025836
    
       $('div.sticky.bar:not(.stop)').each(function() {
    
         var $that = $(this),
             placeholder = $('<div class="sticky placeholder">').insertBefore($that),
             offset = $that.offset(),
             top = offset.top - parseFloat($that.css('marginTop').replace(/auto/, 100)),
    
             stop = $('div.sticky.bar.stop').filter(':visible'),
    
         // Append scroll-up icon and set stop point for this sticky
         $('.content', $that)
         .append($('<a class="only sticky scroll-up" href="#" data-stop='
                 + (placeholder.offset().top-75) +' ><i class="icon-chevron-up icon-large"></i></a>'));
    
    
         if (stop.length) {
           var onmove = function() {
             // Recalc when pictures pop in
             stopAt = stop.offset().top;
           };
           $('#ticket_thread .thread-body img').each(function() {
             this.onload = onmove;
           });
           onmove();
         }
    
    
         // Drop the sticky bar on PJAX navigation
    
         $(document).on('pjax:start', function() {
    
             placeholder.removeAttr('style');
             $that.stop().removeClass('fixed');
             $(window).off('.sticky');
         });
    
    
         $that.find('.content').width($that.width());
    
         $(window).on('scroll.sticky', function (event) {
    
           // what the y position of the scroll is
           var y = $(this).scrollTop();
    
           // whether that's below the form
           if (y >= top && (!stopAt || stopAt > y)) {
             // if so, add the fixed class
             if (!visible) {
               visible = true;
               setTimeout(function() {
                 $that.addClass('fixed').css('top', '-'+$that.height()+'px')
                    .animate({top:0}, {easing: 'swing', duration:'fast'});
    
                 placeholder.height($that.height());
                 $that.find('[data-dropdown]').dropdown('hide');
    
               }, 1);
             }
           } else {
             // otherwise remove it
    
             if (visible) {
               visible = false;
               setTimeout(function() {
                 placeholder.removeAttr('style');
                 $that.find('[data-dropdown]').dropdown('hide');
                 $that.stop().removeClass('fixed');
               }, 1);
             }
    
    Jared Hancock's avatar
    Jared Hancock committed
      $('div.tab_content[id] div.error:not(:empty)').each(function() {
        var div = $(this).closest('.tab_content');
        $('a[href^=#'+div.attr('id')+']').parent().addClass('error');
      });
    
    
      $('[data-toggle="tooltip"]').tooltip()
    
      $('[data-toggle="tooltip"]').on('click', function() {
            $(this).tooltip('hide');
      });
    
    
      $('.attached.input input[autofocus]').parent().addClass('focus')
      $('.attached.input input')
    
        .on('focus', function() { $(this).parent().addClass('focus'); })
    
        .on('blur', function() { $(this).parent().removeClass('focus'); })
    
    $(document).ready(scp_prep);
    
    $(document).on('pjax:end', scp_prep);
    
    var fixupDatePickers = function() {
    
        // Reformat dates
        $('.dp', $(this)).each(function(i, e) {
            var $e = $(e),
                d = $e.datepicker('getDate');
    
            if (!d || $e.data('fixed')) return;
    
            var day = ('0'+d.getDate()).substr(-2),
                month = ('0'+(d.getMonth()+1)).substr(-2),
                year = d.getFullYear();
            $e.val(year+'-'+month+'-'+day);
    
            $e.data('fixed', true);
            $e.on('change', function() { $(this).data('fixed', false); });
    
    };
    $(document).on('submit', 'form', fixupDatePickers);
    
    
        /************ global inits *****************/
    
    //Add CSRF token to the ajax requests.
    // Many thanks to https://docs.djangoproject.com/en/dev/ref/contrib/csrf/ + jared.
    $(document).ajaxSend(function(event, xhr, settings) {
    
        function sameOrigin(url) {
            // url could be relative or scheme relative or absolute
            var host = document.location.host; // host + port
            var protocol = document.location.protocol;
            var sr_origin = '//' + host;
            var origin = protocol + sr_origin;
            // Allow absolute or scheme relative URLs to same origin
            return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
                (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
                // or any other URL that isn't scheme relative or absolute i.e
                // relative.
                !(/^(\/\/|http:|https:).*/.test(url));
        }
    
        function safeMethod(method) {
            return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
        }
        if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
            xhr.setRequestHeader("X-CSRFToken", $("meta[name=csrf_token]").attr("content"));
        }
    
    });
    
    /* Get config settings from the backend */
    jQuery.fn.exists = function() { return this.length>0; };
    
    $.translate_format = function(str) {
        var translation = {
    
            'DD':   'oo',
            'D':    'o',
            'EEEE': 'DD',
            'EEE':  'D',
            'MMMM': '||',   // Double replace necessary
            'MMM':  '|',
            'MM':   'mm',
            'M':    'm',
            '||':   'MM',
            '|':    'M',
            'yyyy': '`',
            'yyy':  '`',
            'yy':   'y',
            '`':    'yy'
    
        };
        // Change PHP formats to datepicker ones
        $.each(translation, function(php, jqdp) {
            str = str.replace(php, jqdp);
    
        return str;
    };
    $(document).keydown(function(e) {
    
        if (e.keyCode == 27 && !$('#overlay').is(':hidden')) {
            $('div.dialog').hide();
    
            $.toggleOverlay(false);
    
            e.stopPropagation();
    
    
    $(document).on('focus', 'form.spellcheck textarea, form.spellcheck input[type=text]', function() {
      var $this = $(this);
      if ($this.attr('lang') !== undefined)
        return;
      var lang = $(this).closest('[lang]').attr('lang');
      if (lang)
        $(this).attr({'spellcheck':'true', 'lang': lang});
    });
    
    
    $(document).on('click', '.thread-entry-group a', function() {
        var inner = $(this).parent().find('.thread-entry-group-inner');
        if (inner.is(':visible'))
          inner.slideUp();
        else
          inner.slideDown();
        return false;
    });
    
    
    $.toggleOverlay = function (show) {
      if (typeof(show) === 'undefined') {
        return $.toggleOverlay(!$('#overlay').is(':visible'));
      }
      if (show) {
    
        $('#overlay').stop().hide().fadeIn();
    
        $('body').css('overflow', 'hidden');
      }
      else {
    
        $('#overlay').stop().fadeOut();
    
        $('body').css('overflow', 'auto');
      }
    };
    
    $.dialog = function (url, codes, cb, options) {
        options = options||{};
    
        if (codes && !$.isArray(codes))
            codes = [codes];
    
    
        var $popup = $('.dialog#popup');
    
    
        $popup.attr('class',
            function(pos, classes) {
                return classes.replace(/\bsize-\S+/g, '');
        });
    
        $popup.addClass(options.size ? ('size-'+options.size) : 'size-normal');
    
    
        $.toggleOverlay(true);
    
        $('div.body', $popup).empty().hide();
    
        $('div#popup-loading', $popup).show()
    
            .find('h1').css({'margin-top':function() { return $popup.height()/3-$(this).height()/3}});
    
        $popup.resize().show();
    
        $('div.body', $popup).load(url, options.data, function () {
    
            $('div#popup-loading', $popup).hide();
    
            $('div.body', $popup).slideDown({
    
                duration: 300,
                queue: false,
    
                complete: function() {
                    if (options.onshow) options.onshow();
                    $(this).removeAttr('style');
                }
    
            $("input[autofocus]:visible:enabled:first", $popup).focus();
    
            var submit_button = null;
    
            $(document).off('.dialog');
    
            $(document).on('click.dialog',
                '#popup input[type=submit], #popup button[type=submit]',
                function(e) { submit_button = $(this); });
    
            $(document).on('submit.dialog', '.dialog#popup form', function(e) {
                e.preventDefault();
    
                var $form = $(this),
                    data = $form.serialize();
                if (submit_button) {
                    data += '&' + escape(submit_button.attr('name')) + '='
                        + escape(submit_button.attr('value'));
                }
    
                $('div#popup-loading', $popup).show()
                    .find('h1').css({'margin-top':function() { return $popup.height()/3-$(this).height()/3}});
    
                $.ajax({
                    type:  $form.attr('method'),
                    url: 'ajax.php/'+$form.attr('action').substr(1),
    
                    cache: false,
                    success: function(resp, status, xhr) {
                        if (xhr && xhr.status && codes
                            && $.inArray(xhr.status, codes) != -1) {
    
                            $.toggleOverlay(false);
    
                            $popup.hide();
    
                            $('div.body', $popup).empty();
    
                            if (cb && (false === cb(xhr, resp)))
                                // Don't fire event if callback returns false
                                return;
                            var done = $.Event('dialog:close');
    
                            $popup.trigger(done, [resp, status, xhr]);
    
                            try {
                                var json = $.parseJSON(resp);
                                if (json.redirect) return window.location.href = json.redirect;
                            }
                            catch (e) { }
    
                            $('div.body', $popup).html(resp);
    
                            $popup.effect('shake');
    
                            $('#msg_notice, #msg_error', $popup).delay(5000).slideUp();
    
                            $('div.tab_content[id] div.error:not(:empty)', $popup).each(function() {
                              var div = $(this).closest('.tab_content');
                              $('a[href^=#'+div.attr('id')+']').parent().addClass('error');
                            });
    
                .done(function() {
                    $('div#popup-loading', $popup).hide();
                })
    
                .fail(function() { });
                return false;
            });
    
        if (options.onload) { options.onload(); }
     };
    
    $(document).on('click', 'a[data-dialog]', function(event) {
        event.preventDefault();
        event.stopImmediatePropagation();
        var link = $(this);
    
        $.dialog($(this).data('dialog'), 201, function(xhr, json) {
          try {
            json = JSON.parse(json);
          } catch (e) {}
          if (link.attr('href').length > 1) {
            // Replace {xx} expressions with data from JSON
            if (typeof json === 'object')
                link.attr('href',
                  link.attr('href').replace(/\{([^}]+)\}/, function($0, $1) { return json[$1]; }));
            $.pjax.click(event, '#pjax-container');
          }
    
          else $.pjax.reload('#pjax-container');
        });
        return false;
    });
    
    $.sysAlert = function (title, msg, cb) {
        var $dialog =  $('.dialog#alert');
        if ($dialog.length) {
    
            $.toggleOverlay(true);
    
            $('#title', $dialog).html(title);
            $('#body', $dialog).html(msg);
    
            $dialog.resize().show();
    
            if (cb)
                $dialog.find('input.ok.close').click(cb);
    
        } else {
            alert(msg);
        }
    };
    
    
    $.confirm = function(message, title, options) {
    
        title = title || __('Please Confirm');
    
        options = options || {};
    
        var D = $.Deferred(),
          $popup = $('.dialog#popup'),
          hide = function() {
    
              $.toggleOverlay(false);
    
              $popup.hide();
          };
          $('div#popup-loading', $popup).hide();
    
          var body = $('div.body', $popup).empty()
    
            .append($('<h3></h3>').text(title))
            .append($('<a class="close" href="#"><i class="icon-remove-circle"></i></a>'))
            .append($('<hr/>'))
            .append($('<p class="confirm-action"></p>')
                .text(message)
            ).append($('<div></div>')
                .append($('<b>').text(__('Please confirm to continue.')))
    
            );
    
          if (Object.keys(options).length)
              body.append('<hr>');
          $.each(options, function(k, v) {
            body.append($('<div>')
              .html('&nbsp;'+v)
              .prepend($('<input type="checkbox">')
                .attr('name', k)
              )
            );
          });
    
          body.append($('<hr style="margin-top:1em"/>'))
    
            .append($('<p class="full-width"></p>')
                .append($('<span class="buttons pull-left"></span>')
                    .append($('<input type="button" class="close"/>')
                        .attr('value', __('Cancel'))
                        .click(function() { hide(); })
    
                )).append($('<span class="buttons pull-right"></span>')
    
                    .append($('<input type="button"/>')
                        .attr('value', __('OK'))
    
                        .click(function() {  hide(); D.resolve(body.find('input').serializeArray()); })
    
            ))).append($('<div class="clear"></div>'));
    
        $.toggleOverlay(true);
    
        $popup.resize().show();
    
    $.userLookup = function (url, cb) {
        $.dialog(url, 201, function (xhr) {
            var user = $.parseJSON(xhr.responseText);
    
            if (cb) return cb(user);
    
        }, {
            onshow: function() { $('#user-search').focus(); }
        });
    };
    
    $.orgLookup = function (url, cb) {
        $.dialog(url, 201, function (xhr) {
            var org = $.parseJSON(xhr.responseText);
            if (cb) cb(org);
        }, {
            onshow: function() { $('#org-search').focus(); }
        });
    };
    
    
    +function($) {
      var MessageBar = function() {
        this.defaults = {
          avatar: 'oscar-boy',
          bar: '<div class="message bar"></div>',
          button: '<button type="button" class="inline button"></button>',
          buttonClass: '',
          buttonText: __('OK'),
          classes: '',
          dismissible: true,
    
          onok: null,
    
        };
    
        this.show = function(title, message, options) {
          this.hide();
          options = $.extend({}, this.defaults, options);
          var bar = this.bar = $(options.bar).addClass(options.classes)
    
            .append($('<div class="title"></div>').html(title))
            .append($('<div class="body"></div>').html(message))
    
            .addClass(options.position);
          if (options.avatar)
            bar.prepend($('<div class="avatar pull-left" title="Oscar"></div>')
                .addClass(options.avatar));
    
          if (options.onok || options.dismissible) {
            bar
              .prepend($('<div><div class="valign-helper"></div></div>')
                // FIXME: This is not compatible with .rtl
                .css({position: 'absolute', top: 0, bottom: 0, right: 0, margin: '0 15px'})
                .append($(options.button)
                  .text(options.buttonText)
                  .click(this.dismiss.bind(this))
                  .addClass(options.buttonClass)
                )
              );
          }
          this.visible = true;
          this.options = options;
    
          $('body').append(bar);
          this.height = bar.height();
    
          // Slight slide in
          if (options.position == 'bottom') {
            bar.css('bottom', -this.height/2).animate({'bottom': 0});
          }
          // Otherwise assume TOP positioning
          else {
            var hovering = false,
                y = $(window).scrollTop(),
                targetY = (y < this.height) ? -this.height - 10 + y : 0;
            bar.css('top', -this.height/2).animate({'top': targetY});
    
            // Plop out on mouse hover
            bar.hover(function() {
              if (!hovering && this.visible && bar.css('top') != '0') {
                bar.stop().animate({'margin-top': -parseInt(bar.css('top'), 10)}, 400, 'easeOutBounce');
                hovering = true;
              }
            }.bind(this), function() {
              if (this.visible && hovering) {
                bar.stop().animate({'margin-top': 0});
                hovering = false;
              }
            }.bind(this));
          }
    
          return bar;
        };
    
        this.scroll = function(event) {
          // Shade on scroll to top
          if (!this.visible || this.options.position != 'top')
            return;
          var y = $(window).scrollTop();
          if (y < this.height) {
            this.bar.css({top: -this.height -10 + y});
            this.shading = true;
          }
          else if (this.bar.css('top') != '0') {
            if (this.shading) {
              this.bar.stop().animate({top: 0});
              this.shading = false;
            }
          }
        };
    
        this.dismiss = function(event) {
          if (this.options.onok) {
            this.bar.find('button').replaceWith(
              $('<i class="icon-spinner icon-spin icon-large"></i>')
            );
            if (this.options.onok(event) === false)
              return;
          }
          this.hide();
        };
    
        this.hide = function() {
          if (!this.bar || !this.visible)
            return;
          var bar = this.bar.removeAttr('style');
          var dir = this.options.position == 'bottom' ? 'down' : 'up';
          // NOTE: destroy() is not called here because a new bar might be
          //       created before the animation finishes
          bar.hide("slide", { direction: dir }, 400, function() { bar.remove(); });
          this.visible = false;
        };
    
        this.destroy = function() {
          if (!this.bar || !this.visible)
            return;
          this.bar.remove();
          this.visible = false;
        };
    
        // Destroy on away navigation
        $(document).on('pjax:start.messageBar', this.destroy.bind(this));
        $(window).on('scroll.messageBar', this.scroll.bind(this));
      };
    
      $.messageBar = new MessageBar();
    }(window.jQuery);
    
    
    Peter Rotich's avatar
    Peter Rotich committed
    $(document).on('click.tab', 'ul.tabs > li > a', function(e) {
    
    Jared Hancock's avatar
    Jared Hancock committed
        e.preventDefault();
        var $this = $(this),
            $ul = $(this).closest('ul'),
            $container = $('#'+$ul.attr('id')+'_container');
        if (!$container.length)
            $container = $ul.parent();
    
        var $tab = $($this.attr('href'), $container);
        if (!$tab.length && $(this).data('url').length > 1) {
            var url = $this.data('url');
            if (url.charAt(0) == '#')
                url = 'ajax.php/' + url.substr(1);
            $tab = $('<div>')
                .addClass('tab_content')
                .attr('id', $this.attr('href').substr(1)).hide();
            $container.append(
                $tab.load(url, function () {
                    // TODO: Add / hide loading spinner
                })
             );
    
    Peter Rotich's avatar
    Peter Rotich committed
            $this.removeData('url');
    
    Jared Hancock's avatar
    Jared Hancock committed
        }
        else {
            $tab.addClass('tab_content');
    
    Jared Hancock's avatar
    Jared Hancock committed
            // Don't change the URL hash for nested tabs or in dialogs
            if ($(this).closest('.tab_content, .dialog').length == 0)
                $.changeHash($(this).attr('href'), true);
    
    Jared Hancock's avatar
    Jared Hancock committed
        }
    
        if ($tab.length) {
            $ul.children('li.active').removeClass('active');
            $(this).closest('li').addClass('active');
            $container.children('.tab_content').hide();
            $tab.fadeIn('fast');
    
    Jared Hancock's avatar
    Jared Hancock committed
            return false;
    
    Jared Hancock's avatar
    Jared Hancock committed
    });
    
    Jared Hancock's avatar
    Jared Hancock committed
    $.changeHash = function(hash, quiet) {
      if (quiet) {
        hash = hash.replace( /^#/, '' );
        var fx, node = $( '#' + hash );
        if ( node.length ) {
          node.attr( 'id', '' );
          fx = $( '<div></div>' )
                  .css({
                      position:'absolute',
                      visibility:'hidden',
                      top: $(document).scrollTop() + 'px'
                  })
                  .attr( 'id', hash )
                  .appendTo( document.body );
        }
        document.location.hash = hash;
        if ( node.length ) {
          fx.remove();
          node.attr( 'id', hash );
        }
      }
      else {
        document.location.hash = hash;
      }
    };
    
    // Forms — submit, stay on same tab
    $(document).on('submit', 'form', function() {
    
        if (!!$(this).attr('action') && $(this).attr('action').indexOf('#') == -1)
    
            $(this).attr('action', $(this).attr('action') + window.location.hash);
    
    //Collaborators
    $(document).on('click', 'a.collaborator, a.collaborators', function(e) {
        e.preventDefault();
        var url = 'ajax.php/'+$(this).attr('href').substr(1);
        $.dialog(url, 201, function (xhr) {
           $('input#emailcollab').show();
           $('#recipients').text(xhr.responseText);
           $('.tip_box').remove();
        }, {
            onshow: function() { $('#user-search').focus(); }
        });
        return false;
     });
    
    
    // NOTE: getConfig should be global
    getConfig = (function() {
    
        var dfd = $.Deferred(),