diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php
index e13128529cc4fa4ba26d8b3cc0f1d03c4d7bb489..721da44032dd29c96893016f5733564157732528 100644
--- a/include/ajax.tickets.php
+++ b/include/ajax.tickets.php
@@ -122,7 +122,10 @@ class TicketsAjaxAPI extends AjaxController {
             return $this->json_encode(array('id'=>0, 'retry'=>true));
         }
 
-        return $this->json_encode(array('id'=>$lock->getId(), 'time'=>$lock->getTime()));
+        return $this->json_encode(array(
+            'id'=>$lock->getId(), 'time'=>$lock->getTime(),
+            'code' => $lock->getCode()
+        ));
     }
 
     function renewLock($tid, $id) {
diff --git a/include/class.lock.php b/include/class.lock.php
index e4870d4652801659d68e6c77bc6d231991f378ea..acbe1365e2c3f8fa2dbb64c4f4f39b227c418890 100644
--- a/include/class.lock.php
+++ b/include/class.lock.php
@@ -38,13 +38,6 @@ class Lock extends VerySimpleModel {
         ),
     );
 
-    var $expiretime;
-
-    function __onload() {
-        if (isset($this->expire))
-            $this->expiretime = strtotime($this->expire);
-    }
-
     function getId() {
         return $this->lock_id;
     }
@@ -62,16 +55,16 @@ class Lock extends VerySimpleModel {
     }
 
     function getExpireTime() {
-        return $this->expire;
+        return strtotime($this->expire);
     }
     //Get remaiming time before the lock expires
     function getTime() {
-        return $this->isExpired()?0:($this->expiretime-time());
+        return $this->isExpired()?0:($this->getExpireTime()-time());
     }
 
     //Should we be doing realtime check here? (Ans: not really....expiretime is local & based on loadtime)
     function isExpired() {
-        return (time()>$this->expiretime);
+        return (time()>$this->getExpireTime());
     }
 
     function getCode() {
@@ -89,7 +82,7 @@ class Lock extends VerySimpleModel {
             SqlFunction::NOW(),
             SqlInterval::MINUTE($lockTime)
         );
-        return $this->save();
+        return $this->save(true);
     }
 
     //release aka delete a lock.
diff --git a/include/staff/footer.inc.php b/include/staff/footer.inc.php
index 5abc0997369e1e00e9e3d79bc98ae92b671438ca..778fbd045397566bdfe42d5d293c8f32ec1d1683 100644
--- a/include/staff/footer.inc.php
+++ b/include/staff/footer.inc.php
@@ -34,7 +34,7 @@ if(is_object($thisstaff) && $thisstaff->isStaff()) { ?>
     <hr style="margin-top:3em"/>
     <p class="full-width">
         <span class="buttons pull-right">
-            <input type="button" value="<?php echo __('OK');?>" class="close">
+            <input type="button" value="<?php echo __('OK');?>" class="close ok">
         </span>
      </p>
     <div class="clear"></div>
diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php
index 0560eaf00ce70eacee1048f45dd9903a13368843..572fc90c6ae09e77c624dbdaf973d10ffa3bc5a9 100644
--- a/include/staff/ticket-view.inc.php
+++ b/include/staff/ticket-view.inc.php
@@ -701,7 +701,7 @@ $tcount = $ticket->getThreadEntries($types)->count();
         echo $ticket->getId(); ?>#note" name="note" method="post" enctype="multipart/form-data">
         <?php csrf_token(); ?>
         <input type="hidden" name="id" value="<?php echo $ticket->getId(); ?>">
-        <input type="hidden" name="locktime" value="<?php echo $cfg->getLockTime(); ?>">
+        <input type="hidden" name="locktime" value="<?php echo $cfg->getLockTime() * 60; ?>">
         <input type="hidden" name="a" value="postnote">
         <input type="hidden" name="lockCode" value="<?php echo $ticket->getLock()->getCode(); ?>">
         <table width="100%" border="0" cellspacing="0" cellpadding="3">
@@ -1065,7 +1065,7 @@ $(function() {
     clearInterval(setLock);
     autoLock.setLock({
       id:<?php echo $lock->getId(); ?>,
-      time: <?php echo $cfg->getLockTime(); ?>}, 'acquire');
+      time: <?php echo $cfg->getLockTime() * 60; ?>}, 'acquire');
   }, 50);
 }();
 <?php } ?>
