import { ipcRenderer , contextBridge } from 'electron' ; import { Droppable , DroppableEventNames , DroppableDroppedEvent } from '@shopify/draggable' ; import 'selector-generator' ; import { connectSocket , sendBackIpc } from './client-ipc' ; import { EmptyElement , DropzoneTags } from './utils/assest' ; import { ElementPayload , ElementActualStatus , BreadcrumbPayload , MainIpcChannel , ElementTag } from './interface' ; import { preloadCSS , sectionHTML } from './preload-inject-code' ; let PROJECTID ; let ISWEAPP = false ; let dataCode = 'data-code' ; let selector ; let activeElement = null ; let hoverElement = null ; let droppable ; const GetStyleClass = ( className ) => { for ( let i = 0 ; i < document . styleSheets . length ; i ++ ) { const styleSheet = document . styleSheets [ i ] ; const rules = styleSheet . cssRules || styleSheet . rules ; for ( let j = 0 ; j < rules . length ; j ++ ) { const rule = rules [ j ] ; if ( rule . selectorText === className ) { return rule . style ; } } } return 0 ; } ; const generator = new ( window as any ) . SelectorGenerator ( ) ; const getSelectorString = ( el ) : string => { return generator . getPath ( el ) . replace ( 'html body ' , '' ) . split ( ' ' ) . join ( '>' ) ; } ; const changeTag = ( el , newTagName ) => { if ( ! el . parentNode ) throw Error ( 'el.parentNode is empty cannot replace the name' ) ; const newEl = document . createElement ( newTagName ) ; while ( el . firstChild ) { newEl . appendChild ( el . firstChild ) ; } Array . from ( el . attributes ) . forEach ( ( attr ) => { newEl . attributes . setNamedItem ( attr . cloneNode ( ) as Attr ) ; } ) ; el . parentNode . replaceChild ( newEl , el ) ; } ; const respElementActualStatus = ( ) : ElementActualStatus | null => { if ( ! PROJECTID || ! activeElement ) return null ; const codePosition = activeElement . getAttribute ( dataCode ) ; if ( ! codePosition ) return null ; const { tagName , className } = activeElement ; const declaration = getComputedStyle ( activeElement ) ; const payload = { projectId : PROJECTID , codePosition , className , tagName , display : declaration . getPropertyValue ( 'display' ) , position : declaration . getPropertyValue ( 'position' ) , background : declaration . getPropertyValue ( 'background-image' ) , } ; if ( activeElement . parentElement ) { payload . parentTagName = activeElement . parentElement . tagName ; const parentDeclaration = getComputedStyle ( activeElement . parentElement ) ; payload . parentDisplay = parentDeclaration . getPropertyValue ( 'display' ) ; } const supportText = ! activeElement . children . length && ! EmptyElement . includes ( tagName . toLowerCase ( ) ) ; if ( supportText ) { payload . text = activeElement . innerText ; } ipcRenderer . send ( MainIpcChannel . RespElementStatus , payload ) ; return payload ; } ; const inspectActiveElement = ( targetOrSelector ) : void => { if ( ! PROJECTID ) return ; selector = undefined ; if ( activeElement ) { activeElement . removeAttribute ( 'data-active' ) ; activeElement . querySelector ( 'ul.de-section' ) ?. remove ( ) ; activeElement = null ; const wrapper = document . querySelector ( 'div.de-wrapper' ) ; if ( wrapper ) { wrapper . parentNode ?. insertBefore ( wrapper . children [ 1 ] , wrapper ) ; wrapper . remove ( ) ; } } if ( typeof targetOrSelector === 'string' ) { selector = targetOrSelector ; if ( selector ) activeElement = document . querySelector ( selector ) ; } else if ( targetOrSelector ) { activeElement = targetOrSelector ; selector = getSelectorString ( activeElement ) ; } else { console . warn ( 'targetOrSelector null' ) ; return ; } if ( ! activeElement ) { ipcRenderer . send ( MainIpcChannel . BlurElement , PROJECTID ) ; return ; } const codePosition = activeElement . getAttribute ( dataCode ) ; if ( ! codePosition ) { alert ( 'This element does not support deraelize update' ) ; return ; } const { className , tagName } = activeElement ; const payload = { projectId : PROJECTID , codePosition , className , selector } ; ipcRenderer . send ( MainIpcChannel . FocusElement , payload ) ; activeElement . setAttribute ( 'data-active' , 'true' ) ; const actualStatus = respElementActualStatus ( ) ; if ( ! actualStatus ) throw new Error ( 'actualStatus null' ) ; } ; const derealizeListener = ( e ) => { if ( ! e . currentTarget || ! PROJECTID ) return ; e . stopPropagation ( ) ; if ( e . type === 'click' ) { const href = ( e . currentTarget as HTMLElement ) . getAttribute ( 'href' ) ; if ( href ) return ; } inspectActiveElement ( e . currentTarget as HTMLElement ) ; } ; ipcRenderer . on ( MainIpcChannel . LiveUpdateClass , ( event , sel , className , needRespStatus ) => { if ( activeElement && sel === selector ) { activeElement . className = className ; if ( needRespStatus ) { respElementActualStatus ( ) ; } } else { const element = document . querySelector ( sel ) as HTMLElement ; if ( element ) { element . className = className ; } } } ) ; ipcRenderer . on ( MainIpcChannel . LiveUpdateText , ( event , sel , text ) => { if ( activeElement && sel === selector ) { activeElement . innerText = text ; respElementActualStatus ( ) ; } else { const element = document . querySelector ( sel ) as HTMLElement ; if ( element ) { element . innerText = text ; } } } ) ; ipcRenderer . on ( MainIpcChannel . LiveUpdateTag , ( event , sel , tag ) => { if ( activeElement && sel === selector ) { changeTag ( activeElement , tag ) ; respElementActualStatus ( ) ; } else { const element = document . querySelector ( sel ) as HTMLElement ; if ( element ) { changeTag ( element , tag ) ; } } } ) ; ipcRenderer . on ( MainIpcChannel . SelectBreadcrumb , ( event , { projectId , index , isClick } ) => { if ( projectId !== PROJECTID || ! selector ) return ; hoverElement ?. removeAttribute ( 'data-hover' ) ; const sels = selector . split ( '>' ) ; const sel = sels . slice ( 0 , index + 1 ) . join ( '>' ) ; const target = document . querySelector ( sel ) ; if ( target ) { if ( isClick ) { inspectActiveElement ( target as HTMLElement ) ; } else { hoverElement = target ; hoverElement . setAttribute ( 'data-hover' , 'true' ) ; } } } ) ; ipcRenderer . on ( MainIpcChannel . DisableLink , ( event , isDisable ) => { GetStyleClass ( 'a' ) . pointerEvents = isDisable ? 'none' : '' ; } ) ; const listenElement = ( ) => { document . querySelectorAll ( `[${ dataCode }]` ) . forEach ( ( el ) => { el . removeEventListener ( 'click' , derealizeListener ) ; el . addEventListener ( 'click' , derealizeListener ) ; el . removeEventListener ( 'contextmenu' , derealizeListener ) ; el . addEventListener ( 'contextmenu' , derealizeListener ) ; } ) ; } ; ipcRenderer . on ( MainIpcChannel . LoadFinish , ( event , socketId , projectId , isWeapp , activeSelector ) => { PROJECTID = projectId ; ISWEAPP = isWeapp ; dataCode = isWeapp ? 'title' : 'data-code' ; connectSocket ( socketId ) ; const style = document . createElement ( 'style' ) ; style . appendChild ( document . createTextNode ( preloadCSS ) ) ; document . head . appendChild ( style ) ; listenElement ( ) ; inspectActiveElement ( activeSelector ) ; } ) ; contextBridge . exposeInMainWorld ( 'derealize' , { isDarwin : process . platform === 'darwin' , listenElement , } ) ;