Skip to content

Commit

Permalink
Old-way is better this case;
Browse files Browse the repository at this point in the history
  • Loading branch information
xobotyi committed Oct 21, 2018
1 parent 8f734de commit 4e6ffee
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 57 deletions.
132 changes: 84 additions & 48 deletions src/util/LoopController.js
Original file line number Diff line number Diff line change
@@ -1,71 +1,107 @@
let loopIsActive = false;
let animationFrame = null;
const loopRegister = [];

class LoopController
{
constructor() {
this.rafStep = this.rafStep.bind(this);
}

getRegisteredItems() {
return [...loopRegister];
}

registerScrollbar(scrollbar) {
if (!loopRegister.includes(scrollbar)) {
loopRegister.push(scrollbar);

this.start();
function LoopControllerClass() {
/**
* @typedef {Object} Scrollbar
* @property {function} update
*/

/**
* @type {Scrollbar[]}
*/
const scrollbarsRegister = [];

/**
* true if loop is active
* @type {boolean}
*/
let isActive = false;
/**
* ID of requested animation frame
* @type {null|number}
*/
let animationFrameId = null;

/**
* Function that called in animation frame
*/
const animationFrameCallback = () => {
if (!isActive) {return;}

for (let scrollbar of scrollbarsRegister) {
scrollbar.update();
}

return this;
requestAnimationFrame(animationFrameCallback);
};

unregisterScrollbar(scrollbar) {
let index = loopRegister.indexOf(scrollbar);
/**
* Stop the loop if it wasn't active
* @return {LoopControllerClass}
*/
this.start = () => {
if (isActive) {return this;}

if (index !== -1) {
loopRegister.length === 1 && this.stop();
isActive = true;

loopRegister.splice(index, 1);
}

return this;
animationFrameId && cancelAnimationFrame(animationFrameId);
requestAnimationFrame(animationFrameCallback);
};
/**
* Stop the loop if it is active
* @return {LoopControllerClass}
*/
this.stop = () => {
if (!isActive) {return this;}

start() {
if (!loopIsActive) {
loopIsActive = true;
isActive = false;

animationFrame && cancelAnimationFrame(animationFrame);
animationFrame = requestAnimationFrame(this.rafStep);
}

return this;
animationFrameId && cancelAnimationFrame(animationFrameId);
animationFrameId = null;
};

rafStep() {
if (!loopIsActive) {return;}
/**
* Return the array pf registered scrollbars
* @return {Scrollbar[]}
*/
this.getRegisteredScrollbars = () => {
return [...scrollbarsRegister];
};
/**
* Add the scrollbar to list to iterate each loop
* @param {Scrollbar} scrollbar
* @return {LoopControllerClass}
*/
this.registerScrollbar = (scrollbar) => {
if (scrollbarsRegister.indexOf(scrollbar) === -1) {
scrollbarsRegister.push(scrollbar);

for (let i = 0; i < loopRegister.length; i++) {
loopRegister[i].update();
this.start();
}

animationFrame = requestAnimationFrame(this.rafStep);
return this;
};
/**
* Remove the scrollbar from list to iterate each loop
* @param {Scrollbar} scrollbar
* @return {LoopControllerClass}
*/
this.unregisterScrollbar = (scrollbar) => {
const index = scrollbarsRegister.indexOf(scrollbar);

stop() {
if (loopIsActive) {
loopIsActive = false;

animationFrame && cancelAnimationFrame(animationFrame);
if (index !== -1) {
scrollbarsRegister.splice(index, 1);
}

return this;
};
}

const instance = new LoopController();
export const LoopController = new LoopControllerClass();
export default LoopController;

export default instance;
/**
* Return new instance of LoopControllerClass
* @return {LoopControllerClass}
*/
export function createLoopController() {
return new LoopControllerClass();
}
23 changes: 14 additions & 9 deletions tests/LoopController.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import expect from "expect";
import React from "react";
import sinon from 'sinon';
import LoopController from '../src/util/LoopController';
import expect from "expect";
import React from "react";
import sinon from 'sinon';
import { createLoopController, LoopController } from '../src/util/LoopController';

describe("LoopController", () => {
const ScrollbarMock = {
Expand All @@ -12,17 +12,18 @@ describe("LoopController", () => {

it("should register the scrollbar", () => {
LoopController.registerScrollbar(ScrollbarMock);
expect(LoopController.getRegisteredItems().length).toEqual(1);
expect(LoopController.getRegisteredScrollbars().length).toEqual(1);
expect(LoopController.getRegisteredScrollbars()[0]).toEqual(ScrollbarMock);
});

it("should call an 'update' method of registered scrollbar", (done) => {
setTimeout(() => {
expect(spy.callCount).toBeGreaterThan(10);
expect(spy.callCount).toBeGreaterThanOrEqual(30);
done();
}, 500);
});

it("should call stop the loop when .stop() executed", (done) => {
it("should stop the loop when .stop() executed", (done) => {
let callCount = spy.callCount * 1;
LoopController.stop();

Expand All @@ -32,7 +33,7 @@ describe("LoopController", () => {
}, 500);
});

it("should call start the loop when .start() executed", (done) => {
it("should start the loop when .start() executed", (done) => {
let callCount = spy.callCount * 1;
LoopController.start();

Expand All @@ -44,6 +45,10 @@ describe("LoopController", () => {

it("should unregister the scrollbar", () => {
LoopController.unregisterScrollbar(ScrollbarMock);
expect(LoopController.getRegisteredItems().length).toEqual(0);
expect(LoopController.getRegisteredScrollbars().length).toEqual(0);
});

it("createLoopController should return new controller", () => {
expect(createLoopController()).not.toEqual(LoopController);
});
});

0 comments on commit 4e6ffee

Please sign in to comment.