Stop x-tags from capturing focus/blur events

烈酒焚心 提交于 2019-12-14 03:19:11

问题


I am trying to create a custom element which wraps tinyMCE functionality.

I have the following:-

(function(xtag) {
    xtag.register('x-tinymce', {
        lifecycle:{
            created: tinymceCreate,
            removed: tinymceDestroy
        },
        accessors: {
            disabled: {
                attribute: {
                    boolean: true
                },
                get: getDisabledAttribute,
                set: setDisabledAttribute
            }
        }
    });    
    function tinymceCreate(){
        var textarea = document.createElement('textarea');
        var currentElement = this;
        currentElement.textAreaId = xtag.uid();
        textarea.id = currentElement.textAreaId;
        currentElement.appendChild(textarea);
        currentElement.currentMode = 'design';
        var complexConfig = {
             selector: '#' + currentElement.textAreaId,
             setup: editorSetup
        }
        tinymce.init(complexConfig)
               .then(function thenRetrieveEditor(editors) {
                    currentElement.currentEditor = editors[0];
                    currentElement.currentEditor.setMode(currentElement.currentMode ? currentElement.currentMode :  'design');
        });    
        function editorSetup(editor) {
            editor.on('blur', function blur(event) {
                editor.save();
                document.getElementById(editor.id).blur();
                xtag.fireEvent(currentElement, 'blur', { detail: event, bubbles: false, cancellable: true });
            });
            editor.on('focus', function focus(event) {
                xtag.fireEvent(currentElement, 'focus', { detail: event, bubbles: false, cancellable: true });
            });
            editor.on('BeforeSetContent', function beforeSetContent(ed) {
                if (ed.content) 
                    ed.content = ed.content.replace(/\t/ig, '    ');
            });
        }
    }

    function tinymceDestroy() {
        if (this.currentEditor)
            tinymce.remove(this.currentEditor);
    }

    function getDisabledAttribute() {
        return this.currentMode === 'readonly';
    }

    function setDisabledAttribute(value) {
        if (value) {
            this.currentMode = 'readonly';
        }
        else {
            this.currentMode = 'design';
        }
        if (this.currentEditor) {
            this.currentEditor.setMode(this.currentMode);
        }
    }
})(xtag);

Now, when I register a blur event, it does get called, but so does the focus event. I think that this is because focus/blur events are captured by x-tag by default. I don't want it to do that. Instead, I want these events fired when the user focusses/blurs tinymce.

I am using xtags 1.5.11 and tinymce 4.4.3.

Update 1

OK, the problem is when I call:-

xtag.fireEvent(currentElement, 'focus', { detail: event, bubbles: false, cancellable: true });

This caused the focus to be lost on the editor and go to the containing eleemnt (x-tinymce). To counter this, I modified my editorSetup to look like this:-

   function editorSetup(editor) {
        // // Backspace is not detected in keypress, so need to include keyup event as well.
        // editor.on('keypress change keyup focus', function(ed) {
        //     $j("#" + editor.id).trigger(ed.type);
        // });
        var isFocusFromEditor = false;
        var isBlurFromEditor = false;
        editor.on('blur', function blurEvent(event) {
            console.log("blurred editor");
            if (!isFocusFromEditor) {
                editor.save();
                xtag.fireEvent(currentElement, 'blur', { detail: event, bubbles: false, cancellable: false });
            }
            else {
                console.log('refocussing');
                isFocusFromEditor = false;
                editor.focus();
                isBlurFromEditor = true;
            }

        });
        editor.on('focus', function focusEvent(event) {
            console.log("Focus triggered");
            isFocusFromEditor = true;
            xtag.fireEvent(currentElement, 'focus', { detail: event, bubbles: false, cancellable: false });
        });
        editor.on('BeforeSetContent', function beforeSetContent(ed) {
            if (ed.content) {
                ed.content = ed.content.replace(/\t/ig, '    ');
            }
        });
    }

This stops the blur event from triggering, unfortuantely, now, the blur event does not get called when you leave the editing area.

This feels like a tinyMCE problem, just not sure what.


