Skip to content

Commit 11cfb58

Browse files
authored
Merge pull request #142 from remotestorage/feature/140-attach_to_element
Attach to a given element instead of only an element id
2 parents 6c406ed + 1b5eab3 commit 11cfb58

File tree

2 files changed

+62
-42
lines changed

2 files changed

+62
-42
lines changed

demo/index.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
</style>
1414
</head>
1515
<body>
16+
<header>
17+
<div id="rs-wrapper" class="rs-wrapper"></div>
18+
</header>
1619
<script type="text/javascript" src="remotestorage.js"></script>
1720
<script type="text/javascript" src="widget.js"></script>
1821
<script>
@@ -33,6 +36,10 @@
3336
//modalBackdrop: true,
3437
logging: true,
3538
});
39+
3640
widget.attach();
41+
// widget.attach('rs-wrapper');
42+
// widget.attach(document.querySelector('header .rs-wrapper'));
43+
// widget.attach('foo'); // throws an error
3744
</script>
3845
</body>

src/widget.js

Lines changed: 55 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)