阻止x-tag捕获焦点/模糊事件

时间:2016-10-09 01:58:39

标签: web-component tinymce-4 x-tag

我正在尝试创建一个包含tinyMCE功能的自定义元素。

我有以下内容: -

(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);

现在,当我注册一个模糊事件时,它会被调用,但焦点事件也是如此。我认为这是因为默认情况下x-tag会捕获焦点/模糊事件。我不希望它那样做。相反,我希望在用户关注/模糊tinymce时触发这些事件。

我正在使用xtags 1.5.11和tinymce 4.4.3。

更新1

好的,问题出在我打电话时: -

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

这导致焦点在编辑器上丢失并转到包含eleemnt(x-tinymce)。为了解决这个问题,我将editorSetup修改为: -

   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, '    ');
            }
        });
    }

这会停止触发模糊事件,但不幸的是,当您离开编辑区域时,不会调用模糊事件。

这感觉就像一个小小的MCE问题,只是不确定是什么。

1 个答案:

答案 0 :(得分:0)

这是一个在自定义元素级别捕获focusblur事件的解决方案。

它使用event.stopImmediatePropagation()方法在需要时停止向其他(外部)事件侦听器传输blur事件。

此外,它还使用了2个隐藏的<input>#FI#FO)控件,以便在按下标签键时捕捉焦点。

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">