aboutsummaryrefslogtreecommitdiff
path: root/src/content
diff options
context:
space:
mode:
authorShin'ya Ueoka <ueokande@i-beam.org>2017-11-11 11:18:01 +0000
committerGitHub <noreply@github.com>2017-11-11 11:18:01 +0000
commit0630c8f56664ac48f4cf8799dc1d88a6388957a6 (patch)
treed9160c76f4c3435b0859669f1254b12eb92d183f /src/content
parent86b534b1e1de03d51efb9f28cd32296d037f07fc (diff)
parentfe8a9283172e43e29480c4293c34565859c04c32 (diff)
Merge pull request #142 from ueokande/find-mode
[WIP] Find mode
Diffstat (limited to 'src/content')
-rw-r--r--src/content/actions/find.js55
-rw-r--r--src/content/actions/index.js3
-rw-r--r--src/content/actions/operation.js9
-rw-r--r--src/content/components/top-content/find.js54
-rw-r--r--src/content/components/top-content/index.js4
-rw-r--r--src/content/console-frames.js10
-rw-r--r--src/content/reducers/find.js18
-rw-r--r--src/content/reducers/index.js3
8 files changed, 154 insertions, 2 deletions
diff --git a/src/content/actions/find.js b/src/content/actions/find.js
new file mode 100644
index 0000000..80d6210
--- /dev/null
+++ b/src/content/actions/find.js
@@ -0,0 +1,55 @@
+//
+// window.find(aString, aCaseSensitive, aBackwards, aWrapAround,
+// aWholeWord, aSearchInFrames);
+//
+// NOTE: window.find is not standard API
+// https://developer.mozilla.org/en-US/docs/Web/API/Window/find
+
+import actions from 'content/actions';
+import * as consoleFrames from '../console-frames';
+
+const postPatternNotFound = (pattern) => {
+ return consoleFrames.postError(
+ window.document,
+ 'Pattern not found: ' + pattern);
+};
+
+const find = (string, backwards) => {
+ let caseSensitive = false;
+ let wrapScan = true;
+
+
+ // NOTE: aWholeWord dows not implemented, and aSearchInFrames does not work
+ // because of same origin policy
+ return window.find(string, caseSensitive, backwards, wrapScan);
+};
+
+const findNext = (keyword, reset, backwards) => {
+ if (reset) {
+ window.getSelection().removeAllRanges();
+ }
+
+ let found = find(keyword, backwards);
+ if (!found) {
+ window.getSelection().removeAllRanges();
+ found = find(keyword, backwards);
+ }
+ if (!found) {
+ postPatternNotFound(keyword);
+ }
+ return {
+ type: actions.FIND_SET_KEYWORD,
+ keyword,
+ found,
+ };
+};
+
+const next = (keyword, reset) => {
+ return findNext(keyword, reset, false);
+};
+
+const prev = (keyword, reset) => {
+ return findNext(keyword, reset, true);
+};
+
+export { next, prev };
diff --git a/src/content/actions/index.js b/src/content/actions/index.js
index 8cc2303..7e32e12 100644
--- a/src/content/actions/index.js
+++ b/src/content/actions/index.js
@@ -21,4 +21,7 @@ export default {
FOLLOW_CONTROLLER_DISABLE: 'follow.controller.disable',
FOLLOW_CONTROLLER_KEY_PRESS: 'follow.controller.key.press',
FOLLOW_CONTROLLER_BACKSPACE: 'follow.controller.backspace',
+
+ // Find
+ FIND_SET_KEYWORD: 'find.set.keyword',
};
diff --git a/src/content/actions/operation.js b/src/content/actions/operation.js
index 897f361..767f14b 100644
--- a/src/content/actions/operation.js
+++ b/src/content/actions/operation.js
@@ -6,6 +6,7 @@ import * as urls from 'content/urls';
import * as consoleFrames from 'content/console-frames';
import * as addonActions from './addon';
+// eslint-disable-next-line complexity
const exec = (operation) => {
switch (operation.type) {
case operations.ADDON_ENABLE:
@@ -14,6 +15,14 @@ const exec = (operation) => {
return addonActions.disable();
case operations.ADDON_TOGGLE_ENABLED:
return addonActions.toggleEnabled();
+ case operations.FIND_NEXT:
+ return window.top.postMessage(JSON.stringify({
+ type: messages.FIND_NEXT,
+ }), '*');
+ case operations.FIND_PREV:
+ return window.top.postMessage(JSON.stringify({
+ type: messages.FIND_PREV,
+ }), '*');
case operations.SCROLL_VERTICALLY:
return scrolls.scrollVertically(window, operation.count);
case operations.SCROLL_HORIZONALLY:
diff --git a/src/content/components/top-content/find.js b/src/content/components/top-content/find.js
new file mode 100644
index 0000000..bccf040
--- /dev/null
+++ b/src/content/components/top-content/find.js
@@ -0,0 +1,54 @@
+import * as findActions from 'content/actions/find';
+import messages from 'shared/messages';
+import * as consoleFrames from '../../console-frames';
+
+export default class FindComponent {
+ constructor(win, store) {
+ this.win = win;
+ this.store = store;
+
+ messages.onMessage(this.onMessage.bind(this));
+ }
+
+ onMessage(message) {
+ switch (message.type) {
+ case messages.CONSOLE_ENTER_FIND:
+ return this.start(message.text);
+ case messages.FIND_NEXT:
+ return this.next();
+ case messages.FIND_PREV:
+ return this.prev();
+ }
+ }
+
+ start(text) {
+ let state = this.store.getState().find;
+
+ if (text.length === 0) {
+ return this.store.dispatch(findActions.next(state.keyword, true));
+ }
+ return this.store.dispatch(findActions.next(text, true));
+ }
+
+ next() {
+ let state = this.store.getState().find;
+
+ if (!state.found) {
+ return consoleFrames.postError(
+ window.document,
+ 'Pattern not found: ' + state.keyword);
+ }
+ return this.store.dispatch(findActions.next(state.keyword, false));
+ }
+
+ prev() {
+ let state = this.store.getState().find;
+
+ if (!state.found) {
+ return consoleFrames.postError(
+ window.document,
+ 'Pattern not found: ' + state.keyword);
+ }
+ return this.store.dispatch(findActions.prev(state.keyword, false));
+ }
+}
diff --git a/src/content/components/top-content/index.js b/src/content/components/top-content/index.js
index 5124f83..cf21ec4 100644
--- a/src/content/components/top-content/index.js
+++ b/src/content/components/top-content/index.js
@@ -1,5 +1,6 @@
import CommonComponent from '../common';
import FollowController from './follow-controller';
+import FindComponent from './find';
import * as consoleFrames from '../../console-frames';
import * as addonActions from '../../actions/addon';
import messages from 'shared/messages';
@@ -14,6 +15,7 @@ export default class TopContent {
new CommonComponent(win, store); // eslint-disable-line no-new
new FollowController(win, store); // eslint-disable-line no-new
+ new FindComponent(win, store); // eslint-disable-line no-new
// TODO make component
consoleFrames.initialize(this.win.document);
@@ -47,7 +49,7 @@ export default class TopContent {
onMessage(message) {
switch (message.type) {
- case messages.CONSOLE_HIDE_COMMAND:
+ case messages.CONSOLE_UNFOCUS:
this.win.focus();
consoleFrames.blur(window.document);
return Promise.resolve();
diff --git a/src/content/console-frames.js b/src/content/console-frames.js
index 35b975f..515ae09 100644
--- a/src/content/console-frames.js
+++ b/src/content/console-frames.js
@@ -1,4 +1,5 @@
import './console-frame.scss';
+import messages from 'shared/messages';
const initialize = (doc) => {
let iframe = doc.createElement('iframe');
@@ -20,4 +21,11 @@ const postMessage = (doc, message) => {
iframe.contentWindow.postMessage(JSON.stringify(message), '*');
};
-export { initialize, blur, postMessage };
+const postError = (doc, message) => {
+ return postMessage(doc, {
+ type: messages.CONSOLE_SHOW_ERROR,
+ text: message,
+ });
+};
+
+export { initialize, blur, postMessage, postError };
diff --git a/src/content/reducers/find.js b/src/content/reducers/find.js
new file mode 100644
index 0000000..eb43c37
--- /dev/null
+++ b/src/content/reducers/find.js
@@ -0,0 +1,18 @@
+import actions from 'content/actions';
+
+const defaultState = {
+ keyword: '',
+ found: false,
+};
+
+export default function reducer(state = defaultState, action = {}) {
+ switch (action.type) {
+ case actions.FIND_SET_KEYWORD:
+ return Object.assign({}, state, {
+ keyword: action.keyword,
+ found: action.found,
+ });
+ default:
+ return state;
+ }
+}
diff --git a/src/content/reducers/index.js b/src/content/reducers/index.js
index 17c0429..2487d85 100644
--- a/src/content/reducers/index.js
+++ b/src/content/reducers/index.js
@@ -1,4 +1,5 @@
import addonReducer from './addon';
+import findReducer from './find';
import settingReducer from './setting';
import inputReducer from './input';
import followControllerReducer from './follow-controller';
@@ -6,6 +7,7 @@ import followControllerReducer from './follow-controller';
// Make setting reducer instead of re-use
const defaultState = {
addon: addonReducer(undefined, {}),
+ find: findReducer(undefined, {}),
setting: settingReducer(undefined, {}),
input: inputReducer(undefined, {}),
followController: followControllerReducer(undefined, {}),
@@ -14,6 +16,7 @@ const defaultState = {
export default function reducer(state = defaultState, action = {}) {
return Object.assign({}, state, {
addon: addonReducer(state.addon, action),
+ find: findReducer(state.find, action),
setting: settingReducer(state.setting, action),
input: inputReducer(state.input, action),
followController: followControllerReducer(state.followController, action),