Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(LayoutManager): add LayoutManger module and fix Infinite scroll #196

Closed
wants to merge 9 commits into from
2 changes: 0 additions & 2 deletions declaration/layouts/Layout.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ export interface Group {
outlines: {
start: number[],
end: number[],
startIndex?: number,
endIndex?: number,
};
}

Expand Down
1 change: 1 addition & 0 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module.exports = function(config) {

// list of files / patterns to load in the browser
files: [
"./node_modules/babel-polyfill/dist/polyfill.js",
"./node_modules/lite-fixture/index.js",
"./test/unit/**/*.spec.js",
'test/unit/image/*.jpg',
Expand Down
37 changes: 36 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"babel-plugin-transform-es3-member-expression-literals": "^6.22.0",
"babel-plugin-transform-es3-property-literals": "^6.22.0",
"babel-plugin-transform-object-assign": "^6.22.0",
"babel-polyfill": "^6.26.0",
"babel-preset-es2015": "^6.24.1",
"chai": "^4.1.2",
"chalk": "^2.3.0",
Expand Down
50 changes: 24 additions & 26 deletions src/DOMRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
MULTI,
GROUPKEY_ATT,
CONTAINER_CLASSNAME,
DEFENSE_BROWSER,
} from "./consts";
import {window, document} from "./browser";
import {
Expand All @@ -18,7 +17,7 @@ import {
} from "./utils";


function _defense(element) {
function createContainer(element) {
const container = document.createElement("div");

container.className = CONTAINER_CLASSNAME;
Expand All @@ -31,7 +30,6 @@ function _defense(element) {
for (let i = 0; i < length; i++) {
container.appendChild(children[0]);
}

element.appendChild(container);
return container;
}
Expand Down Expand Up @@ -72,22 +70,27 @@ export default class DOMRenderer {
parentNode.removeChild(element);
}
static createElements(items) {
if (!items.length || items[0].el) {
return items;
if (!items.length) {
return;
}
const noElementItems = items.filter(item => !item.el);

if (!noElementItems.length) {
return;
}
const elements = $(items.map(({content}) =>
const elements = $(noElementItems.map(({content}) =>
content.replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, "")).join(""), MULTI);

return items.map((item, index) => {
noElementItems.forEach((item, index) => {
item.el = elements[index];
return item;
});
}
constructor(element, options) {
Object.assign(this.options = {
isOverflowScroll: false,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Younkue remove

isEqualSize: false,
horizontal: false,
container: false,
}, options);
this._size = {
container: -1,
Expand All @@ -101,13 +104,11 @@ export default class DOMRenderer {
getStatus() {
return {
cssText: this.container.style.cssText,
options: Object.assign({}, this.options),
_size: Object.assign({}, this._size),
};
}
setStatus(status) {
this.container.style.cssText = status.cssText;
Object.assign(this.options, status.options);
Object.assign(this._size, status._size);
}
updateSize(items) {
Expand Down Expand Up @@ -135,24 +136,23 @@ export default class DOMRenderer {
_init(el) {
const element = $(el);
const style = getStyles(element);
const {isOverflowScroll, horizontal} = this.options;
const {container, horizontal} = this.options;

this._orgStyle = {};

if (style.position === "static") {
this._orgStyle.position = element.style.position;
element.style.position = "relative";
}
if (isOverflowScroll) {
if (container) {
const target = horizontal ? ["X", "Y"] : ["Y", "X"];

this._orgStyle.overflowX = element.style.overflowX;
this._orgStyle.overflowY = element.style.overflowY;
element.style[`overflow${target[0]}`] = "scroll";
element.style[`overflow${target[1]}`] = "hidden";
this.view = element;
// defense code for android < 4.4 or webkit < 537
this.container = horizontal && DEFENSE_BROWSER ? _defense(element) : element;
this.container = container === true ? createContainer(this.view) : container;
} else {
this.view = window;
this.container = element;
Expand All @@ -171,10 +171,10 @@ export default class DOMRenderer {
});
}
createAndInsert(items, isAppend) {
const itemsWithElement = DOMRenderer.createElements(items);
DOMRenderer.createElements(items);

DOMRenderer.renderItems(itemsWithElement);
this._insert(itemsWithElement, isAppend);
DOMRenderer.renderItems(items);
this._insert(items, isAppend);
}
_insert(items, isAppend, styles) {
const container = this.container;
Expand All @@ -199,11 +199,7 @@ export default class DOMRenderer {
return this._size.viewport;
}
setContainerSize(size) {
const {isOverflowScroll, horizontal} = this.options;

if (!isOverflowScroll || (horizontal && DEFENSE_BROWSER)) {
this.container.style[horizontal ? "width" : "height"] = `${size}px`;
}
this.container.style[this.options.horizontal ? "width" : "height"] = `${size}px`;
}
resize() {
const horizontal = this.options.horizontal;
Expand All @@ -224,9 +220,8 @@ export default class DOMRenderer {
}
clear() {
this.container.innerHTML = "";
if (!this.options.isOverflowScroll) {
this.container.style[this.options.horizontal ? "width" : "height"] = "";
}
this.container.style[this.options.horizontal ? "width" : "height"] = "";

this._size = {
item: null,
viewport: -1,
Expand All @@ -236,9 +231,12 @@ export default class DOMRenderer {
}
destroy() {
this.clear();
const container = this.options.container;

for (const p in this._orgStyle) {
this[this.options.isOverflowScroll ? "view" : "container"].style[p] = this._orgStyle[p];
this[container ? "view" : "container"].style[p] = this._orgStyle[p];
}
container && this.container.parentNode.removeChild(this.container);
}
}

88 changes: 44 additions & 44 deletions src/Infinite.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,69 +66,69 @@ class Infinite {
this.setCursor("end", start - 1);
}
}
scroll(scrollPos, isForward) {
const {startCursor, endCursor, size} = this._status;
scroll(scrollPos) {
const startCursor = this.getCursor("start");
const endCursor = this.getCursor("end");
const items = this._items;

if (startCursor === -1 || endCursor === -1) {
if (typeof scrollPos !== "number" || startCursor === -1 ||
endCursor === -1 || !items.size()) {
return;
}
const {append, prepend, threshold} = this.options;
const items = this._items;
const length = items.size();
const endScrollPos = scrollPos + size;
const targetItem = items.getData(isForward ? endCursor : startCursor);
const outlines = targetItem.outlines[isForward ? "end" : "start"];
const edgePos = Math[isForward ? "min" : "max"](...outlines);
const size = this._status.size;
const {threshold, append, prepend} = this.options;
const datas = items.get();
const endScrollPos = Math.max(scrollPos, 0) + size;
const startEdgePos = Math.max(...datas[startCursor].outlines.start);
const endEdgePos = Math.min(...datas[endCursor].outlines.end);
const visibles = datas.map((group, i) => {
const {start, end} = group.outlines;

if (isForward) {
if (endScrollPos >= edgePos - threshold) {
append({cache: length > endCursor + 1 && items.getData(endCursor + 1)});
if (!start.length || !end.length) {
return false;
}
} else if (scrollPos <= edgePos + threshold) {
prepend({cache: (startCursor > 0) && items.getData(startCursor - 1)});
const startPos = Math.min(...start);
const endPos = Math.max(...end);

if (startPos - threshold <= endScrollPos && scrollPos <= endPos + threshold) {
return true;
}
return false;
});
const start = visibles.indexOf(true);
const end = visibles.lastIndexOf(true);

if (~start && start < startCursor) {
prepend({cache: datas.slice(start, Math.min(startCursor, end + 1))});
} else if (endCursor < end) {
append({cache: datas.slice(Math.max(start, endCursor + 1), end + 1)});
} else if (endScrollPos >= endEdgePos - threshold) {
append({cache: datas.slice(endCursor + 1, endCursor + 2)});
} else if (scrollPos <= startEdgePos + threshold) {
prepend({cache: datas.slice(startCursor - 1, startCursor)});
}
}
setCursor(cursor, index) {
const status = this._status;
const items = this._items;
const size = items.size();

if (!this.options.useRecycle) {
status.startCursor = 0;
status.endCursor = this._items.size() - 1;
return;
if (items.getOutline(size - 1, "end").length) {
status.endCursor = size - 1;
return;
} if (cursor !== "end") {
return;
}
}
if (cursor === "start") {
status.startCursor = index;
} else {
status.endCursor = Math.min(this._items.size() - 1, index);
status.endCursor = Math.min(size - 1, index);
}
status.startCursor = Math.max(0, status.startCursor);
}
updateCursor(cursor) {
const {startCursor, endCursor} = this._status;

if (cursor === "start") {
if (startCursor <= 0) {
this.setCursor("start", 0);
this.setCursor("end", endCursor + 1);
} else {
this.setCursor(cursor, startCursor - 1);
}
} else {
this.setCursor(cursor, endCursor + 1);
}
}
setData(item, isAppend = true) {
this._items.set(item, item.groupKey);
this.setCursor(isAppend ? "end" : "start", this._items.indexOf(item));
}
append(item) {
this._items.append(item);
this.updateCursor("end");
}
prepend(item) {
this._items.prepend(item);
this.updateCursor("start");
}
setStatus(status) {
this._status = Object.assign(this._status, status);
}
Expand Down
Loading