Skip to content

Instantly share code, notes, and snippets.

@seyoon20087
Last active November 2, 2021 11:38
Show Gist options
  • Save seyoon20087/87861e753c1f1fab0c3af506585dc901 to your computer and use it in GitHub Desktop.
Save seyoon20087/87861e753c1f1fab0c3af506585dc901 to your computer and use it in GitHub Desktop.
a patch for boostrap to be ssr friendly
diff -u ./bootstrap/js/src/base-component.js ./bootstrap-ssr-friendly/js/src/base-component.js
--- ./bootstrap/js/src/base-component.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/base-component.js 2021-11-02 20:30:24.000000000 +0900
@@ -8,7 +8,9 @@
import Data from './dom/data'
import {
executeAfterTransition,
- getElement
+ getElement,
+ getWindow,
+ getDocument
} from './util/index'
import EventHandler from './dom/event-handler'
@@ -31,6 +33,8 @@
}
this._element = element
+ this._window = getWindow()
+ this._document = getDocument()
Data.set(this._element, this.constructor.DATA_KEY, this)
}
diff -u ./bootstrap/js/src/button.js ./bootstrap-ssr-friendly/js/src/button.js
--- ./bootstrap/js/src/button.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/button.js 2021-11-02 20:30:24.000000000 +0900
@@ -5,7 +5,7 @@
* --------------------------------------------------------------------------
*/
-import { defineJQueryPlugin } from './util/index'
+import { defineJQueryPlugin, getDocument } from './util/index'
import EventHandler from './dom/event-handler'
import BaseComponent from './base-component'
@@ -54,7 +54,7 @@
* Data API implementation
*/
-EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {
+EventHandler.on(getDocument(), EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {
event.preventDefault()
const button = event.target.closest(SELECTOR_DATA_TOGGLE)
diff -u ./bootstrap/js/src/carousel.js ./bootstrap-ssr-friendly/js/src/carousel.js
--- ./bootstrap/js/src/carousel.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/carousel.js 2021-11-02 20:30:24.000000000 +0900
@@ -13,7 +13,9 @@
isVisible,
reflow,
triggerTransitionEnd,
- typeCheckConfig
+ typeCheckConfig,
+ getDocument,
+ getWindow
} from './util/index'
import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
@@ -127,7 +129,7 @@
nextWhenVisible() {
// Don't call next when the page isn't visible
// or the carousel or its parent isn't visible
- if (!document.hidden && isVisible(this._element)) {
+ if (!this._document.hidden && isVisible(this._element)) {
this.next()
}
}
@@ -164,7 +166,7 @@
this._updateInterval()
this._interval = setInterval(
- (document.visibilityState ? this.nextWhenVisible : this.next).bind(this),
+ (this._document.visibilityState ? this.nextWhenVisible : this.next).bind(this),
this._config.interval
)
}
@@ -509,9 +511,9 @@
* Data API implementation
*/
-EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, Carousel.dataApiClickHandler)
+EventHandler.on(getDocument(), EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, Carousel.dataApiClickHandler)
-EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
+EventHandler.on(getWindow(), EVENT_LOAD_DATA_API, () => {
const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)
for (const carousel of carousels) {
diff -u ./bootstrap/js/src/collapse.js ./bootstrap-ssr-friendly/js/src/collapse.js
--- ./bootstrap/js/src/collapse.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/collapse.js 2021-11-02 20:30:24.000000000 +0900
@@ -11,7 +11,8 @@
getElementFromSelector,
getSelectorFromElement,
reflow,
- typeCheckConfig
+ typeCheckConfig,
+ getDocument
} from './util/index'
import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
@@ -289,7 +290,7 @@
* Data API implementation
*/
-EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
+EventHandler.on(getDocument(), EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
// preventDefault only for <a> elements (which change the URL) not inside the collapsible element
if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {
event.preventDefault()
Common subdirectories: ./bootstrap/js/src/dom and ./bootstrap-ssr-friendly/js/src/dom
diff -u ./bootstrap/js/src/dropdown.js ./bootstrap-ssr-friendly/js/src/dropdown.js
--- ./bootstrap/js/src/dropdown.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/dropdown.js 2021-11-02 20:30:24.000000000 +0900
@@ -16,7 +16,8 @@
isRTL,
isVisible,
noop,
- typeCheckConfig
+ typeCheckConfig,
+ getDocument
} from './util/index'
import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
@@ -144,8 +145,8 @@
// empty mouseover listeners to the body's immediate children;
// only needed because of broken event delegation on iOS
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
- if ('ontouchstart' in document.documentElement && !parent.closest(SELECTOR_NAVBAR_NAV)) {
- for (const elem of [].concat(...document.body.children)) {
+ if ('ontouchstart' in this._document.documentElement && !parent.closest(SELECTOR_NAVBAR_NAV)) {
+ for (const elem of [].concat(...this._document.body.children)) {
EventHandler.on(elem, 'mouseover', noop)
}
}
@@ -468,11 +469,13 @@
* Data API implementation
*/
-EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)
-EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)
-EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)
-EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)
-EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
+const documentRef = getDocument()
+
+EventHandler.on(documentRef, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)
+EventHandler.on(documentRef, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)
+EventHandler.on(documentRef, EVENT_CLICK_DATA_API, Dropdown.clearMenus)
+EventHandler.on(documentRef, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)
+EventHandler.on(documentRef, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
event.preventDefault()
Dropdown.getOrCreateInstance(this).toggle()
})
diff -u ./bootstrap/js/src/modal.js ./bootstrap-ssr-friendly/js/src/modal.js
--- ./bootstrap/js/src/modal.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/modal.js 2021-11-02 20:30:24.000000000 +0900
@@ -11,7 +11,8 @@
isRTL,
isVisible,
reflow,
- typeCheckConfig
+ typeCheckConfig,
+ getDocument
} from './util/index'
import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
@@ -212,7 +213,7 @@
if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {
// Don't move modal's DOM position
- document.body.append(this._element)
+ this._document.body.append(this._element)
}
this._element.style.display = 'block'
@@ -275,7 +276,7 @@
this._element.removeAttribute('role')
this._isTransitioning = false
this._backdrop.hide(() => {
- document.body.classList.remove(CLASS_NAME_OPEN)
+ this._document.body.classList.remove(CLASS_NAME_OPEN)
this._resetAdjustments()
this._scrollBar.reset()
EventHandler.trigger(this._element, EVENT_HIDDEN)
@@ -314,7 +315,7 @@
}
const { classList, scrollHeight, style } = this._element
- const isModalOverflowing = scrollHeight > document.documentElement.clientHeight
+ const isModalOverflowing = scrollHeight > this._document.documentElement.clientHeight
// return if the following background transition hasn't yet completed
if ((!isModalOverflowing && style.overflowY === 'hidden') || classList.contains(CLASS_NAME_STATIC)) {
@@ -343,7 +344,7 @@
*/
_adjustDialog() {
- const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight
+ const isModalOverflowing = this._element.scrollHeight > this._document.documentElement.clientHeight
const scrollbarWidth = this._scrollBar.getWidth()
const isBodyOverflowing = scrollbarWidth > 0
@@ -383,7 +384,7 @@
* Data API implementation
*/
-EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
+EventHandler.on(getDocument(), EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
const target = getElementFromSelector(this)
if (['A', 'AREA'].includes(this.tagName)) {
@@ -403,7 +404,7 @@
})
})
- // avoid conflict when clicking moddal toggler while another one is open
+ // avoid conflict when clicking modal toggler while another one is open
const allReadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)
if (allReadyOpen) {
Modal.getInstance(allReadyOpen).hide()
diff -u ./bootstrap/js/src/offcanvas.js ./bootstrap-ssr-friendly/js/src/offcanvas.js
--- ./bootstrap/js/src/offcanvas.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/offcanvas.js 2021-11-02 20:30:24.000000000 +0900
@@ -10,7 +10,9 @@
getElementFromSelector,
isDisabled,
isVisible,
- typeCheckConfig
+ typeCheckConfig,
+ getDocument,
+ getWindow
} from './util/index'
import ScrollBarHelper from './util/scrollbar'
import EventHandler from './dom/event-handler'
@@ -218,7 +220,7 @@
* Data API implementation
*/
-EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
+EventHandler.on(getDocument(), EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
const target = getElementFromSelector(this)
if (['A', 'AREA'].includes(this.tagName)) {
@@ -246,7 +248,7 @@
data.toggle(this)
})
-EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
+EventHandler.on(getWindow(), EVENT_LOAD_DATA_API, () => {
for (const el of SelectorEngine.find(OPEN_SELECTOR)) {
Offcanvas.getOrCreateInstance(el).show()
}
diff -u ./bootstrap/js/src/scrollspy.js ./bootstrap-ssr-friendly/js/src/scrollspy.js
--- ./bootstrap/js/src/scrollspy.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/scrollspy.js 2021-11-02 20:30:24.000000000 +0900
@@ -9,7 +9,8 @@
defineJQueryPlugin,
getElement,
getSelectorFromElement,
- typeCheckConfig
+ typeCheckConfig,
+ getWindow
} from './util/index'
import EventHandler from './dom/event-handler'
import Manipulator from './dom/manipulator'
@@ -63,7 +64,7 @@
class ScrollSpy extends BaseComponent {
constructor(element, config) {
super(element)
- this._scrollElement = this._element.tagName === 'BODY' ? window : this._element
+ this._scrollElement = this._element.tagName === 'BODY' ? this._window : this._element
this._config = this._getConfig(config)
this._offsets = []
this._targets = []
@@ -157,14 +158,14 @@
_getScrollHeight() {
return this._scrollElement.scrollHeight || Math.max(
- document.body.scrollHeight,
- document.documentElement.scrollHeight
+ this._document.body.scrollHeight,
+ this._document.documentElement.scrollHeight
)
}
_getOffsetHeight() {
return this._scrollElement === window ?
- window.innerHeight :
+ this._window.innerHeight :
this._scrollElement.getBoundingClientRect().height
}
@@ -271,7 +272,7 @@
* Data API implementation
*/
-EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
+EventHandler.on(getWindow(), EVENT_LOAD_DATA_API, () => {
for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {
new ScrollSpy(spy) // eslint-disable-line no-new
}
diff -u ./bootstrap/js/src/tab.js ./bootstrap-ssr-friendly/js/src/tab.js
--- ./bootstrap/js/src/tab.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/tab.js 2021-11-02 20:30:24.000000000 +0900
@@ -9,7 +9,8 @@
defineJQueryPlugin,
getElementFromSelector,
isDisabled,
- reflow
+ reflow,
+ getDocument
} from './util/index'
import EventHandler from './dom/event-handler'
import SelectorEngine from './dom/selector-engine'
@@ -184,7 +185,7 @@
* Data API implementation
*/
-EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
+EventHandler.on(getDocument(), EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
if (['A', 'AREA'].includes(this.tagName)) {
event.preventDefault()
}
diff -u ./bootstrap/js/src/tooltip.js ./bootstrap-ssr-friendly/js/src/tooltip.js
--- ./bootstrap/js/src/tooltip.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/tooltip.js 2021-11-02 20:30:24.000000000 +0900
@@ -277,8 +277,8 @@
// empty mouseover listeners to the body's immediate children;
// only needed because of broken event delegation on iOS
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
- if ('ontouchstart' in document.documentElement) {
- for (const element of [].concat(...document.body.children)) {
+ if ('ontouchstart' in this._document.documentElement) {
+ for (const element of [].concat(...this._document.body.children)) {
EventHandler.on(element, 'mouseover', noop)
}
}
@@ -329,8 +329,8 @@
// If this is a touch-enabled device we remove the extra
// empty mouseover listeners we added for iOS support
- if ('ontouchstart' in document.documentElement) {
- for (const element of [].concat(...document.body.children)) {
+ if ('ontouchstart' in this._document.documentElement) {
+ for (const element of [].concat(...this._document.body.children)) {
EventHandler.off(element, 'mouseover', noop)
}
}
@@ -360,7 +360,7 @@
return this.tip
}
- const element = document.createElement('div')
+ const element = this._document.createElement('div')
element.innerHTML = this._config.template
const tip = element.children[0]
Common subdirectories: ./bootstrap/js/src/util and ./bootstrap-ssr-friendly/js/src/util
diff -u ./bootstrap/js/src/util/component-functions.js ./bootstrap-ssr-friendly/js/src/util/component-functions.js
--- ./bootstrap/js/src/util/component-functions.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/util/component-functions.js 2021-11-02 20:30:24.000000000 +0900
@@ -6,13 +6,13 @@
*/
import EventHandler from '../dom/event-handler'
-import { getElementFromSelector, isDisabled } from './index'
+import { getElementFromSelector, isDisabled, getDocument } from './index'
const enableDismissTrigger = (component, method = 'hide') => {
const clickEvent = `click.dismiss${component.EVENT_KEY}`
const name = component.NAME
- EventHandler.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) {
+ EventHandler.on(getDocument(), clickEvent, `[data-bs-dismiss="${name}"]`, function (event) {
if (['A', 'AREA'].includes(this.tagName)) {
event.preventDefault()
}
diff -u ./bootstrap/js/src/util/index.js ./bootstrap-ssr-friendly/js/src/util/index.js
--- ./bootstrap/js/src/util/index.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/util/index.js 2021-11-02 20:30:24.000000000 +0900
@@ -25,7 +25,7 @@
const getUID = prefix => {
do {
prefix += Math.floor(Math.random() * MAX_UID)
- } while (document.getElementById(prefix))
+ } while (getDocument().getElementById(prefix))
return prefix
}
@@ -59,7 +59,7 @@
const selector = getSelector(element)
if (selector) {
- return document.querySelector(selector) ? selector : null
+ return getDocument().querySelector(selector) ? selector : null
}
return null
@@ -68,7 +68,7 @@
const getElementFromSelector = element => {
const selector = getSelector(element)
- return selector ? document.querySelector(selector) : null
+ return selector ? getDocument().querySelector(selector) : null
}
const getTransitionDurationFromElement = element => {
@@ -77,7 +77,7 @@
}
// Get transition-duration of the element
- let { transitionDuration, transitionDelay } = window.getComputedStyle(element)
+ let { transitionDuration, transitionDelay } = getWindow().getComputedStyle(element)
const floatTransitionDuration = Number.parseFloat(transitionDuration)
const floatTransitionDelay = Number.parseFloat(transitionDelay)
@@ -162,7 +162,7 @@
}
const findShadowRoot = element => {
- if (!document.documentElement.attachShadow) {
+ if (!getDocument().documentElement.attachShadow) {
return null
}
@@ -195,13 +195,14 @@
* @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
*/
const reflow = element => {
- element.offsetHeight // eslint-disable-line no-unused-expressions
+ // eslint-disable-next-line no-unused-expressions
+ element.offsetHeight
}
const getjQuery = () => {
const { jQuery } = window
- if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
+ if (jQuery && !getDocument().body.hasAttribute('data-bs-no-jquery')) {
return jQuery
}
@@ -211,10 +212,10 @@
const DOMContentLoadedCallbacks = []
const onDOMContentLoaded = callback => {
- if (document.readyState === 'loading') {
+ if (getDocument().readyState === 'loading') {
// add listener on the first call when the document is in loading state
if (!DOMContentLoadedCallbacks.length) {
- document.addEventListener('DOMContentLoaded', () => {
+ getDocument().addEventListener('DOMContentLoaded', () => {
for (const callback of DOMContentLoadedCallbacks) {
callback()
}
@@ -227,7 +228,7 @@
}
}
-const isRTL = () => document.documentElement.dir === 'rtl'
+const isRTL = () => getDocument().documentElement.dir === 'rtl'
const defineJQueryPlugin = plugin => {
onDOMContentLoaded(() => {
@@ -309,11 +310,26 @@
return list[Math.max(0, Math.min(index, listLength - 1))]
}
+/**
+ * @return {window|{}} The proper element
+ */
+const getWindow = () => {
+ return typeof window !== 'undefined' ? window : {}
+}
+
+/**
+ * @return {document|{}} The proper element
+ */
+const getDocument = () => {
+ return typeof document !== 'undefined' ? document : {}
+}
+
export {
defineJQueryPlugin,
execute,
executeAfterTransition,
findShadowRoot,
+ getDocument,
getElement,
getElementFromSelector,
getjQuery,
@@ -321,6 +337,7 @@
getSelectorFromElement,
getTransitionDurationFromElement,
getUID,
+ getWindow,
isDisabled,
isElement,
isRTL,
diff -u ./bootstrap/js/src/util/sanitizer.js ./bootstrap-ssr-friendly/js/src/util/sanitizer.js
--- ./bootstrap/js/src/util/sanitizer.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/util/sanitizer.js 2021-11-02 20:30:24.000000000 +0900
@@ -5,6 +5,8 @@
* --------------------------------------------------------------------------
*/
+import { getWindow } from './index'
+
const uriAttributes = new Set([
'background',
'cite',
@@ -91,7 +93,8 @@
return sanitizeFn(unsafeHtml)
}
- const domParser = new window.DOMParser()
+ const windowRef = getWindow()
+ const domParser = new windowRef.DOMParser()
const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')
const elements = [].concat(...createdDocument.body.querySelectorAll('*'))
diff -u ./bootstrap/js/src/util/scrollbar.js ./bootstrap-ssr-friendly/js/src/util/scrollbar.js
--- ./bootstrap/js/src/util/scrollbar.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/util/scrollbar.js 2021-11-02 20:30:24.000000000 +0900
@@ -7,7 +7,7 @@
import SelectorEngine from '../dom/selector-engine'
import Manipulator from '../dom/manipulator'
-import { isElement } from './index'
+import { isElement, getDocument } from './index'
/**
* Constants
@@ -22,7 +22,7 @@
class ScrollBarHelper {
constructor() {
- this._element = document.body
+ this._element = getDocument().body
}
// Public
diff -u ./bootstrap/js/src/util/swipe.js ./bootstrap-ssr-friendly/js/src/util/swipe.js
--- ./bootstrap/js/src/util/swipe.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/util/swipe.js 2021-11-02 20:30:24.000000000 +0900
@@ -6,7 +6,7 @@
*/
import EventHandler from '../dom/event-handler'
-import { execute, typeCheckConfig } from './index'
+import { execute, getDocument, getWindow, typeCheckConfig } from './index'
/**
* Constants
@@ -50,7 +50,7 @@
this._config = this._getConfig(config)
this._deltaX = 0
- this._supportPointerEvents = Boolean(window.PointerEvent)
+ this._supportPointerEvents = Boolean(getWindow().PointerEvent)
this._initEvents()
}
@@ -133,7 +133,7 @@
// Static
static isSupported() {
- return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0
+ return 'ontouchstart' in getDocument().documentElement || navigator.maxTouchPoints > 0
}
}
diff -u ./bootstrap/js/src/dom/event-handler.js ./bootstrap-ssr-friendly/js/src/dom/event-handler.js
--- ./bootstrap/js/src/dom/event-handler.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/dom/event-handler.js 2021-11-02 20:30:24.000000000 +0900
@@ -5,7 +5,7 @@
* --------------------------------------------------------------------------
*/
-import { getjQuery } from '../util/index'
+import { getjQuery, getDocument } from '../util/index'
/**
* Constants
@@ -302,7 +302,7 @@
}
if (isNative) {
- evt = document.createEvent('HTMLEvents')
+ evt = getDocument().createEvent('HTMLEvents')
evt.initEvent(typeEvent, bubbles, true)
} else {
evt = new CustomEvent(event, { bubbles, cancelable: true })
diff -u ./bootstrap/js/src/dom/manipulator.js ./bootstrap-ssr-friendly/js/src/dom/manipulator.js
--- ./bootstrap/js/src/dom/manipulator.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/dom/manipulator.js 2021-11-02 20:30:24.000000000 +0900
@@ -5,6 +5,8 @@
* --------------------------------------------------------------------------
*/
+import { getWindow } from '../util/index'
+
function normalizeData(val) {
if (val === 'true') {
return true
@@ -61,10 +63,11 @@
offset(element) {
const rect = element.getBoundingClientRect()
+ const windowRef = getWindow()
return {
- top: rect.top + window.pageYOffset,
- left: rect.left + window.pageXOffset
+ top: rect.top + windowRef.pageYOffset,
+ left: rect.left + windowRef.pageXOffset
}
},
diff -u ./bootstrap/js/src/dom/selector-engine.js ./bootstrap-ssr-friendly/js/src/dom/selector-engine.js
--- ./bootstrap/js/src/dom/selector-engine.js 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/js/src/dom/selector-engine.js 2021-11-02 20:30:24.000000000 +0900
@@ -5,7 +5,7 @@
* --------------------------------------------------------------------------
*/
-import { isDisabled, isVisible } from '../util/index'
+import { getDocument, isDisabled, isVisible } from '../util/index'
/**
* Constants
@@ -14,11 +14,11 @@
const NODE_TEXT = 3
const SelectorEngine = {
- find(selector, element = document.documentElement) {
+ find(selector, element = getDocument().documentElement) {
return [].concat(...Element.prototype.querySelectorAll.call(element, selector))
},
- findOne(selector, element = document.documentElement) {
+ findOne(selector, element = getDocument().documentElement) {
return Element.prototype.querySelector.call(element, selector)
},
--- ./bootstrap/package.json 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/package.json 2021-11-02 20:30:24.000000000 +0900
@@ -116,6 +116,7 @@
"eslint": "^8.1.0",
"eslint-config-xo": "^0.39.0",
"eslint-plugin-import": "^2.25.2",
+ "eslint-plugin-ssr-friendly": "^1.0.5",
"eslint-plugin-unicorn": "^37.0.1",
"find-unused-sass-variables": "^3.1.0",
"glob": "^7.2.0",
--- ./bootstrap/.eslintrc.json 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/.eslintrc.json 2021-11-02 20:30:24.000000000 +0900
@@ -61,5 +61,18 @@
"unicorn/prefer-query-selector": "off",
"unicorn/prefer-spread": "off",
"unicorn/prevent-abbreviations": "off"
- }
+ },
+ "overrides": [
+ {
+ "files": "js/src/**/*.js",
+ "plugins": ["ssr-friendly"],
+ "extends": [
+ "plugin:ssr-friendly/recommended"
+ ],
+ "rules": {
+ "ssr-friendly/no-dom-globals-in-react-cc-render": "off",
+ "ssr-friendly/no-dom-globals-in-react-fc": "off"
+ }
+ }
+ ]
}
--- ./bootstrap/package-lock.json 2021-11-02 20:30:03.000000000 +0900
+++ ./bootstrap-ssr-friendly/package-lock.json 2021-11-02 20:34:52.000000000 +0900
@@ -25,6 +25,7 @@
"eslint": "^8.1.0",
"eslint-config-xo": "^0.39.0",
"eslint-plugin-import": "^2.25.2",
+ "eslint-plugin-ssr-friendly": "^1.0.5",
"eslint-plugin-unicorn": "^37.0.1",
"find-unused-sass-variables": "^3.1.0",
"glob": "^7.2.0",
@@ -1684,9 +1685,9 @@
}
},
"node_modules/@cspell/cspell-bundled-dicts": {
- "version": "5.12.4",
- "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.12.4.tgz",
- "integrity": "sha512-+rbeDNGVX9kYF6ARNLyCRL0lHsS0Kxwb38Dk9bPk/qx3HeKjrVfg6mupFH+kTDWJFCh+ua3D07yPc3TZzcdVIg==",
+ "version": "5.12.5",
+ "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.12.5.tgz",
+ "integrity": "sha512-uuoAYkw1O+AcHx16XN8u42eCm4yLgT0D9vOWnrOKJEScpIvyrgHbL/B71PAkmeTwfhPWhyHb3m/QjYXzio3Olw==",
"dev": true,
"dependencies": {
"@cspell/dict-ada": "^1.1.2",
@@ -1700,7 +1701,7 @@
"@cspell/dict-django": "^1.0.26",
"@cspell/dict-dotnet": "^1.0.32",
"@cspell/dict-elixir": "^1.0.26",
- "@cspell/dict-en_us": "^2.1.2",
+ "@cspell/dict-en_us": "^2.1.3",
"@cspell/dict-en-gb": "^1.1.33",
"@cspell/dict-filetypes": "^2.0.1",
"@cspell/dict-fonts": "^1.0.14",
@@ -3952,17 +3953,17 @@
}
},
"node_modules/cspell": {
- "version": "5.12.4",
- "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.12.4.tgz",
- "integrity": "sha512-O0jA0Hd6AfBJHLATsQ0QUSDrjcDCUsrWMQSBjqK6EEJKZhZjoBDCKrgJqh8Qp3MvLIgHqq4r75JrsfRk5SZwhQ==",
+ "version": "5.12.5",
+ "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.12.5.tgz",
+ "integrity": "sha512-jfHJ5/TpQ2qrP8K474GoW6axMhkbBx4q2P4TojbkSaDQ/KrvXJjPvvGDYBzCTwu0RyosiLEiJfdyUohGi76eLw==",
"dev": true,
"dependencies": {
"chalk": "^4.1.2",
"commander": "^8.3.0",
"comment-json": "^4.1.1",
- "cspell-gitignore": "^5.12.4",
+ "cspell-gitignore": "^5.12.5",
"cspell-glob": "^5.12.4",
- "cspell-lib": "^5.12.4",
+ "cspell-lib": "^5.12.5",
"fast-json-stable-stringify": "^2.1.0",
"file-entry-cache": "^6.0.1",
"fs-extra": "^10.0.0",
@@ -3983,9 +3984,9 @@
}
},
"node_modules/cspell-gitignore": {
- "version": "5.12.4",
- "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-5.12.4.tgz",
- "integrity": "sha512-a5pK6gFEtcGAEESV74m21KvRi0afMw3QE2WXcC0v2lHYyHyHeDK/eLQbk8cVSbuMTaXgDyFtyBwSP7Qq0PAnFg==",
+ "version": "5.12.5",
+ "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-5.12.5.tgz",
+ "integrity": "sha512-I1QizO6LSSpeaEzBjtmcPu09l7bMvvUsVhsHWtzp6RVz3DXQq/ntn/s5HPGCcRVTXO9eeRePTy1LfOsHZO1cMQ==",
"dev": true,
"dependencies": {
"cspell-glob": "^5.12.4",
@@ -4020,12 +4021,12 @@
}
},
"node_modules/cspell-lib": {
- "version": "5.12.4",
- "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.12.4.tgz",
- "integrity": "sha512-NqmQ1j5PsQZJxUqdPaEMrNSKmIiaWSQVzITGfW08FEiTCqSpHxRQdNMM6B7nYUS0NgS5wYwycNMkEWaRQebI+Q==",
+ "version": "5.12.5",
+ "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.12.5.tgz",
+ "integrity": "sha512-7pPFWrojoeQnYchFKLBpeF+39ZKIyLuuneydZCaOIFGzUwyKX6uK4Cfz9rEs0CBLqXqlsectm9WOloW3KTs8KA==",
"dev": true,
"dependencies": {
- "@cspell/cspell-bundled-dicts": "^5.12.4",
+ "@cspell/cspell-bundled-dicts": "^5.12.5",
"@cspell/cspell-types": "^5.12.4",
"clear-module": "^4.1.1",
"comment-json": "^4.1.1",
@@ -4033,7 +4034,7 @@
"cosmiconfig": "^7.0.1",
"cspell-glob": "^5.12.4",
"cspell-io": "^5.12.4",
- "cspell-trie-lib": "^5.12.4",
+ "cspell-trie-lib": "^5.12.5",
"find-up": "^5.0.0",
"fs-extra": "^10.0.0",
"gensequence": "^3.1.1",
@@ -4047,9 +4048,9 @@
}
},
"node_modules/cspell-trie-lib": {
- "version": "5.12.4",
- "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.12.4.tgz",
- "integrity": "sha512-WXnqSVyqP7ZhRWxF3C4olXATETyxD+43f0T0Jzlq0Dz8nxXmzEl79Ws9sEZo4ssLTMXaEcx4Uh361vQYZY+irA==",
+ "version": "5.12.5",
+ "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.12.5.tgz",
+ "integrity": "sha512-oF2LR860BhKISIyQ8FSzq7a+dB9fbFcYP42LeO8NsXk0qhv9gTR3ReiyA1rcp9ocClpg26AhU08dNuAxcHQBmA==",
"dev": true,
"dependencies": {
"fs-extra": "^10.0.0",
@@ -5083,6 +5084,45 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
},
+ "node_modules/eslint-plugin-ssr-friendly": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-ssr-friendly/-/eslint-plugin-ssr-friendly-1.0.5.tgz",
+ "integrity": "sha512-F1vKfzhOnrIXhcx91Y3r1x8vjJAoCex25PUgYErOe6q95T4KuCTz6+LgGQ4TTvhBdCfNqu1U0krAHe3UNuEOqg==",
+ "dev": true,
+ "dependencies": {
+ "globals": "^13.2.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=0.8.0"
+ }
+ },
+ "node_modules/eslint-plugin-ssr-friendly/node_modules/globals": {
+ "version": "13.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz",
+ "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint-plugin-ssr-friendly/node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/eslint-plugin-unicorn": {
"version": "37.0.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-37.0.1.tgz",
@@ -14276,9 +14316,9 @@
}
},
"@cspell/cspell-bundled-dicts": {
- "version": "5.12.4",
- "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.12.4.tgz",
- "integrity": "sha512-+rbeDNGVX9kYF6ARNLyCRL0lHsS0Kxwb38Dk9bPk/qx3HeKjrVfg6mupFH+kTDWJFCh+ua3D07yPc3TZzcdVIg==",
+ "version": "5.12.5",
+ "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-5.12.5.tgz",
+ "integrity": "sha512-uuoAYkw1O+AcHx16XN8u42eCm4yLgT0D9vOWnrOKJEScpIvyrgHbL/B71PAkmeTwfhPWhyHb3m/QjYXzio3Olw==",
"dev": true,
"requires": {
"@cspell/dict-ada": "^1.1.2",
@@ -14292,7 +14332,7 @@
"@cspell/dict-django": "^1.0.26",
"@cspell/dict-dotnet": "^1.0.32",
"@cspell/dict-elixir": "^1.0.26",
- "@cspell/dict-en_us": "^2.1.2",
+ "@cspell/dict-en_us": "^2.1.3",
"@cspell/dict-en-gb": "^1.1.33",
"@cspell/dict-filetypes": "^2.0.1",
"@cspell/dict-fonts": "^1.0.14",
@@ -16053,17 +16093,17 @@
"dev": true
},
"cspell": {
- "version": "5.12.4",
- "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.12.4.tgz",
- "integrity": "sha512-O0jA0Hd6AfBJHLATsQ0QUSDrjcDCUsrWMQSBjqK6EEJKZhZjoBDCKrgJqh8Qp3MvLIgHqq4r75JrsfRk5SZwhQ==",
+ "version": "5.12.5",
+ "resolved": "https://registry.npmjs.org/cspell/-/cspell-5.12.5.tgz",
+ "integrity": "sha512-jfHJ5/TpQ2qrP8K474GoW6axMhkbBx4q2P4TojbkSaDQ/KrvXJjPvvGDYBzCTwu0RyosiLEiJfdyUohGi76eLw==",
"dev": true,
"requires": {
"chalk": "^4.1.2",
"commander": "^8.3.0",
"comment-json": "^4.1.1",
- "cspell-gitignore": "^5.12.4",
+ "cspell-gitignore": "^5.12.5",
"cspell-glob": "^5.12.4",
- "cspell-lib": "^5.12.4",
+ "cspell-lib": "^5.12.5",
"fast-json-stable-stringify": "^2.1.0",
"file-entry-cache": "^6.0.1",
"fs-extra": "^10.0.0",
@@ -16132,9 +16172,9 @@
}
},
"cspell-gitignore": {
- "version": "5.12.4",
- "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-5.12.4.tgz",
- "integrity": "sha512-a5pK6gFEtcGAEESV74m21KvRi0afMw3QE2WXcC0v2lHYyHyHeDK/eLQbk8cVSbuMTaXgDyFtyBwSP7Qq0PAnFg==",
+ "version": "5.12.5",
+ "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-5.12.5.tgz",
+ "integrity": "sha512-I1QizO6LSSpeaEzBjtmcPu09l7bMvvUsVhsHWtzp6RVz3DXQq/ntn/s5HPGCcRVTXO9eeRePTy1LfOsHZO1cMQ==",
"dev": true,
"requires": {
"cspell-glob": "^5.12.4",
@@ -16157,12 +16197,12 @@
"dev": true
},
"cspell-lib": {
- "version": "5.12.4",
- "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.12.4.tgz",
- "integrity": "sha512-NqmQ1j5PsQZJxUqdPaEMrNSKmIiaWSQVzITGfW08FEiTCqSpHxRQdNMM6B7nYUS0NgS5wYwycNMkEWaRQebI+Q==",
+ "version": "5.12.5",
+ "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-5.12.5.tgz",
+ "integrity": "sha512-7pPFWrojoeQnYchFKLBpeF+39ZKIyLuuneydZCaOIFGzUwyKX6uK4Cfz9rEs0CBLqXqlsectm9WOloW3KTs8KA==",
"dev": true,
"requires": {
- "@cspell/cspell-bundled-dicts": "^5.12.4",
+ "@cspell/cspell-bundled-dicts": "^5.12.5",
"@cspell/cspell-types": "^5.12.4",
"clear-module": "^4.1.1",
"comment-json": "^4.1.1",
@@ -16170,7 +16210,7 @@
"cosmiconfig": "^7.0.1",
"cspell-glob": "^5.12.4",
"cspell-io": "^5.12.4",
- "cspell-trie-lib": "^5.12.4",
+ "cspell-trie-lib": "^5.12.5",
"find-up": "^5.0.0",
"fs-extra": "^10.0.0",
"gensequence": "^3.1.1",
@@ -16181,9 +16221,9 @@
}
},
"cspell-trie-lib": {
- "version": "5.12.4",
- "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.12.4.tgz",
- "integrity": "sha512-WXnqSVyqP7ZhRWxF3C4olXATETyxD+43f0T0Jzlq0Dz8nxXmzEl79Ws9sEZo4ssLTMXaEcx4Uh361vQYZY+irA==",
+ "version": "5.12.5",
+ "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-5.12.5.tgz",
+ "integrity": "sha512-oF2LR860BhKISIyQ8FSzq7a+dB9fbFcYP42LeO8NsXk0qhv9gTR3ReiyA1rcp9ocClpg26AhU08dNuAxcHQBmA==",
"dev": true,
"requires": {
"fs-extra": "^10.0.0",
@@ -17037,6 +17077,32 @@
}
}
},
+ "eslint-plugin-ssr-friendly": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-ssr-friendly/-/eslint-plugin-ssr-friendly-1.0.5.tgz",
+ "integrity": "sha512-F1vKfzhOnrIXhcx91Y3r1x8vjJAoCex25PUgYErOe6q95T4KuCTz6+LgGQ4TTvhBdCfNqu1U0krAHe3UNuEOqg==",
+ "dev": true,
+ "requires": {
+ "globals": "^13.2.0"
+ },
+ "dependencies": {
+ "globals": {
+ "version": "13.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz",
+ "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.20.2"
+ }
+ },
+ "type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true
+ }
+ }
+ },
"eslint-plugin-unicorn": {
"version": "37.0.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-37.0.1.tgz",
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment