|
177 | 177 | if (href) { |
178 | 178 | var link = doc.createElement('a'); |
179 | 179 | link.href = href; |
180 | | - link.target = '_blank'; |
181 | | - link.rel = 'noopener noreferrer'; |
182 | 180 | appendText(link, linkMatch[1]); |
183 | 181 | parent.appendChild(link); |
184 | 182 | } else { |
|
277 | 275 | button.className = className; |
278 | 276 | button.dataset.viewerAction = action; |
279 | 277 | button.textContent = label; |
| 278 | + if (action === 'close') button.setAttribute('aria-label', 'Close resource viewer'); |
280 | 279 | return button; |
281 | 280 | } |
282 | 281 |
|
|
294 | 293 | this.downloadObjectUrl = ''; |
295 | 294 | this.requestId = 0; |
296 | 295 | this.initialized = false; |
| 296 | + this.historyEntry = false; |
297 | 297 | this.onDocumentClick = this.onDocumentClick.bind(this); |
298 | 298 | this.onDocumentKeydown = this.onDocumentKeydown.bind(this); |
| 299 | + this.onPopState = this.onPopState.bind(this); |
299 | 300 | this.onDialogClick = this.onDialogClick.bind(this); |
300 | 301 | this.onDialogCancel = this.onDialogCancel.bind(this); |
301 | 302 | this.init(); |
|
307 | 308 | this.buildDialog(); |
308 | 309 | doc.addEventListener('click', this.onDocumentClick); |
309 | 310 | doc.addEventListener('keydown', this.onDocumentKeydown); |
| 311 | + global.addEventListener('popstate', this.onPopState); |
310 | 312 | this.initialized = true; |
311 | 313 | return this; |
312 | 314 | }; |
|
358 | 360 | var download = doc.createElement('a'); |
359 | 361 | download.className = 'resource-viewer-action'; |
360 | 362 | download.textContent = 'Download'; |
361 | | - download.target = '_blank'; |
362 | | - download.rel = 'noopener'; |
363 | 363 | var original = doc.createElement('a'); |
364 | 364 | original.className = 'resource-viewer-action secondary'; |
365 | 365 | original.textContent = 'Open original'; |
366 | | - original.target = '_blank'; |
367 | | - original.rel = 'noopener'; |
368 | 366 | actions.appendChild(download); |
369 | 367 | actions.appendChild(original); |
370 | 368 | footer.appendChild(note); |
|
393 | 391 | this.open(link); |
394 | 392 | }; |
395 | 393 |
|
| 394 | + ProjectResourceViewer.prototype.onPopState = function (event) { |
| 395 | + if (event.state && event.state.projectViewerPath) { |
| 396 | + var links = doc.querySelectorAll('a.resource-link'); |
| 397 | + var link = Array.prototype.find.call(links, function (candidate) { |
| 398 | + return candidate.dataset.path === event.state.projectViewerPath; |
| 399 | + }); |
| 400 | + if (link) { |
| 401 | + this.open(link, { fromHistory: true }); |
| 402 | + return; |
| 403 | + } |
| 404 | + } |
| 405 | + if (this.isOpen()) { |
| 406 | + this.historyEntry = false; |
| 407 | + this.close({ fromPopstate: true }); |
| 408 | + } |
| 409 | + }; |
| 410 | + |
396 | 411 | ProjectResourceViewer.prototype.onDocumentKeydown = function (event) { |
397 | 412 | if (!this.isOpen()) return; |
398 | 413 | if (event.key === 'Escape' || event.key === 'Esc') { |
|
434 | 449 | } |
435 | 450 | }; |
436 | 451 |
|
437 | | - ProjectResourceViewer.prototype.open = function (link) { |
| 452 | + ProjectResourceViewer.prototype.open = function (link, options) { |
| 453 | + options = options || {}; |
438 | 454 | var pathValue = link.dataset.path || link.getAttribute('href') || ''; |
439 | 455 | var url = safeUrl(pathValue, doc.baseURI); |
440 | 456 | if (!url) { |
|
448 | 464 | try { problemFiles = JSON.parse(link.dataset.problemFiles); } catch (error) { problemFiles = []; } |
449 | 465 | } |
450 | 466 | var item = { kind: kind, path: pathValue, url: url, title: title, fileName: link.dataset.fileName || basename(pathValue), problemFiles: problemFiles }; |
| 467 | + if (!options.fromHistory) { |
| 468 | + global.history.pushState({ projectViewerPath: pathValue }, '', global.location.href); |
| 469 | + this.historyEntry = true; |
| 470 | + } |
451 | 471 | this.previousFocus = doc.activeElement; |
452 | 472 | this.requestId += 1; |
453 | 473 | var requestId = this.requestId; |
|
741 | 761 | this.downloadObjectUrl = ''; |
742 | 762 | }; |
743 | 763 |
|
744 | | - ProjectResourceViewer.prototype.close = function () { |
| 764 | + ProjectResourceViewer.prototype.close = function (options) { |
| 765 | + options = options || {}; |
| 766 | + if (this.historyEntry && !options.fromPopstate) { |
| 767 | + this.historyEntry = false; |
| 768 | + global.history.back(); |
| 769 | + } |
745 | 770 | this.requestId += 1; |
746 | 771 | if (this.abortController && typeof this.abortController.abort === 'function') this.abortController.abort(); |
747 | 772 | this.abortController = null; |
|
762 | 787 | this.close(); |
763 | 788 | doc.removeEventListener('click', this.onDocumentClick); |
764 | 789 | doc.removeEventListener('keydown', this.onDocumentKeydown); |
| 790 | + global.removeEventListener('popstate', this.onPopState); |
765 | 791 | if (this.dialog) this.dialog.remove(); |
766 | 792 | this.dialog = null; |
767 | 793 | this.initialized = false; |
|
0 commit comments