Support global marks which select a tab

jh-changes
Shin'ya Ueoka 6 years ago
parent 6e6e306275
commit 003742ec51
  1. 15
      src/background/controllers/mark.js
  2. 19
      src/background/domains/global-mark.js
  3. 14
      src/background/infrastructures/content-message-listener.js
  4. 33
      src/background/repositories/mark.js
  5. 29
      src/background/usecases/mark.js
  6. 20
      src/content/actions/mark.js
  7. 15
      src/content/components/common/mark.js
  8. 3
      src/shared/messages.js
  9. 10
      test/background/domains/global-mark.test.js
  10. 2
      test/background/infrastructures/memory-storage.test.js
  11. 23
      test/background/repositories/mark.test.js

@ -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);
}
}

@ -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);
}
}

@ -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) || {};
}
}

@ -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',

@ -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);

@ -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;
});
});