@@ -18,10 +18,11 @@ class Widget {
1818 constructor ( remoteStorage , options = { } ) {
1919 this . rs = remoteStorage ;
2020
21- this . leaveOpen = options . leaveOpen ? options . leaveOpen : false ;
22- this . autoCloseAfter = options . autoCloseAfter ? options . autoCloseAfter : 1500 ;
23- this . skipInitial = options . skipInitial ? options . skipInitial : false ;
24- this . logging = options . logging ? options . logging : false ;
21+ this . leaveOpen = options . leaveOpen ? options . leaveOpen : false ;
22+ this . autoCloseAfter = options . autoCloseAfter ? options . autoCloseAfter : 1500 ;
23+ this . skipInitial = options . skipInitial ? options . skipInitial : false ;
24+ this . logging = options . logging ? options . logging : false ;
25+ this . parentContainerEl = null ;
2526
2627 if ( options . hasOwnProperty ( 'modalBackdrop' ) ) {
2728 if ( typeof options . modalBackdrop !== 'boolean' && options . modalBackdrop !== 'onlySmallScreens' ) {
@@ -124,13 +125,13 @@ class Widget {
124125 if ( ! state ) return ;
125126 this . log ( 'Setting state ' , state ) ;
126127
127- let lastSelected = document . querySelector ( '.rs-box.rs-selected' ) ;
128+ let lastSelected = this . parentContainerEl . querySelector ( '.rs-box.rs-selected' ) ;
128129 if ( lastSelected ) {
129130 lastSelected . classList . remove ( 'rs-selected' ) ;
130131 lastSelected . setAttribute ( 'aria-hidden' , 'true' ) ;
131132 }
132133
133- let toSelect = document . querySelector ( '.rs-box.rs-box-' + state ) ;
134+ let toSelect = this . parentContainerEl . querySelector ( '.rs-box.rs-box-' + state ) ;
134135 if ( toSelect ) {
135136 toSelect . classList . add ( 'rs-selected' ) ;
136137 toSelect . setAttribute ( 'aria-hidden' , 'false' ) ;
@@ -194,21 +195,26 @@ class Widget {
194195 /**
195196 * Save all interactive DOM elements as variables for later access.
196197 *
198+ * @throws {Error } If parent container element not found
197199 * @private
198200 */
199201 setupElements ( ) {
200- this . rsWidget = document . querySelector ( '.rs-widget' ) ;
201- this . rsBackdrop = document . querySelector ( '.remotestorage-widget-modal-backdrop' ) ;
202- this . rsInitial = document . querySelector ( '.rs-box-initial' ) ;
203- this . rsChoose = document . querySelector ( '.rs-box-choose' ) ;
204- this . rsConnected = document . querySelector ( '.rs-box-connected' ) ;
205- this . rsSignIn = document . querySelector ( '.rs-box-sign-in' ) ;
206-
207- this . rsConnectedLabel = document . querySelector ( '.rs-box-connected .rs-sub-headline' ) ;
208- this . rsChooseRemoteStorageButton = document . querySelector ( 'button.rs-choose-rs' ) ;
209- this . rsChooseDropboxButton = document . querySelector ( 'button.rs-choose-dropbox' ) ;
210- this . rsChooseGoogleDriveButton = document . querySelector ( 'button.rs-choose-googledrive' ) ;
211- this . rsErrorBox = document . querySelector ( '.rs-box-error .rs-error-message' ) ;
202+ if ( ! this . parentContainerEl ) {
203+ throw new Error ( "Parent container element not found" ) ;
204+ }
205+
206+ this . rsWidget = this . parentContainerEl . querySelector ( '.rs-widget' ) ;
207+ this . rsBackdrop = this . parentContainerEl . querySelector ( '.remotestorage-widget-modal-backdrop' ) ;
208+ this . rsInitial = this . parentContainerEl . querySelector ( '.rs-box-initial' ) ;
209+ this . rsChoose = this . parentContainerEl . querySelector ( '.rs-box-choose' ) ;
210+ this . rsConnected = this . parentContainerEl . querySelector ( '.rs-box-connected' ) ;
211+ this . rsSignIn = this . parentContainerEl . querySelector ( '.rs-box-sign-in' ) ;
212+
213+ this . rsConnectedLabel = this . parentContainerEl . querySelector ( '.rs-box-connected .rs-sub-headline' ) ;
214+ this . rsChooseRemoteStorageButton = this . parentContainerEl . querySelector ( 'button.rs-choose-rs' ) ;
215+ this . rsChooseDropboxButton = this . parentContainerEl . querySelector ( 'button.rs-choose-dropbox' ) ;
216+ this . rsChooseGoogleDriveButton = this . parentContainerEl . querySelector ( 'button.rs-choose-googledrive' ) ;
217+ this . rsErrorBox = this . parentContainerEl . querySelector ( '.rs-box-error .rs-error-message' ) ;
212218
213219 // check if apiKeys is set for Dropbox or Google [googledrive, dropbox]
214220 // to show/hide relative buttons only if needed
@@ -220,18 +226,18 @@ class Widget {
220226 this . rsChooseDropboxButton . parentNode . removeChild ( this . rsChooseDropboxButton ) ;
221227 }
222228
223- this . rsSignInForm = document . querySelector ( '.rs-sign-in-form' ) ;
229+ this . rsSignInForm = this . parentContainerEl . querySelector ( '.rs-sign-in-form' ) ;
224230 this . rsAddressInput = this . rsSignInForm . querySelector ( 'input[name=rs-user-address]' ) ;
225- this . rsConnectButton = document . querySelector ( '.rs-connect' ) ;
231+ this . rsConnectButton = this . parentContainerEl . querySelector ( '.rs-connect' ) ;
226232
227- this . rsDisconnectButton = document . querySelector ( '.rs-disconnect' ) ;
228- this . rsSyncButton = document . querySelector ( '.rs-sync' ) ;
229- this . rsLogo = document . querySelector ( '.rs-widget-icon' ) ;
233+ this . rsDisconnectButton = this . parentContainerEl . querySelector ( '.rs-disconnect' ) ;
234+ this . rsSyncButton = this . parentContainerEl . querySelector ( '.rs-sync' ) ;
235+ this . rsLogo = this . parentContainerEl . querySelector ( '.rs-widget-icon' ) ;
230236
231- this . rsErrorReconnectLink = document . querySelector ( '.rs-box-error a.rs-reconnect' ) ;
232- this . rsErrorDisconnectButton = document . querySelector ( '.rs-box-error button.rs-disconnect' ) ;
237+ this . rsErrorReconnectLink = this . parentContainerEl . querySelector ( '.rs-box-error a.rs-reconnect' ) ;
238+ this . rsErrorDisconnectButton = this . parentContainerEl . querySelector ( '.rs-box-error button.rs-disconnect' ) ;
233239
234- this . rsConnectedUser = document . querySelector ( '.rs-connected-text h1.rs-user' ) ;
240+ this . rsConnectedUser = this . parentContainerEl . querySelector ( '.rs-connected-text h1.rs-user' ) ;
235241 }
236242
237243 /**
@@ -254,25 +260,32 @@ class Widget {
254260 /**
255261 * Append widget to the DOM.
256262 *
257- * If an elementId is specified, it will be appended to that element,
258- * otherwise it will be appended to the document's body.
263+ * If a parentElement is specified, the widget will be appended to that
264+ * element, otherwise it will be appended to the document's body. The parent
265+ * element can be given either as a simple element ID or as a valid HTML
266+ * element.
259267 *
260- * @param {String } [elementId] - Widget's parent
268+ * @param {String,HTMLElement } [parentElement] - Parent element
269+ * @throws {Error } If the element is not found or is of an unknown type.
261270 */
262- attach ( elementId ) {
263- const domElement = this . createHtmlTemplate ( ) ;
271+ attach ( element ) {
272+ const domElement = this . createHtmlTemplate ( element ) ;
264273
265- let parentContainerEl ;
274+ this . parentContainerEl ;
266275
267- if ( elementId ) {
268- parentContainerEl = document . getElementById ( elementId ) ;
269- if ( ! parent ) {
270- throw "Failed to find target DOM element with id=\"" + elementId + "\"" ;
276+ if ( element instanceof HTMLElement ) {
277+ this . parentContainerEl = element ;
278+ } else if ( typeof element === "string" ) {
279+ this . parentContainerEl = document . getElementById ( element ) ;
280+ if ( ! this . parentContainerEl ) {
281+ throw new Error ( "Failed to find target DOM element with id=\"" + element + "\"" ) ;
271282 }
283+ } else if ( element ) {
284+ throw new Error ( "Unknown element type. Expected instance of HTMLElement or type of string." ) ;
272285 } else {
273- parentContainerEl = document . body ;
286+ this . parentContainerEl = document . body ;
274287 }
275- parentContainerEl . appendChild ( domElement ) ;
288+ this . parentContainerEl . appendChild ( domElement ) ;
276289
277290 this . setupElements ( ) ;
278291 this . setupHandlers ( ) ;
@@ -283,7 +296,7 @@ class Widget {
283296 setEventListeners ( ) {
284297 this . rsSignInForm . addEventListener ( 'submit' , ( e ) => {
285298 e . preventDefault ( ) ;
286- let userAddress = document . querySelector ( 'input[name=rs-user-address]' ) . value ;
299+ let userAddress = this . parentContainerEl . querySelector ( 'input[name=rs-user-address]' ) . value ;
287300 this . disableConnectButton ( ) ;
288301 this . rs . connect ( userAddress ) ;
289302 } ) ;
@@ -381,7 +394,7 @@ class Widget {
381394 this . rsWidget . classList . remove ( 'rs-closed' ) ;
382395 this . shouldCloseWhenSyncDone = false ; // prevent auto-closing when user opened the widget
383396
384- let selected = document . querySelector ( '.rs-box.rs-selected' ) ;
397+ let selected = this . parentContainerEl . querySelector ( '.rs-box.rs-selected' ) ;
385398 if ( selected ) {
386399 selected . setAttribute ( 'aria-hidden' , 'false' ) ;
387400 }
@@ -400,7 +413,7 @@ class Widget {
400413 if ( ! this . leaveOpen && this . active ) {
401414 this . closed = true ;
402415 this . rsWidget . classList . add ( 'rs-closed' ) ;
403- let selected = document . querySelector ( '.rs-box.rs-selected' ) ;
416+ let selected = this . parentContainerEl . querySelector ( '.rs-box.rs-selected' ) ;
404417 if ( selected ) {
405418 selected . setAttribute ( 'aria-hidden' , 'true' ) ;
406419 }
@@ -509,7 +522,7 @@ class Widget {
509522 }
510523
511524 handleDiscoveryError ( error ) {
512- let msgContainer = document . querySelector ( '.rs-sign-in-error' ) ;
525+ let msgContainer = this . parentContainerEl . querySelector ( '.rs-sign-in-error' ) ;
513526 msgContainer . innerHTML = error . message ;
514527 msgContainer . classList . remove ( 'rs-hidden' ) ;
515528 msgContainer . classList . add ( 'rs-visible' ) ;
0 commit comments