GetmeUK / ContentTools

A JS library for building WYSIWYG editors for HTML content.
http://getcontenttools.com
MIT License
3.96k stars 398 forks source link

Request to create a universal drop handler. #265

Open bfintal opened 8 years ago

bfintal commented 8 years ago

From what I understand, the droppers parameter are used when they match the key. I would like to request a wildcard parameter to match all elements (unless there's a more specific one given).

Something like this:

// Dropper for all elements
MyElement.droppers = {
    '*': MyElement._someDropHandler
};

MyElement._someDropHandler = function( element, target, placement ) {
    // ...
};

Or:

// Dropper for all static elements, then for all others.
MyElement.droppers = {
    'Static': ContentEdit.Element._dropVert,
    '*': MyElement._someDropHandler
};

MyElement._someDropHandler = function( element, target, placement ) {
    // ...
};
anthonyjb commented 8 years ago

Sure - shouldn't be a big change. Can you provide an example case for this, just so I have something to play around with when implementing (even if it's only the concept of what it will be used for).

bfintal commented 8 years ago

I have a Tabs element that's a bit complex and is composed of multiple elements. For example, for an empty 2 tab element, I'd end up with an element with the following element structure:

Tabs
    TabContainer
        Tab
        Tab
    TabPanelContainer
        Panel
        Panel

Each Tab can be dragged onto one another to switch them around. But for the TabContainer itself, I'd like everything to bypass it completely and instead of having items dropped in it, items would drop around the main Tabs element. The * dropper is currently implemented in the TabContainer element.

Here's how I implemented it via patching:

/**
 * Allow `*` droppers.
 */
( function() {
   var proxied = ContentEdit.Element.prototype.drop;
   ContentEdit.Element.prototype.drop = function( element, placement ) {
        var root = ContentEdit.Root.get();
        if ( element && typeof element.type !== 'undefined' ) {
            if ( ! this.constructor.droppers[ element.type() ] && ! element.constructor.droppers[ this.type() ] && element.constructor.droppers['*'] ) {
                element._removeCSSClass( 'ce-element--drop' );
                element._removeCSSClass( 'ce-element--drop-' + placement[0] );
                element._removeCSSClass( 'ce-element--drop-' + placement[1] );
                element.constructor.droppers['*']( this, element, placement );
                root.trigger( 'drop', this, element, placement );
                return;
            }
        }
        return proxied.call( this, element, placement );
    };
} )();
( function() {
   var proxied = ContentEdit.Element.prototype._onOver;
    ContentEdit.Element.prototype._onOver = function(ev) {
        var ret = proxied.call( this, ev );
        if ( ! ret ) {

            var root = ContentEdit.Root.get();
            var dragging = root.dragging();
            if ( ! dragging ) {
                return;
            }
            if ( dragging === this ) {
                return;
            }
            if ( root._dropTarget ) {
                return;
            }
            if ( this.constructor.droppers['*'] ) {
                this._addCSSClass( 'ce-element--drop' );
                return root._dropTarget = this;
            }
        }
        return ret;
    };
} )();