UNPKG

5.29 kBJavaScriptView Raw
1function postMessage(message) {
2 return window.parent.postMessage(JSON.stringify(message), '*')
3}
4
5const skill = {
6 height: 0,
7 minHeight: 0,
8 forceAuth: function() {
9 postMessage('Skill:ForceAuth')
10 },
11 /**
12 * Called anytime a skill is resized to let the parent know what to set the height of the iframe to
13 */
14 resized: function() {
15 var height = 0
16 var body = document.body
17 var docEl = document.documentElement
18
19 var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop
20 var clientTop = docEl.clientTop || body.clientTop || 0
21 var top = scrollTop - clientTop
22 var height = Math.max(this.minHeight, top + body.clientHeight)
23
24 if (height != this.height) {
25 this.height = height
26 postMessage({
27 name: 'Skill:Resized',
28 height: height
29 })
30 }
31 },
32 setMinBodyHeight: function(height) {
33 this.minHeight = height
34 },
35 clearMinBodyHeight: function() {
36 this.minHeight = 0
37 },
38 showUnderlay: function() {
39 postMessage('Skill:ShowUnderlay')
40 },
41
42 hideUnderlay: function() {
43 postMessage('Skill:HideUnderlay')
44 },
45 back: function() {
46 if (window.top === window.self) {
47 window.history.back()
48 } else {
49 postMessage('Skill:Back')
50 }
51 },
52
53 ready: function({ resetUrlTrail = false } = { resetUrlTrail: false }) {
54 this.resized()
55 postMessage({
56 name: 'Skill:Loaded',
57 url: window.location.href,
58 resetUrlTrail
59 })
60 this.resizedInterval = setInterval(this.resized.bind(this), 300)
61 },
62
63 scrollTo: function(offset) {
64 postMessage({
65 name: 'Skill:ScrollTo',
66 offset: offset || 0
67 })
68 },
69
70 scrollBy: function(offset) {
71 if (window.top === window.self) {
72 window.scrollBy({
73 top: offset,
74 behavior: 'smooth'
75 })
76 } else {
77 postMessage({ name: 'Skill:ScrollBy', offset })
78 }
79 },
80
81 requestScroll: function() {
82 postMessage({ name: 'Skill:RequestContainerScrollTop' })
83 },
84
85 fullScreenOn: function() {
86 postMessage({ name: 'Skill:FullScreenOn' })
87 },
88
89 fullScreenOff: function() {
90 postMessage({ name: 'Skill:FullScreenOff' })
91 },
92
93 showHelp: async function({ title, body }) {
94 if (window.top === window.self) {
95 alert(`[${title}] ${body}`)
96 } else {
97 const promise = new Promise((accept, reject) => {
98 this._showHelpAccept = accept
99 })
100
101 postMessage({ name: 'Skill:ShowHelp', title, body })
102
103 return promise
104 }
105 },
106
107 handleIframeMessage: function(e) {
108 if (typeof e.data === 'string') {
109 try {
110 const results = JSON.parse(e.data)
111
112 // TODO make this different?
113 if (results.name === 'Skill:HideHelp') {
114 if (this._showHelpAccept) {
115 this._showHelpAccept()
116 this._showHelpAccept = null
117 }
118 }
119
120 if (results.name === 'Search:SelectUser') {
121 if (this._onSelecUserFormSearchCallback) {
122 this._onSelecUserFormSearchCallback(results.user)
123 this._onSelecUserFormSearchCallback = null
124 }
125 } else if (results.name === 'Search:Cancel') {
126 if (this._onCancelSearchCallback) {
127 this._onCancelSearchCallback()
128 this._onCancelSearchCallback = null
129 }
130 } else if (results.name === 'Skill:DidConfirm') {
131 if (this._confirmAccept) {
132 this._confirmAccept(results.pass)
133 this._confirmAccept = null
134 }
135 } else if (results.name === 'Skill:DidClickStickyElement') {
136 if (this.handleStickElementClick) {
137 this.handleStickElementClick(results.key)
138 }
139 }
140 } catch (err) {}
141 }
142 },
143
144 //TODO move to promise?
145 searchForUser: function({
146 onCancel = () => {},
147 onSelectUser = () => {},
148 roles = ['guest'],
149 locationId
150 } = {}) {
151 postMessage({ name: 'Skill:SearchForUser', roles, locationId })
152
153 this._onCancelSearchCallback = onCancel
154 this._onSelecUserFormSearchCallback = onSelectUser
155 },
156
157 displayMessage: function({ message, type = 'error' }) {
158 if (window.top === window.self) {
159 alert(message)
160 } else {
161 postMessage({ name: 'Skill:DisplayMessage', message, type })
162 }
163 },
164
165 confirm: async function({ message }) {
166 if (window.top === window.self) {
167 return window.confirm(message)
168 } else {
169 const promise = new Promise((accept, reject) => {
170 this._confirmAccept = accept
171 })
172
173 postMessage({ name: 'Skill:PleaseConfirm', message })
174
175 return promise
176 }
177 },
178
179 /**
180 * position: 'top' | 'bottom'
181 * elements: [
182 * {
183 * key: 'first-button', (key is passed back to onClick)
184 * type: 'button'|'title',
185 * leftIcon: 'scissors',
186 * rightIcon: 'pencil'
187 * value: 'Hey There' //value MUST be a string, will be value of button or innerHTML of everything else
188 * }
189 * ]
190 */
191 setStickyElement: function({
192 elements,
193 position = 'top',
194 onClick = () => {}
195 }) {
196 this.handleStickElementClick = onClick
197 postMessage({
198 name: 'Skill:SetStickyElement',
199 elements,
200 position
201 })
202 },
203
204 updateStickyBoundingRect: function(rect) {
205 if (
206 this._lastRect &&
207 this._lastRect.top === rect.top &&
208 this._lastRect.bottom == rect.bottom
209 ) {
210 return
211 }
212
213 this._lastRect = rect
214
215 postMessage({
216 name: 'Skill:SetStickyBoundingRect',
217 boundingRect: rect
218 })
219 },
220
221 clearStickyElements() {
222 postMessage({ name: 'Skill:ClearStickyElements' })
223 },
224
225 notifyOfRouteChangeStart() {
226 postMessage({ name: 'Skill:RouteChangeStart' })
227 }
228}
229
230if (typeof window !== 'undefined') {
231 window.addEventListener('message', skill.handleIframeMessage.bind(skill))
232}
233
234export default skill