Support global marks which select a tab
This commit is contained in:
parent
6e6e306275
commit
003742ec51
11 changed files with 179 additions and 4 deletions
15
src/background/controllers/mark.js
Normal file
15
src/background/controllers/mark.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
import MarkInteractor from '../usecases/mark';
|
||||
|
||||
export default class MarkController {
|
||||
constructor() {
|
||||
this.markInteractor = new MarkInteractor();
|
||||
}
|
||||
|
||||
setGlobal(key, x, y) {
|
||||
this.markInteractor.setGlobal(key, x, y);
|
||||
}
|
||||
|
||||
jumpGlobal(key) {
|
||||
this.markInteractor.jumpGlobal(key);
|
||||
}
|
||||
}
|
19
src/background/domains/global-mark.js
Normal file
19
src/background/domains/global-mark.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
export default class GlobalMark {
|
||||
constructor(tabId, x, y) {
|
||||
this.tabId0 = tabId;
|
||||
this.x0 = x;
|
||||
this.y0 = y;
|
||||
}
|
||||
|
||||
get tabId() {
|
||||
return this.tabId0;
|
||||
}
|
||||
|
||||
get x() {
|
||||
return this.x0;
|
||||
}
|
||||
|
||||
get y() {
|
||||
return this.y0;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import FindController from '../controllers/find';
|
|||
import AddonEnabledController from '../controllers/addon-enabled';
|
||||
import LinkController from '../controllers/link';
|
||||
import OperationController from '../controllers/operation';
|
||||
import MarkController from '../controllers/mark';
|
||||
|
||||
export default class ContentMessageListener {
|
||||
constructor() {
|
||||
|
@ -14,6 +15,7 @@ export default class ContentMessageListener {
|
|||
this.addonEnabledController = new AddonEnabledController();
|
||||
this.linkController = new LinkController();
|
||||
this.backgroundOperationController = new OperationController();
|
||||
this.markController = new MarkController();
|
||||
}
|
||||
|
||||
run() {
|
||||
|
@ -59,6 +61,10 @@ export default class ContentMessageListener {
|
|||
message.newTab, message.url, sender.tab.id, message.background);
|
||||
case messages.BACKGROUND_OPERATION:
|
||||
return this.onBackgroundOperation(message.operation);
|
||||
case messages.MARK_SET_GLOBAL:
|
||||
return this.onMarkSetGlobal(message.key, message.x, message.y);
|
||||
case messages.MARK_JUMP_GLOBAL:
|
||||
return this.onMarkJumpGlobal(message.key);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,4 +108,12 @@ export default class ContentMessageListener {
|
|||
onBackgroundOperation(operation) {
|
||||
return this.backgroundOperationController.exec(operation);
|
||||
}
|
||||
|
||||
onMarkSetGlobal(key, x, y) {
|
||||
return this.markController.setGlobal(key, x, y);
|
||||
}
|
||||
|
||||
onMarkJumpGlobal(key) {
|
||||
return this.markController.jumpGlobal(key);
|
||||
}
|
||||
}
|
||||
|
|
33
src/background/repositories/mark.js
Normal file
33
src/background/repositories/mark.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
import MemoryStorage from '../infrastructures/memory-storage';
|
||||
import GlobalMark from 'background/domains/global-mark';
|
||||
|
||||
const MARK_KEY = 'mark';
|
||||
|
||||
export default class MarkRepository {
|
||||
constructor() {
|
||||
this.cache = new MemoryStorage();
|
||||
}
|
||||
|
||||
getMark(key) {
|
||||
let marks = this.getOrEmptyMarks();
|
||||
let data = marks[key];
|
||||
if (!data) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
let mark = new GlobalMark(data.tabId, data.x, data.y);
|
||||
return Promise.resolve(mark);
|
||||
}
|
||||
|
||||
setMark(key, mark) {
|
||||
let marks = this.getOrEmptyMarks();
|
||||
marks[key] = { tabId: mark.tabId, x: mark.x, y: mark.y };
|
||||
this.cache.set(MARK_KEY, marks);
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
getOrEmptyMarks() {
|
||||
return this.cache.get(MARK_KEY) || {};
|
||||
}
|
||||
}
|
||||
|
29
src/background/usecases/mark.js
Normal file
29
src/background/usecases/mark.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
import GlobalMark from '../domains/global-mark';
|
||||
import TabPresenter from '../presenters/tab';
|
||||
import MarkRepository from '../repositories/mark';
|
||||
import ConsolePresenter from '../presenters/console';
|
||||
|
||||
export default class MarkInteractor {
|
||||
constructor() {
|
||||
this.tabPresenter = new TabPresenter();
|
||||
this.markRepository = new MarkRepository();
|
||||
this.consolePresenter = new ConsolePresenter();
|
||||
}
|
||||
|
||||
async setGlobal(key, x, y) {
|
||||
let tab = await this.tabPresenter.getCurrent();
|
||||
let mark = new GlobalMark(tab.id, x, y);
|
||||
return this.markRepository.setMark(key, mark);
|
||||
}
|
||||
|
||||
async jumpGlobal(key) {
|
||||
let current = await this.tabPresenter.getCurrent();
|
||||
|
||||
let mark = await this.markRepository.getMark(key);
|
||||
if (!mark) {
|
||||
return this.consolePresenter.showError(current.id, 'Mark is not set');
|
||||
}
|
||||
// TODO scroll pages and handle if tab is gone
|
||||
return this.tabPresenter.select(mark.tabId);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import actions from 'content/actions';
|
||||
import messages from 'shared/messages';
|
||||
|
||||
const startSet = () => {
|
||||
return { type: actions.MARK_START_SET };
|
||||
|
@ -21,6 +22,25 @@ const setLocal = (key, x, y) => {
|
|||
};
|
||||
};
|
||||
|
||||
const setGlobal = (key, x, y) => {
|
||||
browser.runtime.sendMessage({
|
||||
type: messages.MARK_SET_GLOBAL,
|
||||
key,
|
||||
x,
|
||||
y,
|
||||
});
|
||||
return { type: '' };
|
||||
};
|
||||
|
||||
const jumpGlobal = (key) => {
|
||||
browser.runtime.sendMessage({
|
||||
type: messages.MARK_JUMP_GLOBAL,
|
||||
key,
|
||||
});
|
||||
return { type: '' };
|
||||
};
|
||||
|
||||
export {
|
||||
startSet, startJump, cancel, setLocal,
|
||||
setGlobal, jumpGlobal,
|
||||
};
|
||||
|
|
|
@ -30,8 +30,10 @@ export default class MarkComponent {
|
|||
|
||||
if (key.ctrlKey || key.metaKey || key.altKey) {
|
||||
consoleFrames.postError(window.document, 'Unknown mark');
|
||||
} else if (key.shiftKey) {
|
||||
consoleFrames.postError(window.document, 'Globa marks not supported');
|
||||
} else if (key.shiftKey && markStage.setMode) {
|
||||
this.doSetGlobal(key);
|
||||
} else if (key.shiftKey && markStage.jumpMode) {
|
||||
this.doJumpGlobal(key);
|
||||
} else if (markStage.setMode) {
|
||||
this.doSet(key);
|
||||
} else if (markStage.jumpMode) {
|
||||
|
@ -56,4 +58,13 @@ export default class MarkComponent {
|
|||
let { x, y } = marks[key.key];
|
||||
scrolls.scrollTo(x, y, smoothscroll);
|
||||
}
|
||||
|
||||
doSetGlobal(key) {
|
||||
let { x, y } = scrolls.getScroll();
|
||||
this.store.dispatch(markActions.setGlobal(key.key, x, y));
|
||||
}
|
||||
|
||||
doJumpGlobal(key) {
|
||||
this.store.dispatch(markActions.jumpGlobal(key.key));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,9 @@ export default {
|
|||
FOLLOW_ACTIVATE: 'follow.activate',
|
||||
FOLLOW_KEY_PRESS: 'follow.key.press',
|
||||
|
||||
MARK_SET_GLOBAL: 'mark.set.global',
|
||||
MARK_JUMP_GLOBAL: 'mark.jump.global',
|
||||
|
||||
FIND_NEXT: 'find.next',
|
||||
FIND_PREV: 'find.prev',
|
||||
FIND_GET_KEYWORD: 'find.get.keyword',
|
||||
|
|
10
test/background/domains/global-mark.test.js
Normal file
10
test/background/domains/global-mark.test.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import GlobalMark from 'background/domains/global-mark';
|
||||
|
||||
describe("background/domains/global-mark", () => {
|
||||
describe("constructor and getter", () => {
|
||||
let mark = new GlobalMark(1, 10, 30);
|
||||
expect(mark.tabId).to.equal(1);
|
||||
expect(mark.x).to.equal(10);
|
||||
expect(mark.y).to.equal(30);
|
||||
});
|
||||
});
|
|
@ -1,8 +1,6 @@
|
|||
import MemoryStorage from 'background/infrastructures/memory-storage';
|
||||
|
||||
describe("background/infrastructures/memory-storage", () => {
|
||||
let versionRepository;
|
||||
|
||||
it('stores values', () => {
|
||||
let cache = new MemoryStorage();
|
||||
cache.set('number', 123);
|
||||
|
|
23
test/background/repositories/mark.test.js
Normal file
23
test/background/repositories/mark.test.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
import MarkRepository from 'background/repositories/mark';
|
||||
import GlobalMark from 'background/domains/global-mark';
|
||||
|
||||
describe("background/repositories/version", () => {
|
||||
let repository;
|
||||
|
||||
beforeEach(() => {
|
||||
repository = new MarkRepository;
|
||||
});
|
||||
|
||||
it('get and set', async() => {
|
||||
let mark = new GlobalMark(1, 10, 30);
|
||||
|
||||
repository.setMark('A', mark);
|
||||
|
||||
let got = await repository.getMark('A');
|
||||
expect(got).to.be.a('object');
|
||||
expect(got.tabId).to.equal(1);
|
||||
|
||||
got = await repository.getMark('B');
|
||||
expect(got).to.be.undefined;
|
||||
});
|
||||
});
|
Reference in a new issue