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;
      }
    
    }
  • 相关阅读:
    写在noi之前
    雅礼集训 Day8
    雅礼集训 Day6
    雅礼集训 Day5
    2017雅礼集训 Day4
    2017雅礼集训 Day2
    2017雅礼集训 Day1
    洛谷 P3426 [POI2005]SZA-Template
    Codeforces Round #368 DIV2 C.
    Educational Codeforces Round 16 D&E.
  • 原文地址:https://www.cnblogs.com/Answer1215/p/7237391.html
Copyright © 2011-2022 走看看