开发者

Firefox's onInput with contentEditable inside a <span> isn't working

开发者 https://www.devze.com 2023-03-01 00:17 出处:网络
I\'ve been fooling around with onInput and contentEditable, trying to make a script that would automatically show the sum of some math. Part of the concept was to have the input grow as the user typed

I've been fooling around with onInput and contentEditable, trying to make a script that would automatically show the sum of some math. Part of the concept was to have the input grow as the user typed, which I found to work very well with a <span> tag using contentEditable. Most of the testing I did was on Google Chrome, and it seems to work there, but the 开发者_开发知识库onInput doesn't seem to work in Firefox (4.0). onKeyUp works in Firefox however, but isn't instant as onInput.

<div id="f">
    <span oninput="go()" id="p" class="x" contenteditable="true">0
    </span>
    % of
    <span oninput="go()" id="n" class="x" contenteditable="true">0
    </span>
    =
    <span id="r" class="x" contenteditable="true">0
    </span>
    <p id="a"></p>
</div>

function go() {
    p = document.getElementById('p').innerHTML;
    n = document.getElementById('n').innerHTML;
    r = document.getElementById('r');
    a = document.getElementById('a');
    r.innerHTML = p / 100 * n;
    a.innerHTML = p + "% of " + n + " equals " + p / 100 * n;
}

Have a look at the script over at jsFiddle.

Thanks.


The input event isn't supported for contenteditable in Firefox. It's likely it will be in future, but for now, you'll have to make do with the more clunky method of intercepting various other events. Your options are a combination of keypress, keyup, mouseup, paste, cut and copy, or more simply if you can ignore IE <= 8, DOM mutation events. Intercepting DOMNodeInserted, DOMNodeRemoved and DOMCharacterDataModified should do the trick:

document.addEventListener("DOMNodeInserted", go, false);
document.addEventListener("DOMNodeRemoved", go, false);
document.addEventListener("DOMCharacterDataModified", go, false);

One thing you need to be aware of is that in WebKit, DOM mutation events are asynchronous for editable content.


I realize that this is no longer an issue for known html elements, however, this is still a very real issue for elements that have no oninput method associated with them like custom elements (e.g. <cstm></cstm>). Yes, I know there is a right way to create such user-defined elements and this is not it, but in any event, the following works and may be beneficial for known HTML elements in really old browsers.

I've written a little code that can be used with any element. It takes advantage of event delegation and keeps track of events that are registered for elements. Simply include the following JavaScript in your page.

/*-----------------------------------------------------------------------------------*/
/*------------------- code to add document-level event delegation -------------------*/
/*-----------------------------------------------------------------------------------*/
// create an array for storing events
var documentLevelEvents = [];

// add a new delegated document-level listener function to all objects of type Element
Element.prototype.addDocumentLevelEventListener = function (eventType, fn) {
    // get a count of registered document-level event listeners for a given event type
    function documentLevelEventListenerCount(eventType) {
        var eventCount = documentLevelEvents.filter(e => {
            return e.eventType === eventType;
        }).length;
        return eventCount;
    }

    // filter the documentLevelEvents array and return only those that match the 
    // specified element and eventType
    function getDocumentLevelEvents(element, eventType) {
        var events = documentLevelEvents.filter(function (e) {
            return e.element === element && e.eventType === eventType;
        });
        return events;
    }

    // grab the count of listeners registered for this event type before registering
    // the submitted event
    var listenerExists = documentLevelEventListenerCount(eventType);

    // register the new document-level event listener
    documentLevelEvents.push({
        eventType: eventType,
        element: this,
        fn: fn
    });

    // if the document object does not already have a listener for this event type,
    // create a new event listener on the document object.
    if (!listenerExists) {
        document.addEventListener(eventType, function (evt) {
            var target = evt.target;

            // get an array of all registered events matching the target element
            // and the triggered event type
            var events = getDocumentLevelEvents(target, eventType);
            // iterate through the array and run the registered listener functions
            for (var i = 0; i < events.length; ++i) {
                event = events[i];
                event.fn(evt);
            }
        });
    }
};

/*-----------------------------------------------------------------------------------*/
/*---------------------------------- example usage ----------------------------------*/
/*-----------------------------------------------------------------------------------*/
element = document.getElementById('#element-id');
element.addDocumentLevelEventListener('input', ()=>{console.log('innerText changed!')})
// anytime the text of the element changes on account of input, a notice will be logged
// to console.

What's happening here? We've added a new function to all objects of type Element (or those that extend Element). This function creates a delegated event listener that uses the document object to listen for events. To ensure that our event is limited to the elements specified, we keep track of all registered events in the documentLevelEvents array. When one of our registered document listeners hears an event, it checks the array of events to see if it matches one or more registered element/event bindings. For every match it finds, it runs the function that was passed to the addDocumentLevelListener function, passing along the event.

Here's a jsfiddle that shows it in action.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号