1+ import React from 'react' ;
2+ import './retool.css' ;
3+
4+ class Retool extends React . Component {
5+ constructor ( props ) {
6+ super ( props ) ;
7+ this . state = {
8+ url : props . url ,
9+ elementWatchers : { }
10+ }
11+ }
12+
13+ componentDidMount ( ) {
14+ this . startListening ( )
15+ this . startWatchers ( )
16+ }
17+
18+ startListening = ( ) => {
19+ window . addEventListener ( 'message' , ( e ) => this . handle ( e ) ) ;
20+ }
21+
22+ startWatchers = ( ) => {
23+ var watcherKeys = Object . keys ( this . state . elementWatchers )
24+
25+ for ( var i = 0 ; i < watcherKeys . length ; i ++ ) {
26+ var key = watcherKeys [ i ]
27+ var watcher = this . state . elementWatchers [ key ]
28+ var selector = watcher . selector
29+ var node = document . querySelector ( selector )
30+ var value = node ?. textContent
31+ if ( value !== watcher . prevValue ) {
32+ watcher . prevValue = value
33+ watcher . iframe . contentWindow . postMessage (
34+ {
35+ type : 'PARENT_WINDOW_RESULT' ,
36+ result : value ,
37+ id : watcher . queryId ,
38+ pageName : watcher . pageName ,
39+ } ,
40+ '*' ,
41+ )
42+ }
43+ }
44+
45+ setTimeout ( this . startWatchers , 100 )
46+ }
47+
48+ createOrReplaceWatcher = ( selector , pageName , queryId ) => {
49+ var watcherId = pageName + '-' + queryId
50+ var watchers = { ...this . state . elementWatchers }
51+
52+ watchers [ watcherId ] = {
53+ iframe : this . iframe ,
54+ selector : selector ,
55+ pageName : pageName ,
56+ queryId : queryId ,
57+ prevValue : null ,
58+ }
59+
60+ this . setState ( { elementWatchers : watchers } )
61+ }
62+
63+ handle = ( event ) => {
64+ if ( ! this . iframe . contentWindow ) return
65+
66+ var node ;
67+
68+ if ( event . data . type === 'PARENT_WINDOW_QUERY' ) {
69+ node = document . querySelector ( event . data . selector )
70+ this . createOrReplaceWatcher ( event . data . selector , event . data . pageName , event . data . id )
71+
72+ this . iframe . contentWindow . postMessage (
73+ {
74+ type : 'PARENT_WINDOW_RESULT' ,
75+ result : node ?. textContent ,
76+ id : event . data . id ,
77+ pageName : event . data . pageName ,
78+ } ,
79+ '*' ,
80+ )
81+ }
82+
83+ if ( event . data . type === 'PARENT_WINDOW_PREVIEW_QUERY' ) {
84+ node = document . querySelector ( event . data . selector )
85+ this . iframe . contentWindow . postMessage (
86+ {
87+ type : 'PARENT_WINDOW_PREVIEW_RESULT' ,
88+ result : node ?. textContent ,
89+ id : event . data . id ,
90+ } ,
91+ '*' ,
92+ )
93+ }
94+
95+ }
96+
97+ render ( ) {
98+ return (
99+ < iframe
100+ frameBorder = "none"
101+ src = { this . state . url }
102+ ref = { e => {
103+ this . iframe = e
104+ } }
105+ >
106+ </ iframe >
107+ ) ;
108+ }
109+ }
110+
111+ export default Retool ;
112+
0 commit comments