LP#1862235 - Create MARC Record - Keyboard workflow enhancements user/stompro/lp1862235_create_marc_record_workflow_squashed
authorJosh Stompro <stompro@stompro.org>
Mon, 10 Feb 2020 14:18:03 +0000 (08:18 -0600)
committerJosh Stompro <stompro@stompro.org>
Wed, 12 Feb 2020 21:06:32 +0000 (15:06 -0600)
LP#1862235 - Create MARC Record - Global Keyboard Shortcut

Added ctrl+f3 to launch the create MARC record interface.

Signed-off-by: Josh Stompro <stompro@stompro.org>
LP#1862235 - Create MARC Record - Focus on template on load

Focus on the template selector dropdown when interface loads.

This removes the need to use the mouse, and speeds up using the
interface.  Pressing tab, then enter will submit
the form with the default template selected.

If the template needs to be changed, then pressing the first letter
of the template will switch between the different options.

This adds a directive named autoFocus to staff/cat/catalog/app.js,
so adding "auto-focus" to an element will cause that element
to have focus on load.

Signed-off-by: Josh Stompro <stompro@stompro.org>
LP#1862235 - Set unique page title for create marc record.

Add an egCore string for page title translation, and set
page title for Create New MARC Record.

Signed-off-by: Josh Stompro <stompro@stompro.org>
LP#1862235 - Create MARC Record - focus on item add and call number

This change sets the focus on the "Add Item" checkbox when the marc editor
is opened with fast item add enabled.  This allows the user to just press space
to enable Add item.

When the add item checkbox is enabled, the focus is moved to the call number field.

This adds a directive to app.js called focusOnShow that makes it easy
to mark an element to have focus when it becomes visible when using ng-show.

I had to add in a bit of redundancy in t_marcedit.tt2, the Add Item checkbox
needs to have it's own ng-show directive for the focus-on-show to work.

Signed-off-by: Josh Stompro <stompro@stompro.org>
LP#1862235 - Create MARC Record - Hide help button for flat editor

The help button only works for the non flat editor, so show it only
when flat editor isn't in use.

Signed-off-by: Josh Stompro <stompro@stompro.org>
LP#1862235 - Create MARC Record - Flat Editor - Keyboard Shortcut for Saving

Adds ctrl+s as a keyboard shortcut for saving the marc record while in the
flat text editor.

Signed-off-by: Josh Stompro <stompro@stompro.org>
LP#1862235 - Create MARC Record - Non-Flat Editor - Keyboard Shortcuts

Added the following shortcuts to the marc editor keyboard shortcuts.

Ctrl+s for save,
Ctrl+l for validate,
Ctrl+? for toggle help

Signed-off-by: Josh Stompro <stompro@stompro.org>
LP#1862235 - Create MARC Record - Jump to Flat Editor - Keyboard Shortcut

Added ctrl+e to jump to the flat editor textarea.

Signed-off-by: Josh Stompro <stompro@stompro.org>
Open-ILS/src/templates/staff/cat/catalog/index.tt2
Open-ILS/src/templates/staff/cat/catalog/t_new_bib.tt2
Open-ILS/src/templates/staff/cat/share/t_marcedit.tt2
Open-ILS/src/templates/staff/navbar.tt2
Open-ILS/web/js/ui/default/staff/cat/catalog/app.js
Open-ILS/web/js/ui/default/staff/cat/services/marcedit.js

index be572de..7bac1a1 100644 (file)
     s.SERIALS_ISSUANCE_SUCCESS_SAVE = "[% l('Issuance saved') %]";
     s.PAGE_TITLE_CATALOG_CONTEXT = "[% l('Catalog') %]";
     s.PAGE_TITLE_BIB_DETAIL = "[% l('Bib [_1]', '{{record_id}}') %]";
+    s.PAGE_TITLE_CREATE_MARC = "[% l('Create MARC Record') %]";
+
+    s.HOTKEY_SAVE_RECORD = "[% l('Save Record') %]";
+    s.HOTKEY_FOCUS_EDITOR = "[% l('Jump to editor') %]";
 
   }])
 </script>
index c5ffa77..e183b7e 100644 (file)
@@ -2,7 +2,7 @@
     <div class="col-xs-6">
         <div class="form-group">
             <label for="select-marc-template" class="control-label">[% l('Select MARC template') %]</label>
