Skip to content

Commit

Permalink
Remake translate buttons;
Browse files Browse the repository at this point in the history
Replace 'showButtonAfterSelect' with 'translateButtons'.
Now multiple buttons can be displayed at the same time.
Uncheck every buttons means disable 'showButtonAfterSelect'.

fix: translate button can be showed outside the screen;
  • Loading branch information
chunibyocola committed Aug 13, 2021
1 parent f10fc03 commit 22af8e2
Show file tree
Hide file tree
Showing 14 changed files with 233 additions and 44 deletions.
17 changes: 16 additions & 1 deletion public/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@
"message": "Dark Mode"
},
"optionsShowButtonAfterSelect": {
"message": "Show button after select text"
"message": "Show buttons after selecting text"
},
"optionsShowButtonAfterSelectDescription": {
"message": "When you select some text and release the left mouse button, the buttons you checked below will be displayed. The order of the buttons is related to the order in which you checked. If you don't want to show any buttons, just uncheck all the buttons."
},
"optionsAudio": {
"message": "Audio"
Expand Down Expand Up @@ -308,6 +311,18 @@
"optionsCustomizeStyleNotice": {
"message": "Notice: there is no guarantee that elements or class names wil not be changed. Once elements or class names are changed, the CSS you input might cause \"style disorder\", then, you might need to adjust the CSS you input here."
},
"optionsPreview": {
"message": "Preview:"
},
"optionsButtonTranslate": {
"message": "Translate"
},
"optionsButtonListen": {
"message": "Listen"
},
"optionsButtonCopy": {
"message": "Copy"
},
"themePreset": {
"message": "Preset"
},
Expand Down
15 changes: 15 additions & 0 deletions public/_locales/ja/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
"optionsShowButtonAfterSelect": {
"message": "テキストを選択した後にボタンを表示"
},
"optionsShowButtonAfterSelectDescription": {
"message": "テキストを選択した後にマウスの左ボタンを離すと、下でチェックしたボタンが表示されます。ボタンの順序は、チェックした順序に関連しています。ボタンを表示したくない場合は、すべてのボタンのチェックを外してください。"
},
"optionsAudio": {
"message": "音声"
},
Expand Down Expand Up @@ -308,6 +311,18 @@
"optionsCustomizeStyleNotice": {
"message": "注意:要素とクラス名が変更されないという保証はありません。要素とクラス名が変更されると、入力したCSSによって「スタイルの乱れ」が発生する可能性があるため、ここで入力したCSSを調整する必要がある場合があります。"
},
"optionsPreview": {
"message": "プレビュー:"
},
"optionsButtonTranslate": {
"message": "翻訳"
},
"optionsButtonListen": {
"message": "音声を聞く"
},
"optionsButtonCopy": {
"message": "コピー"
},
"themePreset": {
"message": "プリセット"
},
Expand Down
15 changes: 15 additions & 0 deletions public/_locales/zh_CN/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
"optionsShowButtonAfterSelect": {
"message": "选择文本后展示按钮"
},
"optionsShowButtonAfterSelectDescription": {
"message": "当你选择一些文本并释放鼠标左键后,将显示你在下方所勾选的按钮。按钮的顺序与你勾选的顺序相关。如果你不想显示任何按钮,只需取消勾选所有按钮即可。"
},
"optionsAudio": {
"message": "朗读"
},
Expand Down Expand Up @@ -308,6 +311,18 @@
"optionsCustomizeStyleNotice": {
"message": "注意:不能保证元素和类名不会更改。一旦元素和类名被更改了,你在此输入的 CSS 可能会造成样式错乱,然后你可能会需要调整你所输入的 CSS。"
},
"optionsPreview": {
"message": "预览:"
},
"optionsButtonTranslate": {
"message": "翻译"
},
"optionsButtonListen": {
"message": "朗读"
},
"optionsButtonCopy": {
"message": "复制"
},
"themePreset": {
"message": "预设"
},
Expand Down
15 changes: 15 additions & 0 deletions public/_locales/zh_TW/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
"optionsShowButtonAfterSelect": {
"message": "選擇文本後展示按鈕"
},
"optionsShowButtonAfterSelectDescription": {
"message": "當你選擇一些文本並釋放鼠標左鍵後,將顯示你在下方所勾選的按鈕。按鈕的順序與你勾選的順序相關。如果你不想顯示任何按鈕,只需取消勾選所有按鈕即可。"
},
"optionsAudio": {
"message": "朗讀"
},
Expand Down Expand Up @@ -308,6 +311,18 @@
"optionsCustomizeStyleNotice": {
"message": "注意:不能保證元素和類名不會更改。一旦元素和類名被更改了,你在此輸入的 CSS 可能會造成樣式錯亂,然後你可能會需要調整你所輸入的 CSS。"
},
"optionsPreview": {
"message": "預覽:"
},
"optionsButtonTranslate": {
"message": "翻譯"
},
"optionsButtonListen": {
"message": "朗讀"
},
"optionsButtonCopy": {
"message": "複製"
},
"themePreset": {
"message": "預設"
},
Expand Down
70 changes: 49 additions & 21 deletions src/components/TsBtn/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,38 @@ import { DefaultOptions, Position } from '../../types';
import { callOutPanel, closePanel, requestToHidePanel, showPanelAndSetPosition } from '../../redux/slice/panelStatusSlice';
import { mtSetText } from '../../redux/slice/multipleTranslateSlice';
import { stSetText } from '../../redux/slice/singleTranslateSlice';
import { translateButtonContext, TRANSLATE_BUTTON_COPY, TRANSLATE_BUTTON_LISTEN, TRANSLATE_BUTTON_TRANSLATE } from '../../constants/translateButtonTypes';

const initText = '';
const initPos = { x: 5, y: 5 };
const btnWidth = 24;
const btnHeight = 24;

type PickedOptions = Pick<
DefaultOptions,
'translateDirectly' |
'showButtonAfterSelect' |
'translateWithKeyPress' |
'hideButtonAfterFixedTime' |
'hideButtonFixedTime' |
'respondToSeparateWindow' |
'translateDirectlyWhilePinning' |
'doNotRespondInTextBox'
'doNotRespondInTextBox' |
'translateButtons'
>;
const useOptionsDependency: (keyof PickedOptions)[] = [
'translateDirectly',
'showButtonAfterSelect',
'translateWithKeyPress',
'hideButtonAfterFixedTime',
'hideButtonFixedTime',
'respondToSeparateWindow',
'translateDirectlyWhilePinning',
'doNotRespondInTextBox'
'doNotRespondInTextBox',
'translateButtons'
];

const calculateBtnPos = ({ x, y }: Position) => {
const calculateBtnPos = ({ x, y }: Position, translateButtonElement: HTMLDivElement | null) => {
const { btnPosition } = getOptions();
const rect = translateButtonElement?.getBoundingClientRect();
const btnHeight = rect?.height ?? 22;
const btnWidth = rect?.width ?? 22;
let tmpX = x + btnPosition.x, tmpY = y + btnPosition.y;

const dH = document.documentElement.clientHeight;
Expand All @@ -61,6 +63,11 @@ const calculateBtnPos = ({ x, y }: Position) => {
if (bR > dW) tmpX = x - 5 - btnWidth;
if (bL < 0) tmpX = x + 5;

if (tmpX + btnWidth + 5 > dW) tmpX = dW - btnWidth - 5;
if (tmpX < 5) tmpX = 5;
if (tmpY + btnHeight + 5 > dH) tmpY = dH - btnHeight - 5;
if (tmpY < 5) tmpY = 5;

return { x: tmpX, y: tmpY };
};

Expand All @@ -72,18 +79,19 @@ const TsBtn: React.FC = () => {
const ctrlPressing = useRef(false);
const debounceHideButtonAfterFixedTime = useRef<ReturnType<typeof debounce>>();
const oldChromeMsg = useRef<any>(null);
const translateButtonEleRef = useRef<HTMLDivElement>(null);

const { pinning } = useAppSelector(state => state.panelStatus);

const {
translateDirectly,
showButtonAfterSelect,
translateWithKeyPress,
hideButtonAfterFixedTime,
hideButtonFixedTime,
respondToSeparateWindow,
translateDirectlyWhilePinning,
doNotRespondInTextBox
doNotRespondInTextBox,
translateButtons
} = useOptions<PickedOptions>(useOptionsDependency);

const isEnableTranslate = useIsEnable('translate', window.location.host);
Expand All @@ -102,6 +110,23 @@ const TsBtn: React.FC = () => {
getOptions().multipleTranslateMode ? dispatch(mtSetText({ text })) : dispatch(stSetText({ text }));
}, [dispatch, respondToSeparateWindow]);

const handleTranslateButtonClick = (translateButton: string) => {
setShowBtn(false);

switch (translateButton) {
case TRANSLATE_BUTTON_TRANSLATE:
handleForwardTranslate(text, pos);
break;
case TRANSLATE_BUTTON_LISTEN:
sendAudio(text, {});
break;
case TRANSLATE_BUTTON_COPY:
navigator.clipboard.writeText(text);
break;
default: break;
}
};

useEffect(() => {
if (!translateWithKeyPress) return;

Expand Down Expand Up @@ -158,19 +183,20 @@ const TsBtn: React.FC = () => {

if (doNotRespondInTextBox && document.activeElement && isTextBox(document.activeElement)) { return; }

const nextPos = calculateBtnPos(pos);

if ((translateWithKeyPress && ctrlPressing.current) || translateDirectly || (pinning && translateDirectlyWhilePinning)) {
handleForwardTranslate(text, nextPos);
handleForwardTranslate(text, calculateBtnPos(pos, null));
return;
}

setPos(nextPos);
setText(text);
if (showButtonAfterSelect) {
if (translateButtons.length > 0) {
setShowBtn(true);
setPos(calculateBtnPos(pos, translateButtonEleRef.current));
hideButtonAfterFixedTime && debounceHideButtonAfterFixedTime.current?.();
}
else {
setPos(calculateBtnPos(pos, null));
}

dispatch(requestToHidePanel());
}, () => {
Expand All @@ -185,20 +211,22 @@ const TsBtn: React.FC = () => {

return (
<div
ref={translateButtonEleRef}
className='translate-button'
style={{
display: isEnableTranslate && showBtn ? 'block' : 'none',
display: isEnableTranslate && showBtn && translateButtons.length > 0 ? 'flex' : 'none',
left: `${pos.x}px`,
top: `${pos.y}px`
}}
onMouseUp={(e) => {
setShowBtn(false);
handleForwardTranslate(text, pos);
e.stopPropagation();
}}
onMouseUp={e => e.stopPropagation()}
onMouseDown={e => e.stopPropagation()}
>
<IconFont iconName='#icon-MdTranslate' style={{display: 'block'}} />
{translateButtons.map((translateButton) => (translateButtonContext[translateButton].type === 'icon' && <div
className='translate-button__item iconfont--enable'
onClick={() => handleTranslateButtonClick(translateButton)}
>
<IconFont iconName={translateButtonContext[translateButton].iconName} />
</div>))}
</div>
);
};
Expand Down
10 changes: 7 additions & 3 deletions src/components/TsBtn/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
border-radius: 3px;
padding: 3px;
box-shadow: 0px 0px 4px -1px rgba(0, 0, 0, .88) ;
cursor: pointer;
color: var(--text-normal);
background: var(--bg-content);
position: fixed;
z-index: 2147483647;
}
.translate-button .iconfont {
.translate-button__item {
display: inline-flex;
}
.translate-button__item .iconfont {
display: block;
font-size: 16px;
}
.translate-button__item + .translate-button__item {
margin-left: 3px;
}
5 changes: 3 additions & 2 deletions src/constants/defaultOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { LANG_EN } from './langCode';
import { styleVarsList } from './defaultStyleVars';
import { defaultContextMenus } from './contextMenusIds';
import { DefaultOptions } from '../types';
import { defaultTranslateButtons } from './translateButtonTypes';

const defaultOptions: DefaultOptions = {
userLanguage: LANG_EN,
Expand All @@ -14,7 +15,6 @@ const defaultOptions: DefaultOptions = {
translateHostList: [],
historyBlackListMode: false,
historyHostList: [],
showButtonAfterSelect: true,
defaultAudioSource: GOOGLE_COM,
translateWithKeyPress: false,
useDotCn: false,
Expand Down Expand Up @@ -56,7 +56,8 @@ const defaultOptions: DefaultOptions = {
autoInsertResult: false,
textPreprocessingRegExpList: [],
textPreprocessingPreset: { convertCamelCase: false },
customizeStyleText: ''
customizeStyleText: '',
translateButtons: defaultTranslateButtons
};

export default defaultOptions;
15 changes: 15 additions & 0 deletions src/constants/translateButtonTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export const TRANSLATE_BUTTON_TRANSLATE = 'TRANSLATE_BUTTON_TRANSLATE';
export const TRANSLATE_BUTTON_LISTEN = 'TRANSLATE_BUTTON_LISTEN';
export const TRANSLATE_BUTTON_COPY = 'TRANSLATE_BUTTON_COPY';

export const defaultTranslateButtons = [TRANSLATE_BUTTON_TRANSLATE];

type TranslateButtonContext = {
[key: string]: { type: 'icon', iconName: string }
};

export const translateButtonContext: TranslateButtonContext = {
TRANSLATE_BUTTON_TRANSLATE: { type: 'icon', iconName: '#icon-MdTranslate' },
TRANSLATE_BUTTON_LISTEN: { type: 'icon', iconName: '#icon-GoUnmute' },
TRANSLATE_BUTTON_COPY: { type: 'icon', iconName: '#icon-copy' }
};
12 changes: 9 additions & 3 deletions src/entry/background/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import defaultOptions from '../../constants/defaultOptions';
import { getLocalStorage } from '../../public/chrome-call';
import { defaultStyleVars } from '../../constants/defaultStyleVars';
import { TRANSLATE_CURRENT_PAGE, TRANSLATE_SELECTION_TEXT } from '../../constants/contextMenusIds';
import { DefaultOptions } from '../../types';
import { DefaultOptions, DeprecatedOptions } from '../../types';
import { TRANSLATE_BUTTON_TRANSLATE } from '../../constants/translateButtonTypes';

const initStorageOnInstalled = (userLang: string, update: boolean) => {

Expand All @@ -25,7 +26,7 @@ const initStorageOnInstalled = (userLang: string, update: boolean) => {
preferredLangCode[LANG_ZH_CN].some((v) => (v.code === userLang)) && (defaultSet.preferredLanguage = userLang);
defaultSet.preferredLanguage === 'en' && (defaultSet.secondPreferredLanguage = 'es');

getLocalStorage<DefaultOptions & { [key: string]: any }>(Object.keys(defaultOptions), (data) => {
getLocalStorage<DefaultOptions & DeprecatedOptions>(null, (data) => {
// in new version, use 'useDotCn' instead of 'xxx.cn'
if (update && (data.defaultTranslateSource === 'google.cn' || data.defaultTranslateSource === 'bing.cn' || data.defaultAudioSource === 'google.cn')) {
data.useDotCn = true;
Expand All @@ -37,7 +38,7 @@ const initStorageOnInstalled = (userLang: string, update: boolean) => {
if (update && 'enableContextMenus' in data && !('contextMenus' in data)) {
const index = defaultSet.contextMenus.findIndex(v => v.id === TRANSLATE_SELECTION_TEXT);
if (index >= 0) {
defaultSet.contextMenus[index].enabled = data.enableContextMenus as boolean;
defaultSet.contextMenus[index].enabled = (data as DeprecatedOptions).enableContextMenus;
}
}

Expand All @@ -48,6 +49,11 @@ const initStorageOnInstalled = (userLang: string, update: boolean) => {
}
}

// In 3.9.0, remake translate button
if (update && 'showButtonAfterSelect' in data && !('translateButtons' in data)) {
(data as DefaultOptions).translateButtons = (data as DeprecatedOptions).showButtonAfterSelect ? [TRANSLATE_BUTTON_TRANSLATE] : [];
}

if (data.styleVarsList?.[0]?.styleVars) {
(data.styleVarsList[0].styleVars = defaultStyleVars);
}
Expand Down
Loading

0 comments on commit 22af8e2

Please sign in to comment.