Search code examples
javascriptjquerywymeditorwysiwym

How to manually execute WYMeditor function w/o errors?


For debug, watch jquery.wymeditor.js.

I need to execute commands like "Strong", "Indent", etc. from my custom toolbar (to be precise, ribbon) via JavaScript and without errors. 80% are done, I can execute commands, but have a strange error.

So, what I do, when document is ready (with contained textarea "#doc"):

myDoc = $("#doc").wymeditor()[0];
myDoc_wym = $.getWymeditorByTextarea(myDoc);

setTimeout(function() {
    console.log(myDoc_wym._iframe.contentWindow); // contentWindow returns proper Window object of editor IFrame
    $(myDoc_wym._doc).keydown(function(e) {
        if (e.which == 112) {
            console.log(myDoc_wym); // must return extended jQuery editor object
            myDoc_wym.__proto__._exec("Strong"); // BREAKPOINT
            console.log("It might be done!"); // no luck today
            return false;
        }
    });
}, 1000); // to be sure, that myDoc_wym._doc exists, I just enforced timeout
  1. WYMeditor on half way to be fully prepared.
  2. Get its extended editor object with getWymeditorByTextarea.
  3. Wait a second.
  4. Log Window object of editor's IFrame.
  5. When we press F1:

    1. Log myDoc_wym.
    2. myDoc_wym.__proto__._exec("Strong"); - execute prototyped function _exec with command "Strong"...

Here goes a crash of keydown. What I get in Chromium (above last released NW.JS) console:

Whole log

Error is caused in prototyped function hasSelection. So, it's saying that _iframe is undefined in that code:

WYMeditor.editor.prototype.hasSelection = function () {
    var wym = this;

    if (
        // `isSelectionValid` is undocumented in current Rangy (`1.2.2`).
        // It seems to be required because the `rangeCount` in `IE <= 8` seems
        // to be misleading.
        rangy.isSelectionValid(wym._iframe.contentWindow) !== true
    ) {
        return false;
    }

    if (wym.selection().rangeCount === 0) {
        return false;
    }

    return true;
};

After this tried to enable my own call for this function by pasting in console input similar code, but with debug needs (console.log(wym);):

WYMeditor.editor.prototype.hasSelection = function () {
    var wym = this;
    console.log(wym);
    //console.log(wym._iframe);
    //console.log(wym._iframe.contentWindow);
    if (rangy.isSelectionValid(wym._iframe.contentWindow) !== true) return false;
    if (wym.selection().rangeCount === 0) return false;
    return true;
};

Pressing F1: Playing with custom function

  1. First object is what I get before executing WYMeditor command.
  2. Second has no _iframe, so it's returning undefined.
  3. Accordingly, cannot read from undefined.
  4. It seems like hasSelection is called twice (for example, selectedContainer, that calls hasSelection, may be called 3 times by _exec). At this time we see _iframe, but it isn't longer needed.

It turns out that:

  1. at first time hasSelection called, wym returned as prototyped object, but...
  2. at second time wym returned as full "editor object" with needed properties (such as _iframe).

Weird object

Something weird going up there and I don't know what. When pressing on default toolbar buttons all works perfectly.


Solution

  • Use only public API

    Here (a bit too tucked away for my taste) are the docs for WYMeditor's public API.

    Interact with WYMeditor only through what's documented there, if possible.

    If you use private methods/properties, we couldn't reasonably support that use.

    If a property/method starts with an underscore, it is private.

    What you're trying to do

    Please rewrite your implementation using the public API.

    You'll find combokeys and exec (not _exec) useful for what it seems to me you're trying to achieve.