diff --git a/js/redactor-osticket.js b/js/redactor-osticket.js
index 39ffaad3051debd0098e3c67400ebe5a8e405222..ac1ca3bef84c791b631143f1cf1e4d395bd16a6b 100644
--- a/js/redactor-osticket.js
+++ b/js/redactor-osticket.js
@@ -209,6 +209,16 @@ RedactorPlugins.signature = function() {
   }
 };
 
+RedactorPlugins.autolock = function() {
+  return {
+    init: function() {
+      var code = this.$box.closest('form').find('[name=lockCode]');
+      if ($.autoLock && code.length)
+        this.opts.keydownCallback = $.autoLock.handleEvent;
+    }
+  };
+}
+
 /* Redactor richtext init */
 $(function() {
     var captureImageSizes = function(html) {
@@ -245,7 +255,7 @@ $(function() {
                 'focus': false,
                 'plugins': el.hasClass('no-bar')
                   ? ['imagepaste','imagemanager','definedlinks']
-                  : ['imagepaste','imagemanager','imageannotate','table','video','definedlinks'],
+                  : ['imagepaste','imagemanager','imageannotate','table','video','definedlinks','autolock'],
                 'imageUpload': 'tbd',
                 'imageManagerJson': 'ajax.php/draft/images/browse',
                 'syncBeforeCallback': captureImageSizes,
diff --git a/scp/js/scp.js b/scp/js/scp.js
index edb2cf0c0ccf6750c3a9b58584ab3b0a1dbd1687..44a99523514927c5b32076477b1ce350b7ab94a3 100644
--- a/scp/js/scp.js
+++ b/scp/js/scp.js
@@ -617,6 +617,8 @@ $.sysAlert = function (title, msg, cb) {
         $('#title', $dialog).html(title);
         $('#body', $dialog).html(msg);
         $dialog.show();
+        if (cb)
+            $dialog.find('input.ok.close').click(cb);
     } else {
         alert(msg);
     }
diff --git a/scp/js/ticket.js b/scp/js/ticket.js
index 37b828a172974f4b0bcb9265c9cd358bbd4361ad..7082679962d08b54af60a24b6b85645812613e55 100644
--- a/scp/js/ticket.js
+++ b/scp/js/ticket.js
@@ -17,12 +17,14 @@ var autoLock = {
 
     // Defaults
     lockId: 0,
+    lockCode: '',
     timerId: 0,
     lasteventTime: 0,
+    lastcheckTime: 0,
     lastattemptTime: 0,
     acquireTime: 0,
     renewTime: 0,
-    renewFreq: 0, //renewal frequency in seconds...based on returned lock time.
+    renewFreq: 10000, //renewal frequency in seconds...based on returned lock time.
     time: 0,
     lockAttempts: 0, //Consecutive lock attempt errors
     maxattempts: 2, //Maximum failed lock attempts before giving up.
@@ -53,16 +55,6 @@ var autoLock = {
 
     //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
             $(document).on('pjax:beforeSend.changed', function(e) {
@@ -72,8 +64,23 @@ var autoLock = {
                 return __("Any changes or info you've entered will be discarded!");
              });
         }
+        // Handle events only every few seconds
+        var now = new Date().getTime(),
+            renewFreq = autoLock.renewFreq;
+
+        if (autoLock.lasteventTime && now - autoLock.lasteventTime < renewFreq)
+            return;
+
+        autoLock.lasteventTime = now;
+
+        if (!autoLock.lockId) {
+            // Retry every 5 seconds??
+            if (autoLock.retry)
+                autoLock.acquireLock(e,autoLock.warn);
+        } else {
+            autoLock.renewLock(e);
+        }
 
-        autoLock.lasteventTime=new Date().getTime();
     },
 
     //Watch activity on individual form.
@@ -126,7 +133,6 @@ var autoLock = {
         void(autoLock.lockTime=parseInt($(':input[name=locktime]',fObj).val()));
 
         autoLock.watchDocument();
-        autoLock.resetTimer();
         autoLock.addEvent(window,'unload',autoLock.releaseLock,true); //Release lock regardless of any activity.
     },
 
@@ -168,9 +174,7 @@ var autoLock = {
                 success: function(lock){
                     autoLock.setLock(lock,'acquire',warn);
                 }
-            })
-            .done(function() { })
-            .fail(function() { });
+            });
         }
 
         return autoLock.lockId;
@@ -179,22 +183,25 @@ var autoLock = {
     //Renewal only happens on form activity..
     renewLock: function(e) {
 
-        if(!autoLock.lockId) { return false; }
+        if (!autoLock.lockId)
+            return false;
 
-        var now= new Date().getTime();
-        if(!autoLock.lastcheckTime || (now-autoLock.lastcheckTime)>=(autoLock.renewFreq*1000)){
-            $.ajax({
-                type: 'POST',
-                url: 'ajax.php/tickets/'+autoLock.tid+'/lock/'+autoLock.lockId+'/renew',
-                dataType: 'json',
-                cache: false,
-                success: function(lock){
-                    autoLock.setLock(lock,'renew',autoLock.warn);
-                }
-            })
-            .done(function() {  })
-            .fail(function() { });
-        }
+        var now = new Date().getTime(),
+            renewFreq = autoLock.renewFreq;
+
+        if (autoLock.lastcheckTime && now - autoLock.lastcheckTime < renewFreq)
+            return;
+
+        autoLock.lastcheckTime = now;
+        $.ajax({
+            type: 'POST',
+            url: 'ajax.php/tickets/'+autoLock.tid+'/lock/'+autoLock.lockId+'/renew',
+            dataType: 'json',
+            cache: false,
+            success: function(lock){
+                autoLock.setLock(lock,'renew',autoLock.warn);
+            }
+        });
     },
 
     releaseLock: function(e) {
@@ -209,22 +216,23 @@ var autoLock = {
             success: function() {
                 autoLock.lockId = 0;
             }
-        })
-        .done(function() { })
-        .fail(function() { });
+        });
     },
 
     setLock: function(lock, action, warn) {
         var warn = warn || false;
 
-        if(!lock) return false;
+        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.
 
+        if (lock.code) {
+            autoLock.lockCode = lock.code;
+            // Update the lock code for the upcoming POST
+            var el = $('input[name=lockCode]').val(lock.code);
+        }
+
         switch(action){
             case 'renew':
                 if(!lock.id && lock.retry) {
@@ -242,6 +250,10 @@ var autoLock = {
                 }
                 break;
         }
+
+        if (lock.id && lock.time) {
+            autoLock.resetTimer((lock.time - 10) * 1000);
+        }
     },
 
     discardWarning: function(e) {
@@ -250,17 +262,25 @@ var autoLock = {
 
     //TODO: Monitor events and elapsed time and warn user when the lock is about to expire.
     monitorEvents: function() {
-       // warn user when lock is about to expire??;
-        //autoLock.resetTimer();
+        $.sysAlert(
+            __('Your lock is expiring soon'),
+            __('The lock you hold on this ticket will expire soon. Would you like to renew the lock?'),
+            function() {
+                autoLock.renewLock();
+            }
+        );
     },
 
     clearTimer: function() {
         clearTimeout(autoLock.timerId);
     },
 
-    resetTimer: function() {
+    resetTimer: function(time) {
         clearTimeout(autoLock.timerId);
-        autoLock.timerId=setTimeout(function () { autoLock.monitorEvents() },30000);
+        autoLock.timerId = setTimeout(
+          function () { autoLock.monitorEvents(); },
+          time || 30000
+        );
     }
 };
 $.autoLock = autoLock;
diff --git a/scp/tickets.php b/scp/tickets.php
index 0a57e94c53c053b377504484ca5f80c98fa8a355..620f8cfc47facd0375e695076fd0f1e5dd653429 100644
--- a/scp/tickets.php
+++ b/scp/tickets.php
@@ -76,7 +76,10 @@ if($_POST && !$errors):
                 elseif ($lock->getStaffId()!=$thisstaff->getId()) {
                     $errors['err'] = __('Action Denied. Ticket is locked by someone else!');
                 }
-                elseif ($lock->getCode() != $_POST['lockCode']) {
+                // Attempt to renew the lock if possible
+                elseif (($lock->isExpired() && !$lock->renew())
+                    ||($lock->getCode() != $_POST['lockCode'])
+                ) {
                     $errors['err'] = __('Your lock has expired. Please try again');
                 }