Skip to content

Commit

Permalink
feat(InfiniteGrid): save/restore scroll position in get/setStatus (#38)
Browse files Browse the repository at this point in the history
* feat(InfiniteGrid): save/restore scroll position in get/setStatus

Close #36 
Fixed #38
  • Loading branch information
sculove authored Sep 20, 2017
1 parent ae71b6b commit 1576c44
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 85 deletions.
12 changes: 7 additions & 5 deletions src/InfiniteGrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ const InfiniteGrid = class InfiniteGrid
}
base.style.overflowY = "scroll";
base.appendChild(container);
this.view = base;
this.el = container;
}
this.view = base;
this.el = container;
} else {
this.view = window;
this.el = base;
Expand Down Expand Up @@ -163,18 +163,20 @@ const InfiniteGrid = class InfiniteGrid
layoutManager: this.layoutManager.getStatus(),
options: Object.assign({}, this.options),
prop: data,
scrollPos: utils.scrollTop(this.view),
};
}

/**
* Sets the state of the eg.InfiniteGrid module with the information returned through a call to the getStatue() method.
* @ko getStatue() 메서드가 저장한 정보로 eg.InfiniteGrid 모듈의 상태를 설정한다.
* @param {Object} status State object of the eg.InfiniteGrid module <ko>eg.InfiniteGrid 모듈의 상태 객체</ko>
* @param {boolean} applyScrollPos Checks whether to scroll<ko>스크롤의 위치를 복원할지 결정한다.</ko>
* @return {eg.InfiniteGrid} An instance of a module itself<ko>모듈 자신의 인스턴스</ko>
*/
setStatus(status) {
setStatus(status, applyScrollPos) {
if (!status || !status.options || !status.prop ||
!status.layoutManager || !status.html || !status.cssText) {
!status.layoutManager || !status.html || !status.cssText || !("scrollPos" in status)) {
return this;
}
const target = status.options.isOverflowScroll ? this.view : this.el;
Expand All @@ -189,7 +191,7 @@ const InfiniteGrid = class InfiniteGrid
this._status.topElement = this.getTopElement();
this._status.bottomElement = this.getBottomElement();
this._attachEvent();

applyScrollPos && utils.scrollTo(this.view, 0, status.scrollPos);
return this;
}

Expand Down
5 changes: 3 additions & 2 deletions src/infinitegrid.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ interface InfiniteGridStatus {
};
html: string;
cssText: string;
scrollPos: number;
}

