New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

node-marquee

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-marquee - npm Package Compare versions

Comparing version 2.0.9 to 3.0.5

build/cdn/index.js

107

package.json
{
"name": "node-marquee",
"version": "2.0.9",
"version": "3.0.5",
"description": "Custom Marquee element",
"browserslist": [
"last 20 versions, > 0.5%, ie >= 10"
],
"scripts": {
"release": "npm publish",
"prepare": "npm version patch && npm run prepare:all && npm run docs && npm run demo-build",
"docs": "typedoc --out docs ./src/ts --excludeNotExported --plugin typedoc-plugin-nojekyll",
"pages-build": "webpack --config ./examples-src/webpack/prod.js",
"pages-dev": "webpack serve --config ./examples-src/webpack/dev.js",
"prepare:all": "npm run prepare:es && npm run prepare:cjs && npm run prepare:cdn",
"prepare:es": "tsc ./src/ts/index.ts --allowJs true --outDir ./dist/es --target es6 --moduleResolution node --declaration true --declarationDir ./dist/types --declarationMap true",
"prepare:cjs": "tsc ./src/ts/index.ts --allowJs true --outDir ./dist/cjs --target es5 --module commonjs",
"prepare:cdn": "NODE_ENV=production webpack --config ./webpack/webpack.cdn.conf.js",
"demo-build": "NODE_ENV=production webpack --config ./webpack/webpack.build.conf.js",
"demo-start": "webpack-dev-server --config ./webpack/webpack.dev.conf.js",
"prepare:es": "tsc ./src/ts/index.ts --outDir ./build/es --target es6 --module es6 --moduleResolution node --esModuleInterop true --allowSyntheticDefaultImports true --declaration true --declarationDir ./build/types --declarationMap true",
"prepare:cjs": "tsc ./src/ts/index.ts --outDir ./build/cjs --target es5 --module commonjs --moduleResolution node --esModuleInterop true --allowSyntheticDefaultImports true",
"prepare:cdn": "webpack --config ./config/webpack.cdn.js",
"docs": "typedoc --out examples-build/docs ./src/ts --theme default --hideGenerator",
"gh-pages": "git add examples-build/docs/* && git commit -m \"Update github pages\" && git subtree push --prefix examples-build/ origin gh-pages",
"lint:js": "eslint . --ext .ts,.js",
"lint:scss": "npx stylelint \"**/*.scss\"",
"precommit": "npm run lint:js && npm run lint:scss"
"prepare": "npm run lint:js && npm run prepare:all && npm run pages-build && npm run docs && npm run gh-pages",
"release": "npm version patch && npm publish"
},
"main": "dist/cjs/index.js",
"types": "./dist/types/index.d.ts",
"module": "./dist/es/index.js",
"jsdelivr": "dist/cdn/index.js",
"main": "./build/cjs/index.js",
"types": "./build/types/index.d.ts",
"module": "./build/es/index.js",
"jsdelivr": "./build/cdn/index.js",
"sideEffects": false,
"repository": {

@@ -28,3 +31,4 @@ "type": "git",

"keywords": [
"keyword"
"marquee",
"custom marquee"
],

@@ -34,39 +38,36 @@ "author": "Anthony Bobrov <anton.bobrov@hotmail.com>",

"devDependencies": {
"@babel/cli": "^7.10.5",
"@babel/core": "^7.11.4",
"@typescript-eslint/eslint-plugin": "^3.10.1",
"@typescript-eslint/parser": "^3.10.1",
"autoprefixer": "^9.8.6",
"babel-loader": "^8.1.0",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^6.0.3",
"css-loader": "^4.2.2",
"css-mqpacker": "^7.0.0",
"cssnano": "^4.1.10",
"eslint": "^7.5.0",
"eslint-config-airbnb": "^18.2.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-jsdoc": "^30.0.0",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-react": "^7.20.3",
"file-loader": "^6.0.0",
"html-webpack-plugin": "^4.3.0",
"mini-css-extract-plugin": "^0.10.0",
"postcss-loader": "^3.0.0",
"sass": "^1.26.10",
"sass-loader": "^10.0.1",
"source-map": "^0.7.3",
"style-loader": "^1.2.1",
"stylelint": "^13.6.1",
"stylelint-scss": "^3.18.0",
"terser-webpack-plugin": "^4.1.0",
"ts-loader": "^8.0.3",
"typedoc": "^0.18.0",
"typedoc-plugin-nojekyll": "^1.0.1",
"typescript": "^4.0.2",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^5.1.2",
"normalize-scss": "^7.0.1"
"@babel/core": "^7.14.6",
"@babel/preset-env": "^7.14.7",
"@babel/preset-typescript": "^7.15.0",
"@types/lodash.mergewith": "^4.6.6",
"@types/normalize-wheel": "^1.0.0",
"@typescript-eslint/eslint-plugin": "^4.28.1",
"@typescript-eslint/parser": "^4.28.1",
"babel-loader": "^8.2.2",
"bootstrap": "^5.0.2",
"clean-webpack-plugin": "^4.0.0-alpha.0",
"copy-webpack-plugin": "^9.0.1",
"css-loader": "^6.2.0",
"cssnano": "^5.0.7",
"eslint": "^7.29.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsdoc": "^35.4.1",
"html-webpack-plugin": "^5.3.2",
"mini-css-extract-plugin": "^2.1.0",
"node-sass": "^6.0.1",
"normalize-scss": "^7.0.1",
"path": "^0.12.7",
"postcss-loader": "^6.1.1",
"postcss-preset-env": "^6.7.0",
"sass-loader": "^12.1.0",
"style-loader": "^3.2.1",
"terser-webpack-plugin": "^5.1.4",
"ts-loader": "^9.2.3",
"typedoc": "^0.22.7",
"typescript": "^4.3.5",
"webpack": "^5.41.1",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2",
"webpack-merge": "^5.8.0"
},

@@ -73,0 +74,0 @@ "dependencies": {

# Custom Marquee element
## Documentation: https://antonbobrov.github.io/node-marquee/
<br>
### Demo: https://antonbobrov.github.io/node-marquee/
### Documentation: https://antonbobrov.github.io/node-marquee/docs/
<br>
## How to start with NPM

@@ -21,3 +28,3 @@ ```sh

```html
<div class="node-marquee">This is a marquee element.</div>
<div id="node-marquee">This is a marquee element.</div>
```

@@ -29,4 +36,4 @@ ```js

nodeMarquee({
selector: '.node-marquee'
parent: '#node-marquee'
});
```

@@ -1,2 +0,2 @@

import { selectOne, isElement, addEventListener } from 'vevet-dom';
import { selectOne, addEventListener, createElement } from 'vevet-dom';
import { NodeMarqueeProp, NodeMarquee } from './types';

@@ -9,64 +9,55 @@

/**
* Custom Marquee
* Custom Marquee element
*/
export default function nodeMarquee (
prop: NodeMarqueeProp = {},
argProp: NodeMarqueeProp = {},
): (NodeMarquee | false) {
const className = 'node-marquee';
let destroyed = false;
// default properties
const DEFAULT_PROP: NodeMarqueeProp = {
selector: '.node-marquee',
const defaults: Required<NodeMarqueeProp> = {
parent: '#node-marquee',
speed: 1,
minQuantity: 4,
autoplay: true,
pauseOnHover: false,
applyOuterStyles: true,
optimizeCalculation: false,
useParentStyles: true,
prependWhitespace: true,
};
// extend properties
prop = Object.assign(DEFAULT_PROP, prop);
const prop = Object.assign(defaults, argProp);
// states
const className = 'node-marquee';
// get the outer element
const OUTER = selectOne(prop.selector) as HTMLElement;
// return if the element doesn't exist
if (!isElement(OUTER)) {
// get parent element
const parent = selectOne(prop.parent) as HTMLElement;
if (!(parent instanceof HTMLElement)) {
return false;
}
// add the default class
OUTER.classList.add(className);
parent.classList.add(className);
// states
let isDestroyed = false;
let isPlaying = false;
let progress = 0;
let animationFrame: (false | number) = false;
// get inner text
let text = OUTER.innerHTML;
// quantity of elements
// data
let defaultHTML = parent.innerHTML;
let quantity = 0;
let elements: HTMLElement[] = [];
let elementsWidth: number[] = [];
let items: HTMLElement[] = [];
let itemWidth = 0;
// vars
let translateX = 0;
let isPlaying = false;
// minimum amount of text elements
const MIN_AMOUNT = 4;
// events
let observer: false | MutationObserver = false;
let mutations: undefined | MutationObserver;
const listeners = [
addEventListener(window, 'resize', create),
addEventListener(parent, 'mouseenter', handleMouseEnter),
addEventListener(parent, 'mouseleave', handleMouseLeave),
];
// create the marquee
create();
// create the marquee element
createMarquee();
// set animation frame
let animationFrame: (false | number) = false;
if (prop.autoplay) {

@@ -78,89 +69,76 @@ play();

// set events
const RESIZE_LISTENER = addEventListener(window, 'resize', createMarquee.bind(this));
const MOUSEENTER_LISTENER = addEventListener(OUTER, 'mouseenter', onMouseEnter.bind(this));
const MOUSELEAVE_LISTENER = addEventListener(OUTER, 'mouseleave', onMouseLeave.bind(this));
/**
* Create the marquee elemetnt
*/
function create () {
// reset events
disconnectMutations();
// Create the marquee element
function createMarquee () {
// disable mutation observer
disconnectMutationsObserver();
// clear the outer element
quantity = 0;
elements = [];
elementsWidth = [];
OUTER.innerHTML = '';
items = [];
parent.innerHTML = '';
// apply styles to the outer
if (prop.applyOuterStyles) {
OUTER.style.position = 'relative';
OUTER.style.width = '100%';
OUTER.style.overflow = 'hidden';
OUTER.style.whiteSpace = 'nowrap';
if (prop.useParentStyles) {
parent.style.position = 'relative';
parent.style.width = '100%';
parent.style.overflow = 'hidden';
parent.style.whiteSpace = 'nowrap';
}
// create the first element
const firstEl = createElement();
let firstElWidth = firstEl.clientWidth;
if (firstElWidth <= 0) {
firstElWidth = window.innerWidth;
// create the first item and get its sizes
// to calculate the further quantity of inner elements
const firstItem = createItem();
itemWidth = firstItem.clientWidth;
if (itemWidth <= 0) {
itemWidth = window.innerWidth;
}
// calculate how much elements we need to create in addition to the first one
if (firstElWidth < OUTER.clientWidth) {
quantity = Math.ceil(OUTER.clientWidth * 1.5 / firstElWidth);
if (itemWidth < parent.clientWidth) {
quantity = Math.ceil((parent.clientWidth + itemWidth) / itemWidth);
}
if (quantity < MIN_AMOUNT) {
quantity = MIN_AMOUNT;
if (quantity < prop.minQuantity) {
quantity = prop.minQuantity;
}
// and create them
for (let i = 0; i < quantity - 1; i++) {
createElement(true);
// now when we know the total quantity,
// we can create the rest of the items
for (let index = 1; index < quantity; index += 1) {
createItem(true);
}
// update sizes of the elements
updateSizes();
// render
renderElements();
// render for the first time
renderItems();
// enable mutation observer
observeMutations();
// and to be sure, update sizes once more
if (prop.optimizeCalculation) {
setTimeout(() => {
updateSizes();
}, 500);
}
setTimeout(() => {
updateSizes();
}, 500);
}
function createElement (
absolutePosition = false,
/**
* Create a single element inside the marquee
*/
function createItem (
isAbsolute = false,
) {
const element = createElement('div', {
class: `${className}__el`,
html: `${prop.prependWhitespace ? '&nbsp;' : ''}${defaultHTML}`,
});
const el = document.createElement('div');
el.classList.add(`${className}__el`);
// set text
el.innerHTML = `&nbsp;${text}`;
// apply styles
if (absolutePosition) {
el.style.position = 'absolute';
el.style.top = '0';
el.style.left = '0';
if (isAbsolute) {
element.style.position = 'absolute';
element.style.top = '0';
element.style.left = '0';
}
el.style.display = 'inline-block';
element.style.display = 'inline-block';
// add the element
OUTER.appendChild(el);
elements.push(el);
// append the element
parent.appendChild(element);
items.push(element);
return el;
return element;
}

@@ -170,4 +148,6 @@

// when the marquee is hovered
function onMouseEnter () {
/**
* Event on hover - ON
*/
function handleMouseEnter () {
if (prop.pauseOnHover) {

@@ -178,4 +158,6 @@ pause();

// when the marquee is not hovered anymore
function onMouseLeave () {
/**
* Event on hover - OFF
*/
function handleMouseLeave () {
if (prop.pauseOnHover) {

@@ -188,32 +170,48 @@ play();

// observe changes in DOM
// when there happen some changes, we recreate the marquee element
/**
* Observe DOM content changes
* If a change happend inside the parent element,
* we recreate the marquee element
*/
function observeMutations () {
// observer config
if (mutations) {
return;
}
const config: MutationObserverInit = {
childList: true,
};
// oserver callback
const callback: MutationCallback = (mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === 'childList') {
text = OUTER.innerHTML;
createMarquee();
defaultHTML = parent.innerHTML;
create();
}
}
};
mutations = new MutationObserver(callback);
mutations.observe(parent, config);
}
// create the observer
observer = new MutationObserver(callback);
observer.observe(OUTER, config);
/**
* Destroy mutation observer
*/
function disconnectMutations () {
if (mutations) {
mutations.disconnect();
mutations = undefined;
}
}
function disconnectMutationsObserver () {
if (observer) {
observer.disconnect();
/**
* Update sizes
*/
function updateSizes () {
if (isDestroyed) {
return;
}
const width: number[] = [];
for (let index = 0; index < quantity; index += 1) {
width.push(items[index].clientWidth);
}
itemWidth = Math.max(...width);
}

@@ -223,73 +221,46 @@

// Render the marquee element
/**
* Render the marquee
*/
function render () {
renderElements();
if (isPlaying) {
animationFrame = window.requestAnimationFrame(render.bind(this));
animationFrame = window.requestAnimationFrame(render);
}
renderItems();
}
// Render the Marquee Elements
function renderElements (
/**
* Render inner elements
*/
function renderItems (
speed = prop.speed,
) {
progress -= speed;
translateX += speed;
let moveToEnd: (HTMLElement | false) = false;
let moveToEndIndex = 0;
// get total width
const totalWidth = itemWidth * (quantity - 1);
let w = 0;
// render elements
for (let i = 0; i < quantity; i++) {
const el = elements[i];
// get width of the current element
if (!prop.optimizeCalculation) {
elementsWidth[i] = el.clientWidth;
}
const elWidth = elementsWidth[i];
for (let index = 0; index < quantity; index += 1) {
const el = items[index];
// calulate transforms
const x = w - translateX;
w += elWidth;
const x = wrap(
-itemWidth,
totalWidth,
progress + itemWidth * index,
);
// apply transforms
el.style.transform = `matrix3d(1,0,0.00,0,0.00,1,0.00,0,0,0,1,0, ${x}, 0, 0,1)`;
if (x < elWidth * -1) {
moveToEnd = el;
moveToEndIndex = i;
}
}
}
if (moveToEnd) {
elements.push(elements.splice(elements.indexOf(moveToEnd), 1)[0]);
translateX -= prop.optimizeCalculation ? elementsWidth[moveToEndIndex] : moveToEnd.clientWidth;
if (prop.optimizeCalculation) {
updateSizes();
}
}
function wrap (
min: number, max: number, value: number,
) {
const range = max - min;
return conditionalReturn(value, (val) => ((range + ((val - min) % range)) % range) + min);
}
// Update elements' width
function updateSizes () {
if (destroyed) {
return;
}
for (let i = 0; i < quantity; i++) {
let width = elements[i].clientWidth;
width = elements[i].clientWidth;
if (width <= 0) {
width = window.innerWidth;
}
elementsWidth[i] = width;
}
function conditionalReturn (value: number, func: (val: number) => number) {
return value || value === 0 ? func(value) : func;
}

@@ -299,11 +270,15 @@

// Start the animation frame
/**
* Play the marquee
*/
function play () {
if (!animationFrame) {
isPlaying = true;
animationFrame = window.requestAnimationFrame(render.bind(this));
animationFrame = window.requestAnimationFrame(render);
}
}
// Stop the animation frame
/**
* Pause the marquee
*/
function pause () {

@@ -319,16 +294,13 @@ isPlaying = false;

// Destroy the marquee
/**
* Destroy the marquee element
*/
function destroy () {
destroyed = true;
isDestroyed = true;
pause();
disconnectMutationsObserver();
RESIZE_LISTENER.remove();
MOUSEENTER_LISTENER.remove();
MOUSELEAVE_LISTENER.remove();
OUTER.innerHTML = text;
disconnectMutations();
listeners.forEach((listener) => {
listener.remove();
});
parent.innerHTML = defaultHTML;
}

@@ -339,11 +311,10 @@

return {
play: play.bind(this),
pause: pause.bind(this),
play,
pause,
isPlaying: () => isPlaying,
render: renderElements.bind(this),
recreate: createMarquee.bind(this),
updateSizes: updateSizes.bind(this),
destroy: destroy.bind(this),
render: renderItems,
recreate: create,
updateSizes,
destroy,
};
}
export interface NodeMarqueeProp {
/**
* The selector of the element or the elements itself.
* @default '.node-marquee'
* @default '#node-marquee'
*/
selector?: HTMLElement | string;
parent?: HTMLElement | string;
/**

@@ -13,2 +13,7 @@ * The amount of pixels to move with each frame.

/**
* Minimal amount of inner elements
* @default 1
*/
minQuantity?: number;
/**
* If you want the marquee element to start moving after its initializing.

@@ -24,17 +29,10 @@ * @default true

/**
* If you need to apply default style to the outer element
* If you need to apply default style to the parent element
* @default true
*/
applyOuterStyles?: boolean;
useParentStyles?: boolean;
/**
* By default, the script copies the text and moves it. To calculate the transformations,
* it needs to know the width of each element.
* This very width is calculated with each animation frame
* and in some cases may influence performance.
* If you want to avoid this, set the property as "true", and it won't recalculate
* styles with each frame, though when changing styles of the marquee (f.e., font-size),
* the marquee must be manually recreated.
* @default false
* If need to append a whitespace before each element
*/
optimizeCalculation?: boolean;
prependWhitespace?: boolean;
}

@@ -41,0 +39,0 @@

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc