[Vanilla JS] VanillaJS로 구현한 AJAX

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
export const parseJSXstr = (parent, JSXstr) => {
    const processedJSXstr = preprocessJSXstr(JSXstr)
    const result = generateObject(processedJSXstr, 0)
    const generatedJSXobj = result.JSXobj
    parseJSXobj(parent, generatedJSXobj)
}

const parseJSXobj = (parent, JSXobj) => {
    const ignorePropertyList = ["type", "children"]
    
    const $element = document.createElement(JSXobj.type)
    // Handle properties that need to be added to the element
    for (let prop in JSXobj){
        if(!ignorePropertyList.includes(prop))
            $element[matchPropName(prop)] = JSXobj[prop]
    }
    // Handle children elements
    if("children" in JSXobj){
        JSXobj.children.forEach((childElem, index) => {
            parseJSXobj($element, childElem)
        })
    }
    parent.appendChild($element)
}

const stripString = (str) => {
    return str.replace(/^\s+|\s+$/g, '');
};

const matchPropName = (prop) => {
    const substituteReacttoVanilla = {
        text: "textContent",
        onClick: "onclick"
    }
    if(prop in substituteReacttoVanilla)
        return substituteReacttoVanilla[prop]
    else
        return prop
}

const preprocessJSXstr = (JSXstr) => {
    const splitStr = JSXstr.split('<')
    return splitStr
    .filter(str => {
        //Handle empty string elements
        if(!stripString(str))
            return false
        return true
    })
    .map(str => {
        return stripString(str)
    })
}

const generateObject = (arr, checkIndex) => {
    let obj = { children: [] }
    let generatedObj
    //Found Closing Tag
    if(arr[checkIndex][0] == '/'){
        return {
            nextCheckIndex: checkIndex + 1,
            JSXobj: null
        }
    }
    //If not starting with closing tag
    else {
        generatedObj = generateObject(arr, checkIndex+1)
        //loop until my closing tag appears
        while(true){
            //return from children element
            if(generatedObj.JSXobj != null){
                obj.children.push(generatedObj.JSXobj)
                generatedObj = generateObject(arr, generatedObj.nextCheckIndex)
            }
            //return from closing tag
            else
                break
        }
    }

    let element = arr[checkIndex]

    //Cut out onClick function string
    const searchTermStart = " onClick"
    const startIndex = element.indexOf(searchTermStart)
    if(startIndex !== -1){
        const searchTermEnd = "}"
        const endIndex = element.lastIndexOf(searchTermEnd)
        
        //Assign onclick
        const tempFuncStr = element.slice(startIndex,endIndex)
        const funcStartIndex = tempFuncStr.indexOf("{")
        obj.onclick = eval(tempFuncStr.slice(funcStartIndex+1, endIndex))

        const tempElement = element.slice(0, startIndex) + element.slice(endIndex+1,element.length)
        element = tempElement
    }

    const elementContent = element.split('>')
    obj.text = elementContent[1]

    const elementProps = elementContent[0].split(' ')
    elementProps.forEach((prop, index) => {
        if(index === 0)
            obj.type = prop
        else{
            //split prop name and value
            const splitProp = prop.split('=')
            const propName = splitProp[0]
            const propValue = splitProp[1].replace(/"/g,"").replace(/'/g,"")
            obj[propName] = propValue
        }
    })
    return {
        nextCheckIndex: generatedObj.nextCheckIndex,
        JSXobj: obj
    }
}