javascriptjquerysizzle

Most efficient way to create an element from any jquery selector string


What I need to do

I would like to create an element that matches any selector string

Quick example.

var targetString = "a.exaggerated#selector[data-myattr='data-here']";
var targetEl = $(targetString);

if(!targetEl.length){

    var newEl = //create target
    $(body).append(newEl);
}

output

<body>
    <a class="exaggerated" id="selector" data-myattr="date-here"></a>
</body>

why

I have buttons which when clicked do different tasks depending on its data-attributes. One of which is a data-target. I would like the ability to use ANY sizzlejs/jquery selector as the target, and if no target elements exist in the dom then create it. e.g.

<button data-create-target="true" data-target=".mytarget">clickme</button> <button data-create-target="true" data-target="a.[data-type='popup']">clickme</button>


I'm hoping that there is a way to use jquery's selector engine to do this because analysing the selector string again and extracting its attributes seems very long winded.

Many thanks


Solution

  • Ive created a plugin to solve the problem.

    $("a.exaggerated#selector[data-myattr='data-here']").create().appendTo('body');
    

    jquery version 2.1.1 and obove is required to access the $.find.tokenize method

    $.fn.create = function( elem, dataAndEvents, deepDataAndEvents ) { 
    
        if(this.length){
    
            return $(this).clone( elem, dataAndEvents, deepDataAndEvents );
    
        } else {
    
        var selector = this.selector;
            var rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/;
            var match, elem, m;
    
            if(!selector){
                return $(document.createElement('div'));
            } 
            if(match = rquickExpr.exec( selector )){
    
                if ( match[2] ) {
                    return $(document.createElement(selector));
                } else {
    
                    var elem = document.createElement('div');
                    if ( (m = match[1]) ) {             
                        elem.id = m;            
                    } else if ( (m = match[3])) {
                        elem.className = m ; 
                    }
                    return $(elem);
                }
            }
            selector = selector.replace( rtrim, "$1" );
            match = $.find.tokenize(selector);
    
            if ( match.length === 1 ) {
    
                var attrs = '';
                var tag = 'div';
                var classList = [];
                var type, value, matches;
                var tokens = match[0] = match[0].slice( 0 );
    
                for (var i = 0; i < tokens.length; i++) {
    
                    type = tokens[i].type;
                    value = tokens[i].value
                    matches = tokens[i].matches;
    
                    if ( type === "ID" ){
                        attrs += 'id="' + matches[0] + '" ';
                        continue;
                    }
                    else if ( type === "CLASS" ){
                        classList.push(matches[0]+matches[1]+matches[2]);
                        continue;
                    }
                    else if ( type === "TAG" ){
                        tag = matches[0];
                        continue;
                    }
                    else if ( type === "ATTR" ){
                        attrs += matches[0]+ (matches[1] ? matches[1] : '' ) + (matches[2] ? '"' + matches[2] + '"': '' )+ ' ';
                    }
                    else if ( type === "PSEUDO" ){
    
                    }
                    else if ( type === "CHILD" ){
    
                    } 
                };
    
                if(classList.length){
                    attrs += 'class="';
                    for (var i = 0; i < classList.length; i++) {
                         attrs +=  classList[i] + ' ';
                    };
                    attrs += '"';
                }
                return $('<' + tag + ' ' + attrs + '></' + tag + '>');
            }
            return $(document.createElement('div'));
        }
    }