From 11cbc1f0d5da66cd3af6355e23d3b7ae8f6842a1 Mon Sep 17 00:00:00 2001 From: Cesar Velez Date: Mon, 4 Dec 2017 12:45:35 -0500 Subject: [PATCH] LP#1691263: make webstaff MARC editor wrap long fields This patch makes the MARC editor wrap long fields (e.g., bibliographic 505 fields) so that they fit the width of the enclosing window or modal. The approach taken is replacing the text input elements with contenteditable divs, which in turn can be better styled. To test ------- [1] Apply the patch. [2] Locate a record with a long 505 field and open it in the MARC editor. Verify that the contents of the field wrap. [3] Verify that record editing and saving work as expected. Signed-off-by: Cesar Velez Signed-off-by: Galen Charlton Signed-off-by: Kathy Lussier --- .../staff/cat/share/t_marcedit_editable.tt2 | 20 ++++ .../ui/default/staff/cat/services/marcedit.js | 105 ++++++++++++++---- 2 files changed, 102 insertions(+), 23 deletions(-) create mode 100644 Open-ILS/src/templates/staff/cat/share/t_marcedit_editable.tt2 diff --git a/Open-ILS/src/templates/staff/cat/share/t_marcedit_editable.tt2 b/Open-ILS/src/templates/staff/cat/share/t_marcedit_editable.tt2 new file mode 100644 index 0000000000..1e5888f000 --- /dev/null +++ b/Open-ILS/src/templates/staff/cat/share/t_marcedit_editable.tt2 @@ -0,0 +1,20 @@ + + + +
{{content}}
+
diff --git a/Open-ILS/web/js/ui/default/staff/cat/services/marcedit.js b/Open-ILS/web/js/ui/default/staff/cat/services/marcedit.js index 2430dc0847..4411098a68 100644 --- a/Open-ILS/web/js/ui/default/staff/cat/services/marcedit.js +++ b/Open-ILS/web/js/ui/default/staff/cat/services/marcedit.js @@ -44,18 +44,34 @@ angular.module('egMarcMod', ['egCoreMod', 'ui.bootstrap']) } }]) +.directive("contenteditable", function() { + return { + restrict: "A", + require: "ngModel", + link: function(scope,element,attrs,ngModel){ + + function read(){ + // save new text into model + var elhtml = element.text(); + ngModel.$setViewValue(elhtml); + } + + ngModel.$render = function(){ + element.text(ngModel.$viewValue || ""); + }; + + element.bind("blur.c_e keyup.c_e change.c_e", function(){ + scope.$apply(read); + }); + } + }; +}) + .directive("egMarcEditEditable", ['$timeout', '$compile', '$document', function ($timeout, $compile, $document) { return { restrict: 'E', replace: true, - template: '', + templateUrl: './cat/share/t_marcedit_editable', scope: { field: '=', onKeydown: '=', @@ -66,11 +82,12 @@ angular.module('egMarcMod', ['egCoreMod', 'ui.bootstrap']) max: '@', itype: '@', selectOnFocus: '=', - advanceFocusAfterInput: '=' + advanceFocusAfterInput: '=', + isDisabled: "=" }, controller : ['$scope', function ( $scope ) { - + $scope.isInputDisabled = $scope.isDisabled == 'disabled'; if ($scope.contextItemContainer && angular.isArray($scope.$parent[$scope.contextItemContainer])) $scope.item_container = $scope.$parent[$scope.contextItemContainer]; else if ($scope.contextItemGenerator) @@ -146,9 +163,24 @@ angular.module('egMarcMod', ['egCoreMod', 'ui.bootstrap']) if (Boolean(scope.selectOnFocus)) { element.addClass('noSelection'); - element.bind('focus', function () { element.select() }); + element.bind('focus', function (e) { + var el = $(e.target).children('input').first(); + if (el.select) { el.select(); } + }); } + element.children("div[contenteditable]").each(function() { + $(this).focus(function(e) { + var tNode = e.target.firstChild; + var range = document.createRange(); + range.setStart(tNode, 0); + range.setEnd(tNode, tNode.length); + var sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + }); + }); + function findCaretTarget(id, itype) { var tgt = null; if (itype == 'tag') { @@ -349,6 +381,7 @@ angular.module('egMarcMod', ['egCoreMod', 'ui.bootstrap']) '/>'+ ''+ '= new_sf) sf[2]++; - if (sf[2] == index_sf) sf[1] = event.target.value.substring(0,start) + event.target.value.substring(end); + if (sf[2] == index_sf) { + sf[1] = event.target.value ? + event.target.value.substring(0,start) + event.target.value.substring(end) : + element.text().substring(0, start); + } }); event.data.scope.field.subfields.splice( new_sf, @@ -914,7 +958,8 @@ angular.module('egMarcMod', ['egCoreMod', 'ui.bootstrap']) deleteDatafield(event); event_return = false; - } else if (event.which == 46 && event.shiftKey && $(event.target).hasClass('marcsf')) { // shift+del, remove subfield + } else if (event.which == 46 && event.shiftKey && ($(event.target).hasClass('marcsf') || $(event.target.parentNode).hasClass('marcsf'))) { + // shift+del, remove subfield var sf = event.data.scope.subfield[2] - 1; if (sf == -1) sf = 0; @@ -1047,7 +1092,7 @@ angular.module('egMarcMod', ['egCoreMod', 'ui.bootstrap']) event_return = false; } else { // Assumes only marc editor elements have IDs that can trigger this event handler. - $scope.current_event_target = $(event.target).attr('id'); + $scope.current_event_target = $(event.target).hasClass('focusable') ? $(event.target) : null;//.attr('id'); if ($scope.current_event_target) { $scope.current_event_target_cursor_pos = event.target.selectionDirection=='backward' ? @@ -1065,7 +1110,7 @@ angular.module('egMarcMod', ['egCoreMod', 'ui.bootstrap']) if (!$scope.current_event_target_cursor_pos_end) $scope.current_event_target_cursor_pos_end = $scope.current_event_target_cursor_pos - var element = $('#'+$scope.current_event_target).get(0); + var element = $('#'+$scope.current_event_target + " .focusable").get(0); if (element) { element.focus(); if (element.setSelectionRange) { @@ -1074,10 +1119,24 @@ angular.module('egMarcMod', ['egCoreMod', 'ui.bootstrap']) $scope.current_event_target_cursor_pos_end ); } - $scope.current_event_cursor_pos_end = null; - $scope.current_event_target = null; + } + $scope.current_event_cursor_pos_end = null; + $scope.current_event_target = null; + } + } + + function getCaretPosEditableDiv(editableDiv){ + var caretPos = 0, sel, range; + if (window.getSelection) { + sel = window.getSelection(); + if (sel.rangeCount) { + range = sel.getRangeAt(0); + if (range.commonAncestorContainer.parentNode == editableDiv[0]) { + caretPos = range.endOffset; + } } } + return caretPos; } function loadRecord() { -- 2.43.2