Skip to content
This repository was archived by the owner on Apr 1, 2021. It is now read-only.

Commit 9cf54ce

Browse files
committed
Merge pull request #30 from canalplus/add_start_exit_strategy
add start exitStrategy
2 parents 62d006a + 6723064 commit 9cf54ce

9 files changed

Lines changed: 143 additions & 62 deletions

File tree

.eslintrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
],
1919
"no-underscore-dangle": 0,
2020
"no-restricted-syntax": 0,
21-
"arrow-body-style": 0
21+
"arrow-body-style": 0,
22+
"no-case-declarations": 0
2223
}
2324
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ renderWithId('mosaic-1-1');
8989
* `wrapper` (string / *optional*) DOM selector which define parent element (default `ul`)
9090
* `wChildren` (string / *optional*) DOM selector which define children elements (default `li`)
9191
* `strategy` (string / *optional*) define strape strategy : `progressive` / `cut` / `bounds` (default `progressive`)
92-
* `exitStrategy` (string / *optional*) define strape strategy : `none` / `mirror` (default `none`)
92+
* `exitStrategy` (string / *optional*) define strape strategy : `start` / `mirror` / `none` (default `none`)
9393
* `circular` (boolean / *optional*) define if strape has no boundaries (default `false`)
9494
* `gap` (number / *optional*) reduce or increase elements margin (default `0`)
9595
* `lastGap` (number / *optional*) reduce or increase last element margin (default `0`)

