1class LoadTree { 2 static SERVICE_API_PATH = "https://service.canonizer.com/api/v1/tree/get"; 3 static CSS_URL = "https://canonizer3.canonizer.com/embed/embed.css"; 4 static API_PATH = "https://api3.canonizer.com/api/v3/embedded-code-tracking"; 5 6 static IP_API = "https://api.ipify.org?format=json"; 7 8 static async init(params) { 9 const { selector, topic_num, camp_num } = params; 10 11 const asofdate = new Date().getTime(), 12 algorithm = "blind_popularity"; 13 14 const tree = await this.getTree(topic_num, camp_num, asofdate, algorithm); 15 16 const elm = document.querySelector(selector); 17 18 if (elm) elm.innerHTML = tree; 19 20 this.expandParent(elm); 21 const session = await sessionStorage.getItem("created_at"); 22 if (!session) this.saveUserAgent(); 23 } 24 25 static async getTree(topic_num, camp_num, asofdate, algorithm) { 26 const reqBody = { 27 topic_num, 28 camp_num, 29 algorithm, 30 asofdate, 31 update_all: 1, 32 asOf: "default", 33 fetch_topic_history: null, 34 }, 35 option = { 36 method: "POST", 37 body: JSON.stringify(reqBody), 38 headers: { 39 Accept: "application/json", 40 "Content-Type": "application/json", 41 }, 42 }; 43 44 const res = await fetch(LoadTree.SERVICE_API_PATH, option); 45 const resData = await res.json(); 46 47 if (res.status === 200) { 48 const generatedTree = await this.renderTreeNodes( 49 "", 50 resData?.data?.at(0), 51 camp_num 52 ); 53 const temp = `<html lang="en"><head><link href="https://cdnjs.cloudflare.com/ajax/libs/ionicons/2.0.1/css/ionicons.css" rel="stylesheet" type="text/css" /><link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Asap:wght@400;500;600;700&display=swap" rel="stylesheet"><link rel="stylesheet" type="text/css" href="${LoadTree.CSS_URL}" /></head><body><nav class="tree-nav">${generatedTree}</nav></body></html>`; 54 55 return temp; 56 } 57 return "Something went wrong!"; 58 } 59 60 static renderTreeNodes(prevNodes = "", data, camp_num, idx) { 61 let sortedData = Object.keys(data) 62 .map((key) => [Number(key), data[key]]) 63 .sort((a, b) => b[1].score - a[1].score); 64 65 let nodes = "", 66 index = idx || 0; 67 68 sortedData.forEach((itemWithData) => { 69 let item = itemWithData[0]; 70 71 if (data[item].children) { 72 nodes += `<details class="tree-nav__item ${ 73 data[item].children?.length == 0 ? "is_empty" : "is-expandable" 74 } ${+data[item].camp_id === +camp_num ? "need_parent_expand" : ""}" ${ 75 index === 0 || +data[item].camp_id === +camp_num ? "open" : "" 76 } ><summary class="tree-nav__item-title"><a class="tree-nav__item-title" href="${ 77 data[item].link 78 }" id="camp-${data[item].camp_id}">${ 79 data[item]?.title 80 } <span class="scroe">${parseFloat(data[item].score)?.toFixed( 81 2 82 )}</span></a></summary>`; 83 index++; 84 nodes += LoadTree.renderTreeNodes( 85 prevNodes, 86 data[item].children, 87 camp_num, 88 index 89 ); 90 nodes += `</details>`; 91 } else { 92 index++; 93 nodes += `<a class="tree-nav__item-title" href="${ 94 data[item].link 95 }" id="camp-${data[item].camp_id}">${ 96 data[item]?.title 97 } <span class="scroe">${parseFloat(data[item].score)?.toFixed( 98 2 99 )}</span></a>`; 100 } 101 }); 102 103 return nodes; 104 } 105 106 static async expandParent(elm) { 107 const child = elm.querySelector(".need_parent_expand"); 108 109 if (child) { 110 let parent = child.parentNode; 111 112 while (parent) { 113 if (parent?.tagName?.toLowerCase() === "details") { 114 if (!parent.hasAttribute("open")) { 115 parent.setAttribute("open", ""); 116 } 117 } 118 parent = parent.parentNode; 119 } 120 } 121 } 122 123 static async saveUserAgent() { 124 const josnRes = await fetch(LoadTree.IP_API), 125 ipRes = await josnRes.json(), 126 reqBody = { 127 url: window.location.href, 128 ip_address: ipRes.ip, 129 user_agent: navigator.userAgent, 130 }, 131 option = { 132 method: "POST", 133 body: JSON.stringify(reqBody), 134 headers: { 135 Accept: "application/json", 136 "Content-Type": "application/json", 137 }, 138 }; 139 140 const res = await fetch(LoadTree.API_PATH, option); 141 const resData = await res.json(); 142 143 if (res.status === 200) { 144 sessionStorage.setItem( 145 "created_at", 146 JSON.stringify(resData.data.created_at) 147 ); 148 } 149 } 150}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.