zoukankan      html  css  js  c++  java
  • [Angular] The Select DOM Event and Enabling Text Copy

    When we "Tab" into a input field, we want to select all the content, if we start typing, it should remove the existing content and add new content.

    We can use HMTL 'select' event.

      @HostListener('select', ['$event'])
      onSelect($event: UIEvent) {
        this.fullFieldSelected = this.input.selectionStart === 0
          && this.input.selectionEnd === this.input.value.length;
      }

    'fullFieldSelected' variable check whether the field is selected. 

    If we start typing, it should clean the input value and move the cursor to the first placeholder place.

        // Select the whole field
        if (this.fullFieldSelected) {
          this.input.value = this.buildPlaceHolder();
          const firstPlaceHolderPos = findIndex(this.input.value, (char) => char === '_');
          this.input.setSelectionRange(firstPlaceHolderPos, firstPlaceHolderPos);
        }

    There is one problem, if using trying to do Ctrl + C, it will clean up the field and put 'c' there. So we should prevent this happen.

      @HostListener('keydown', ['$event', '$event.keyCode'])
      onKeyDown($event: KeyboardEvent, keyCode) {
    
        // if user trying to do copy & paste, then we don't want to
        // overwrite the value
        if ($event.metaKey || $event.ctrlKey) {
          return;
        }
    
        if(keyCode !== TAB) {
          $event.preventDefault();
        }
    
        // get value for the key
        const val = String.fromCharCode(keyCode);
        // get position
        const cursorPos = this.input.selectionStart;
    
        // Select the whole field
        if (this.fullFieldSelected) {
          this.input.value = this.buildPlaceHolder();
          const firstPlaceHolderPos = findIndex(this.input.value, (char) => char === '_');
          this.input.setSelectionRange(firstPlaceHolderPos, firstPlaceHolderPos);
        }
    
        switch(keyCode) {
          case LEFT_ARROW:
            this.handleLeftArrow(cursorPos);
            return;
          case RIGHT_ARROW:
            this.handleRightArrow(cursorPos);
            return;
          case BACKSPACE:
            this.handleBackSpace(cursorPos);
            return;
          case DELETE:
            this.handleDelete(cursorPos);
            return;
        }
    
        const maskDigit = this.mask.charAt(cursorPos);
        const digitValidator = digitValidators[maskDigit] || neverValidator;
        if (digitValidator(val)) {
          overWriteCharAtPosition(this.input, val, cursorPos);
          this.handleRightArrow(cursorPos);
        }
      }

    So, we check whether '$event.metaKey or $event.ctrlKey', if those keys are pressed, then we consider user is trying to copy & paste.

    --------

    import {Directive, ElementRef, HostListener, Input, OnInit} from '@angular/core';
    
    import * as includes from 'lodash.includes';
    import * as findLastIndex from 'lodash.findlastindex';
    import * as findIndex from 'lodash.findIndex';
    import {SPECIAL_CHARACTERS, TAB, overWriteCharAtPosition, LEFT_ARROW, RIGHT_ARROW, BACKSPACE, DELETE} from './mask.utils';
    import {digitValidators, neverValidator} from './digit_validation';
    
    @Directive({
      selector: '[au-mask]'
    })
    export class AuMaskDirective implements OnInit {
    
      @Input('au-mask') mask = '';
    
      input: HTMLInputElement;
      fullFieldSelected = false;
    
      ngOnInit() {
        this.input.value = this.buildPlaceHolder();
      }
    
      constructor(el: ElementRef) {
        this.input = el.nativeElement;
      }
    
      @HostListener('select', ['$event'])
      onSelect($event: UIEvent) {
        this.fullFieldSelected = this.input.selectionStart === 0
          && this.input.selectionEnd === this.input.value.length;
      }
    
      @HostListener('keydown', ['$event', '$event.keyCode'])
      onKeyDown($event: KeyboardEvent, keyCode) {
    
        // if user trying to do copy & paste, then we don't want to
        // overwrite the value
        if ($event.metaKey || $event.ctrlKey) {
          return;
        }
    
        if(keyCode !== TAB) {
          $event.preventDefault();
        }
    
        // get value for the key
        const val = String.fromCharCode(keyCode);
        // get position
        const cursorPos = this.input.selectionStart;
    
        // Select the whole field
        if (this.fullFieldSelected) {
          this.input.value = this.buildPlaceHolder();
          const firstPlaceHolderPos = findIndex(this.input.value, (char) => char === '_');
          this.input.setSelectionRange(firstPlaceHolderPos, firstPlaceHolderPos);
        }
    
        switch(keyCode) {
          case LEFT_ARROW:
            this.handleLeftArrow(cursorPos);
            return;
          case RIGHT_ARROW:
            this.handleRightArrow(cursorPos);
            return;
          case BACKSPACE:
            this.handleBackSpace(cursorPos);
            return;
          case DELETE:
            this.handleDelete(cursorPos);
            return;
        }
    
        const maskDigit = this.mask.charAt(cursorPos);
        const digitValidator = digitValidators[maskDigit] || neverValidator;
        if (digitValidator(val)) {
          overWriteCharAtPosition(this.input, val, cursorPos);
          this.handleRightArrow(cursorPos);
        }
      }
    
      handleDelete(cursorPos) {
        overWriteCharAtPosition(this.input, '_', cursorPos);
        this.input.setSelectionRange(cursorPos, cursorPos);
      }
    
      handleBackSpace(cursorPos) {
        const previousPos = this.calculatePreviousCursorPos(cursorPos);
        if (previousPos > -1) {
          overWriteCharAtPosition(this.input, '_', previousPos);
          this.input.setSelectionRange(previousPos, previousPos);
        }
      }
    
      calculateNextCursorPos(cursorPos) {
        const valueBeforeCursor = this.input.value.slice(cursorPos + 1);
        const nextPos = findIndex(valueBeforeCursor, (char) => !includes(SPECIAL_CHARACTERS, char));
        return nextPos;
      }
    
      calculatePreviousCursorPos(cursorPos) {
        const valueBeforeCursor = this.input.value.slice(0, cursorPos);
        const previousPos = findLastIndex(valueBeforeCursor, (char) => !includes(SPECIAL_CHARACTERS, char));
        return previousPos;
      }
    
      handleRightArrow(cursorPos) {
        const nextPos = this.calculateNextCursorPos(cursorPos);
        if(nextPos > -1) {
          const newNextPos = cursorPos + nextPos + 1;
          this.input.setSelectionRange(newNextPos, newNextPos);
        }
      }
    
      handleLeftArrow(cursorPos) {
        const previousPos = this.calculatePreviousCursorPos(cursorPos);
        if(previousPos > -1) {
          this.input.setSelectionRange(previousPos, previousPos);
        }
      }
    
      buildPlaceHolder(): string {
        const chars = this.mask.split('');
    
        const value = chars.reduce((acc, curr) => {
          return acc += includes(SPECIAL_CHARACTERS, curr) ?
            curr :
            '_';
        }, '');
    
        return value;
      }
    
    }
  • 相关阅读:
    我是如何用三小时搞出个赚钱产品的?
    搭建一个基于nuxt.js的项目
    栅格系统
    git使用
    通过JS获取屏幕高度,借助屏幕高度设置div的高度
    如何理解盒模型
    e.target.value 和 this 的区别
    组件化设计:弹窗的使用逻辑
    uni-app 入坑记
    MAC 系统快捷键
  • 原文地址:https://www.cnblogs.com/Answer1215/p/7237391.html
Copyright © 2011-2022 走看看