-            <select id="select-marc-template" class="form-control" ng-model="template_name" ng-options="name as name for name in template_list"></select>
+            <select id="select-marc-template" class="form-control" ng-model="template_name" ng-options="name as name for name in template_list" auto-focus></select>
         </div>
         <button class="btn btn-primary" ng-click="loadTemplate()">[% l('Load') %]</button>
         <button class="btn btn-default" ng-click="setDefaultTemplate()">[% l('Set Workstation Default') %]</button>
index 5ba7859..de6aceb 100644 (file)
@@ -1,10 +1,10 @@
 <div>
   <div ng-show="bre && fastAdd" class="row pad-vert marcfastitemadd">
     <div class="col-md-2">
-      <label><input type="checkbox" ng-model="enable_fast_add"/> [% l('Add Item') %]</label>
+      <label><input ng-show="bre && fastAdd" type="checkbox" ng-model="enable_fast_add" focus-on-show/> [% l('Add Item') %]</label>
     </div>
     <div class="col-md-2">
-      <input id="mfiacn" class="form-control" ng-show="enable_fast_add" type="text" placeholder="[% l('Call Number') %]" ng-model="fast_item_callnumber"/>
+      <input id="mfiacn" class="form-control" ng-show="enable_fast_add" type="text" placeholder="[% l('Call Number') %]" ng-model="fast_item_callnumber" focus-on-show/>
     </div>
     <div class="col-md-2">
       <input id="mfiabc" class="form-control" ng-show="enable_fast_add" type="text" placeholder="[% l('Barcode') %]" ng-model="fast_item_barcode"/>
@@ -46,7 +46,7 @@
           <button ng-hide="brandNewRecord || Record().deleted() != 't'" class="btn btn-default" ng-click="undeleteRecord()">[% l('Undelete') %]</button>
         </span>
         <span class="btn-group">
-          <button class="btn btn-default" ng-click="showHelp = !showHelp">[% l('Help') %]</button>
+          <button ng-show="!flatEditor.isEnabled" class="btn btn-default" ng-click="showHelp = !showHelp">[% l('Help') %]</button>
         </span>
       </div>
     </div>
                <li>[% l('Redo: CTRL-y') %]</li>
                <li>[% l('Add Row: CTRL+Enter') %]</li>
                <li>[% l('Insert Row: CTRL+Shift+Enter') %]</li>
+               <li>[% l('Save Record: CTRL+s') %]</li>
             </ul>
           </div>
           <div class="col-md-4">
                <li>[% l('Copy Current Row Below: CTRL+Down') %]</li>
                <li>[% l('Add Subfield: CTRL+D or CTRL+I') %]</li>
                <li>[% l('Remove Row: CTRL+Del') %]</li>
+               <li>[% l('Validate Headings: CTRL+l') %]</li>
             </ul>
           </div>
           <div class="col-md-4">
                <li>[% l('Create/Replace 006: Shift+F6') %]</li>
                <li>[% l('Create/Replace 007: Shift+F7') %]</li>
                <li>[% l('Create/Replace 008: Shift+F8') %]</li>
+               <li>[% l('Toggle Help: CTRL+?') %]</li>
             </ul>
           </div>
         </div>
index 1028f42..62b2f52 100644 (file)
           </li>
           <li class="divider"></li>
           <li>
-            <a href="./cat/catalog/new_bib" target="_self">
+            <a href="./cat/catalog/new_bib" target="_self"
+              eg-accesskey="[% l('ctrl+f3') %]"
+              eg-accesskey-desc="[% l('Create New MARC Record') %]">
               <span class="glyphicon glyphicon-plus"></span>
               [% l('Create New MARC Record') %]
             </a>
index f05c363..ad7f57e 100644 (file)
@@ -222,6 +222,8 @@ function($scope , $routeParams , $location , $window , $q , egCore) {
     $scope.template_name = '';
     $scope.new_bib_id = 0;
 
+    egCore.strings.setPageTitle(egCore.strings.PAGE_TITLE_CREATE_MARC);
+
     egCore.net.request(
         'open-ils.cat',
         'open-ils.cat.marc_template.types.retrieve'
@@ -269,6 +271,45 @@ function($scope , $routeParams , $location , $window , $q , egCore) {
     
 
 }])