dev/dev.jsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const PureMosaic = ({strape1, strape2}) => {
3838
id="strape-1"
3939
wrapper="#wrapper"
4040
strategy="bounds"
41-
exitStrategy="mirror"
41+
exitStrategy="start"
4242
onDownExit="strape-2"
4343
gap={30}
4444
lastGap={10}
@@ -64,8 +64,9 @@ const PureMosaic = ({strape1, strape2}) => {
6464
wrapper="#wrapper2"
6565
onUpExit="strape-1"
6666
strategy="bounds"
67-
exitStrategy="mirror"
67+
exitStrategy="start"
6868
gap={30}
69+
lastGap={10}
6970
onEnter={onEnter}>
7071
<div id="wrapper2">
7172
<ul style={ulStyle2}>

dev/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
ul {
1616
width: 4000px;
17+
padding: 0px;
1718
}
1819

1920
li {

src/constants.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@ export const C_UP = 'up';
22
export const C_DOWN = 'down';
33
export const C_LEFT = 'left';
44
export const C_RIGHT = 'right';
5+
6+
export const EXIT_STRATEGY_MIRROR = 'mirror';
7+
export const EXIT_STRATEGY_START = 'start';

src/engines/strape.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,32 @@ import {trigger} from '../events';
22
import {hasDiff} from '../hasDiff';
33
import {C_LEFT, C_RIGHT} from '../constants';
44

5+
export function findMirrorExitId(leftElement, children) {
6+
const leftPx = leftElement ? leftElement.getBoundingClientRect().left : 0;
7+
const nextFocusedId = children
8+
.map(el => {
9+
return {
10+
id: el.id,
11+
diff: Math.abs(el.getBoundingClientRect().left - leftPx),
12+
};
13+
})
14+
.sort((a, b) => a.diff - b.diff);
15+
return nextFocusedId[0].id;
16+
}
17+
18+
export function findStartExitId(children) {
19+
const nextFocusedId = children
20+
.map(el => {
21+
return {
22+
id: el.id,
23+
left: el.getBoundingClientRect().left,
24+
};
25+
})
26+
.filter(el => el.left > 0)
27+
.sort((a, b) => a.left - b.left);
28+
return nextFocusedId[0].id;
29+
}
30+
531
export function calculateBounds(dir, el, wrapperPosition, initialMarginLeft, props) {
632
const element = document.getElementById(el.id).getBoundingClientRect();
733
let marginLeft = initialMarginLeft;

src/redux/actions.js

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import {globalStore} from '../listener';
2+
import {findMirrorExitId, findStartExitId} from '../engines/strape';
3+
import {EXIT_STRATEGY_MIRROR, EXIT_STRATEGY_START} from '../constants';
4+
15
export const NAME = '@@keys';
26
export const ACTIVE_KEYBINDER = [NAME, '/ACTIVE_KEYBINDER'].join('');
37
export const ADD_KEYBINDER_TO_STORE = [NAME, '/ADD_KEYBINDER_TO_STORE'].join('');
48
export const UPDATE_SELECTED_KEY = [NAME, '/UPDATE_SELECTED_KEY'].join('');
59
export const UPDATE_BINDER_STATE = [NAME, '/UPDATE_BINDER_STATE'].join('');
6-
import {globalStore} from '../listener';
710

811
export function clone(obj) {
912
const cloneObject = {};
@@ -63,26 +66,22 @@ export function _updateBinderState(binderId, binderState) {
6366
export function exitBinder(strategy, callback, nextElId) {
6467
if (callback) {
6568
if (typeof callback === 'string') {
66-
if (strategy === 'mirror') {
67-
const dom = document.getElementById(callback);
68-
if (dom) {
69+
const dom = document.getElementById(callback) || document;
70+
const exitBinderState = globalStore.getState()[NAME][callback] || {};
71+
const children = [].slice.call(dom.querySelectorAll(exitBinderState.wChildren));
72+
switch (strategy) {
73+
case EXIT_STRATEGY_MIRROR:
6974
const leftElement = document.getElementById(nextElId);
70-
const leftPx = leftElement ? leftElement.getBoundingClientRect().left : 0;
71-
const exitBinderState = globalStore.getState()[NAME][callback];
72-
const nextFocusedId = [].slice.call(dom.querySelectorAll(exitBinderState.wChildren))
73-
.map(el => {
74-
return {
75-
id: el.id,
76-
diff: Math.abs(el.getBoundingClientRect().left - leftPx),
77-
};
78-
})
79-
.sort((a, b) => a.diff - b.diff);
80-
_activeKeyBinder(callback, nextFocusedId[0] ? nextFocusedId[0].id : null);
81-
} else {
75+
const mirrorId = findMirrorExitId(leftElement, children);
76+
_activeKeyBinder(callback, mirrorId);
77+
break;
78+
case EXIT_STRATEGY_START:
79+
const startId = findStartExitId(children);
80+
_activeKeyBinder(callback, startId);
81+
break;
82+
default:
8283
_activeKeyBinder(callback);
83-
}
84-
} else {
85-
_activeKeyBinder(callback);
84+
break;
8685
}
8786
} else {
8887
callback();

test/engines/strape.spec.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import {
1010
build,
1111
calculateBounds,
1212
selectedElement,
13+
findMirrorExitId,
14+
findStartExitId,
1315
} from '../../src/engines/strape';
1416
import {C_RIGHT, C_LEFT} from '../../src/constants';
1517
import {expect} from 'chai';
@@ -31,6 +33,75 @@ describe('engine/strape.js', () => {
3133
list.should.have.lengthOf(2);
3234
list[0].should.be.instanceOf(HTMLLIElement);
3335
});
36+
37+
describe('exitStrategy', () => {
38+
describe('findMirrorExitId', () => {
39+
it('should return id of mirrored element', () => {
40+
const leftElement = {
41+
getBoundingClientRect: () => {
42+
return {left: 10};
43+
},
44+
};
45+
const children = [{
46+
id: 1,
47+
getBoundingClientRect: () => {
48+
return {left: -10};
49+
},
50+
}, {
51+
id: 2,
52+
getBoundingClientRect: () => {
53+
return {left: 0};
54+
},
55+
}, {
56+
id: 3,
57+
getBoundingClientRect: () => {
58+
return {left: 10};
59+
},
60+
}];
61+
findMirrorExitId(leftElement, children).should.equal(3);
62+
});
63+
it('should return id of mirrored element of 0 position when no leftElement', () => {
64+
const children = [{
65+
id: 1,
66+
getBoundingClientRect: () => {
67+
return {left: -10};
68+
},
69+
}, {
70+
id: 2,
71+
getBoundingClientRect: () => {
72+
return {left: 0};
73+
},
74+
}, {
75+
id: 3,
76+
getBoundingClientRect: () => {
77+
return {left: 10};
78+
},
79+
}];
80+
findMirrorExitId(null, children).should.equal(2);
81+
});
82+
});
83+
describe('findStartExitId', () => {
84+
it('should return closed element to 0 left', () => {
85+
const children = [{
86+
id: 1,
87+
getBoundingClientRect: () => {
88+
return {left: -10};
89+
},
90+
}, {
91+
id: 2,
92+
getBoundingClientRect: () => {
93+
return {left: 2};
94+
},
95+
}, {
96+
id: 3,
97+
getBoundingClientRect: () => {
98+
return {left: 12};
99+
},
100+
}];
101+
findStartExitId(children).should.equal(2);
102+
});
103+
});
104+
});
34105
describe('strategy : bounds', () => {
35106
describe('calculateBounds', () => {
36107
it('should return same marginLeft on right action when next card in inside bounds',

test/redux/actions.spec.js

Lines changed: 18 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import * as actions from '../../src/redux/actions';
33
import * as module from '../../src/listener';
44
import {createStore} from 'redux';
55
import sinon from 'sinon';
6-
import jsdom from 'jsdom';
6+
import * as strape from '../../src/engines/strape';
7+
import {EXIT_STRATEGY_MIRROR, EXIT_STRATEGY_START} from '../../src/constants';
78

89
describe('redux/actions.js', () => {
910
describe('clone', () => {
@@ -135,48 +136,26 @@ describe('redux/actions.js', () => {
135136
callback.should.have.been.calledOnce;
136137
}));
137138

138-
it('should call dispatcher when callback is a string and no strategy', sinon.test(function() {
139-
const store = createStore((state = {
140-
'@@keys': {
141-
binderId: {active: false, selectedId: 1, marginLeft: 0},
142-
},
143-
}) => state);
144-
module._init({store: store}); // init globalStore
145-
this.mock(module.globalStore)
146-
.expects('dispatch')
139+
it('should call findMirrorExitId when strategy is mirror', sinon.test(function() {
140+
this.mock(strape)
141+
.expects('findMirrorExitId')
147142
.once();
148-
actions.exitBinder(null, 'binderId', 'nextEl1');
143+
actions.exitBinder(EXIT_STRATEGY_MIRROR, 'strape', 'ID');
149144
}));
150145

151-
it('should call dispatcher when callback is a string with mirror stategy',
152-
sinon.test(function() {
153-
const store = createStore((state = {
154-
'@@keys': {
155-
binderId: {active: false, selectedId: 1, marginLeft: 0},
156-
},
157-
}) => state);
158-
module._init({store: store}); // init globalStore
159-
this.mock(module.globalStore)
160-
.expects('dispatch')
161-
.once();
162-
actions.exitBinder('mirror', 'binderId', 'nextEl1');
163-
}));
164-
165-
/* eslint no-native-reassign: 0 */
166-
it('should', sinon.test(function() {
167-
document = jsdom.jsdom('<div id="wrapper"><ul><li id="1"></li></ul></div>' +
168-
'<div id="binderId"><ul><li></li></ul></div>');
169-
const store = createStore((state = {
170-
'@@keys': {
171-
binderId: {active: false, selectedId: 1, marginLeft: 0},
172-
},
173-
}) => state);
174-
module._init({store: store}); // init globalStore
175-
this.mock(module.globalStore)
176-
.expects('dispatch')
146+
it('should call findStartExitId when strategy is start', sinon.test(function() {
147+
this.mock(strape)
148+
.expects('findStartExitId')
177149
.once();
178-
actions.exitBinder('mirror', 'binderId', 'nextEl1');
179-
document = null;
150+
actions.exitBinder(EXIT_STRATEGY_START, 'strape', 'ID');
151+
}));
152+
153+
it('should not call any engine when other strategy', sinon.test(function() {
154+
const mirrorSpy = this.spy(strape, 'findMirrorExitId');
155+
const startSpy = this.spy(strape, 'findStartExitId');
156+
actions.exitBinder('FUCKING_STRATEGY', 'strape', 'ID');
157+
mirrorSpy.should.have.been.not.called;
158+
startSpy.should.have.been.not.called;
180159
}));
181160
});
182161
});

0 commit comments

Comments
 (0)