moribvndvs / ng2-idle

Responding to idle users in Angular (not AngularJS) applications.
https://moribvndvs.github.io/ng2-idle
Apache License 2.0
315 stars 128 forks source link

idle doesn't work with CKEditor #31

Closed frankpolkm closed 6 years ago

frankpolkm commented 7 years ago

Hi, the idle function doesn't work with CKEditor. When user typing in the CKEditor, always got idle and timeout. How to fix that?

Thanks

moribvndvs commented 7 years ago

It looks like CKEditor uses IFRAMEs. @ng-idle will not be able to attach to those and listen for your input events because they are on a separate document. You'll likely need to create your own component or directive that takes in Idle service as a dependency, and - after the CKEditor is initialized - uses the CKEditor/DOM to listen to the desired events and call Idle.interrupt().

benbabics commented 5 years ago

Hello,

I ran into this issue with iframes as well and ended up creating my own custom InterruptSource based on DocumentInterruptSource except instead of having the first argument hard-coded as document.documentElement, it accepts an element in the constructor to accept an iframe's contentDocument property (e.g. this.myIframe.nativeElement.contentDocument).

While not the official way of doing this, something like this should work:

app.component.ts

import { Idle, DEFAULT_INTERRUPTSOURCES } from "@ng-idle/core";

export class AppComponent {
  ...

  loadFrame() {
    this.myPageIFrame.nativeElement.addEventListener('load', () => {
      const el = this.myPageIFrame.nativeElement.contentDocument;
      this.setInterruptSource(el);
    });
  }

  unloadFrame() {
    // clean-up iframe
    this.setInterruptSource(); // resets back to initial interrupt(s) without the custom interrupt for the iframe
  }

  setInterruptSource(elementForInterrupt?: ElementRef): void {
    const interrupts = [ ...DEFAULT_INTERRUPTSOURCES ];

    if (elementForInterrupt) {
      const interrupt = new CustomDocumentInterruptSource(elementForInterrupt);
      interrupts.push(interrupt);
    }

    this.idle.stop(); // stop watchers
    this.idle.setInterrupts(interrupts);
    this.idle.watch(); // restart watchers with new interrupt(s)
  }
}

This will create an instance of CustomDocumentInterruptSource with the iframe's contentDocument. It will stop the idle watchers, set the interrupts (including new interrupt(s), and then restart the watchers (I'm not clear if you have to stop and then start, or just re-call start).

CustomDocumentInterruptSource.ts

import { EventTargetInterruptSource, EventTargetInterruptOptions } from "@ng-idle/core";
import { ElementRef } from "@angular/core";

/*
 * Custom interrupt source that uses events on the document element (html tag).
 *
 * This has been modeled after DocumentInterruptSource that hardocdes `document.documentElement`
 * as the first argument. We may need to create a custom interrupt from the document of another frame
 * other than the document on window.
 * 
 * Original source for DocumentInterruptSource: https://github.com/HackedByChinese/ng2-idle/blob/master/modules/core/src/documentinterruptsource.ts
 */
class CustomDocumentInterruptSource extends EventTargetInterruptSource {
  constructor(el: ElementRef, events: string = DEFAULT_EVENTS, options?: number | EventTargetInterruptOptions) {
    super(el, events, options);
  }

  /*
   * Checks to see if the event should be filtered.
   * @param event - The original event object.
   * @return True if the event should be filtered (don't cause an interrupt); otherwise, false.
   */
  filterEvent(event: any): boolean {
    // some browser bad input hacks
    if (event.type === 'mousemove'
      // fix for Chrome destop notifications
      && ((event.originalEvent && event.originalEvent.movementX === 0 &&
        event.originalEvent.movementY === 0)
        // fix for webkit fake mousemove
        || (event.movementX !== void 0 && !event.movementX || !event.movementY))) {
      return true;
    }

    return false;
  }
}

const DEFAULT_EVENTS: string = 'mousemove keydown DOMMouseScroll mousewheel mousedown touchstart touchmove scroll';
export default CustomDocumentInterruptSource;
sdvivas commented 2 years ago

Hi, I'm just beginning So do you have the main code for this example?? I wanna to use IDLE with Iframes

npandu commented 2 years ago

I tried with @benbabics solution. It's adding the the custom source into exiting one. But it's not working. I think some small changes have to be made.