| Name | Modified | Size | Downloads / Week |
|---|---|---|---|
| Parent folder | |||
| README.md | 2026-08-29 | 11.9 kB | |
| v1.2.0 source code.tar.gz | 2026-08-29 | 205.7 kB | |
| v1.2.0 source code.zip | 2026-08-29 | 221.5 kB | |
| Totals: 3 Items | 439.1 kB | 0 | |
A full review of src/ turned up a teardown that tore nothing down, a video that
restarted itself after the visitor had paused it, and a second instance that
quietly killed the first. Nothing in the public API was renamed except one event:
the group unmute event went out as video-background-group-umnute, and listeners
bound to that spelling need updating. The jQuery plugin is deprecated here and is
removed in 2.0.0.
Added
-
VideoBackgrounds.disconnect(), full teardown. It destroys every instance, disconnects both observers and removes the two global listeners the factory registered;destroyAll()leaves the factory itself listening, as it always did. -
destroy()onSeekBar,PlayToggleandMuteToggle. None had one, and every listener was attached through a fresh.bind()with no reference kept, so a control removed from the page stayed alive through the element it pointed at and kept running on everyvideo-background-time-update. The controls are documented now, as the optional part of the package they are. -
data-ytbgis read as a source URL.setSource()had always written back to it, but nothing ever read it, so an element carrying onlydata-ytbgwas never picked up. -
An
exportsmap.import { VideoBackgrounds } from 'youtube-background'hands you the class.require()and the CDN keep getting the IIFE bundle, which has no exports — loading it registerswindow.VideoBackgroundsas a side effect. -
Tests, linting and CI.
npm testruns jest over the pure logic behind every fix below,npm run lintruns eslint, and CI runs both plus the build, failing if the checked-in build output is stale.
Changed
-
SeekBarmoves smoothly. It advanced only onvideo-background-time-update, which every provider sends about four times a second, so the thumb visibly stepped; while the video plays it now moves on an animation frame, extrapolating from the last report, and holds rather than stepping back when a report lands a few milliseconds behind it. -
The group unmute event is
video-background-group-unmute. It was dispatched asvideo-background-group-umnute— the only rename in this release, and the only thing here that breaks a listener. -
The source URL is read from
data-vbg,data-youtube, thendata-ytbg.data-youtubeused to win overdata-vbg, which only shows up on an element carrying both. -
setSource()writes back the URL you gave it, not the generated embed URL, so reading the attribute back no longer hands youplayer.vimeo.com/video/…. -
.avisources are typedvideo/x-msvideo, the registered MIME type, instead of the inventedvideo/avi. -
The published package is sources and bundles only — no site, scripts or tests.
-
Sources are now
.mjs. Jest will not treat.jsas ESM while the package stays CommonJS, and it has to stay CommonJS because the published bundles are IIFE and have to remainrequire()-able — the published files and their paths are unchanged. -
The demo page is generated.
site/index.mdgoes throughpoops-docs-themeinto_site/and is deployed by a workflow, and it now documents the options, events and API alongside the live examples. Poops^1.0.18→^3.0.0,poops-docs-theme^1.1.2→^5.1.1— the page gains a theme switcher, a footer and copy buttons, and its stylesheet and script grow from 12KB and 2KB to 40KB and 25KB. Nothing published to npm is affected; both are build-time only. -
book-of-spells^1.0.18→^2.8.0. The.movfix below landed in1.3.1. All eleven helpers the bundle imports are byte-identical across the majors, so nothing here changes behaviour — but the new one carries constants that survive tree shaking, so the minified bundle grows 485 bytes, 288 gzipped. -
The inert
&loop=1is gone from the YouTube embed URL. The embed ignores it without aplaylistparameter, and looping already runs throughonVideoEnded(), which respectsstart-at. -
The README is reconciled with the code — a default export that never existed, a wrong
mobiledefault, an instance variable (playing) that does not exist, a missing event and attribute, and a browser support table listing browsers that cannot run the ES2019 bundles.
Deprecated
- The jQuery plugin,
jQuery('[data-vbg]').youtube_background(). It is removed in 2.0.0; the first call now warns once in the console.new VideoBackgrounds('[data-vbg]')does the same job and has since 1.0.6 — the plugin only ever wrapped it.
Removed
-
onVideoError()onYoutubeBackgroundandVimeoBackground. The lines that would have wired them to the players had been commented out, so neither was ever called. -
VideoBackgroundGroup.onVideoPause(), whose body did nothing the other handlers were not already doing.
Fixed
-
.mov,.m4vand.qtURLs are recognised. They were inMIME_MAPbut detection ran through book-of-spells'RE_VIDEO, which whitelisted onlymp4|ogg|ogv|ogm|webm|avi, so those elements were silently skipped; fixed upstream inbook-of-spells@1.3.1, where a trailing query string or hash no longer blocks a match either. A test keepsMIME_MAPandRE_VIDEOfrom drifting apart. -
autoplay: falseholds on scroll-in. The IntersectionObserver started any video entering the viewport that the visitor had not paused,autoplayor not; it now asksshouldPlay(), the gate the tab-switch path already used (#74). The same gate keeps a video that ended withloopoff from restarting when scrolled back in. -
A user-initiated pause survives a tab switch.
shouldPlay()ignored thepausedflag that exists to prevent exactly that, so returning to the tab restarted a video the visitor had stopped. -
A user-initiated pause survives the end of a looping video.
onVideoEnded()rewound and played on regardless, soloopoverrode the visitor. -
The plugin's own buttons are named for the action they will take, and nothing else. They announced as a bare "button" — their only content an icon — and then carried
aria-pressedreporting the opposite of their state; now the name isPausewhile playing andPlaywhile paused,Mute/Unmutelikewise, with an explicittype="button"and noaria-pressed, since a name that swaps and a pressed state together say it twice (#72). -
PlayToggleandMuteToggleare toggle buttons, not switches.role="switch", which expectsaria-checked, is gone; the name you gave the button stays,aria-pressedalone carries the state, andtype="button"is added where you gave none.SeekBarnames its inputSeekwhen you gave it no name. -
The play button starts in the right state. Its initial state read
params['paused'], which does not exist, so the value wasundefinedand only came out right by accident. -
video-background-group-forward-rewindand-backward-rewindfire. Both were dispatched on a condition tested after the index had already been clamped, so neither could ever be true. -
A missing video link no longer crashes detection.
getVidID()used&&where it meant||, so its null guard never fired and an element with no source attribute threw aTypeError. -
VideoBackgroundandVimeoBackgroundno longer dereference their arguments before checking them. Both read a property off the video data on the way intosuper(), one line above the guard that was supposed to catch it being missing. -
A statically positioned parent gets
position: relative. The check was inverted twice — anabsoluteparent was overwritten withrelativewhile the static parent that actually needs a containing block was left alone. It readsgetComputedStylenow, so a parent positioned from a CSS class is seen too. -
The jQuery plugin survives the second call. It passed a jQuery object to
add(), which expects a DOM element. -
VideoBackgroundGroup.destroy()removes its listeners. Every one was attached and detached through a fresh.bind(), so no removal ever matched and each group leaked all six.VideoBackgroundGroups.destroy()anddestroyAll()guarded onhasOwnProperty('destroy'), never true for a prototype method, so they tore nothing down either. -
VideoBackgrounds.destroyAll()destroys. It passed each instance'splayerElementtodestroy(), butdata-vbg-uidonly ever lands on the wrapper element, so the lookup returnednulland the call was a silent no-op. -
The factory releases its global listeners. It attached a
visibilitychangelistener todocument, plus aresizelistener towindowwhenResizeObserveris missing, and offered no way to remove either;disconnect()above is that way. -
A factory built from an empty selector honours tab visibility. The
visibilitychangelistener was attached after the constructor's early return, so elements added later throughadd()were never resumed. -
add()no longer writes to the params object you passed it. With noIntersectionObserverit setalways-playon that object, which the caller usually shares across every element. -
destroy()no longer throws on mobile-disabled instances, where the constructor returns before a player exists. It also blanked the element's inlinestyleattribute, taking any styles the page had set with it; the original is restored. -
A second
VideoBackgroundsno longer kills the first.window.onYouTubeIframeAPIReadyandwindow.onVimeoIframeAPIReadywere overwritten rather than chained, so the first instance never initialised its players — and any handler the host page had registered was discarded. -
The IntersectionObserver callback survives an unknown element. Entries whose uid was missing or unindexed fell into a branch that dereferenced the missing entry outside the
try/catch. -
A lazy YouTube video no longer autoplays while offscreen. The
notstartedstate YouTube reports on load played the video unconditionally, skipping the intersection check every other path makes. -
looptogether withstart-atreturns tostart-at. The nativeloopattribute wraps to 0:00 and never firesended, so the loop is driven fromonVideoEnded()instead — andsetStartAt()re-decides the attribute, rather than leaving whatever the constructor chose. -
Seeking a video that had not started leaves it visible. The opacity reset compared a CSS string against the number
0. -
fastSeekis used when it exists.hasOwnPropertycannot see a prototype method, so the fast path never ran; it also returned before dispatchingvideo-background-seeked, and both paths emit it now. -
A video URL without a usable extension works. An extensionless URL threw on
.toLowerCase(), and an extension outsideMIME_MAPproducedtype="undefined"on the<source>; the type attribute is omitted when the container is unknown, leaving the browser to sniff it. -
percentCompletereports 0 while the duration is still unknown, where it used to report 100 — every time is past a duration of zero.end-atnow caps the duration through oneMath.minrather than four branches that disagreed at the edges. -
An unlisted Vimeo video survives
setSource(). Theh=hash was dropped on the way to the new embed URL, and the player 404s without it; a public/channels/…/123456789URL no longer reads its own id as a hash either. -
An unrecognised source type no longer dereferences an unassigned index entry. The
switchinadd()had nodefault.
Full Changelog: https://github.com/stamat/youtube-background/compare/v1.1.8...v1.2.0