diff --git a/src/can-i-use.ts b/src/can-i-use.ts index 5ba2dfb..c7c53df 100644 --- a/src/can-i-use.ts +++ b/src/can-i-use.ts @@ -1,7 +1,7 @@ import { Base } from './core/base' -const isWindowsOS = (platform: Base['platform']) => platform.os === 'win' -const isMacOS = (platform: Base['platform']) => platform.os === 'mac' +export const isWindowsOS = (platform: Base['platform']) => platform.os === 'win' +export const isMacOS = (platform: Base['platform']) => platform.os === 'mac' const InitCanIUse = ( fn: (...args: A) => boolean diff --git a/src/core/base/index.ts b/src/core/base/index.ts index 7109d8e..656b78a 100644 --- a/src/core/base/index.ts +++ b/src/core/base/index.ts @@ -6,7 +6,7 @@ import { load as loadPreferences, Preferences, SiteSettingFloorID, SiteSettings import { hasStrongMobileAccessMode } from '../../preferences/site-settings' import { getCurrentDisplayLimit, Limit } from './limit' import { autoAdjustHeight, autoAdjustWidth } from './auto-adjust' -import { initSearchMatrix } from './search-matrix' +import { initWindowOptionMatrix } from './window-option-matrix' import { getControlWindowHeight } from './control-window-height' import { getFilteredFloor } from '../../x-state/filtered-floor' import { specifyFloorIdxBySearchText } from '../../hooks/useSearchForm' @@ -47,10 +47,13 @@ export function initLayoutInfo( max_window_per_line, total_width, window_width } = autoAdjustWidth(gap_horizontal, limit.width) + console.warn('max_window_per_line', max_window_per_line) + const [ total_row, - search_matrix - ] = initSearchMatrix(max_window_per_line, site_settings) + window_option_matrix, + // search_matrix + ] = initWindowOptionMatrix(max_window_per_line, site_settings) const { window_height, total_height } = autoAdjustHeight( [...cfg.SEARCH_WINDOW_HEIGHT_LIST], @@ -67,7 +70,7 @@ export function initLayoutInfo( total_width, window_width, total_row, - search_matrix, + window_option_matrix, window_height, total_height } as const diff --git a/src/core/base/search-matrix.ts b/src/core/base/search-matrix.ts deleted file mode 100644 index 3927a37..0000000 --- a/src/core/base/search-matrix.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { map, curry, range, nth, compose } from 'ramda' -import cfg from '../../config' -import { Matrix, Row } from '../common' - -import { - toSearchURL, - addMobileIdentifier, - SiteOption, - SiteSettings, - toMatrix -} from '../../preferences/site-settings' - -type GetSearchURLFn = (keyword: string) => string -export type SearchOption = { - is_plain: true - site_option: undefined - getSearchURL: GetSearchURLFn -} | { - is_plain: false - site_option: SiteOption - getSearchURL: GetSearchURLFn -} -type SearchRow = Array -export type SearchMatrix = Array - -function GetSearchURL( - plain_window_url_pattern: string, - site_row: Row, - col: number -): GetSearchURLFn { - const site_opt = nth(col, site_row) - if (site_opt === undefined) { - return curry(toSearchURL)(plain_window_url_pattern) - } else { - const toUrl = curry(toSearchURL)(site_opt.url_pattern) - if (site_opt.access_mode === 'MOBILE') { - return compose(addMobileIdentifier, toUrl) - } else { - return toUrl - } - } -} - -function fillSearchRow( - plain_window_url_pattern: string, - max_window_per_line: number, - site_row: Row, -): SearchRow { - return map( - (col) => { - const getSearchURL = GetSearchURL(plain_window_url_pattern, site_row, col) - const site_option = nth(col, site_row) - if (site_option === undefined) { - return { - is_plain: true, - site_option: undefined, - getSearchURL, - } - } else { - return { - is_plain: false, - site_option, - getSearchURL, - } - } - }, - range(0, max_window_per_line) - ) -} - -function createSearchMatrix( - plain_window_url_pattern: string, - max_window_per_row: number, - site_matrix: Matrix, -): SearchMatrix { - if (site_matrix.length === 0) { - return [] - } else { - const [cols, ...remain_matrix] = site_matrix - - if (max_window_per_row < cols.length) { - return createSearchMatrix( - plain_window_url_pattern, - max_window_per_row, - [ - cols.slice(0, max_window_per_row), - cols.slice(max_window_per_row, cols.length), - ...remain_matrix - ], - ) - } else { - return [ - fillSearchRow(plain_window_url_pattern, max_window_per_row, cols), - ...createSearchMatrix(plain_window_url_pattern, max_window_per_row, remain_matrix) - ] - } - } -} - -export function initSearchMatrix( - max_window_per_line: number, - site_settings: SiteSettings -) { - const search_matrix = createSearchMatrix( - cfg.PLAIN_SEARCH_WINDOW_URL_PATTERN, - max_window_per_line, - toMatrix(site_settings), - ) - const search_count = search_matrix.flat().length - const total_row = Math.ceil(search_count / max_window_per_line) - - return [ total_row, search_matrix ] as const -} diff --git a/src/core/base/window-option-matrix.ts b/src/core/base/window-option-matrix.ts new file mode 100644 index 0000000..b094a66 --- /dev/null +++ b/src/core/base/window-option-matrix.ts @@ -0,0 +1,150 @@ +import { curry, nth, compose } from 'ramda' +import cfg from '../../config' +import { Matrix, Row } from '../common' + +import { + toSearchURL, + addMobileIdentifier, + SiteOption, + SiteSettings, + toMatrix +} from '../../preferences/site-settings' + +export type WindowOptionType = 'NORMAL' | 'FILL' | 'EMPTY' | 'PLAIN' +type ComposeSearchURLFn = (keyword: string) => string +type DefineWindowOption = { + type: T + width_size: W + site_option: S + composeSearchURL: ComposeSearchURLFn +} + +export type WindowOption = + DefineWindowOption<'NORMAL', number, SiteOption> | + DefineWindowOption<'FILL', 1, undefined> | + DefineWindowOption<'EMPTY', 1, undefined> | + DefineWindowOption<'PLAIN', 1, undefined> + +type WindowOptionRow = Array +export type WindowOptionMatrix = Array + +function ComposeSearchURL( + plain_window_url_pattern: string, + site_row: Row, + col: number +): ComposeSearchURLFn { + const site_opt = nth(col, site_row) + if (site_opt === undefined) { + return curry(toSearchURL)(plain_window_url_pattern) + } else { + const toUrl = curry(toSearchURL)(site_opt.url_pattern) + if (site_opt.access_mode === 'MOBILE') { + return compose(addMobileIdentifier, toUrl) + } else { + return toUrl + } + } +} + +function fillRow( + plain_window_url_pattern: string, + max_window_per_line: number, + site_row: Row, +): WindowOptionMatrix { + let result: WindowOptionRow = [] + + for (let idx = 0; idx < max_window_per_line; ++idx) { + const composeSearchURL = ComposeSearchURL(plain_window_url_pattern, site_row, idx) + const site_option = site_row[idx] + console.log('idx', idx, max_window_per_line, site_option) + + if (result.length >= max_window_per_line) { + // 超过了, + // const remain: Row = site_row.slice(idx, max_window_per_line) + const remain: Row = site_row.slice(idx, max_window_per_line) + console.warn('超过了', remain, result.length, max_window_per_line) + + if (remain.length) { + return [ + result.slice(0, max_window_per_line), + ...fillRow(plain_window_url_pattern, max_window_per_line, remain), + ] + } else { + return [ result ] + } + } + + if (site_option === undefined) { + result.push({ + type: 'PLAIN', width_size: 1, site_option: undefined, composeSearchURL, + }) + } else { + result.push({ + type: 'NORMAL', + width_size: site_option.width_size, + site_option, + composeSearchURL, + }) + if (site_option.width_size > 1) { + for (let r = site_option.width_size; r > 1; --r) { + result.push({ + type: 'FILL', + width_size: 1, + site_option: undefined, + composeSearchURL, + }) + } + } + } + } + + return [ result ] +} + +function createWindowOptionMatrix( + plain_window_url_pattern: string, + max_window_per_row: number, + site_matrix: Matrix, +): WindowOptionMatrix { + if (site_matrix.length === 0) { + return [] + } else { + const [cols, ...remain_matrix] = site_matrix + return [ + ...fillRow(plain_window_url_pattern, max_window_per_row, cols), + ...createWindowOptionMatrix(plain_window_url_pattern, max_window_per_row, remain_matrix) + ] + // if (cols.length > max_window_per_row) { + // return createSearchMatrix( + // plain_window_url_pattern, + // max_window_per_row, + // [ + // cols.slice(0, max_window_per_row), + // cols.slice(max_window_per_row, cols.length), + // ...remain_matrix + // ], + // ) + // } else { + // return [ + // ...fillRow(plain_window_url_pattern, max_window_per_row, cols), + // ...createSearchMatrix(plain_window_url_pattern, max_window_per_row, remain_matrix) + // ] + // } + } +} + +export function initWindowOptionMatrix( + max_window_per_line: number, + site_settings: SiteSettings +) { + const search_matrix = createWindowOptionMatrix( + cfg.PLAIN_SEARCH_WINDOW_URL_PATTERN, + max_window_per_line, + toMatrix(site_settings), + ) + console.warn('search_matrix', search_matrix, toMatrix(site_settings)) + const search_count = search_matrix.flat().length + const total_row = Math.ceil(search_count / max_window_per_line) + + return [ total_row, search_matrix ] as const +} diff --git a/src/core/layout/index.ts b/src/core/layout/index.ts index a42ca41..143379c 100644 --- a/src/core/layout/index.ts +++ b/src/core/layout/index.ts @@ -35,22 +35,32 @@ export async function CreateSearchLayout({ console.log('CreateSearchLayout') function getRegIds(): number[] { - return getMatrix().flat().filter(u => u.state !== 'EMPTY').map(u => u.windowId) + return ( + getMatrix() + .flat() + .filter(u => u.type !== 'EMPTY') + .filter(u => u.type !== 'FILL') + .map(u => u.windowId) + ) } async function refreshLayout(skip_ids: number[]) { - await renderMatrix(base, layout_info, getMatrix(), true, false, skip_ids) + await renderMatrix(base.platform, base.limit, layout_info, getMatrix(), { + preset_focused: true, + reset_size: false, + skip_ids + }) if (skip_ids.indexOf(control_window_id) === -1) { await chrome.windows.update(control_window_id, { focused: true }) } } - const { search_matrix } = layout_info + const { window_option_matrix } = layout_info const [getMatrix, setMatrix] = Memo( await constructSearchWindowsFast( base, layout_info, - search_matrix, + window_option_matrix, keyword, creating_signal, stop_creating_signal @@ -78,7 +88,12 @@ export async function CreateSearchLayout({ const [need_update, update] = selectWindow(getMatrix(), focused_window_id) if (need_update) { const col_refresh_waiting = renderCol( - base, layout_info, update.new_matrix, update.col, true, true + base.platform, base.limit, layout_info, update.new_matrix, + { + select_col: update.col, + preset_focused: true, + reset_size: true + } ) if (needRefocusingLayout()) { diff --git a/src/core/layout/pos.ts b/src/core/layout/pos.ts index b5c4b45..0644591 100644 --- a/src/core/layout/pos.ts +++ b/src/core/layout/pos.ts @@ -3,23 +3,43 @@ import { LayoutInfo } from '../base' import { calcWindowsTotalWidth } from '../base/auto-adjust' import { Limit } from '../base/limit' +// function calcWindowLeft( +// previous_width_size_map: number[], +// gap_horizontal: number, +// window_width: number +// ) { +// const gap_total = previous_width_size_map.reduce((v, width_size) => { +// return v + (width_size * gap_horizontal) +// }, 0) +// return gap_total + ( +// previous_width_size_map +// .map(ws => ws * window_width) +// .reduce((v, a) => v + a, 0) +// ) +// } + type Pos = Readonly<[number, number]> -type LayoutPosInfo = { +type WindowInfo = { + width_size: number window_width: number gap_horizontal: number titlebar_height: number } -function calcLayoutPos( - info: LayoutPosInfo, +function calcWindowPos( + info: WindowInfo, line: number, - index: number + index: number, ): Pos { const total_width = calcWindowsTotalWidth( index + 1, info.window_width, info.gap_horizontal ) - const left = total_width - info.window_width + const left = total_width - calcWindowsTotalWidth( + info.width_size, + info.window_width, + info.gap_horizontal + ) const top = line * info.titlebar_height return [left, top] } @@ -28,14 +48,16 @@ export function calcRealPos( limit: Limit, info: LayoutInfo, line: number, - index: number + index: number, + width_size: number ) { const [toRealLeft, toRealTop] = ToRealPos( limit, info.total_width, info.total_height, ) - const [l, t] = calcLayoutPos({ + const [l, t] = calcWindowPos({ + width_size, window_width: info.window_width, gap_horizontal: info.gap_horizontal, titlebar_height: info.titlebar_height diff --git a/src/core/layout/render.ts b/src/core/layout/render.ts index 99aa783..f498cd0 100644 --- a/src/core/layout/render.ts +++ b/src/core/layout/render.ts @@ -4,46 +4,50 @@ import { calcRealPos } from './pos' import { isCurrentRow } from './matrix' import { SearchWindow } from './window' import { Limit } from '../base/limit' +import { isWindowsOS } from '../../can-i-use' -async function refreshWindow( +async function resetSearchWindow( limit: Limit, layout_info: LayoutInfo, opts: { window: SearchWindow, - // windowId: number, focused?: boolean, - resetSize?: boolean + reset_size?: boolean row: number col: number } ): Promise { - const [left, top] = calcRealPos(limit, layout_info, opts.row, opts.col) + const [left, top] = calcRealPos(limit, layout_info, opts.row, opts.col, 1) + // opts.window.init_height - const { state, windowId } = opts.window - if (state === 'EMPTY') { + const { type, windowId } = opts.window + if (type === 'EMPTY') { + return + } if (type === 'FILL') { return } else { await chrome.windows.update(windowId, { focused: opts.focused, left, top, - width: opts.resetSize ? layout_info.window_width : undefined, - height: opts.resetSize ? layout_info.window_height : undefined, + width: opts.reset_size ? layout_info.window_width : undefined, + height: opts.reset_size ? layout_info.window_height : undefined, }) return } } export async function renderMatrix( - base: Base, + platform: Base['platform'], + limit: Limit, layout_info: LayoutInfo, matrix: Matrix, - presetFocused: undefined | boolean = undefined, - resetSize: boolean = false, - skip_ids: number[] = [] + { preset_focused, reset_size = false, skip_ids = [] }: { + preset_focused?: boolean, + reset_size?: boolean + skip_ids?: number[] + } ) { - const isWin = base.platform.os === 'win' - const promises: Promise[] = [] for (let [row, line] of matrix.entries()) { for (let [col, win] of line.entries()) { @@ -52,10 +56,10 @@ export async function renderMatrix( if (skip_ids.indexOf(win.windowId) !== -1) { promises.push(Promise.resolve(undefined)) } else { - const p = refreshWindow(base.limit, layout_info, { + const p = resetSearchWindow(limit, layout_info, { window: win, - focused: (presetFocused === undefined) ? (isWin || isLastLine) : presetFocused, - resetSize, + focused: (preset_focused === undefined) ? (isWindowsOS(platform) || isLastLine) : preset_focused, + reset_size, row, col, }) @@ -68,24 +72,25 @@ export async function renderMatrix( } export function renderCol( - base: Base, + platform: Base['platform'], + limit: Limit, layout_info: LayoutInfo, matrix: Matrix, - selectCol: number, - presetFocused: undefined | boolean = undefined, - resetSize: boolean = false + { select_col, preset_focused, reset_size = false }: { + select_col: number, + preset_focused?: boolean, + reset_size?: boolean + } ) { - const isWin = base.platform.os === 'win' - const promises: Promise[] = [] for (let [row, line] of matrix.entries()) { for (let [col, win] of line.entries()) { - if (selectCol === col) { + if (select_col === col) { const isLastLine = isCurrentRow(matrix, row) - const p = refreshWindow(base.limit, layout_info, { + const p = resetSearchWindow(limit, layout_info, { window: win, - focused: (presetFocused === undefined) ? (isWin || isLastLine) : presetFocused, - resetSize, + focused: (preset_focused === undefined) ? (isWindowsOS(platform) || isLastLine) : preset_focused, + reset_size, row, col }) diff --git a/src/core/layout/window-create.ts b/src/core/layout/window-create.ts index 4a2eb45..8d1e047 100644 --- a/src/core/layout/window-create.ts +++ b/src/core/layout/window-create.ts @@ -1,12 +1,15 @@ import { SearchWindowMatrix, SearchWindowRow, TabID, WindowID } from './window' import { Base, LayoutInfo } from '../base' -import { SearchMatrix, SearchOption } from '../base/search-matrix' +import { Limit } from '../base/limit' +import { Preferences } from '../../preferences' +import { WindowOption, WindowOptionMatrix } from '../base/window-option-matrix' import { calcRealPos } from './pos' import { isCurrentRow } from './matrix' import { renderMatrix } from './render' -import { Signal } from 'vait' +import { Signal, timeout } from 'vait' import { removeAllFakeUARules, setFakeUA } from '../../utils/fake-ua' import cfg from '../../config' +import { calcWindowsTotalWidth } from '../base/auto-adjust' type PlainUnit = null type Unit = PlainUnit | { @@ -51,45 +54,57 @@ function OpenSearchWindow(url: string, CreateData: chrome.windows.CreateData) { return [newUnit, createP] as const } -type CreateOption = { +type Preparation = { url: string - search_option: SearchOption + window_option: WindowOption window_data: chrome.windows.CreateData -} | null +} -export async function constructSearchWindowsFast( - base: Base, - layout_info: LayoutInfo, - search_matrix: SearchMatrix, +function createPreparationMatrix( keyword: string, - creating_signal: Signal, - stop_creating_signal: Signal, -): Promise { - search_matrix = [...search_matrix].reverse() + limit: Limit, + layout_info: LayoutInfo, + preferences: Preferences, + window_option_matrix: WindowOptionMatrix +): Preparation[][] { + const preparation_matrix: Preparation[][] = [] - const create_matrix: CreateOption[][] = [] + for (let [row, cols] of window_option_matrix.entries()) { + const preparation_row: Preparation[] = [] + preparation_matrix.push(preparation_row) - for (let [row, cols] of search_matrix.entries()) { - const create_row: CreateOption[] = [] - create_matrix.push(create_row) + for (let [col, window_option] of cols.entries()) { + const { composeSearchURL, type, width_size } = window_option + const url = composeSearchURL(keyword) - for (let [col, search_option] of cols.entries()) { - const { getSearchURL, is_plain } = search_option - const url = getSearchURL(keyword) + const [left, top] = calcRealPos(limit, layout_info, row, col, 1) - const [left, top] = calcRealPos(base.limit, layout_info, row, col) + console.log('left, top', left, top) - if (is_plain && (!base.preferences.fill_empty_window)) { - create_row.push(null) + if ( type === 'FILL' ) { + preparation_row.push({ + url: '', + window_option, + window_data: {} + }) + } + else if ((type === 'PLAIN') && (!preferences.fill_empty_window)) { + preparation_row.push({ + url: '', + window_option, + window_data: {} + }) } - else if (isCurrentRow(search_matrix, row)) { - create_row.push({ + else if (isCurrentRow(window_option_matrix, row)) { + // search_option.width_size + preparation_row.push({ url, - search_option, + window_option, window_data: { type: 'popup', focused: true, - width: layout_info.window_width, + // width: layout_info.window_width + width: calcWindowsTotalWidth(width_size, layout_info.window_width, layout_info.gap_horizontal), height: layout_info.window_height, left, top, @@ -97,13 +112,14 @@ export async function constructSearchWindowsFast( }) } else { - create_row.push({ + preparation_row.push({ url, - search_option, + window_option, window_data: { type: 'popup', focused: false, - width: layout_info.window_width, + // width: layout_info.window_width, + width: calcWindowsTotalWidth(width_size, layout_info.window_width, layout_info.gap_horizontal), height: layout_info.titlebar_height, left, top, @@ -113,14 +129,24 @@ export async function constructSearchWindowsFast( } } - let __is_creating_close__ = false + return preparation_matrix +} + +async function openingSearchWindowMatrixEffect( + creating_signal: Signal, + stop_creating_signal: Signal, + preparation_matrix: Preparation[][], + base: Base, + layout_info: LayoutInfo, +): Promise { + let __suspend__ = false const handler_list: ((closedWindowId: number) => void)[] = [] const created_window_ids: number[] = [] let new_matrix: SearchWindowMatrix = [] const stopCreatingHandler = () => { stop_creating_signal.unReceive(stopCreatingHandler) - __is_creating_close__ = true + __suspend__ = true created_window_ids.forEach(id => { chrome.windows.remove(id) }) @@ -129,26 +155,31 @@ export async function constructSearchWindowsFast( await removeAllFakeUARules() - for (const [row, create_row] of [...create_matrix].reverse().entries()) { + for (const [row, preparation_row] of [...preparation_matrix].reverse().entries()) { const new_row: SearchWindowRow = [] new_matrix.push(new_row) - for (const create_opt of create_row) { - if (__is_creating_close__) { + for (const preparation of preparation_row) { + if (__suspend__) { creating_signal.trigger() throw Object.assign(Error(), { cancel: true }) } - else if (create_opt === null) { + else if ( + (preparation.window_option.type === 'EMPTY') || + (preparation.window_option.type === 'FILL') + ) { new_row.push({ - state: 'EMPTY', + type: preparation.window_option.type, windowId: -9, tabId: -9, - is_debugger_attach: false + is_debugger_attach: false, + init_height: 0, + init_width: 0, }) } else { - const [win, p] = OpenSearchWindow(create_opt.url, { - ...create_opt.window_data + const [win, p] = OpenSearchWindow(preparation.url, { + ...preparation.window_data }) await p const windowId = win.getWindowId() @@ -157,13 +188,15 @@ export async function constructSearchWindowsFast( await setFakeUA(tabId) - const { search_option } = create_opt - const is_debugger_attach = (search_option?.site_option?.access_mode === 'MOBILE-STRONG') + const { window_option } = preparation + const is_debugger_attach = (window_option?.site_option?.access_mode === 'MOBILE-STRONG') new_row.push({ - state: search_option.is_plain ? 'PLAIN' : 'NORMAL', + type: window_option.type, windowId, tabId, is_debugger_attach, + init_width: preparation.window_data.width, + init_height: preparation.window_data.height, }) if (is_debugger_attach) { @@ -176,8 +209,8 @@ export async function constructSearchWindowsFast( chrome.debugger.sendCommand({ tabId }, 'Emulation.setDeviceMetricsOverride',{ mobile: true, deviceScaleFactor: 0, - width: create_opt.window_data.width, - height: create_opt.window_data.height, + width: preparation.window_data.width, + height: preparation.window_data.height, }) ]) } @@ -186,7 +219,7 @@ export async function constructSearchWindowsFast( if (windowId === closedWindowId) { console.log('creating close') chrome.windows.onRemoved.removeListener(h) - __is_creating_close__ = true + __suspend__ = true } } handler_list.push(h) @@ -203,7 +236,10 @@ export async function constructSearchWindowsFast( new_matrix = [...new_matrix].reverse() - const waitting_render = renderMatrix(base, layout_info, new_matrix, true, false) + const waitting_render = renderMatrix(base.platform, base.limit, layout_info, new_matrix, { + preset_focused: true, + reset_size: false + }) await waitting_render // 要在 renderMatrix 之后才取消 stop_creating_signal 的监听 @@ -215,4 +251,27 @@ export async function constructSearchWindowsFast( return new_matrix } -const timeout = (ms: number) => new Promise(res => setTimeout(res, ms)) +export async function constructSearchWindowsFast( + base: Base, + layout_info: LayoutInfo, + window_option_matrix: WindowOptionMatrix, + keyword: string, + creating_signal: Signal, + stop_creating_signal: Signal, +): Promise { + const preparation_matrix = createPreparationMatrix( + keyword, + base.limit, + layout_info, + base.preferences, + [...window_option_matrix].reverse() + ) + + return openingSearchWindowMatrixEffect( + creating_signal, + stop_creating_signal, + preparation_matrix, + base, + layout_info + ) +} diff --git a/src/core/layout/window.ts b/src/core/layout/window.ts index 11e265e..884be13 100644 --- a/src/core/layout/window.ts +++ b/src/core/layout/window.ts @@ -1,14 +1,18 @@ import { nth } from 'ramda' +import { WindowOptionType } from '../base/window-option-matrix' export type WindowID = number export type TabID = number -export type SearchWindowState = 'NORMAL' | 'EMPTY' | 'PLAIN' export type SearchWindow = Readonly<{ - state: SearchWindowState + type: WindowOptionType + windowId: WindowID tabId: TabID is_debugger_attach: boolean + + init_width?: number + init_height?: number }> export type SearchWindowRow = Array export type SearchWindowMatrix = Array diff --git a/src/pages/Control/hooks/useChangeRow.ts b/src/pages/Control/hooks/useChangeRow.ts index 4ffb07c..9d11e0f 100644 --- a/src/pages/Control/hooks/useChangeRow.ts +++ b/src/pages/Control/hooks/useChangeRow.ts @@ -39,11 +39,14 @@ export default function useChangeRow( } await renderMatrix( - base, + base.platform, + base.limit, layout_info, newMatrix, - type === 'next' ? true : undefined, - true + { + preset_focused: type === 'next' ? true : undefined, + reset_size: true + } ) search_layout.setMatrix(newMatrix) diff --git a/src/pages/Options/components/SiteSettingsManager/EditLayout.tsx b/src/pages/Options/components/SiteSettingsManager/EditLayout.tsx index 1a6dca5..1d2f93d 100644 --- a/src/pages/Options/components/SiteSettingsManager/EditLayout.tsx +++ b/src/pages/Options/components/SiteSettingsManager/EditLayout.tsx @@ -4,6 +4,7 @@ import { getFormItem } from '../../../../utils/form' import AccessModeSetting from './AccessModeSetting' import s from './EditLayout.module.css' +import { pipe } from 'ramda' function getAccessMode(formData: FormData): SiteOption['access_mode'] { const val = formData.get('access_mode') @@ -22,6 +23,7 @@ function formDataTransform(sourceOption: SiteOption, e: React.FormEvent void } +function getChangeValue(e: React.ChangeEvent) { + return e.target.value +} + +function parseWidthSizeInput(raw: string) { + const v = parseInt(raw) + if (isNaN(v)) { + return 1 + } else { + return v + } +} + export function RenderEditLayout({ formRef, siteOption, @@ -67,6 +82,7 @@ export function RenderEditLayout({ const [failure, setFailure] = useState(null) const [urlPattern, setUrlPattern] = useState(siteOption.url_pattern) const [accessMode, setAccessMode] = useState(siteOption.access_mode) + const [widthSize, setWidthSize] = useState(siteOption.width_size) const failureNode = useMemo(() => { if (failure) { @@ -108,9 +124,9 @@ export function RenderEditLayout({ URL setUrlPattern(e.target.value)} name="url_pattern" + value={ urlPattern } + onChange={ pipe(getChangeValue, setUrlPattern) } /> + ), buttonGroup: ( diff --git a/src/preferences/default.ts b/src/preferences/default.ts index 39f73bf..c1bd2e1 100644 --- a/src/preferences/default.ts +++ b/src/preferences/default.ts @@ -19,7 +19,7 @@ export default function getDefaultPreferences( ): Preferences { return { __is_poker__: true, - version: 4, + version: 5, fill_empty_window: false, refocus_window: false, launch_poker_contextmenu: true, @@ -35,5 +35,6 @@ export function generateExampleOption(): SiteOption { name: '_DEFAULT_NAME_', url_pattern: `https://example.com?search=${cfg.KEYWORD_REPLACEHOLDER}`, access_mode: 'MOBILE', + width_size: 1 } } diff --git a/src/preferences/index.ts b/src/preferences/index.ts index 6011e4c..6871532 100644 --- a/src/preferences/index.ts +++ b/src/preferences/index.ts @@ -4,7 +4,7 @@ import InitStorage from '../utils/storage' import getDefaultPreferences from './default' import checkPreferences from './check' -import { AllVersion, checkVersion, CURRENT_PREFERENCES_VERSION, LatestVersion } from './versions' +import { AllVersion, versionNeedUpdate, CURRENT_PREFERENCES_VERSION, LatestVersion } from './versions' import { updatePreferences } from './versions/update' import { saveFilteredFloor } from '../x-state/filtered-floor' @@ -33,7 +33,7 @@ async function initPreferences() { export async function load(): Promise { if (await isFoundStorage()) { const preferences = await loadStorage() - if (checkVersion(preferences)) { + if (versionNeedUpdate(preferences)) { const updated_preferences = updatePreferences(preferences) console.log('new', updated_preferences) await save(updated_preferences) diff --git a/src/preferences/versions/index.ts b/src/preferences/versions/index.ts index af4e573..00b7b32 100644 --- a/src/preferences/versions/index.ts +++ b/src/preferences/versions/index.ts @@ -2,15 +2,21 @@ import { PreferencesV1 } from './v1-type' import { PreferencesV2 } from './v2-type' import { PreferencesV3 } from './v3-type' import { PreferencesV4 } from './v4-type' +import { PreferencesV5 } from './v5-type' + +export type DefinePreferences = Readonly // -------- 每次添加新的版本后,都得修改这块地方 -------- // -------- 隔壁 update.ts 的 updater 也要更新 -------- -export const CURRENT_PREFERENCES_VERSION = 4 -export * from './v4-type' -export type LatestVersion = PreferencesV4 -export type AllVersion = LatestVersion | PreferencesV3 | PreferencesV2 | PreferencesV1 +export const CURRENT_PREFERENCES_VERSION = 5 +export * from './v5-type' +export type LatestVersion = PreferencesV5 +export type AllVersion = LatestVersion | PreferencesV4 | PreferencesV3 | PreferencesV2 | PreferencesV1 // ------------------------------------------------------ -export const checkVersion = (loaded_options: AllVersion) => { +export const versionNeedUpdate = (loaded_options: AllVersion) => { return CURRENT_PREFERENCES_VERSION !== loaded_options.version } diff --git a/src/preferences/versions/update.ts b/src/preferences/versions/update.ts index 2164149..53e424c 100644 --- a/src/preferences/versions/update.ts +++ b/src/preferences/versions/update.ts @@ -2,21 +2,16 @@ import { AllVersion, LatestVersion } from '.' import { updater as v2Updater } from './v2' import { updater as v3Updater } from './v3' import { updater as v4Updater } from './v4' +import { updater as v5Updater } from './v5' // -------- 每次添加新的版本后,都得修改这块地方 -------- // -------- 隔壁 index.ts 也要更新 -------- -export function updatePreferences(s_opts: AllVersion): LatestVersion { - switch (s_opts.version) { - case 1: - return updatePreferences(v2Updater(s_opts)) - - case 2: - return updatePreferences(v3Updater(s_opts)) - - case 3: - return updatePreferences(v4Updater(s_opts)) - - default: - return s_opts +export function updatePreferences(p: AllVersion): LatestVersion { + switch (p.version) { + case 1: return updatePreferences(v2Updater(p)) + case 2: return updatePreferences(v3Updater(p)) + case 3: return updatePreferences(v4Updater(p)) + case 4: return updatePreferences(v5Updater(p)) } + return p } diff --git a/src/preferences/versions/v1-type.ts b/src/preferences/versions/v1-type.ts index 3c9bbe7..7baa077 100644 --- a/src/preferences/versions/v1-type.ts +++ b/src/preferences/versions/v1-type.ts @@ -1,12 +1,12 @@ type URLPattern = string -export type SiteOption = { +type SiteOption = { id: string icon: string name: string url_pattern: URLPattern } -export type SiteRow = Array -export type SiteMatrix = Array +type SiteRow = Array +type SiteMatrix = Array export type PreferencesV1 = Readonly<{ version: 1 diff --git a/src/preferences/versions/v2-type.ts b/src/preferences/versions/v2-type.ts index 56fe907..a17db98 100644 --- a/src/preferences/versions/v2-type.ts +++ b/src/preferences/versions/v2-type.ts @@ -1,13 +1,13 @@ -export type URLPattern = string -export type SiteOption = { +type URLPattern = string +type SiteOption = { id: string icon: string | null name: string url_pattern: URLPattern enable_mobile: boolean } -export type SiteRow = Array -export type SiteMatrix = Array +type SiteRow = Array +type SiteMatrix = Array export type PreferencesV2 = Readonly<{ version: 2 diff --git a/src/preferences/versions/v3-type.ts b/src/preferences/versions/v3-type.ts index 74e03ce..1d6dbad 100644 --- a/src/preferences/versions/v3-type.ts +++ b/src/preferences/versions/v3-type.ts @@ -1,21 +1,21 @@ -export type URLPattern = string -export type SiteOption = { +import { DefinePreferences } from './' + +type URLPattern = string +type SiteOption = { id: string icon: string | null name: string url_pattern: URLPattern enable_mobile: boolean } -export type SiteSettingsRow = { +type SiteSettingsRow = { id: string name: string row: Array } -export type SiteSettings = Array +type SiteSettings = Array -export type PreferencesV3 = Readonly<{ - __is_poker__: true, - version: 3 +export type PreferencesV3 = DefinePreferences<3, { launch_poker_contextmenu: boolean site_settings: SiteSettings }> diff --git a/src/preferences/versions/v4-type.ts b/src/preferences/versions/v4-type.ts index 84597cd..003103e 100644 --- a/src/preferences/versions/v4-type.ts +++ b/src/preferences/versions/v4-type.ts @@ -1,22 +1,22 @@ -export type URLPattern = string -export type SiteOption = { +import { DefinePreferences } from './' + +type URLPattern = string +type SiteOption = { id: string icon: string | null name: string url_pattern: URLPattern access_mode: 'DESKTOP' | 'MOBILE' | 'MOBILE-STRONG' } -export type SiteSettingFloorID = string -export type SiteSettingFloor = { +type SiteSettingFloorID = string +type SiteSettingFloor = { id: SiteSettingFloorID name: string row: Array } -export type SiteSettings = Array +type SiteSettings = Array -export type PreferencesV4 = Readonly<{ - __is_poker__: true, - version: 4 +export type PreferencesV4 = DefinePreferences<4, { launch_poker_contextmenu: boolean fill_empty_window: boolean diff --git a/src/preferences/versions/v4.ts b/src/preferences/versions/v4.ts index 3d99102..2e7a0aa 100644 --- a/src/preferences/versions/v4.ts +++ b/src/preferences/versions/v4.ts @@ -6,8 +6,7 @@ export function updater(v3: PreferencesV3): PreferencesV4 { __is_poker__: true, version: 4, - launch_poker_contextmenu: true, - + launch_poker_contextmenu: v3.launch_poker_contextmenu, fill_empty_window: true, refocus_window: true, diff --git a/src/preferences/versions/v5-type.ts b/src/preferences/versions/v5-type.ts new file mode 100644 index 0000000..a95f9b9 --- /dev/null +++ b/src/preferences/versions/v5-type.ts @@ -0,0 +1,33 @@ +// v2.0.0 启用 + +import { DefinePreferences } from './' + +export type URLPattern = string +export type SiteOption = { + id: string + icon: string | null + name: string + url_pattern: URLPattern + access_mode: 'DESKTOP' | 'MOBILE' | 'MOBILE-STRONG' + width_size: number +} +export type SiteSettingFloorID = string +export type SiteSettingFloor = { + id: SiteSettingFloorID + name: string + row: Array +} +export type SiteSettings = Array + +export type PreferencesV5 = DefinePreferences<5, { + // 右键菜单栏【启动Poker】 + launch_poker_contextmenu: boolean + + // 将每一层的页面填充满 + fill_empty_window: boolean + + // 「唤回 Poker」窗口 + refocus_window: boolean + + site_settings: SiteSettings +}> diff --git a/src/preferences/versions/v5.ts b/src/preferences/versions/v5.ts new file mode 100644 index 0000000..8c8fa89 --- /dev/null +++ b/src/preferences/versions/v5.ts @@ -0,0 +1,22 @@ +import { PreferencesV4 } from './v4-type' +import { PreferencesV5 } from './v5-type' + +export function updater(v4: PreferencesV4): PreferencesV5 { + return { + ...v4, + + version: 5, + + site_settings: v4.site_settings.map(settings_row => { + return { + ...settings_row, + row: settings_row.row.map(opt => { + return { + ...opt, + width_size: 1 + } + }) + } + }), + } +}