Skip to content

Commit

Permalink
fix(Layout): fix bug for empty array
Browse files Browse the repository at this point in the history
  • Loading branch information
daybrush authored and sculove committed Nov 3, 2017
1 parent d543ae4 commit 30fd684
Show file tree
Hide file tree
Showing 21 changed files with 685 additions and 230 deletions.
2 changes: 1 addition & 1 deletion config/webpack.config.layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var config = {
"JustifiedLayout": "./src/layouts/JustifiedLayout.js",
"GridLayout": "./src/layouts/GridLayout.js",
"FrameLayout": "./src/layouts/FrameLayout.js",
"FacebookLayout": "./src/layouts/FacebookLayout.js",
"SquareLayout": "./src/layouts/SquareLayout.js",
"LightBoxLayout": "./src/layouts/LightBoxLayout.js",
"PackingLayout": "./src/layouts/PackingLayout.js"
},
Expand Down
3 changes: 2 additions & 1 deletion karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ module.exports = function(config) {
// list of files / patterns to load in the browser
files: [
"./node_modules/lite-fixture/index.js",
"./test/unit/**/*.spec.js"
// "./test/unit/**/*.spec.js",
"./test/unit/layouts/*.spec.js",
],

client: {
Expand Down
23 changes: 10 additions & 13 deletions src/ImageLoaded.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,7 @@ class ImageLoaded {
}
});
}
constructor(options) {
Object.assign(this.options = {
widthAttr: "data-width",
heightAttr: "data-height",
}, options);
}
checkImageLoaded(el) {
const widthAttr = this.options.widthAttr;
const heightAttr = this.options.heightAttr;
static checkImageLoaded(el, widthAttr, heightAttr) {
let width;
let height;

Expand All @@ -52,16 +44,21 @@ class ImageLoaded {
}
});
}
check(elements, callback) {
static check(elements, options) {
const opt = Object.assign({
widthAttr: "data-width",
heightAttr: "data-height",
}, options);

const needCheck = elements
.reduce((acc, v) => acc.concat(this.checkImageLoaded(v)), []);
.reduce((acc, v) => acc.concat(this.checkImageLoaded(v, opt.widthAttr, opt.heightAttr)), []);

if (needCheck.length > 0) {
ImageLoaded.waitImageLoaded(needCheck, callback);
ImageLoaded.waitImageLoaded(needCheck, opt.callback);
} else {
// convert to async
setTimeout(() => {
callback && callback();
opt.callback && opt.callback();
}, 0);
}
}
Expand Down
219 changes: 75 additions & 144 deletions src/Infinite.js
Original file line number Diff line number Diff line change
@@ -1,127 +1,78 @@
import Component from "@egjs/component";
import ItemManager from "./ItemManager";
import ItemRenderer from "./ItemRenderer";
import ImageLoaded from "./ImageLoaded";
// import GridLayout from "./layouts/GridLayout";
// import FrameLayout from "./layouts/FrameLayout";

import GridLayout from "./layouts/GridLayout";
import FrameLayout from "./layouts/FrameLayout";
import FacebookLayout from "./layouts/FacebookLayout";
import PackingLayout from "./layouts/PackingLayout";
import JustifiedLayout from "./layouts/JustifiedLayout";

import {
APPEND,
PREPEND,
DUMMY_POSITION,
MULTI,
CACHE,
NO_CACHE,
} from "./consts";
import {
$,

} from "./utils";

export class ItemRenderer {
constructor(element) {
this._el = $(element);
this._el.style.position = "relative";
}
static renderItem(item, styles) {
if (item.el) {
const elStyle = item.el.style;

// for debugging
item.el.setAttribute("data-groupkey", item.groupKey);
elStyle.position = "absolute";
["left", "top", "width", "height"].forEach(p => {
(p in styles) && (elStyle[p] = `${styles[p]}px`);
});
}
}
static removeItems(items) {
items.forEach(item => {
if (item.el) {
item.el.parentNode.removeChild(item.el);
item.el = null;
}
});
}
append(items) {
this._insert(items, APPEND, {
top: DUMMY_POSITION,
});
}
prepend(items) {
this._insert(items, PREPEND, {
top: DUMMY_POSITION,
});
}
createAndInsert(items, isAppend) {
const elements = $(items.reduce((acc, v) => acc.concat(v.content), []).join(
""), MULTI);
const itemsWithElement = items.map((item, index) => {
item.el = elements[index];
return item;
});

ItemRenderer.render(itemsWithElement);
this._insert(itemsWithElement, isAppend);
}
_insert(items, isAppend, styles) {
const df = document.createDocumentFragment();

items.forEach(item => {
styles && ItemRenderer.renderItem(item, styles);

isAppend ? df.appendChild(item.el) : df.insertBefore(item.el, df.firstChild);
});
isAppend ? this._el.appendChild(df) : this._el.insertBefore(df, this._el.firstChild);
}
static render(items) {
items.forEach(item => {
ItemRenderer.renderItem(item, item.rect);
});
}
}
// import {
// $,
// addEvent,
// removeEvent,
// } from "./utils";

export {JustifiedLayout, GridLayout, FrameLayout, FacebookLayout, PackingLayout};

export class Infinite extends Component {
constructor(element, options) {
super();
Object.assign(this.options = {
itemSelector: "*",
count: 60,
widthAttr: "data-width",
heightAttr: "data-height",
}, options);
this._startCursor = -1;
this._endCursor = -1;
// @todo
this._layout = new JustifiedLayout({
direction: "vertical",
minSize: 100,
});
// this._layout = new GridLayout({
// direction: "vertical",
// align: "start",
// // minSize: 100,
// });
// this._layout = new FrameLayout({
// direction: "vertical",
// margin: 20,
// minSize: 100,
// frame: [
// [1, 0, 1, 0, 1],
// [2, 2, 2, 3, 3],
// [2, 2, 2, 3, 3],
// [0, 4, 0, 4, 0],
// ],
// frameFill: true,
// });
this._layout.setViewport(471, 1320);
this._checkImageloaded = new ImageLoaded();
this._itemManager = new ItemManager();
this._items = new ItemManager();
this._renderer = new ItemRenderer(element);
}
append(elements, groupKey) { // 사용자가 append를 호출
this._insert(elements, groupKey, APPEND);
// called by user
append(elements, groupKey) {
this._layout && this._insert(elements, groupKey, APPEND);
}
// called by user
prepend(elements, groupKey) {
this._layout && this._insert(elements, groupKey, PREPEND);
}
prepend(elements, groupKey) { // 사용자가 prepend를 호출
this._insert(elements, groupKey, PREPEND);
setLayout(layout) {
this._layout = layout;
}
setViewport(width, height) {
this._layout && this._layout.setViewport(width, height);
}
getVisibleItems() {
return this._items.getItems(this._startCursor, this._endCursor);
}
getItems(isAppend) {
let items = [];
const size = this._items.size();

// from cache
if (size > 0 && this._startCursor !== -1 && this._endCursor !== -1) {
if (isAppend && size > this._endCursor + 1) {
items = this._items.getItems(this._endCursor + 1);
} else if (!isAppend && this._startCursor > 0) {
items = this._items.getItems(this._startCursor - 1);
}
}
return items;
}
clear() {
this._renderer.clear();
this._items.clear();
this._startCursor = -1;
this._endCursor = -1;
}
_insert(elements, groupKey, isAppend) {
const key = typeof groupKey === "undefined" ? (new Date().getTime() + Math.floor(
Expand All @@ -142,18 +93,16 @@ export class Infinite extends Component {
// add items, and remove items for recycling
_recycle(items, isAppend) {
const baseCount = items.length - this.options.count;
/* eslint-disable no-unused-vars */
let diff;
/* eslint-enable no-unused-vars */

while ((diff = this.getVisibleItems().length + baseCount) > 0) {
// @todo range가 넘어가는 경우에대한 별도의 처리 및 테스트가 필요함.
let toRemoveItems;
const toRemoveItems = this._items.getItems(isAppend ? this._startCursor : this._endCursor);

console.log(diff, "recyle이 필요함, DOM 삭제");
if (isAppend) {
toRemoveItems = this._itemManager.getItems(this._startCursor);
this._startCursor++;
} else {
toRemoveItems = this._itemManager.getItems(this._endCursor);
this._endCursor--;
}
// recycle
Expand All @@ -174,31 +123,12 @@ export class Infinite extends Component {
}
console.warn("_updateCursor [", this._startCursor, this._endCursor, "]");
}
_insertItemManager(layouted, isAppend) {
_insertItems(layouted, isAppend) {
layouted.groupKey = layouted.items[0].groupKey;
this._itemManager[isAppend ? "append" : "prepend"](layouted);
}
getVisibleItems() {
return this._itemManager.getItems(this._startCursor, this._endCursor);
this._items[isAppend ? "append" : "prepend"](layouted);
}
getItems(isAppend) {
let items = [];
const size = this._itemManager.size();

// 데이터가 존재한다.
if (size > 0 && this._startCursor !== -1 && this._endCursor !== -1) {
if (isAppend && size > this._endCursor + 1) {
console.log("데이터가 있다");
items = this._itemManager.getItems(this._endCursor + 1);
} else if (!isAppend && this._startCursor > 0) {
console.log("데이터가 있다");
items = this._itemManager.getItems(this._startCursor - 1);
}
}
return items;
}

requestAppend() { // visible이 호출
// called by visible
_requestAppend() {
const items = this.getItems(APPEND);

if (items.length) {
Expand All @@ -208,7 +138,8 @@ export class Infinite extends Component {
this.trigger("append");
}
}
requestPrepend() { // visible이 호출
// called by visible
_requestPrepend() {
const items = this.getItems(PREPEND);

if (items.length) {
Expand All @@ -227,22 +158,22 @@ export class Infinite extends Component {

this._renderer[method](items);
// check image sizes after elements are attated on DOM
this._checkImageloaded.check(items.map(item => item.el), () => {
const layouted = this._layout[method](
ItemManager.updateSize(items),
this._itemManager.getOutline(
isAppend ? this._endCursor : this._startCursor,
isAppend)
);

this._insertItemManager(layouted, isAppend);
this._updateCursor(isAppend);
ItemRenderer.render(layouted.items);
ImageLoaded.check(items.map(item => item.el), {
widthAttr: this.options.widthAttr,
heightAttr: this.options.heightAttr,
callback: () => {
const layouted = this._layout[method](
ItemManager.updateSize(items),
this._items.getOutline(
isAppend ? this._endCursor : this._startCursor,
isAppend)
);

this._insertItems(layouted, isAppend);
this._updateCursor(isAppend);
ItemRenderer.render(layouted.items);
},
});
}
}

setLayout(layout) {
this._layout = layout;
}
}
12 changes: 1 addition & 11 deletions src/ItemManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,7 @@ export default class ItemManager {
});
}

constructor(options) {
Object.assign(this.options = {
}, options);
constructor() {
this.clear();
}
size() {
Expand All @@ -69,20 +67,12 @@ export default class ItemManager {
}
append(layouted) {
this.data.push(layouted);
// this.endCursor++;
console.log("append", this.data);

// 레이아웃에 의해 변경된 아이템 정보
return layouted.items;
}
prepend(layouted) {
// ItemManager.setGroupKey(layouted, groupKey);
this.data.unshift(layouted);
// this.startCursor = 0;
// this.endCursor++;
console.log("prepend", this.data);

// 레이아웃에 의해 변경된 아이템 정보
return layouted.items;
}
clear() {
Expand Down
Loading

0 comments on commit 30fd684

Please sign in to comment.