+
+.directive('autoFocus', function($timeout) {
+    return {
+        restrict: 'AC',
+        link: function(_scope, _element) {
+            $timeout(function(){
+                _element[0].focus();
+            }, 0);
+        }
+    };
+})
+
+.directive('focusOnShow', function($timeout) {
+    return {
+        restrict: 'A',
+        link: function($scope, $element, $attr) {
+            if ($attr.ngShow){
+                $scope.$watch($attr.ngShow, function(newValue){
+                    if(newValue){
+                        $timeout(function(){
+                            $element[0].focus();
+                        }, 0);
+                    }
+                })
+            }
+            if ($attr.ngHide){
+                $scope.$watch($attr.ngHide, function(newValue){
+                    if(!newValue){
+                        $timeout(function(){
+                            $element[0].focus();
+                        }, 0);
+                    }
+                })
+            }
+
+        }
+    };
+})
+
 .controller('CatalogCtrl',
        ['$scope','$routeParams','$location','$window','$q','egCore','egHolds','egCirc','egConfirmDialog','ngToast',
         'egGridDataProvider','egHoldGridActions','egProgressDialog','$timeout','$uibModal','holdingsSvc','egUser','conjoinedSvc',
index 09b46d0..f34a874 100644 (file)
@@ -697,9 +697,9 @@ angular.module('egMarcMod', ['egCoreMod', 'ui.bootstrap'])
 
         },
         controller : ['$timeout','$scope','$q','$window','egCore', 'egTagTable',
-                      'egConfirmDialog','egAlertDialog','ngToast','egStrings',
+                      'egConfirmDialog','egAlertDialog','ngToast','egStrings','hotkeys',
             function ( $timeout , $scope , $q,  $window , egCore ,  egTagTable , 
-                       egConfirmDialog , egAlertDialog , ngToast , egStrings) {
+                       egConfirmDialog , egAlertDialog , ngToast , egStrings, hotkeys) {
 
 
                 $scope.onSaveCallback = $scope.onSave;
@@ -719,6 +719,37 @@ angular.module('egMarcMod', ['egCoreMod', 'ui.bootstrap'])
                     }
                 );
 
+                hotkeys.add({
+                    combo: 'ctrl+s',
+                    description: egCore.strings.HOTKEY_SAVE_RECORD,
+                    callback: function(event, hotkey) {
+
+                        event.preventDefault();
+                        if($scope.flatEditor.isEnabled){
+                            $scope.saveFlatTextMARC();
+                        }
+                        $scope.saveRecord();
+                    },
+                    allowIn : ['INPUT','SELECT','TEXTAREA']
+                });
+
+                hotkeys.add({
+                    combo: 'ctrl+e',
+                    description: egCore.strings.HOTKEY_FOCUS_EDITOR,
+                    callback: function(event, hotkey) {
+                        event.preventDefault();
+                        if($scope.flatEditor.isEnabled){
+                            var editor = $window.document.getElementsByTagName('textarea');
+                            editor[0].focus();
+                        }
+                        else {
+                            console.log('Jump focus to non-flattext editor not implemented.');
+                        }
+                    },
+                    allowIn : ['INPUT','SELECT','TEXTAREA']
+                });
+
+
                 MARC21.Record.delimiter = '$';
 
                 $scope.enable_fast_add = false;
@@ -970,7 +1001,18 @@ angular.module('egMarcMod', ['egCoreMod', 'ui.bootstrap'])
                     } else if (event.which == 119 && event.shiftKey) { // shift + F8, insert/replace 008
                         reify008(event);
                         event_return = false;
-
+                    } else if (event.which == 83 && event.ctrlKey) { //ctrl + s, save
+                        //alert("Ctrl-s pressed");
+                        event.preventDefault();
+                        $scope.saveRecord();
+                        event_return = false;
+                    } else if (event.which == 76 && event.ctrlKey) { //ctrl + l, validate
+                        event.preventDefault();
+                        $scope.validateHeadings();
+                        event_return = false;
+                    } else if (event.which == 191 && event.ctrlKey) { //ctrl + ?, help
+                        $scope.showHelp = !$scope.showHelp;
+                        event_return = true;
                     } else if (event.which == 13 && event.ctrlKey) { // ctrl+enter, insert datafield
                         addDatafield(event, event.shiftKey); // shift key inserts before
                         event_return = false;