declare class InfiniteGrid {
Expand All @@ -51,7 +52,7 @@ declare class InfiniteGrid {
isRecycling(): boolean;
layout(isRelayout?: boolean): InfiniteGrid;
remove(item: HTMLElement): Item;
setStatus(status: InfiniteGridStatus): InfiniteGrid;
setStatus(status: InfiniteGridStatus, applyScrollPos: boolean): InfiniteGrid;
}

declare namespace InfiniteGrid {
Expand All @@ -67,5 +68,5 @@ declare namespace InfiniteGrid {
function isRecycling(): boolean;
function layout(isRelayout?: boolean): InfiniteGrid;
function remove(item: HTMLElement): Item;
function setStatus(status: InfiniteGridStatus): InfiniteGrid;
function setStatus(status: InfiniteGridStatus, applyScrollPos: boolean): InfiniteGrid;
}
198 changes: 120 additions & 78 deletions test/unit/InfiniteGrid.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {window} from "../../src/browser";
import {utils} from "../../src/utils";
import {CONTAINER_CLASSNAME} from "../../src/consts";
import {Content} from "../content";
import {compareStatus, checkGetStatus} from "./TestHelper";


describe("InfiniteGrid Test", function() {
describe("initailization Test", function() {
Expand Down Expand Up @@ -789,6 +791,7 @@ describe("InfiniteGrid Test", function() {
it("should check a prepend workaround code (doublecheck)", done => {
// Given
const prependHandler = sinon.spy();
document.body.style.height = '10000px'; // for Scroll

this.inst = new InfiniteGrid("#nochildren_grid", {
"count" : 18
Expand All @@ -797,7 +800,7 @@ describe("InfiniteGrid Test", function() {
"layoutComplete": e => {
// Then
expect(e.isAppend).to.be.false;
window.scrollTo(0, 0);
window.scrollTo(0,0);
expect(prependHandler.callCount).to.be.equal(0);
}
});
Expand Down Expand Up @@ -832,6 +835,8 @@ describe("InfiniteGrid Test", function() {

describe("setStatus/getStatue Test", function() {
beforeEach(() => {
document.body.style.height = "10000px"; // for Scroll
window.scrollTo(0, 0);
this.el = sandbox();
this.el.innerHTML = `<ul id="grid"></ul>`;
this.inst = new InfiniteGrid("#grid", {
Expand All @@ -849,12 +854,20 @@ describe("InfiniteGrid Test", function() {
it("should check object in restore method", () => {
// Given
const before = this.inst.getStatus();

this.inst.setStatus({});

// Then
const data = {
options: {},
prop: {},
layoutManager: {},
html: "setStatus",
cssText: "setStatus",
};
this.inst.setStatus(data);

// Then (scrollPos is needed)
expect(this.inst.el.style.cssText).to.be.equal(before.cssText);
expect(this.inst.el.style.cssText).to.be.not.equal(data.cssText);
expect(this.inst.el.innerHTML).to.be.equal(before.html);
expect(this.inst.el.innerHTML).to.be.not.equal(data.html);

// When
this.inst.setStatus();
Expand All @@ -865,79 +878,71 @@ describe("InfiniteGrid Test", function() {
});

it("should check getStatus values", done => {
// Given
const toScroll = 300;

this.inst.on("layoutComplete", function(e) {
// Given
// When
const beforeStatus = this.getStatus();
const beforeLayoutStatus = beforeStatus.layoutManager;

// Then
expect(beforeStatus.html).to.be.equal(this.el.innerHTML);
expect(beforeStatus.cssText).to.be.equal(this.el.style.cssText);

beforeLayoutStatus.items.forEach((v, i) => {
expect(v.position).to.be.deep.equal(this.layoutManager.items[i].position);
expect(v.size).to.be.deep.equal(this.layoutManager.items[i].size);
});
for (let v in beforeStatus.status) {
expect(this._status[v]).to.be.equal(beforeStatus.status[v]);
}
checkGetStatus(this, this.getStatus());
done();
});
window.scrollTo(0, toScroll);
this.inst.append(Content.append(50));
});

it("should check restore status", done => {
function parseCssText(str) {
const ht = {};
this.inst.on("layoutComplete", function(e) {
// Given
const beforeScrollPos = 300;
// When
window.scrollTo(0, beforeScrollPos);
// Then
expect(utils.scrollTop(window)).to.be.equal(beforeScrollPos);

str.split(";").map(v => v.trim())
.filter(v => !utils.isEmptyObject(v))
.forEach(v => {
const a = v.split(":");
const val = a[1].trim();
const beforeStatus = this.getStatus();

window.scrollTo(0, 0);
this.destroy();

if (!utils.isEmptyObject(val)) {
ht[a[0]] = a[1].trim();
}
});
return ht;
}
const infinite = new InfiniteGrid("#grid", {
"count": 18,
});

// When
infinite.setStatus(beforeStatus);

// Then
compareStatus(infinite, beforeStatus, beforeScrollPos);
expect(utils.scrollTop(window)).to.be.equal(0);
done();
});
this.inst.append(Content.append(50));
});

it("should check restore status (apply scroll position)", done => {
this.inst.on("layoutComplete", function(e) {
// Given
const beforeScrollPos = 300;
// When
window.scrollTo(0, beforeScrollPos);
// Then
expect(utils.scrollTop(window)).to.be.equal(beforeScrollPos);

const beforeStatus = this.getStatus();
const beforeLayoutStatus = beforeStatus.layoutManager;

window.scrollTo(0, 0);
this.destroy();
const infinite = new InfiniteGrid("#grid", {
"count": 18,
});

// When
infinite.setStatus(beforeStatus);
infinite.setStatus(beforeStatus, true);

// Then (check infiniteGrid)
expect(infinite.options).to.be.deep.equal(beforeStatus.options);
for(let v in beforeStatus.prop) {
expect(infinite._status[v]).to.be.equal(beforeStatus.prop[v]); // check infiniteGrid properties
};
expect(parseCssText(infinite.el.style.cssText)).to.be.deep.equal(parseCssText(beforeStatus.cssText));

// Then (check layoutManager)
for (let v in beforeLayoutStatus.prop) {
if (v !== "items") {
expect(infinite.layoutManager[v]).to.be.deep.equal(beforeLayoutStatus.prop[v]); // check LayoutManager properties
}
};
infinite.layoutManager.items.forEach((v, i) => {
expect(v.position).to.be.deep.equal(beforeLayoutStatus.items[i].position); // check html and position information
expect(v.size).to.be.deep.equal(beforeLayoutStatus.items[i].size); // check html and size information
expect(v.position).to.be.deep.equal({
"x": parseInt(v.el.style.left, 10),
"y": parseInt(v.el.style.top, 10),
});
});
// Then
compareStatus(infinite, beforeStatus, beforeScrollPos);
expect(utils.scrollTop(window)).to.be.equal(beforeScrollPos);
done();
});
this.inst.append(Content.append(50));
Expand All @@ -952,6 +957,8 @@ describe("InfiniteGrid Test", function() {
"count": 18,
"isOverflowScroll": true,
});
this.inst.el.style.height = "10000px";
this.inst.view.style.height = "50px";
});
afterEach(() => {
if (this.inst) {
Expand All @@ -961,42 +968,77 @@ describe("InfiniteGrid Test", function() {
cleanup();
});

it("should check object in restore method", () => {
it("should check getStatus values", done => {
// Given
const before = this.inst.getStatus();
const toScroll = 100;

this.inst.setStatus({});
this.inst.on("layoutComplete", function(e) {
// Given
// When
checkGetStatus(this, this.getStatus());
done();
});
utils.scrollTo(this.inst.view, 0, toScroll);
this.inst.append(Content.append(50));
});

// Then
expect(this.inst.view.style.cssText).to.be.equal(before.cssText);
expect(this.inst.view.innerHTML).to.be.equal(before.html);
it("should check restore status", done => {
this.inst.on("layoutComplete", function(e) {
// Given
const beforeScrollPos = 100;
// When
utils.scrollTo(this.view, 0, beforeScrollPos);
// Then
expect(utils.scrollTop(this.view)).to.be.equal(beforeScrollPos);

// When
this.inst.setStatus();
const beforeStatus = this.getStatus();

utils.scrollTo(this.view, 0, 0);
this.destroy();

// Then
expect(this.inst.view.style.cssText).to.be.equal(before.cssText);
expect(this.inst.view.innerHTML).to.be.equal(before.html);
const infinite = new InfiniteGrid("#grid", {
"count": 18,
"isOverflowScroll": true,
});
// infinite.el.style.height = "10000px";
// infinite.view.style.height = "50px";

// When
infinite.setStatus(beforeStatus);

// Then
compareStatus(infinite, beforeStatus, beforeScrollPos);
expect(utils.scrollTop(infinite.view)).to.be.equal(0);
done();
});
this.inst.append(Content.append(50));
});

it("should check getStatus values", done => {
it("should check restore status (apply scroll position)", done => {
this.inst.on("layoutComplete", function(e) {
// Given
const beforeScrollPos = 100;
// When
const beforeStatus = this.getStatus();
const beforeLayoutStatus = beforeStatus.layoutManager;
utils.scrollTo(this.view, 0, beforeScrollPos);
// Then
expect(utils.scrollTop(this.view)).to.be.equal(beforeScrollPos);

// Then
expect(beforeStatus.html).to.be.equal(this.view.innerHTML);
expect(beforeStatus.cssText).to.be.equal(this.view.style.cssText);
const beforeStatus = this.getStatus();

utils.scrollTo(this.view, 0, 0);
this.destroy();

beforeLayoutStatus.items.forEach((v, i) => {
expect(v.position).to.be.deep.equal(this.layoutManager.items[i].position);
expect(v.size).to.be.deep.equal(this.layoutManager.items[i].size);
const infinite = new InfiniteGrid("#grid", {
"count": 18,
"isOverflowScroll": true,
});
for (let v in beforeStatus.status) {
expect(this._status[v]).to.be.equal(beforeStatus.status[v]);
}

// When
infinite.setStatus(beforeStatus, true);

// Then
compareStatus(infinite, beforeStatus, beforeScrollPos);
expect(utils.scrollTop(infinite.view)).to.be.equal(beforeScrollPos);
done();
});
this.inst.append(Content.append(50));
Expand Down
Loading

0 comments on commit 1576c44

Please sign in to comment.