回答1:


Here is a solution that catches focus and blur events at the custom element level.

It uses the event.stopImmediatePropagation() method to stop the transmission of the blur event to other (external) event listeners when needed.

Also, it uses 2 hidden <input> (#FI and #FO) controls in order to catch the focus when the tab key is pressed.

document.registerElement('x-tinymce', {
  prototype: Object.create(HTMLElement.prototype, {
    createdCallback: {
      value: function() {
        var textarea = this.querySelector('textarea')
        var output = this.querySelector('output')
        output.textContent = "state"
        var self = this
        self.textAreaId = this.dataset.id // xtag.uid();
        textarea.id = self.textAreaId
        var complexConfig = {
          selector: '#' + self.textAreaId,
          setup: editorSetup,
        }

        var FI = this.querySelector('#FI')
        FI.addEventListener('focus', function(ev) {
          if (ev.relatedTarget) {
            var ev = new FocusEvent('focus')
            self.dispatchEvent(ev)
          } else {
            var ev = new FocusEvent('blur')
            self.dispatchEvent(ev)
            focusNextElement(-1)
          }
        })

        var FO = this.querySelector('#FO')
        FO.addEventListener('focus', function(ev) {
          if (!ev.relatedTarget) {
            var ev = new FocusEvent('blur')
            self.dispatchEvent(ev)
            focusNextElement(1)
          } else {
            var ev = new FocusEvent('focus')
            self.dispatchEvent(ev)
          }
        })


        var focused = false

        this.addEventListener('focus', function(ev) {
          console.log('{focus} in ', this.localName)
          if (!focused) {
            focused = true
            output.textContent = focused
            self.editor.focus()								
          } else {
            console.error('should not be here')
            ev.stopImmediatePropagation()
          }
        })

        this.addEventListener('blur', function(ev) {
          console.log('{blur} in %s', this.localName)
          if (focused) {
            focused = false
            output.textContent = focused
          } else {
            console.log('=> cancel blur')
            ev.stopImmediatePropagation()
          }
        })

        tinymce.init(complexConfig).then(function(editors) {
          //self.currentEditor = editors[0]
        })

        //private 

        function focusNextElement(diff) {
          //add all elements we want to include in our selection
          var focussableElements = 'a:not([disabled]), button:not([disabled]), input[type=text]:not([disabled]), [tabindex]:not([disabled]):not([tabindex="-1"])'
          if (document.activeElement) {
            var focussable = Array.prototype.filter.call(document.querySelectorAll(focussableElements), function(element) {
              //check for visibility while always include the current activeElement 
              return element.offsetWidth > 0 || element.offsetHeight > 0 || element === document.activeElement
            })
            var index = focussable.indexOf(document.activeElement)
            focussable[index + diff].focus()
          }
        }

        function editorSetup(editor) {
          console.warn('editor setup')
          self.editor = editor

          editor.on('focus', function(event) {
            if (!focused) {
              var ev = new FocusEvent('focus')
              self.dispatchEvent(ev)
            }
          })

          editor.on('blur', function(event) {
              //if ( focused ) 
              {
                var ev = new FocusEvent('blur')
                self.dispatchEvent(ev)
              }
          })
        }
      }
    },
    detachedCallback: {
      value: function() {
        if (this.editor)
          tinymce.remove(this.editor)
      }
    }
  })
})

var xElem = document.querySelector('x-tinymce')
xElem.addEventListener('focus', function(ev) {
  console.info('focus!')
})
xElem.addEventListener('blur', function(ev) {
  console.info('blur!')
})
<script src="http://cdn.tinymce.com/4/tinymce.min.js"></script>
<input type="text">
<x-tinymce data-id="foo">
  <output id=output></output>
  <input type=text id=FI style='width:0;height:0;border:none'>
  <textarea>content</textarea>
  <input type=text id=FO style='width:0;height:0;border:none'>
</x-tinymce>
<input type="text">


来源:https://stackoverflow.com/questions/39939211/stop-x-tags-from-capturing-focus-blur-events

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!