Skip to content

gordianknotC/baseCaptchaTS

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

生成文字圖片,用於不想爬蟲抓到文字的情境中。

source

type none = null | undefined;
type CaptchaCallback = (response: "success" | "error", captcha: Element, numberOfTries: number) => void;

export type CaptchaOptions = {
  el: string;
  canvasClass?: string | none;
  numbersOfTries: number;
  beforeGenerateCaptcha: (captcha: Captcha)=>void;
  onRenderCaptcha: (captcha: Captcha)=>void;
  onValidate: (c: Captcha)=>boolean;
  onValidateSuccess: (c: Captcha)=>void;
  onValidateError: (c: Captcha)=>void;
  onMaxRetries: (c: Captcha)=>boolean;

  canvasStyle: {
    width: number ;
    height: number ;
    font?: string | none;
    fontSize?: string | none;
    fillStyle?: string | none;
    textAlign?: CanvasTextAlign | none;
    textBaseline?: CanvasTextBaseline | none;
  };
}

function _setCanvas($el: Element, options: CaptchaOptions){
  // const lastChild = $el.children[$el.children.length -1];
  // if (lastChild.constructor.name == "HTMLCanvasElement")
  //   $el.removeChild(lastChild);
  const child: HTMLElement = document.createElement("section");
  child.innerHTML = `<canvas 
      class="${options.canvasClass}"
      width="${options.canvasStyle.width}" 
      height="${options.canvasStyle.height}">
    </canvas>`;
  $el.innerHTML = "";
  $el.appendChild(child.children[0]);
}

const defaultOption: CaptchaOptions = {
  el: '.jCaptcha',
  canvasClass: 'jCaptchaCanvas',
  beforeGenerateCaptcha: (c)=>null,
  onRenderCaptcha: (c)=>{
    const text: string = "captcha text";
    c.clearText();
    c.fillText(text);
  },
  onValidate: (c: Captcha)=>true,
  onMaxRetries: (c: Captcha)=>true,
  onValidateSuccess: (c: Captcha)=>null,
  onValidateError: (c: Captcha)=>null,
  numbersOfTries: 3,
  canvasStyle: {
    width: 100,
    height: 100,
  }
};

const SOLID = "POSITIVE_NEGATIVE";


function transformFont(font: string, fontSize: string){
  return `${fontSize} ${font}`;
}
export
class Captcha{
  $el?: Element | none;
  $captchaEl?: HTMLCanvasElement | none;
  $captchaTextContext?: CanvasRenderingContext2D | none;
  currentRetries: number = 0;

  constructor(public options: CaptchaOptions = defaultOption) {
    this.options = Object.assign(defaultOption, options);
    this.options.canvasStyle.font = transformFont(this.options.canvasStyle.font!, this.options.canvasStyle.fontSize!);

    document.querySelector(this.options.el!);
    this.$el = document.querySelector(this.options.el!);
    assert(this.$el, `unexpect null dom, selector: ${this.options.el}`);

    this.options.beforeGenerateCaptcha(this);
    this.setCaptcha(false);
  }

  clearText(){
    this.$captchaTextContext!.clearRect(0, 0, this.options.canvasStyle.width, this.options.canvasStyle.height);
  }

  fillText(text: string, x?:number, y?:number){
    x ??= this.$captchaEl!.clientWidth! / 2 - 20;
    y ??= this.$captchaEl!.clientHeight! / 2;
    this.$captchaTextContext!.fillText(text, x, y);
    this.$captchaTextContext!.font = ""
    this.$captchaTextContext!.textAlign = this.options.canvasStyle.textAlign!;
    this.$captchaTextContext!.textBaseline = this.options.canvasStyle.textBaseline!
  }

  resize(width: number, height: number){
    this.options.canvasStyle.width = width
    this.options.canvasStyle.height = height
    this.setCaptcha(true);
  }

  setCaptcha(shouldReset: boolean) {
    const $el = this.$el!;
    const options = this.options;
    if (!shouldReset) {
      _setCanvas($el, options);

      this.$captchaEl = $el.querySelector(`.${options.canvasClass}`) as HTMLCanvasElement;
      this.$captchaTextContext = this.$captchaEl.getContext('2d');
      this.$captchaTextContext = Object.assign(this.$captchaTextContext!, options.canvasStyle);
    }
    this.options.onRenderCaptcha(this);
  }

  validate() {
    this.currentRetries++;
    console.log(1);
    if (this.options.numbersOfTries < this.currentRetries){

      console.log(2);
      if(this.options.onMaxRetries(this)){
        this.currentRetries = 0;
        this.reset();
        return;
      }else{
      }
    }
    console.log(3);
    if (this.options.onValidate(this)) {
      this.options.onValidateSuccess(this);
    } else {
      this.options.onValidateError(this);
    }
  }

  reset() {
    this.options.beforeGenerateCaptcha(this);
    this.setCaptcha(true);
  }
}

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published