1import Local from '/src/local.js' 2import Site from '/src/site.js' 3import Page from '/src/page.js' 4import Template from '/src/template.js' 5import RenderInfo from '/src/renderInfo.js' 6import { getSiteData, getSiteNavData } from '/src/api/site.js' 7 8import Cell from '/src/package/cell.js' 9import { CustomError, lazyBGImg } from '/src/function.js' 10import DesignBox from './design-box.js' 11import { PostMessages } from './messages.js' 12import viewsData from '/dist/template/views-data.js' 13import hooks from '../../src/hooks/index.js' 14class Design { 15 /** 16 * æé 彿° 17 */ 18 constructor() { 19 this.ctx = {} 20 this.oldUnitTypeList = [] 21 this.$loading = document.getElementById('design-loading') 22 } 23 /** 24 * å便¨¡å¼ 25 */ 26 static ins() { 27 if (!this.instance) return this.instance = new Design() 28 return this.instance 29 } 30 31 /** 32 * åå§åè¦è°çåç§æ¹æ³ 33 */ 34 async init() { 35 // åå§åwindow.renderInfoä¿¡æ¯1 36 window.app.info.site.site_domain = Utilts.ins().getCookie('domain') 37 window.app.info.server.visitorIp = '127.0.0.1' 38 // åå§åctx 39 await this.initCtx() 40 // ejs 41 await new Load('/assets/plugins/ejs.min.js') 42 // 妿æ¯å°iframeï¼çå¾ ç¶çªå£ä¼ å ¥æ°æ®ååç»§ç» 43 if (this.ctx.query.render && !this.ctx.state.postCtxState) { 44 await new Promise(resolve => window.addEventListener('receiveCtxState', () => resolve())) 45 } 46 // åå§åè£ ä¿® 47 await this.initDesign() 48 // ææææ°æ®ä¼ ç»å¤é¨ 49 if (!this.ctx.query.render) PostMessages.ins().initDesignData(this.ctx.state) 50 // ä¿®æ¹é¡µé¢page-type ç±»å 51 this.updatePageType() 52 // ç§»é¤loading 53 window.addEventListener('appInitEnd', () => { 54 if (this.$loading) this.$loading.remove() 55 }) 56 } 57 /** åå§å渲æ */ 58 async initDesign() { 59 // æ¿å°æ¬å°é ç½® 60 this.ctx.state.local = await new Local(this.ctx).init() 61 // æ¿å°ç«ç¹æ°æ® 62 this.ctx.state.site = await new Site(this.ctx).init() 63 /** ç¿»è¯æ¹æ³ */ 64 this.ctx.state.$t = text => this.ctx.state.$T ? this.ctx.state.$T.$t(this.ctx.state.site.show_language_code || this.ctx.state.site.language_code, text) : text 65 66 if (this.ctx.state.site.site_id !== 0) { 67 // æ¿å°é¡µé¢æ°æ® 68 const page = new Page(this.ctx) 69 this.ctx.state.page = await page.init() 70 // æ¿å°æ¨¡æ¿æ°æ® 71 this.ctx.state.template = new Template(this.ctx) 72 await this.ctx.state.template.init() 73 74 // 渲æç¨çæ°æ® 75 this.ctx.state.renderInfo = new RenderInfo(this.ctx) 76 } 77 if (this.ctx.state.site.site_id === 0 || this.ctx.state.page.page_type == 404) this.ctx.status = 404 78 79 window.app.info.updata(this.ctx.state.renderInfo) 80 // è·åejsè§å¾çæ°æ® 81 this.viewsData = viewsData 82 83 // 渲æ 84 await this.render('app') 85 } 86 /** 87 * åå§åæ°æ®ï¼å¦ææç°æçæ°æ®ï¼æè®¸ä¸ç¨éæ°è·å 88 */ 89 async initCtx() { 90 // åå§å 91 this.ctx = window.ctx 92 // éå®å 93 this.ctx.custom = { error: CustomError } 94 // è¯·æ±æ¥å£çæ¹æ³ 95 this.ctx.state.request = (ctx, { url, params, method, prefix, stringify, headers }) => { 96 return Utilts.ins().request({ url, params, method, prefix, stringify, headers }) 97 } 98 // éå®åçæ¹æ³ 99 this.ctx.state.redirect = (code, url) => { 100 if (url.indexOf('?') >= 0) url += '&' 101 else url += '?' 102 Object.keys(ctx.query).forEach(key => { 103 if (url.indexOf(`?${key}=`) >= 0 || url.indexOf(`&${key}=`) >= 0) return 104 url += `${key}=${ctx.query[key]}&` 105 }) 106 url = url.substr(0, url.length - 1) 107 window.location.href = url 108 } 109 // cookiesè·åä¸è®¾ç½® 110 this.ctx.cookies = { 111 get(key) { 112 const res = Utilts.ins().getCookie(key) 113 return res 114 }, 115 set(key, value) { 116 const res = Utilts.ins().setCookie(key, value) 117 return res 118 } 119 } 120 this.ctx.state.lazyBGImg = (ctx, thisPackage) => lazyBGImg(ctx, thisPackage) 121 this.ctx.state.$t = text => text 122 } 123 /** 124 * æ¸²ææ¹æ³ï¼ä¼ å ¥idä½ä¸ºæ¸²æçèå´ 125 * @param attr_id packageãid 126 * isRefres æ¯å¦æ¯æ¤æ¶ï¼è¿å 127 */ 128 async render(attr_id, isRefres = false) { 129 let origin_attr_id = attr_id 130 if (this.packages[attr_id]?.hook) { 131 let res = this.packages[attr_id].hook.beforeRender({attr_id, isRefres}) 132 if (!res) return 133 attr_id = res.attr_id 134 isRefres = res.isRefres 135 } 136 137 const element = document.getElementById(attr_id) 138 if (!element) return 139 // è·åæ ·å¼ 140 await this.renderCss() 141 // HTML 142 let html = this.getEjsResult(`/layout/${attr_id.split('-')[0]}`, { package: this.packages[attr_id] }) 143 attr_id !== 'app' ? element.outerHTML = html : element.innerHTML = html 144 // è¿è¡èæ¬ 145 this.runScript() 146 // 妿æ¯ä¸çäºapp,æè æ¯æ¤æ¶ï¼æè æ¯éæ©æ¨¡ååç»ä»¶æ¶ 147 if (attr_id !== 'app' || isRefres || this.ctx.state.postCtxState) {
148 await window.app.initPlug(attr_id) 149 await window.app.initScriptQueue(window.scriptQueue, 1) 150 } 151 // åå§åè£ ä¿®å·¥å · 152 if (!this.ctx.state.postCtxState) { 153 this.initTool(attr_id) 154 } 155 this.setAddIframEvent() 156 // const newTime = new Date().getTime() 157 // console.log(`渲æç¨æ¶${newTime - oldTime}毫ç§`) 158 // å¦ææ¯æ¸²æå ¨é¨é¡µé¢ï¼åéä¸ä¸ªæ¶æ¯ç»è£ ä¿® 159 if (attr_id === 'app') PostMessages.ins().loadPageComplete() 160 if (this.packages[origin_attr_id]?.hook) { 161 this.packages[origin_attr_id].hook.afterRender({attr_id, isRefres}) 162 } 163 if (attr_id === 'app') { 164 for (const key in hooks) { 165 if (Object.prototype.hasOwnProperty.call(hooks, key)) { 166 hooks[key]?.afterRenderApp() 167 } 168 } 169 } 170 } 171 /** æ¸²ææ ·å¼ */ 172 async renderCss() { 173 // è·åæ ·å¼ 174 const styleStr = this.ctx.state.template.getStyleString(this.ctx.state.template.initStyleData()) 175 const $style = document.getElementById('style') 176 // æ°çæ ·å¼ 177 $style.innerHTML = styleStr 178 const newUnitTypeList = [] 179 180 const styleLink = $style.parentNode.querySelectorAll('[rel="stylesheet"]') 181 let existStyle = [] 182 for (let $el of styleLink) { 183 if ($el.getAttribute('href').indexOf('unit=') > -1) { 184 existStyle = existStyle.concat($el.getAttribute('href').split('unit=')[1].split(',')) 185 } 186 } 187 this.ctx.state.template.getUnitTypeList().forEach(name => { 188 if (name === 'content-list') name = 'list' // 使ç¨list.css 189 if (this.oldUnitTypeList.includes(name)) return 190 this.oldUnitTypeList.push(name) 191 newUnitTypeList.push(name) 192 }) 193 194 if (!this.ctx.state.postCtxState) { 195 if ( 196 !existStyle.includes('social-media-chat') && 197 (this.ctx.state.site.site_plugins.filter(p=>p.status === 1).length || this.ctx.state.site.site_inquiry) 198 ) { 199 newUnitTypeList.push('social-media-chat') 200 } 201 if (!existStyle.includes('cookie-settings')) { 202 newUnitTypeList.push('cookie-settings') 203 } 204 } 205 206 if (newUnitTypeList.length > 0) { 207 const newNode = document.createElement('link') 208 newNode.rel = 'stylesheet' 209 newNode.href = `/style/unit.css?unit=${newUnitTypeList.toString()}` 210 $style.parentNode.insertBefore(newNode, $style) 211 } 212 } 213 /** innerHTML,ä¸è½æ§è¡èæ¬ï¼æä»¥éæ°è¿è¡ä¸ä¸javascript */ 214 runScript() { 215 const body = document.getElementById('app') 216 const scripts = body.querySelectorAll('script') 217 window.scriptQueue = []; 218 if (scripts.length === 0) return 219 scripts.forEach(script => { 220 if (script.type && /json/i.test(script.type)) { 221 return 222 } 223 // ç´æ¥ document.head.appendChild(script) æ¯ä¸ä¼çæçï¼éè¦éæ°å建ä¸ä¸ª 224 const newScript = document.createElement('script') 225 // è·å inline script 226 newScript.innerHTML = script.innerHTML 227 // åå¨ src 屿§çè¯ 228 const src = script.getAttribute('src') 229 if (src) newScript.setAttribute('src', src) 230 document.head.appendChild(newScript) 231 document.head.removeChild(newScript) 232 }) 233 } 234 /** 235 * è·åHTML 236 */ 237 /** 238 * è·åHTML 239 */ 240 getEjsResult(path, data) { 241 data = this.getEjsParmes(data) 242 const ejsOptions = { client: true, delimiter: '?' } 243 const viewString = this.viewsData[path] 244 const viewCompile = window.ejs.compile(viewString, ejsOptions) 245 const viewHtml = viewCompile(data, null, (sonPath, sonData) => { 246 let thisViewString = this.viewsData[sonPath] 247 if (thisViewString) { 248 if (thisViewString.indexOf('include(') >= 1) { 249 thisViewString = this.getEjsResult(sonPath, sonData) 250 } 251 sonData = this.getEjsParmes(sonData) 252 const template = window.ejs.render(thisViewString, sonData, ejsOptions) 253 return template 254 } else { 255 console.log(sonPath) 256 console.error(`${sonPath} æªæ¾å°å¯¹åºçhtmlã`) 257 } 258 }) 259 return viewHtml 260 } 261 /** 模å弿忰 */ 262 getEjsParmes(data) { 263 return { 264 ...this.ctx.state, 265 ...data, 266 getViewsPath: path => path, 267 translate: text => text 268 } 269 } 270 /** 271 * åå§åè£ ä¿®å·¥å · 272 */ 273 initTool(att_id) { 274 const packages = this.packages 275 if (att_id === 'app') { // åå§åææ
276 Object.keys(packages).forEach(key => { 277 packages[key].designBox = new DesignBox(packages[key]) 278 }) 279 } else { // åå§åå½åå 280 // åå§åèªå·± 281 packages[att_id].designBox = new DesignBox(packages[att_id]) 282 // åå§åchildren 283 const setDesignBox = (children) => { 284 if (children && children.length > 0) { 285 children.forEach(item => { 286 const sub_attr_id = item.attr_id 287 packages[sub_attr_id].designBox = null 288 packages[sub_attr_id].designBox = new DesignBox(packages[sub_attr_id]) 289 setDesignBox(item.children) 290 }) 291 } 292 } 293 setDesignBox(packages[att_id].children) 294 } 295 // åå§åå¯ææ¬ 296 DesignBox.initTinyMce(att_id,packages) 297 } 298 /** åå§ç«ç¹æ ·å¼ */ 299 siteStyle(data) { 300 this.ctx.state.site.style.init(data) 301 // è·åæ ·å¼ 302 this.renderCss() 303 } 304 /** å®ä¾åä¸ä¸ªåå æ ¼ */ 305 getCell(packageItem) { 306 return new Cell({ 307 params: { 308 cols_col: packageItem.cols_col || 12, 309 cols_md: packageItem.cols_md || 12, 310 cols_xl: packageItem.cols_xl || 12 311 } 312 }) 313 } 314 315 /** ä¿®æ¹è£ ä¿®æ¶ï¼æ·»å page-typeæ¥æ¾ç¤ºå½å页é¢çç±»å */ 316 updatePageType() { 317 const page = this.ctx.state.page || {} 318 const page_type = page.page_type || 'index' 319 document.querySelector('#app').setAttribute('page-type', page_type) 320 } 321 322 /** å¦ææ¯æ·»å ç»ä»¶ææ¨¡åæ¶ï¼å¤çç¹å»äºä»¶åéèä¸éè¦çdiv */ 323 setAddIframEvent() { 324 if (!this.ctx.state.postCtxState) return 325 const body = document.querySelector('body') 326 body.style.overflow = 'hidden' 327 const $popDiv = document.createElement('div') 328 $popDiv.style = `width:100%;height:100%;position:fixed;z-index:100;left:0;top:0;cursor: pointer;` 329 $popDiv.onclick = async (event) => { 330 event.stopPropagation() 331 PostMessages.ins().checkedPackage() 332 } 333 body.appendChild($popDiv) 334 document.querySelectorAll('[package-item="module"]').forEach(thisModule => { 335 const grid = thisModule.querySelector('[package-group="grid"]') 336 if (grid.innerHTML.trim() === '') thisModule.classList.add('d-none') 337 }) 338 PostMessages.ins().postIframeIsLoading(true) 339 } 340 341 /** éæ°æ¸²æå¯¼èªæ */ 342 async resetSiteNav() { 343 let siteData = await getSiteData(this.ctx, { 344 domain: window.app.info.site.site_domain 345 }) 346 347 let [nav, nav_all] = await getSiteNavData(this.ctx, { 348 site_id: this.ctx.state.site.site_id, 349 language_code: this.ctx.state.site.language_code, 350 }) 351 this.ctx.state.site.nav = nav 352 this.ctx.state.site.nav_all = nav_all 353 354 if (siteData.is_show_home) { 355 this.ctx.state.site.nav.unshift({ title: this.ctx.state.$t(siteData.home_name || 'home'), href: '/', children: [], bubble: {} }) 356 } 357 358 if (ctx.state.template.block['header']) { 359 const headerAttrId = ctx.state.template.block['header'].attr_id 360 this.render(headerAttrId) 361 } 362 363 for (const key in this.packages) { 364 if (Object.prototype.hasOwnProperty.call(this.packages, key)) { 365 const pkg = this.packages[key]; 366 if (['list-nav', 'list_sort'].includes(pkg.type)) { 367 if (['list_sort'].includes(pkg.type)) { 368 if (this.ctx.state.page.parents.length > 1) { 369 let pData = this.ctx.state.page.parents[1] 370 if (pData.id) this.ctx.state.page.children = [this.ctx.state.site.nav.find(p => p.id === pData.id)] 371 } 372 } 373 this.render(pkg.attr_id) 374 } 375 } 376 } 377 } 378 379 _removeAnimate() { 380 // å é¤å¨ç»cssï¼æ¾ç¤ºæ¨¡å 381 document.querySelectorAll('.animate').forEach(unit => { 382 unit.classList.remove('animate') 383 }) 384 } 385 386 /** æ´æ°æ¸²æèç¹å 容 */ 387 updateRenderAttr(info) { 388 const $doms = document.querySelectorAll(`[${info.attr}]`) 389 for (let $el of $doms) { 390 if (info.value) { 391 const oldValue = $el.getAttribute(info.domAttr) 392 const oldInfo = { attr: info.attr, domAttr: info.domAttr, value: oldValue } 393 $el.setAttribute('data-attr-info', JSON.stringify(oldInfo)) 394 $el.setAttribute(info.domAttr, info.value) 395 } 396 } 397 } 398 /** è¿åèç¹å 容 */ 399 resetRenderAttr() { 400 const $doms = document.querySelectorAll(`[data-attr-info]`) 401 for (let $el of $doms) { 402 let oldValue = $el.getAttribute('data-attr-info') 403 if (oldValue) oldValue = JSON.parse(oldValue) 404 $el.setAttribute(oldValue.domAttr, oldValue.value) 405 $el.removeAttribute('data-attr-info') 406 } 407 } 408 /** å ¨å±ä¿å以忏 空è¦è¿åç屿§èç¹ */ 409 clearRenderAttr() { 410 const $doms = document.querySelectorAll(`[data-attr-info]`) 411 for (let $el of $doms) { 412 $el.removeAttribute('data-attr-info') 413 } 414 } 415 416 get packages() { 417 const data = {}
418 Object.keys(this.ctx.state.template.block).forEach(blockSign => { 419 const thisBlock = this.ctx.state.template.block[blockSign] 420 if(thisBlock) data[thisBlock.attr_id] = thisBlock 421 thisBlock?.children?.forEach(thisModule => { 422 if(thisModule) data[thisModule.attr_id] = thisModule 423 thisModule?.children?.forEach(thisGrid => { 424 if(thisGrid) data[thisGrid.attr_id] = thisGrid 425 thisGrid?.children?.forEach(thisCell => { 426 if(thisCell) data[thisCell.attr_id] = thisCell 427 thisCell?.children?.forEach(thisUnit => { 428 if(thisUnit) data[thisUnit.attr_id] = thisUnit 429 }) 430 }) 431 }) 432 }) 433 }) 434 return data 435 } 436 437 stringify() { 438 const obj = JSON.parse(JSON.stringify(this)) 439 obj.packages = this.packages 440 return JSON.stringify(obj) 441 } 442} 443window.design = new Design()
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.