Commit 9df06ae6 by Иван Кубота

Cards:

Change storage from {c1,c2,c3...} to {cat1: {c1,c2,c3}, cat2: ...} DOM: Fix error in removing removed children Store: AsyncResourceLoaderQueue - Made generic method for loading cached resources Model: async categories.load(id) - load category data with subitems async cards.load(category, id) - load full card data cards.load and new cards populate the same store. Useful for cache. Marked full data as `detailed` Views: Product card display: InfoCard.jsx — display Item and back\next logics ProductCard.jsx — fill markup with data InfoPage.jsx — logics of loading data
parent d485803b
......@@ -3,9 +3,15 @@ import { API } from "../dict/Consts";
Model.cards.getArray = function() {
const out = [];
for(let key in this._props){
if(key !== 'commit'){
out.push(this._props[key]);
let categoryItems;
for(let categoryID in this._props){
if(categoryID !== '_VERSION_'){
categoryItems = this._props[categoryID]
for(let id in categoryItems){
out.push(categoryItems[id]);
}
}
}
return out;
......@@ -16,9 +22,8 @@ store.sub(['navigation.current', 'loaded.cards'], async function(page, loaded) {
if(page !== 'Login' && !loaded){
//try{
const result = await AsyncAuthAjax.get( API.ENDPOINTS.GET_USER_NEW_CARDS() );
result.forEach(function(card) {
Model.cards.set(card.id+'', Object.assign({},card, {seen: false}));
Model.cards.set(card.category_id+'.'+card.id, Object.assign({},card, {seen: false}));
});
store.set('loaded.cards', true);
......
......@@ -260,9 +260,9 @@ NS.apply = function(a,b) {
el.appendChild( tmp );
var list = [];
subEl( function(){
// TODO: append 2 TextNodes and remove children between them
for( var i = 0, _i = list.length; i < _i; i++ ){
el.removeChild( list[ i ] );
list[ i ].parentNode === el && el.removeChild( list[ i ] );
}
var fragment = document.createDocumentFragment();
D.appendChild( fragment, [].slice.call( arguments ) );
......
......@@ -284,8 +284,11 @@ Store.IF = function(cfg, children){
};
if(cfg.condition instanceof HookPrototype){
cfg.condition.hook( hook );
}else{
}else if(typeof cfg.condition === 'function'){
cfg.condition( hook );
}else{
// TODO other hooklikes
hook(cfg.condition)
}
}
};
......
......@@ -29,7 +29,7 @@ const Consts = {
// Knowledge Endpoints
GET_CARD_PRODUCTS: "/api/card_products",
GET_CARD_INFOS: "/api/card_infos",
GET_CARD_PRODUCTS_CARD: id => `/api/card_products/${id}`,
GET_CARD_PRODUCTS_ITEM: id => `/api/card_products/${id}`,
GET_CARD_INFO_CARD: id => `/api/card_infos/${id}`,
GET_CARD_INFO_ITEM: id => `/api/card_info_items/${id}`,
CATEGORIES_CATEGORY: id => `/api/categories/${id}`,
......
import { AsyncAuthAjax } from "../controller/Ajax";
import { API } from "../dict/Consts";
let latest, STORE_VERSION = 'v0.2';
let latest, STORE_VERSION = 'v0.3';
const store = new Store(latest = {
_VERSION_: STORE_VERSION,
'navigation': {
......@@ -77,6 +77,7 @@ const createSavableStore = function(name) {
};
const cards = createSavableStore('cards');
//const products = createSavableStore('products');
const categories = createSavableStore('categories');
const Model = {
cards: cards,
......@@ -84,28 +85,94 @@ const Model = {
};
categories.loading = {};
categories.load = async function(category, cb) {
category+='';
if(this.get(category)){
cb(this.get(category))
}else if(this.loading[category]){
this.loading[category].push(cb)
const AsyncResourceLoaderQueue = function(cfg) {
const loading = {};
cfg = Object.assign({
key: (a)=>a,
arg: (a)=>a
}, cfg);
return async function() {
let arg = await cfg.arg.apply(this, arguments),
key = cfg.key.call(this, arg);
if(cfg.checkExist.call(this, arg)){
return cfg.getExisted.call(this, arg);
}else if(loading[key]){
return new Promise((resolve, reject)=>
loading[key].push({resolve, reject}));
}else{
this.loading[category] = [cb];
loading[key] = [];
try{
const result = await AsyncAuthAjax.get( API.ENDPOINTS.CATEGORIES_CATEGORY( category ) );
Model.categories.set(category, result);
this.loading[category].forEach((cb)=>cb(result));
delete this.loading[category];
}catch(e){
const result = await cfg.fetch.call(this, arg);
loading[key].forEach((promise)=>{
promise.resolve(result);
});
delete loading[key];
return result;
}catch(e){
loading[key].forEach((promise)=>{
promise.reject(e);
});
throw new Error(e)
}
}
if(!this.loading[category]){
}
};
categories.load = AsyncResourceLoaderQueue({
arg: (category)=>category+'',
checkExist(category){
return this.get(category) !== void 0
},
getExisted(category) {
return this.get(category)
},
async fetch(category){
const result = await AsyncAuthAjax.get( API.ENDPOINTS.CATEGORIES_CATEGORY( category ) );
this.set(category, result);
return result
}
});
/*categories.load = async function(category) {
return category+='';
};*/
cards.load = AsyncResourceLoaderQueue({
async arg(category, id){
const categoryInfo = await Model.categories.load(category);
return {category, id, type: categoryInfo.type, key: [category,id].join('.')}
},
key: ({key})=>key,
checkExist({key}){
let item = this.get(key);
if(item === void 0)
return false;
if(!item.detailed)
return false;
return true;
},
getExisted({key}) {
return this.get(key)
},
async fetch( {category, id, type, key}){
console.log(type)
const result = await AsyncAuthAjax.get( API.ENDPOINTS[type===1?'GET_CARD_PRODUCTS_ITEM' : 'GET_CARD_INFO_ITEM']( id ) ),
data = {...result, seen: result.isView, type: type, category_id: category, detailed: true};
this.set(key, data);
return data
}
});
/*async function(category, id, cb) {
const data = await categories.load(category);
if(data.type)
data.type
}*/
const tmpStore = new Store({
loaded: false,
navigation: {current: 'Login'},
......
......@@ -108,7 +108,7 @@ const CardSlider = (function(){
let firstItem = Math.round( fromLeft / ( this.preset.cardWidth + this.world.padding ));
this.leftButtonDisabled.set(firstItem===0);
this.rightButtonDisabled.set(firstItem+this.world.fullCardsCount>=this.items.length);
console.log(this.leftButtonDisabled.get(), this.rightButtonDisabled.get())
//console.log(this.leftButtonDisabled.get(), this.rightButtonDisabled.get())
},
untune: function() {
this.updateButtonsState();
......
......@@ -4,22 +4,63 @@ import ProductCard from '../productCard/ProductCard.jsx';
import Back from '/svg/arr-back.svg';
import Arr from '/svg/arr.svg';
const InfoCard = D.declare('view.cmp.InfoCard', (cfg) => {
const InfoCard = D.declare('view.cmp.InfoCard', ({item, category}) => {
console.log({item, category})
let backHidden = true,
forwardHidden = true,
sorted = [];
try{
sorted = category.cardProduct.slice().sort((a,b)=>a.id - b.id);
backHidden = sorted[0].id === item.id;
forwardHidden = sorted[sorted.length - 1].id === item.id;
}catch(e){
console.error('format changed', category);
}
let next = function(){
if( forwardHidden )
return false;
for( let i = 0, _i = sorted.length; i < _i; i++ ){
if( sorted[ i ].id === item.id ){
store.set( 'navigation.data.id', sorted[ i + 1 ].id );
break;
}
}
},
back = function() {
if(backHidden)
return false;
for( let i = 0, _i = sorted.length; i < _i; i++ ){
if( sorted[ i ].id === item.id ){
store.set( 'navigation.data.id', sorted[ i - 1 ].id );
break;
}
}
};
let content;
if(item.type === 1){
content = <ProductCard item={item} category={category}/>;
}else{
//content = <ProductCard item={item} category={category}/>;
}
return <div class="info-card">
<div className="info-card__header">
<h1 className="info-card__title">Печенье "Орешки"</h1>
<p className="info-card__category">Категория Топ 35</p>
<div>TYPE: {item.type}</div>
<h1 className="info-card__title">{item.name}</h1>
<p className="info-card__category">{category.name}</p>
<div className="info-card__stats">
<p>Карточек в категории: <b>20</b></p>
<p>Просмотрено: <em>2</em></p>
<p>Карточек в категории: <b>{category.count||0}</b></p>
<p>Просмотрено: <em>{category.countView||0}</em></p>
</div>
</div>
<div className="info-card__body">
<ProductCard/>
{content}
</div>
<div className="info-card__footer">
<Button class={"button info-card__link"}><Back width="17" height="11"/><span>Предыдущая карточка</span></Button>
<Button class={"button info-card__link"}><span>Следующая карточка</span><Arr width="17" height="11"/></Button>
<Button class={D.cls("button info-card__link", {'info-card__link-hidden': backHidden})} onclick={back}><Back width="17" height="11"/><span>Предыдущая карточка</span></Button>
<Button class={D.cls("button info-card__link", {'info-card__link-hidden': forwardHidden})} onclick={next}><span>Следующая карточка</span><Arr width="17" height="11"/></Button>
</div>
</div>
})
......
......@@ -111,3 +111,6 @@
}
}
}
.info-card__link-hidden {
display: none;
}
\ No newline at end of file
import './productCard.scss';
import Info from "/svg/info.svg";
const ProductCard = D.declare('view.cmp.ProductCard', () => {
import Format from "../format/Format";
const {IF} = Store;
const ProductCard = D.declare('view.cmp.ProductCard', ({item}) => {
return <div class="product-card">
<div className="product-card__image">
<img src="/uploads/images/product1.jpg" alt=""/>
<img src={item.image} alt=""/>
</div>
<div className="product-card__list">
<IF condition={item.items && item.items.length}>
<h2>Ингредиенты</h2>
<ul>
<li>Вареная сгущенка </li>
<li>Мука </li>
<li>Масло сливочное </li>
<li>Сахар </li>
<li>Ингредиент</li>
{
item.items.map(
subItem=>
<li>{subItem.name}</li>)
}
</ul>
</IF>
</div>
<div className="product-card__text">
<Info width="30" height="30"/>
<p><b>Важно знать.</b>Информация о&nbsp;продукте. Все, что вы&nbsp;хотели знать, но&nbsp;боялись спросить.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi lacinia augue quam, in&nbsp;dapibus nulla ullamcorper nec. Mauris ac&nbsp;magna est. Vivamus dapibus venenatis nisi, sit amet dictum tellus aliquam sit amet. Proin sit amet suscipit nisl. </p>
<p>Mauris ac&nbsp;magna est. Vivamus dapibus venenatis nisi, sit amet dictum tellus aliquam sit amet. Proin sit amet suscipit nisl.</p>
<p><b>Важно знать.</b></p>
<Format>{item.text}</Format>
</div>
</div>
})
......
......@@ -13,24 +13,30 @@ const InfoPage = D.declare('view.page.InfoPage', () => {
</button>
<div class="info-page__card">
{( update ) => {
let un, un2;
tmpStore.valEqualOnly( 'afterNavigation.to', 'InfoPage' )( async() => {
let un;
tmpStore.valEqualOnly( 'beforeNavigation.to', 'InfoPage' )(() => {
update(<div>LOADER</div>)
un && un();
un2 && un2();
un = store.sub('navigation.data.category', function(category) {
Model.categories.load(category, function(data) {
debugger
});
un = store.sub(['navigation.data.category', 'navigation.data.id'], async function(categoryID, cardID) {
const category = await Model.categories.load(categoryID);
const card = await Model.cards.load(categoryID, cardID);
update(<InfoCard category={category} item={card}/>)
/*
if(card.type === 1){
/!*update(<StdCard item={card} category={cat}/>)
}else{*!/
}
*/
});
console.log( 'data', store.get( 'navigation.data' ) )
} );
}}
<InfoCard/>
</div>
</div>
</div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment