Skip to content
Snippets Groups Projects
ticket.js 15.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jared Hancock's avatar
    Jared Hancock committed
    /*********************************************************************
        ticket.js
    
        Ticket utility loaded on ticket view!
    
        Useful for UI config settings, ticket locking ...etc
    
        Peter Rotich <peter@osticket.com>
    
        Copyright (c) 2006-2013 osTicket
    
    Jared Hancock's avatar
    Jared Hancock committed
        http://www.osticket.com
    
        Released under the GNU General Public License WITHOUT ANY WARRANTY.
    
        vim: expandtab sw=4 ts=4 sts=4:
    **********************************************************************/
    var autoLock = {
    
    Jared Hancock's avatar
    Jared Hancock committed
        addEvent: function(elm, evType, fn, useCapture) {
            if(elm.addEventListener) {
                elm.addEventListener(evType, fn, useCapture);
                return true;
            }else if(elm.attachEvent) {
                return elm.attachEvent('on' + evType, fn);
            }else{
                elm['on' + evType] = fn;
            }
        },
    
        removeEvent: function(elm, evType, fn, useCapture) {
            if(elm.removeEventListener) {
                elm.removeEventListener(evType, fn, useCapture);
                return true;
            }else if(elm.detachEvent) {
                return elm.detachEvent('on' + evType, fn);
            }else {
                elm['on' + evType] = null;
            }
        },
    
        //Incoming event...
        handleEvent: function(e) {
            if(!autoLock.lockId) {
                var now = new Date().getTime();
                //Retry every 5 seconds??
                if(autoLock.retry && (!autoLock.lastattemptTime || (now-autoLock.lastattemptTime)>5000)) {
                    autoLock.acquireLock(e,autoLock.warn);
                    autoLock.lastattemptTime=new Date().getTime();
                }
            }else{
                autoLock.renewLock(e);
            }
    
    
            if(!autoLock.lasteventTime) { //I hate nav away warnings..but
                $(window).bind('beforeunload', function(e) {
                    return "Any changes or info you've entered will be discarded!";
                 });
            }
    
    Jared Hancock's avatar
    Jared Hancock committed
            autoLock.lasteventTime=new Date().getTime();
        },
    
        //Watch activity on individual form.
        watchForm: function(fObj,fn) {
            if(!fObj || !fObj.length)
                return;
    
            //Watch onSubmit event on the form.
            autoLock.addEvent(fObj,'submit',autoLock.onSubmit,true);
            //Watch activity on text + textareas + select fields.
            for (var i=0; i<fObj.length; i++) {
                switch(fObj[i].type) {
                    case 'textarea':
                    case 'text':
                        autoLock.addEvent(fObj[i],'keyup',autoLock.handleEvent,true);
                        break;
                    case 'select-one':
                    case 'select-multiple':
    
                        if(fObj.name!='reply') //Bug on double ajax call since select make it's own ajax call. TODO: fix it
    
    Jared Hancock's avatar
    Jared Hancock committed
                            autoLock.addEvent(fObj[i],'change',autoLock.handleEvent,true);
                        break;
                    default:
                }
            }
        },
    
        //Watch all the forms on the document.
        watchDocument: function() {
    
            //Watch forms of interest only.
            for (var i=0; i<document.forms.length; i++) {
                if(!document.forms[i].id.value || parseInt(document.forms[i].id.value)!=autoLock.tid)
                    continue;
                autoLock.watchForm(document.forms[i],autoLock.checkLock);
            }
        },
    
        Init: function(config) {
    
    
            //make sure we are on ticket view page & locking is enabled!
    
            var fObj=$('form#note');
    
            if(!fObj
                    || !$(':input[name=id]',fObj).length
    
                    || !$(':input[name=locktime]',fObj).length
                    || $(':input[name=locktime]',fObj).val()==0) {
                return;
    
            void(autoLock.tid=parseInt($(':input[name=id]',fObj).val()));
            void(autoLock.lockTime=parseInt($(':input[name=locktime]',fObj).val()));
    
    
    Jared Hancock's avatar
    Jared Hancock committed
            autoLock.lockId=0;
            autoLock.timerId=0;
            autoLock.lasteventTime=0;
            autoLock.lastattemptTime=0;
            autoLock.acquireTime=0;
            autoLock.renewTime=0;
            autoLock.renewFreq=0; //renewal frequency in seconds...based on returned lock time.
            autoLock.time=0;
            autoLock.lockAttempts=0; //Consecutive lock attempt errors
            autoLock.maxattempts=2; //Maximum failed lock attempts before giving up.
            autoLock.warn=true;
            autoLock.retry=true;
            autoLock.watchDocument();
            autoLock.resetTimer();
            autoLock.addEvent(window,'unload',autoLock.releaseLock,true); //Release lock regardless of any activity.
        },
    
    Jared Hancock's avatar
    Jared Hancock committed
    
        onSubmit: function(e) {
            if(e.type=='submit') { //Submit. double check!
                //remove nav away warning if any.
    
                $(window).unbind('beforeunload');
    
    Jared Hancock's avatar
    Jared Hancock committed
                //Only warn if we had a failed lock attempt.
                if(autoLock.warn && !autoLock.lockId && autoLock.lasteventTime) {
                    var answer=confirm('Unable to acquire a lock on the ticket. Someone else could be working on the same ticket. \
                        Please confirm if you wish to continue anyways.');
                    if(!answer) {
                        e.returnValue=false;
                        e.cancelBubble=true;
                        if(e.preventDefault) {
                            e.preventDefault();
                        }
                        return false;
                    }
                }
            }
            return true;
        },
    
    
        acquireLock: function(e,warn) {
    
    Jared Hancock's avatar
    Jared Hancock committed
    
            if(!autoLock.tid) { return false; }
    
            var warn = warn || false;
    
            if(autoLock.lockId) {
                autoLock.renewLock(e);
            } else {
                $.ajax({
    
                    type: "POST",
    
                    url: 'ajax.php/tickets/'+autoLock.tid+'/lock',
    
    Jared Hancock's avatar
    Jared Hancock committed
                    dataType: 'json',
                    cache: false,
                    success: function(lock){
                        autoLock.setLock(lock,'acquire',warn);
                    }
                })
                .done(function() { })
                .fail(function() { });
            }
    
    Jared Hancock's avatar
    Jared Hancock committed
            return autoLock.lockId;
        },
    
    
        //Renewal only happens on form activity..
    
    Jared Hancock's avatar
    Jared Hancock committed
        renewLock: function(e) {
    
    Jared Hancock's avatar
    Jared Hancock committed
            if(!autoLock.lockId) { return false; }
    
    
            var now= new Date().getTime();
    
    Jared Hancock's avatar
    Jared Hancock committed
            if(!autoLock.lastcheckTime || (now-autoLock.lastcheckTime)>=(autoLock.renewFreq*1000)){
                $.ajax({
                    type: 'POST',
    
                    url: 'ajax.php/tickets/'+autoLock.tid+'/lock/'+autoLock.lockId+'/renew',
    
    Jared Hancock's avatar
    Jared Hancock committed
                    dataType: 'json',
                    cache: false,
                    success: function(lock){
                        autoLock.setLock(lock,'renew',autoLock.warn);
                    }
                })
                .done(function() {  })
                .fail(function() { });
            }
    
    Jared Hancock's avatar
    Jared Hancock committed
        releaseLock: function(e) {
            if(!autoLock.tid) { return false; }
    
            $.ajax({
                type: 'POST',
    
                url: 'ajax.php/tickets/'+autoLock.tid+'/lock/'+autoLock.lockId+'/release',
    
    Jared Hancock's avatar
    Jared Hancock committed
                data: 'delete',
    
    Jared Hancock's avatar
    Jared Hancock committed
                cache: false,
                success: function(){
    
    Jared Hancock's avatar
    Jared Hancock committed
                }
            })
            .done(function() { })
            .fail(function() { });
        },
    
        setLock: function(lock, action, warn) {
            var warn = warn || false;
    
    Jared Hancock's avatar
    Jared Hancock committed
            if(!lock) return false;
    
            if(lock.id) {
                autoLock.renewFreq=lock.time?(lock.time/2):30;
                autoLock.lastcheckTime=new Date().getTime();
            }
    
            autoLock.lockId=lock.id; //override the lockid.
    
    
    Jared Hancock's avatar
    Jared Hancock committed
            switch(action){
                case 'renew':
                    if(!lock.id && lock.retry) {
                        autoLock.lockAttempts=1; //reset retries.
                        autoLock.acquireLock(e,false); //We lost the lock?? ..try to re acquire now.
                    }
                    break;
                case 'acquire':
                    if(!lock.id) {
                        autoLock.lockAttempts++;
                        if(warn && (!lock.retry || autoLock.lockAttempts>=autoLock.maxattempts)) {
                            autoLock.retry=false;
    
                            alert('Unable to lock the ticket. Someone else could be working on the same ticket.');
    
    Jared Hancock's avatar
    Jared Hancock committed
        discardWarning: function(e) {
            e.returnValue="Any changes or info you've entered will be discarded!";
        },
    
    
        //TODO: Monitor events and elapsed time and warn user when the lock is about to expire.
    
    Jared Hancock's avatar
    Jared Hancock committed
        monitorEvents: function() {
           // warn user when lock is about to expire??;
            //autoLock.resetTimer();
        },
    
        clearTimer: function() {
            clearTimeout(autoLock.timerId);
        },
    
    Jared Hancock's avatar
    Jared Hancock committed
        resetTimer: function() {
            clearTimeout(autoLock.timerId);
            autoLock.timerId=setTimeout(function () { autoLock.monitorEvents() },30000);
        }
    
    };
    $.autoLock = autoLock;
    
    Jared Hancock's avatar
    Jared Hancock committed
    
    /*
       UI & form events
    */
    
    jQuery(function($) {
        $('#response_options form').hide();
        $('#ticket_notes').hide();
        if(location.hash != "" && $('#response_options '+location.hash).length) {
            $('#response_options '+location.hash+'_tab').addClass('active');
            $('#response_options '+location.hash).show();
    
    Peter Rotich's avatar
    Peter Rotich committed
        } else if(location.hash == "#notes" && $('#ticket_notes').length) {
    
    Jared Hancock's avatar
    Jared Hancock committed
            $('#response_options #note_tab').addClass('active');
            $('#response_options form').hide();
            $('#response_options #note').show();
            $('#ticket_thread').hide();
            $('#ticket_notes').show();
            $('#toggle_ticket_thread').removeClass('active');
            $('#toggle_notes').addClass('active');
        } else {
    
            $('#response_options ul.tabs li:first a').addClass('active');
            $('#response_options '+$('#response_options ul.tabs li:first a').attr('href')).show();
    
    Jared Hancock's avatar
    Jared Hancock committed
        }
    
        $('#reply_tab').click(function() {
    
           $(this).removeClass('tell');
    
    Jared Hancock's avatar
    Jared Hancock committed
         });
    
        $('#note_tab').click(function() {
            if($('#response').val() != '') {
                $('#reply_tab').addClass('tell');
            }
         });
    
    
        $('#response_options ul.tabs li a').click(function(e) {
    
    Jared Hancock's avatar
    Jared Hancock committed
            e.preventDefault();
    
            $('#response_options ul.tabs li a').removeClass('active');
    
    Jared Hancock's avatar
    Jared Hancock committed
            $(this).addClass('active');
            $('#response_options form').hide();
            //window.location.hash = this.hash;
            $('#response_options '+$(this).attr('href')).show();
            $("#msg_error, #msg_notice, #msg_warning").fadeOut();
         });
    
        $('#toggle_ticket_thread, #toggle_notes, .show_notes').click(function(e) {
            e.preventDefault();
            $('#threads a').removeClass('active');
    
            if($(this).attr('id') == 'toggle_ticket_thread') {
                $('#ticket_notes').hide();
                $('#ticket_thread').show();
                $('#toggle_ticket_thread').addClass('active');
                $('#reply_tab').removeClass('tell').click();
            } else {
                $('#ticket_thread').hide();
                $('#ticket_notes').show();
                $('#toggle_notes').addClass('active');
                $('#note_tab').click();
                if($('#response').val() != '') {
                    $('#reply_tab').addClass('tell');
                }
            }
         });
    
    Peter Rotich's avatar
    Peter Rotich committed
        //Start watching the form for activity.
        autoLock.Init();
    
        /*** Ticket Actions **/
        //print options
    
        $('a#ticket-print').click(function(e) {
            e.preventDefault();
            $('#overlay').show();
    
    Peter Rotich's avatar
    Peter Rotich committed
            $('.dialog#print-options').show();
    
    Peter Rotich's avatar
    Peter Rotich committed
        //ticket status (close & reopen)
        $('a#ticket-close, a#ticket-reopen').click(function(e) {
            e.preventDefault();
            $('#overlay').show();
            $('.dialog#ticket-status').show();
            return false;
        });
    
    Peter Rotich's avatar
    Peter Rotich committed
        //ticket actions confirmation - Delete + more
    
        $('a#ticket-delete, a#ticket-claim, #action-dropdown-more li a:not(.change-user)').click(function(e) {
    
    Peter Rotich's avatar
    Peter Rotich committed
            e.preventDefault();
            if($('.dialog#confirm-action '+$(this).attr('href')+'-confirm').length) {
                var action = $(this).attr('href').substr(1, $(this).attr('href').length);
                $('.dialog#confirm-action #action').val(action);
                $('#overlay').show();
                $('.dialog#confirm-action .confirm-action').hide();
                $('.dialog#confirm-action p'+$(this).attr('href')+'-confirm')
                .show()
                .parent('div').show().trigger('click');
    
            } else {
                alert('Unknown action '+$(this).attr('href')+'- get technical help.');
            }
    
            return false;
        });
    
    
        $(document).on('change', 'form#reply select#emailreply', function(e) {
             var $cc = $('form#reply tbody#cc_sec');
            if($(this).val() == 0)
                $cc.hide();
            else
                $cc.show();
         });
    
    
        var showNonLocalImage = function(div) {
            var $div = $(div),
                $img = $div.append($('<img>')
                  .attr('src', $div.data('src'))
                  .attr('alt', $div.attr('alt'))
                  .attr('title', $div.attr('title'))
                  .attr('style', $div.data('style'))
                );
            if ($div.attr('width'))
                $img.width($div.attr('width'));
            if ($div.attr('height'))
                $img.height($div.attr('height'));
        };
    
        // Optionally show external images
        $('.thread-entry').each(function(i, te) {
            var extra = $(te).find('.textra'),
    
                imgs = $(te).find('.non-local-image[data-src]');
    
            if (!extra) return;
            if (!imgs.length) return;
            extra.append($('<a>')
              .addClass("action-button show-images")
              .css({'font-weight':'normal'})
              .text(' Show Images')
              .click(function(ev) {
                imgs.each(function(i, img) {
                  showNonLocalImage(img);
                  $(img).removeClass('non-local-image')
                    // Remove placeholder sizing
    
                    .css({'display':'inline-block'})
    
                    .width('auto')
                    .height('auto')
                    .removeAttr('width')
                    .removeAttr('height');
                  extra.find('.show-images').hide();
                });
              })
              .prepend($('<i>')
                .addClass('icon-picture')
              )
            );
            imgs.each(function(i, img) {
                var $img = $(img);
                // Save a copy of the original styling
                $img.data('style', $img.attr('style'));
    
                $img.removeAttr('style');
    
                // If the image has a 'height' attribute, use it, otherwise, use
                // 40px
    
                $img.height(($img.attr('height') || '40') + 'px');
    
                // Ensure the image placeholder is visible width-wise
                if (!$img.width())
    
                    $img.width(($img.attr('width') || '80') + 'px');
    
                // TODO: Add a hover-button to show just one image
            });
        });
    
    Jared Hancock's avatar
    Jared Hancock committed
    });
    
    
    showImagesInline = function(urls, thread_id) {
        var selector = (thread_id == undefined)
            ? '.thread-body img[data-cid]'
            : '.thread-body#thread-id-'+thread_id+' img[data-cid]';
        $(selector).each(function(i, el) {
    
            var cid = $(el).data('cid').toLowerCase(),
    
                info = urls[cid],
                e = $(el);
            if (info) {
                // Add a hover effect with the filename
    
                var timeout, caption = $('<div class="image-hover">')
    
    Jared Hancock's avatar
    Jared Hancock committed
                    .css({'float':e.css('float')});
    
    Jared Hancock's avatar
    Jared Hancock committed
                e.wrap(caption).parent()
    
                        function() {
                            var self = this;
                            timeout = setTimeout(
                                function() { $(self).find('.caption').slideDown(250); },
                                500);
                        },
                        function() {
                            clearTimeout(timeout);
                            $(this).find('.caption').slideUp(250);
                        }
    
                    ).append($('<div class="caption">')
                        .append('<span class="filename">'+info.filename+'</span>')
                        .append('<a href="'+info.download_url+'" class="action-button"><i class="icon-download-alt"></i> Download</a>')
    
    Jared Hancock's avatar
    Jared Hancock committed
                    );