nnnjjj123
2020-11-17 1b2c1edb61190eeb19f465ff031eaa3b2a1b8dbc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/* A minimal version of put-selector, to be used for standalone */
    var selectorParse = /(?:\s*([-+ ,<>]))?\s*(\.|!\.?|#)?([-\w%$|]+)?(?:\[([^\]=]+)=?['"]?([^\]'"]*)['"]?\])?/g,
        ieCreateElement = typeof doc.createElement == "object"; // telltale sign of the old IE behavior with createElement that does not support later addition of name 
    function insertTextNode(element, text){
        element.appendChild(doc.createTextNode(text));
    }
    function put(referenceElement, selector, text){
        var fragment, lastSelectorArg, nextSibling, current = referenceElement,
            args = arguments,
            returnValue = args[0]; // use the first argument as the default return value in case only an element is passed in
        function insertLastElement(){
            // we perform insertBefore actions after the element is fully created to work properly with 
            // <input> tags in older versions of IE that require type attributes
            //    to be set before it is attached to a parent.
            // We also handle top level as a document fragment actions in a complex creation 
            // are done on a detached DOM which is much faster
            // Also if there is a parse error, we generally error out before doing any DOM operations (more atomic) 
            if(current && referenceElement && current != referenceElement){
                referenceElement.
                                insertBefore(current, nextSibling || null); // do the actual insertion
            }
        }
                lastSelectorArg = true;
                var leftoverCharacters = selector.replace(selectorParse, function(t, combinator, prefix, value, attrName, attrValue){
                    if(combinator){
                        // insert the last current object
                        insertLastElement();
                        if(combinator == '-' || combinator == '+'){
                            // + or - combinator, 
                            // TODO: add support for >- as a means of indicating before the first child?
                            referenceElement = (nextSibling = (current || referenceElement)).parentNode;
                            current = null;
                            if(combinator == "+"){
                                nextSibling = nextSibling.nextSibling;
                            }// else a - operator, again not in CSS, but obvious in it's meaning (create next element before the current/referenceElement)
                        }else{
                            if(combinator == "<"){
                                // parent combinator (not really in CSS, but theorized, and obvious in it's meaning)
                                referenceElement = current = (current || referenceElement).parentNode;
                            }else{
                                if(combinator == ","){
                                    // comma combinator, start a new selector
                                    referenceElement = topReferenceElement;
                                }else if(current){
                                    // else descendent or child selector (doesn't matter, treated the same),
                                    referenceElement = current;
                                }
                                current = null;
                            }
                            nextSibling = 0;
                        }
                        if(current){
                            referenceElement = current;
                        }
                    }
                    var tag = !prefix && value;
                    if(tag || (!current && (prefix || attrName))){
                        // Need to create an element
                        tag = tag || put.defaultTag;
                        var ieInputName = ieCreateElement && args[i +1] && args[i +1].name;
                        if(ieInputName){
                            // in IE, we have to use the crazy non-standard createElement to create input's that have a name 
                            tag = '<' + tag + ' name="' + ieInputName + '">';
                        }
                        // we swtich between creation methods based on namespace usage
                        current = doc.createElement(tag);
                    }
                    if(prefix){
                        if(prefix == "#"){
                            // #id was specified
                            current.id = value;
                        }else{
                            // we are in the className addition and removal branch
                            var currentClassName = current.className;
                            // remove the className (needed for addition or removal)
                            // see http://jsperf.com/remove-class-name-algorithm/2 for some tests on this
                            var removed = currentClassName && (" " + currentClassName + " ").replace(" " + value + " ", " ");
                            if(prefix == "."){
                                // addition, add the className
                                current.className = currentClassName ? (removed + value).substring(1) : value;
                            }
                        }
                    }
                    if(attrName){
                        var method = attrName.charAt(0) == "!" ? (attrName = attrName.substring(1)) && 'removeAttribute' : 'setAttribute';
                        attrValue = attrValue === '' ? attrName : attrValue;
                        // determine if we need to use a namespace
                        current[method](attrName, attrValue);
                    }
                    return '';
                });
                insertLastElement();
                if(text){
                    insertTextNode(current, text);
                }
                return current;
            }