/** * @ngdoc fbDokumentVaerde * @name fasit.i.#fbDokumentVaerde * @fbDokumentVaerde * * @description * Directive som används för att ha redigerbara fält i dokument * Tillhandahåller menyer för att ändra storlek, fetstil, kursivt, understruket osv. * För textredigeringen. * * * @param {original-vaerde} Måste få attributet original-vaerde för att veta vad defaultvärdet på fältet ska vara * @param {dokument-vaerde} Anpassat värde som endast gäller detta dokument, innehållande styling-information och senast sparade texten */ angular.module('fasit') .directive('fbDokumentField', ['$compile', 'textWidthService', '$sce', 'commonService', '$rootScope', '$timeout', '$parse', '$filter', '$rootScope', function ( $compile: ng.ICompileService, textWidthService: fb.ITextWidthService, $sce: ng.ISCEService, commonService: fb.ICommonService, rootScope: fb.IRootScope, $timeout: ng.ITimeoutService, $parse, $filter: ng.IFilterService, $rootScope: fb.IRootScope ) { 'use strict'; function link( scope: fb.IFbDokumentFieldScope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes, ngModel: ng.INgModelController ) { // Definierar de characters som tillåts i currency-fält: ,-.0123456789 var currencyCharacters = [44, 45, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57]; //[.,0-9] var noDecimalCurrencyCharacter = [45, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57]; var yearCharacters = [48, 49, 50, 51, 52, 53, 54, 55, 56, 57]; //[0-9] var EMPTY_FIELD_CLASS = 'fb-dokument-empty-field'; scope.editing = false; // Om inte ett dokumentVaerde var specificerat så skapas det som ett tomt objekt, annars initieras directivet med värden från dokumentVaerdet if (typeof scope.dokumentVaerde === 'undefined') { scope.dokumentVaerde = new fb.DokumentVaerde({}); if (scope.originalVaerde || scope.statisktVaerde) { scope.dokumentVaerde.Vaerde = scope.originalVaerde ? scope.originalVaerde : scope.statisktVaerde; } else { scope.dokumentVaerde.Vaerde = ''; } } if (scope.originalVaerde || scope.statisktVaerde) { scope.dokumentVaerde.originalVaerde = scope.originalVaerde ? scope.originalVaerde : scope.statisktVaerde; } else { scope.dokumentVaerde.originalVaerde = ''; } if (scope.originalVaerde && typeof scope.originalVaerde === 'string') { scope.originalVaerde = scope.originalVaerde.replace(/(?:\r\n|\r|\n)/g, '
'); scope.dokumentVaerde.originalVaerde = scope.dokumentVaerde.originalVaerde.replace(/(?:\r\n|\r|\n)/g, '
'); scope.dokumentVaerde.Vaerde = scope.dokumentVaerde.Vaerde.replace(/(?:\r\n|\r|\n)/g, '
'); } // Sätts för att snabbt kunna avgöra om ett värde är länkat eller inte if (((attrs).originalVaerde && typeof scope.originalVaerde !== "undefined") || scope.laenkatVaerde) { scope.laenkatVaerde = true; } else { scope.laenkatVaerde = false; } var popovers = { linked: null, linkedScope: null, unlinked: null, unlinkedScope: null, currentPopover: null }; var linkBroken = function (): boolean { return scope.laenkatVaerde && (scope.dokumentVaerde.Vaerde !== scope.dokumentVaerde.originalVaerde || scope.editMade || scope.dokumentVaerde.save); }; // Funktion som returnerar det popover-innehåll som ska visas vid editering var getPopoverContent = function (): any { var linkedFieldHeader = 'Länkat fält'; var linkedFieldBody = 'Detta fält är länkat'; var unlinkedFieldHeader = 'Bruten länk'; var unlinkedFieldBody = 'Värdet har ändrats i detta dokument och kommer inte längre uppdateras då länkning är bruten. Återställ koppling'; // jshint ignore:start if (linkBroken()) { if (popovers.unlinkedScope) { popovers.unlinkedScope.$destroy(); } popovers.unlinkedScope = scope.$new(); popovers.unlinked = $compile('
' + unlinkedFieldHeader + '
' + '
' + unlinkedFieldBody + '
')(popovers.unlinkedScope); popovers.currentPopover = 'unlinked'; return popovers.unlinked; } else if (scope.laenkatVaerde) { if (popovers.linkedScope) { popovers.linkedScope.$destroy(); } popovers.linkedScope = scope.$new(); popovers.linked = $compile('
' + linkedFieldHeader + '
' + '
' + linkedFieldBody + '
')(popovers.linkedScope); popovers.currentPopover = 'linked'; return popovers.linked; } // jshint ignore:end }; // Variabel för lagring av referens till det editerbara elementet, samt getter-funktion var editableElement: ng.IAugmentedJQuery; var getEditableElement = function () { if (editableElement) { return editableElement; } else { editableElement = element.find('.fb-dokument-field-editable-field'); if (editableElement) { // initialize popover editableElement.popover({ html: true, content: getPopoverContent(), placement: (scope.popoverPlacement) ? scope.popoverPlacement : 'top', trigger: 'manual', container: '#dokument-sidan' }); return editableElement; } } return null; }; // Om editable är satt till false, sätts elementet till att inte vara editerbart if (scope.editable === 'false') { getEditableElement()[0].contentEditable = 'false'; } // Vi lägger till editableFontsize för att ha ett redigerbart värde för font-storleken och kunna visa ett värde för användaren även om fontSize inte är satt och värdet därmed är null if (!$rootScope.dokumentApp) { if (!scope.dokumentVaerde.FontSize) { scope.dokumentVaerde.editableFontSize = parseInt(getEditableElement().css('fontSize').replace('px', '')); } else { scope.dokumentVaerde.editableFontSize = scope.dokumentVaerde.FontSize; } scope.dokumentVaerde.originalFontSize = scope.dokumentVaerde.editableFontSize; } // Om någon obligatorisk parameter saknas så skapas elementet som ett icke redigerbart element if (typeof ngModel === undefined || !ngModel) { if (scope.dokumentVaerde !== undefined) { getEditableElement()[0].innerHTML = scope.dokumentVaerde.Vaerde; } else { getEditableElement()[0].innerHTML = scope.originalVaerde ? scope.originalVaerde : scope.statisktVaerde; } getEditableElement()[0].contentEditable = 'false'; return; } // När modellen kallas på att renderas om så avgörs vilken text som ska visas ngModel.$render = function () { commonService.angularFunctions.safeApply(scope, function () { updateHTML(); }); }; // När värdet ändras så sparas det till scope och renderas ut till html flyttad så att värden uppdateras vid focusout... för att förbättra prestanda element.on('keyup change', function (e) { if (e.keyCode === 9) { return; } commonService.angularFunctions.safeApply(scope, function () { scope.dokumentVaerde.save = true; scope.editMade = true; refreshPopover(); }); }); scope.$on('$destroy', function () { element.off('paste'); element.off('focusin'); element.off('focusout'); element.off('keyup'); if (getEditableElement().data('bs.popover')) { getEditableElement().data('bs.popover').hide(); } angular.element('#dokument-sidan > .popover').remove(); }); // interceptar paste event för att ta bort formatering från inklistrad text element.on('paste', function (e: fb.IPasteEvent) { var text: any; e.preventDefault(); if (e.clipboardData) { text = e.clipboardData.getData('text/plain'); } else if (( window).clipboardData) { text = ( window).clipboardData.getData('Text'); } else if (e.originalEvent && e.originalEvent.clipboardData) { text = $('
').text(e.originalEvent.clipboardData.getData('text')); } if (text) { if (document.queryCommandSupported('insertText')) { document.execCommand('insertHTML', false, $(text).html()); } else { // fix för paste in IE 11 var fbWindow: fb.IWindow = window; var offset: number = fbWindow.getSelection().focusOffset; if (fbWindow.getSelection().focusNode.innerHTML) { var html = fbWindow.getSelection().focusNode.innerHTML; var newContent = html.substring(0, offset) + text + html.substring(offset, html.length); fbWindow.getSelection().focusNode.innerHTML = newContent; } else { var content = fbWindow.getSelection().focusNode; fbWindow.getSelection().focusNode.insertData(offset, text); } } } }); scope.$watch('granska', function () { if (!getEditableElement()[0]) { return; } if (scope.granska || scope.editable === 'false') { getEditableElement()[0].contentEditable = 'false'; } else { getEditableElement()[0].contentEditable = 'true'; } }); var refreshPopover = function () { if (!getEditableElement()[0]) { return; } var popover = getEditableElement().data('bs.popover'); if ((linkBroken() && popovers.currentPopover !== 'unlinked') || (!linkBroken() && popovers.currentPopover !== 'linked')) { // Måste sätta content till '' för att undvika buggar där båda popoversen visas popover.options.content = ''; popover.setContent(); popover.options.content = getPopoverContent(); popover.setContent(); popover.$tip.addClass(popover.options.placement); } if (!popover.tip().hasClass('in')) { popover.show(); } }; // **************** Radjusteringar och sidindelningar ***************************** element.on('focusin', function (event) { commonService.angularFunctions.safeApply(scope, function () { if (!getEditableElement()[0]) { return; } element.removeClass(EMPTY_FIELD_CLASS); scope.editMade = false; scope.styleObject.styleVaerde = scope.dokumentVaerde; scope.editing = true; var html = getEditableElement()[0].innerHTML; if (scope.statiskPlaceholder && scope.dokumentVaerde.Vaerde === scope.statisktVaerde) { getEditableElement()[0].innerHTML = ''; return; } //getEditableElement()[0].innerHTML = html.replace(/
/g, ' '); refreshPopover(); if (scope.isCurrency || scope.isPercent) { getEditableElement()[0].innerHTML = getEditableElement()[0].innerHTML.replace(/ /g, ''); element.on('keypress', function (event) { if (currencyCharacters.indexOf(event.charCode) < 0) { event.preventDefault(); } }); } else if (scope.isNoDecimalCurrency) { getEditableElement()[0].innerHTML = getEditableElement()[0].innerHTML.replace(/ /g, ''); element.on('keypress', function (event) { if (noDecimalCurrencyCharacter.indexOf(event.charCode) < 0) { event.preventDefault(); } }); } else if (scope.isYear) { element.on('keypress', function (event) { if (yearCharacters.indexOf(event.charCode) < 0) { event.preventDefault(); } else { var rawValue = getEditableElement()[0].innerHTML; if (rawValue.length >= 4) { event.preventDefault(); } } }); } }); }); var updateModelFromHTML = function () { if (scope.dokumentVaerde.Vaerde !== getEditableElement()[0].innerHTML) { if (scope.isCurrency || scope.isPercent) { var rawValue = getEditableElement()[0].innerHTML; var regexMatch = rawValue.match(/[-0-9.,]+/g); scope.dokumentVaerde.Vaerde = (regexMatch && regexMatch[0] && regexMatch[0].length > 0) ? regexMatch[0] : ""; } else if (scope.isNoDecimalCurrency) { var rawValue2 = getEditableElement()[0].innerHTML; var regexMatch2 = rawValue2.match(/[-0-9]+/g); scope.dokumentVaerde.Vaerde = (regexMatch2 && regexMatch2[0] && regexMatch2[0].length > 0) ? regexMatch2[0] : ""; } else if (scope.isYear) { var rawValue3 = getEditableElement()[0].innerHTML; var regexMatch3 = rawValue3.match(/[0-9]+/g); scope.dokumentVaerde.Vaerde = (regexMatch3 && regexMatch3[0] && regexMatch3[0].length > 0) ? regexMatch3[0] : ""; } else { scope.dokumentVaerde.Vaerde = getEditableElement()[0].innerHTML; } } } element.on("keyup", function () { commonService.angularFunctions.safeApply(scope, function () { if (scope.isYear || scope.isDate) { element.off('keyup'); } else { updateModelFromHTML(); } }); }); element.on('focusout', function () { commonService.angularFunctions.safeApply(scope, function () { scope.editMade = false; scope.editing = false; updateModelFromHTML(); updateHTML(); // Vänta 100 ms med att dölja popover så att den går att klicka på $timeout(function () { if (!getEditableElement()[0]) { return; } if (getEditableElement().data('bs.popover')) { getEditableElement().data('bs.popover').hide(); } }, 100); if (scope.isCurrency) { element.off('keypress'); } }); }); // Lyssnar på förändringar från andra källor för att uppdatera sitt värde scope.$watch('dokumentVaerde.Vaerde', function (newValue: fb.DokumentVaerde, oldValue: fb.DokumentVaerde) { if (!getEditableElement()[0]) { return; } updateHTML(); }); var updateHTML = function () { if (scope.editing || typeof scope.dokumentVaerde === 'undefined' || !getEditableElement()[0]) { return; } if (scope.isCurrency || scope.isPercent) { var regexMatch = (scope.dokumentVaerde.Vaerde + '').match(/[-0-9.,]+/g); var vaerdeFiltered = (regexMatch && regexMatch[0] && regexMatch[0].length > 0) ? regexMatch[0] : scope.dokumentVaerde.Vaerde; getEditableElement()[0].innerHTML = $filter('fbDokumentCurrency')(vaerdeFiltered); return; } var content = scope.dokumentVaerde.Vaerde + ''; if (!content) { getEditableElement()[0].innerHTML = ''; } else if (getEditableElement()[0]) { getEditableElement()[0].innerHTML = $sce.trustAsHtml(content); } if (!content) { element.addClass(EMPTY_FIELD_CLASS); } else { element.removeClass(EMPTY_FIELD_CLASS); } }; // återställer värdet till originalvärdet scope.reset = function (): void { scope.dokumentVaerde.save = false; scope.editMade = false; scope.dokumentVaerde.Vaerde = scope.dokumentVaerde.originalVaerde; }; } var compile = function (element, attrs) { return link; }; return { restrict: 'E', require: '?ngModel', scope: { originalVaerde: '=', statisktVaerde: '@', statiskPlaceholder: '@', dokumentVaerde: '=', maxWidth: '=', pageSplit: '=', splittable: '=', styleObject: '=', granska: '=', laangText: '@', editable: '@', viktigt: '@', isCurrency: '@', isNoDecimalCurrency: '@', isPercent: '@', isYear: '@', isDate: '@', hideWhenEmpty: '@', popoverPlacement: '@', laenkatVaerde: '@', ngShow: '=' }, //link: link, compile: compile, templateUrl: $rootScope.dokumentApp ? 'app/Directives/fbDokumentField/fbDokumentFieldPDF.html' : 'app/Directives/fbDokumentField/fbDokumentField.html', transclude: false, replace: false }; }]);