diff --git a/apps/common/mobile/lib/view/Search.jsx b/apps/common/mobile/lib/view/Search.jsx index 51bca9ca5..9decff1c8 100644 --- a/apps/common/mobile/lib/view/Search.jsx +++ b/apps/common/mobile/lib/view/Search.jsx @@ -1,11 +1,13 @@ + import React, { Component } from 'react'; import { Searchbar, Popover, Popup, View, Page, List, ListItem, Navbar, NavRight, Link } from 'framework7-react'; import { Toggle } from 'framework7-react'; import { f7 } from 'framework7-react'; import { Dom7 } from 'framework7'; import { Device } from '../../../../common/mobile/utils/device'; -import { observable } from "mobx"; +import { observable, runInAction } from "mobx"; import { observer } from "mobx-react"; +import { useTranslation, withTranslation } from 'react-i18next'; const searchOptions = observable({ usereplace: false @@ -24,18 +26,23 @@ class SearchSettingsView extends Component { this.state = { useReplace: false, - caseSensitive: false, - markResults: false + // caseSensitive: false, + // markResults: false + searchIn: 0, + searchBy: 1, + lookIn: 1, + isMatchCase: false, + isMatchCell: false }; } onFindReplaceClick(action) { - searchOptions.usereplace = action == 'replace'; + runInAction(() => searchOptions.usereplace = action == 'replace'); + this.setState({ useReplace: searchOptions.usereplace }); - if (this.onReplaceChecked) {} } @@ -43,17 +50,18 @@ class SearchSettingsView extends Component { } render() { - const show_popover = true; + const show_popover = !Device.phone; const navbar = {!show_popover && Done - } + + } ; const extra = this.extraSearchOptions(); const content = - + {navbar} @@ -66,7 +74,7 @@ class SearchSettingsView extends Component { return ( show_popover ? {content} : - {content} + {content} ) } } @@ -76,6 +84,13 @@ class SearchView extends Component { constructor(props) { super(props); + this.state = { + searchQuery: '', + replaceQuery: '' + }; + + const $$ = Dom7; + $$(document).on('page:init', (e, page) => { if ( page.name == 'home' ) { this.searchbar = f7.searchbar.create({ @@ -84,7 +99,7 @@ class SearchView extends Component { expandable: true, backdrop: false, on: { - search: (bar, curval, prevval) => { + search: (bar, curval, prevval) => { }, enable: this.onSearchbarShow.bind(this, true), disable: this.onSearchbarShow.bind(this, false) @@ -97,8 +112,9 @@ class SearchView extends Component { // return (m = /(iPad|iPhone|iphone).*?(OS |os |OS\_)(\d+((_|\.)\d)?((_|\.)\d)?)/.exec(ua)) ? parseFloat(m[3]) : 0; // } - const $$ = Dom7; const $editor = $$('#editor_sdk'); + const $replaceLink = $$('#replace-link'); + if (false /*iOSVersion() < 13*/) { // $editor.single('mousedown touchstart', _.bind(me.onEditorTouchStart, me)); // $editor.single('mouseup touchend', _.bind(me.onEditorTouchEnd, me)); @@ -109,21 +125,23 @@ class SearchView extends Component { $editor.on('pointerdown', this.onEditorTouchStart.bind(this)); $editor.on('pointerup', this.onEditorTouchEnd.bind(this)); + // $replaceLink.on('click', this.onReplaceHold.bind(this)); } }); this.onSettingsClick = this.onSettingsClick.bind(this); this.onSearchClick = this.onSearchClick.bind(this); + this.onReplaceClick = this.onReplaceClick.bind(this); } componentDidMount(){ const $$ = Dom7; - this.$repalce = $$('#idx-replace-val'); + this.$replace = $$('#idx-replace-val'); } onSettingsClick(e) { if ( Device.phone ) { - // f7.popup.open('.settings-popup'); + f7.popup.open('.search-settings-popup'); } else f7.popover.open('#idx-search-settings', '#idx-btn-search-settings'); } @@ -132,35 +150,64 @@ class SearchView extends Component { find: this.searchbar.query }; - if ( searchOptions.usereplace ) + if (searchOptions.usereplace) { params.replace = this.$replace.val(); + } return params; } onSearchClick(action) { - if ( this.searchbar && this.searchbar.query) { - if ( this.props.onSearchQuery ) { + if (this.searchbar && this.state.searchQuery) { + if (this.props.onSearchQuery) { let params = this.searchParams(); + params.find = this.state.searchQuery; params.forward = action != SEARCH_BACKWARD; + console.log(params); this.props.onSearchQuery(params); } } } + onReplaceClick() { + if (this.searchbar && this.state.searchQuery) { + if (this.props.onReplaceQuery) { + let params = this.searchParams(); + params.find = this.state.searchQuery; + // console.log(params); + + this.props.onReplaceQuery(params); + } + } + } + + onReplaceAllClick() { + if (this.searchbar && this.state.searchQuery) { + if (this.props.onReplaceAllQuery) { + let params = this.searchParams(); + params.find = this.state.searchQuery; + // console.log(params); + + this.props.onReplaceAllQuery(params); + } + } + } + onSearchbarShow(isshowed, bar) { if ( !isshowed ) { - this.$repalce.val(''); + this.$replace.val(''); } } onEditorTouchStart(e) { this.startPoint = this.pointerPosition(e); + // console.log(this.startPoint); } onEditorTouchEnd(e) { const endPoint = this.pointerPosition(e); + // console.log(endPoint); if ( this.searchbar.enabled ) { const distance = (this.startPoint.x === undefined || this.startPoint.y === undefined) ? 0 : @@ -187,35 +234,68 @@ class SearchView extends Component { return out; } + changeSearchQuery(value) { + this.setState({ + searchQuery: value + }); + } + + changeReplaceQuery(value) { + this.setState({ + replaceQuery: value + }); + } + render() { const usereplace = searchOptions.usereplace; const hidden = {display: "none"}; + const searchQuery = this.state.searchQuery; + const replaceQuery = this.state.replaceQuery; + const isIos = Device.ios; + + // const _t = this.t('View.Settings', {returnObjects: true}); + // console.log(this.state.searchQuery, this.state.replaceQuery); + + if(this.searchbar && this.searchbar.enabled) { + usereplace ? this.searchbar.el.classList.add('replace') : this.searchbar.el.classList.remove('replace'); + } + return (
-
+ {isIos ?
: null}
-
+ -
- - - +
+
+ {this.changeSearchQuery(e.target.value)}} /> + {isIos ? : null} + +
+
+ {this.changeReplaceQuery(e.target.value)}} /> + {isIos ? : null} + +
-
- - - -
- @@ -223,4 +303,4 @@ class SearchView extends Component { } } -export {SearchView as default, SearchView, SearchSettingsView}; +export {SearchView as default, SearchView, SearchSettingsView}; \ No newline at end of file diff --git a/apps/common/mobile/resources/less/common-ios.less b/apps/common/mobile/resources/less/common-ios.less index 00cf701a0..df66e1e81 100644 --- a/apps/common/mobile/resources/less/common-ios.less +++ b/apps/common/mobile/resources/less/common-ios.less @@ -417,4 +417,71 @@ } } } + + // Find and Replace + + .navbar { + .searchbar-input-wrap { + margin-right: 10px; + height: 28px; + } + .buttons-row-replace a { + color: @themeColor; + } + } + + .searchbar input[type=search] { + box-sizing: border-box; + width: 100%; + height: 100%; + display: block; + border: none; + appearance: none; + border-radius: 5px; + font-family: inherit; + color: @black; + font-size: 14px; + font-weight: 400; + padding: 0 8px; + background-color: @white; + padding: 0 28px; + } + + .searchbar-inner { + &__right { + .buttons-row a.next { + margin-left: 15px; + } + } + } + + @media(max-width: 550px) + { + .searchbar-expandable.searchbar-enabled { + top: 0; + .searchbar-inner { + &__left { + margin-right: 15px; + } + &__center { + flex-direction: column; + } + &__right { + flex-direction: column-reverse; + margin-left: 10px; + } + } + &.replace { + height: 88px; + .searchbar-inner { + height: 100%; + &__center { + .searchbar-input-wrap { + margin: 8px 0; + } + } + } + } + } + } } diff --git a/apps/common/mobile/resources/less/common-material.less b/apps/common/mobile/resources/less/common-material.less index 9b7ec4fa2..6887a13fc 100644 --- a/apps/common/mobile/resources/less/common-material.less +++ b/apps/common/mobile/resources/less/common-material.less @@ -311,4 +311,116 @@ } } } + + // Find and Replace + + .searchbar-inner { + &__center { + flex-wrap: wrap; + } + &__left { + padding-top: 4px; + } + } + + .buttons-row-replace a { + color: @white; + } + + .navbar { + .searchbar-input-wrap { + height: 32px; + margin-right: 10px; + margin: 4px 0; + } + &-inner { + overflow: initial; + } + } + + .searchbar .input-clear-button { + width: 18px; + height: 18px; + &:after { + color: @white; + font-size: 19px; + } + } + + .searchbar-icon { + &:after { + color: @white; + font-size: 19px; + } + } + + .searchbar input[type=search] { + box-sizing: border-box; + width: 100%; + display: block; + border: none; + appearance: none; + border-radius: 0; + font-family: inherit; + color: @white; + font-size: 16px; + font-weight: 400; + padding: 0; + border-bottom: 1px solid @white; + height: 100%; + padding: 0 36px 0 24px; + background-color: transparent; + background-repeat: no-repeat; + background-position: 0 center; + opacity: 1; + background-size: 24px 24px; + transition-duration: .3s; + .encoded-svg-background(''); + } + + .searchbar input[type=search]::placeholder { + color: @white; + } + + .navbar { + .searchbar-expandable.searchbar-enabled { + top: 0; + // height: 100%; + .searchbar-inner { + height: 100%; + &__center { + flex-direction: column; + } + &__right { + flex-direction: column-reverse; + } + } + &.replace { + height: 96px; + } + } + a.link { + padding: 0 16px; + } + a.icon-only { + width: auto; + height: 48px; + } + .buttons-row-replace a { + color: @white; + } + .searchbar .buttons-row { + align-self: flex-start; + } + } + + @media(max-width: 550px) { + .searchbar-expandable.searchbar-enabled { + .searchbar-inner { + &__left { + margin-right: 33px; + } + } + } + } } diff --git a/apps/common/mobile/resources/less/icons.less b/apps/common/mobile/resources/less/icons.less new file mode 100644 index 000000000..72d751add --- /dev/null +++ b/apps/common/mobile/resources/less/icons.less @@ -0,0 +1,10 @@ +@import "./ios/icons"; +@import "./material/icons"; + +i.icon { + // &.icon-paste { + // width: 24px; + // height: 24px; + // .encoded-svg-uncolored-mask(''); + // } +} \ No newline at end of file diff --git a/apps/common/mobile/resources/less/ios/icons.less b/apps/common/mobile/resources/less/ios/icons.less new file mode 100644 index 000000000..726a98f46 --- /dev/null +++ b/apps/common/mobile/resources/less/ios/icons.less @@ -0,0 +1,23 @@ +.device-ios { + i.icon { + &.icon_mask { + background-color: white; + } + &.icon-prev { + width: 22px; + height: 22px; + .encoded-svg-background(''); + &:after { + display: none; + } + } + &.icon-next { + width: 22px; + height: 22px; + .encoded-svg-background(''); + &:after { + display: none; + } + } + } +} \ No newline at end of file diff --git a/apps/common/mobile/resources/less/material/icons.less b/apps/common/mobile/resources/less/material/icons.less new file mode 100644 index 000000000..d1865a795 --- /dev/null +++ b/apps/common/mobile/resources/less/material/icons.less @@ -0,0 +1,23 @@ +.device-android { + i.icon { + &.icon_mask { + background-color: black; + } + &.icon-prev { + width: 20px; + height: 20px; + .encoded-svg-background(''); + &:after { + display: none; + } + } + &.icon-next { + width: 20px; + height: 20px; + .encoded-svg-background(''); + &:after { + display: none; + } + } + } +} \ No newline at end of file diff --git a/apps/common/mobile/resources/less/search.less b/apps/common/mobile/resources/less/search.less index 21249b941..caf870f49 100644 --- a/apps/common/mobile/resources/less/search.less +++ b/apps/common/mobile/resources/less/search.less @@ -14,7 +14,59 @@ } } - .searchbar-input-wrap { - margin-right: 10px; + .searchbar-inner { + &__center { + display: flex; + align-items: center; + width: 100%; + } + &__right { + display: flex; + align-items: center; + } + } + + .searchbar-expandable { + transition-duration: 0s; + } + + .buttons-row-replace { + display: flex; + flex-direction: column; + align-items: center; + width: max-content; + a { + font-size: 15px; + height: auto; + display: block; + line-height: normal; + } + } + + @media(max-width: 550px) + { + .searchbar-expandable.searchbar-enabled { + .searchbar-inner { + &__left { + min-width: 22px; + max-width: 22px; + } + &__center { + flex-direction: column; + } + &__right { + flex-direction: column-reverse; + } + } + &.replace { + top: 0; + .searchbar-inner { + height: 100%; + &__left { + align-self: flex-start; + } + } + } + } } } diff --git a/apps/spreadsheeteditor/mobile/locale/en.json b/apps/spreadsheeteditor/mobile/locale/en.json index a3174d952..a7c61168d 100644 --- a/apps/spreadsheeteditor/mobile/locale/en.json +++ b/apps/spreadsheeteditor/mobile/locale/en.json @@ -290,7 +290,24 @@ "textEmail": "Email", "textAddress": "Address", "textTel": "Tel", - "textPoweredBy": "Powered By" + "textPoweredBy": "Powered By", + "textFind": "Find", + "textSearch": "Search", + "textReplace": "Replace", + "textMatchCase": "Match Case", + "textMatchCell": "Match Cell", + "textSearchIn": "Search In", + "textWorkbook": "Workbook", + "textSheet": "Sheet", + "textHighlightRes": "Highlight results", + "textByColumns": "By columns", + "textByRows": "By rows", + "textSearchBy": "Search", + "textLookIn": "Look In", + "textFormulas": "Formulas", + "textValues": "Values", + "textNoTextFound": "Text not found", + "textReplaceAll": "Replace All" } }, "Common": { diff --git a/apps/spreadsheeteditor/mobile/src/controller/Search.jsx b/apps/spreadsheeteditor/mobile/src/controller/Search.jsx new file mode 100644 index 000000000..52ec2cb8c --- /dev/null +++ b/apps/spreadsheeteditor/mobile/src/controller/Search.jsx @@ -0,0 +1,195 @@ +import React, { Fragment } from 'react'; +import { List, ListItem, Toggle, BlockTitle } from 'framework7-react'; +import { SearchController, SearchView, SearchSettingsView } from '../../../../common/mobile/lib/controller/Search'; +import { f7 } from 'framework7-react'; +import { useTranslation, withTranslation } from 'react-i18next'; +import { Dom7 } from 'framework7'; + +class SearchSettings extends SearchSettingsView { + constructor(props) { + super(props); + + // this.state = { + // searchIn: 0, + // searchBy: 1, + // lookIn: 1, + // isMatchCase: false, + // isMatchCell: false + // } + + this.onToggleMarkResults = this.onToggleMarkResults.bind(this); + } + + onToggleMarkResults(checked) { + const api = Common.EditorApi.get(); + api.asc_selectSearchingResults(checked); + } + + extraSearchOptions() { + const anc_markup = super.extraSearchOptions(); + + const markup = ( + + Search In + + this.setState({ + searchIn: 0 + })} /> + this.setState({ + searchIn: 1 + })} /> + + Search + + this.setState({ + searchBy: 0 + })} /> + this.setState({ + searchBy: 1 + })} /> + + Look In + + this.setState({ + lookIn: 0 + })} /> + this.setState({ + lookIn: 1 + })} /> + + + + this.setState({ + isMatchCase: !this.state.isMatchCase + })} /> + + + this.setState({ + isMatchCell: !this.state.isMatchCell + })} /> + + + + + + + ) + + return {...anc_markup, ...markup}; + } +} + +class SESearchView extends SearchView { + searchParams() { + let params = super.searchParams(); + const $$ = Dom7; + + const checkboxMatchCase = f7.toggle.get('.toggle-match-case'), + checkboxMatchCell = f7.toggle.get('.toggle-match-cell'), + checkboxMarkResults = f7.toggle.get('.toggle-mark-results'), + checkboxSearchIn = $$('[name="search-in-checkbox"]:checked')[0], + checkboxSearchBy = $$('[name="search-by-checkbox"]:checked')[0], + checkboxLookIn = $$('[name="look-in-checkbox"]:checked')[0]; + + const searchOptions = { + caseSensitive: checkboxMatchCase.checked, + highlight: checkboxMarkResults.checked, + matchCell: checkboxMatchCell.checked, + searchIn: checkboxSearchIn.value, + searchBy: checkboxSearchBy.value, + lookIn: checkboxLookIn.value, + }; + + return {...params, ...searchOptions}; + } + + onSearchbarShow(isshowed, bar) { + super.onSearchbarShow(isshowed, bar); + + const api = Common.EditorApi.get(); + if ( isshowed ) { + const checkboxMarkResults = f7.toggle.get('.toggle-mark-results'); + api.asc_selectSearchingResults(checkboxMarkResults.checked); + } else api.asc_selectSearchingResults(false); + } +} + +const Search = props => { + // const { t } = useTranslation(); + // const _t = t('View.Settings', {returnObjects: true}); + + const onSearchQuery = params => { + const api = Common.EditorApi.get(); + let lookIn = +params.lookIn === 0; + let searchIn = +params.searchIn === 1; + let searchBy = +params.searchBy === 0; + + if (params.find && params.find.length) { + let options = new Asc.asc_CFindOptions(); + + options.asc_setFindWhat(params.find); + options.asc_setScanForward(params.forward); + options.asc_setIsMatchCase(params.caseSensitive); + options.asc_setIsWholeCell(params.matchCell); + options.asc_setScanOnOnlySheet(searchIn); + options.asc_setScanByRows(searchBy); + options.asc_setLookIn(lookIn ? Asc.c_oAscFindLookIn.Formulas : Asc.c_oAscFindLookIn.Value); + + if (!api.asc_findText(options)) { + f7.dialog.alert(null, 'Text not Found'); + } + } + }; + + const onReplaceQuery = params => { + const api = Common.EditorApi.get(); + let lookIn = +params.lookIn === 0; + let searchIn = +params.searchIn === 1; + let searchBy = +params.searchBy === 0; + + if (params.find && params.find.length) { + api.isReplaceAll = false; + + let options = new Asc.asc_CFindOptions(); + + options.asc_setFindWhat(params.find); + options.asc_setReplaceWith(params.replace); + options.asc_setIsMatchCase(params.caseSensitive); + options.asc_setIsWholeCell(params.matchCell); + options.asc_setScanOnOnlySheet(searchIn); + options.asc_setScanByRows(searchBy); + options.asc_setLookIn(lookIn ? Asc.c_oAscFindLookIn.Formulas : Asc.c_oAscFindLookIn.Value); + options.asc_setIsReplaceAll(false); + + api.asc_replaceText(options); + } + } + + const onReplaceAllQuery = params => { + const api = Common.EditorApi.get(); + let lookIn = +params.lookIn === 0; + let searchIn = +params.searchIn === 1; + let searchBy = +params.searchBy === 0; + + if (params.find && params.find.length) { + api.isReplaceAll = true; + + let options = new Asc.asc_CFindOptions(); + + options.asc_setFindWhat(params.find); + options.asc_setReplaceWith(params.replace); + options.asc_setIsMatchCase(params.caseSensitive); + options.asc_setIsWholeCell(params.matchCell); + options.asc_setScanOnOnlySheet(searchIn); + options.asc_setScanByRows(searchBy); + options.asc_setLookIn(lookIn ? Asc.c_oAscFindLookIn.Formulas : Asc.c_oAscFindLookIn.Value); + options.asc_setIsReplaceAll(true); + + api.asc_replaceText(options); + } + } + + return +}; + +export {Search, SearchSettings} \ No newline at end of file diff --git a/apps/spreadsheeteditor/mobile/src/less/app.less b/apps/spreadsheeteditor/mobile/src/less/app.less index 3941298d0..386e8d550 100644 --- a/apps/spreadsheeteditor/mobile/src/less/app.less +++ b/apps/spreadsheeteditor/mobile/src/less/app.less @@ -9,7 +9,9 @@ @import '../../../../common/mobile/resources/less/common.less'; @import '../../../../common/mobile/resources/less/common-ios.less'; @import '../../../../common/mobile/resources/less/common-material.less'; +@import '../../../../common/mobile/resources/less/icons.less'; @import '../../../../common/mobile/resources/less/dataview.less'; +@import '../../../../common/mobile/resources/less/search.less'; @import './app-material.less'; @import './app-ios.less'; @import './icons-ios.less'; diff --git a/apps/spreadsheeteditor/mobile/src/page/main.jsx b/apps/spreadsheeteditor/mobile/src/page/main.jsx index 8ea7ea17a..94680f9f4 100644 --- a/apps/spreadsheeteditor/mobile/src/page/main.jsx +++ b/apps/spreadsheeteditor/mobile/src/page/main.jsx @@ -8,6 +8,8 @@ import CellEditor from '../controller/CellEditor'; import Statusbar from '../controller/StatusBar' import AddOptions from "../view/add/Add"; import EditOptions from "../view/edit/Edit"; +import { Device } from '../../../../common/mobile/utils/device'; +import { Search, SearchSettings } from '../controller/Search'; import {FunctionGroups} from "../controller/add/AddFunction"; @@ -56,44 +58,47 @@ export default class MainPage extends Component { render() { return ( - + {/* Top Navbar */} - - {/*
*/} - - - - - - this.handleClickToOpenOptions('edit')}> - this.handleClickToOpenOptions('add')}> - this.handleClickToOpenOptions('coauth')}> - this.handleClickToOpenOptions('settings')}> - -
- this.handleClickToOpenOptions('add', {panels: panels, button: button})}/> - {/* Page content */} - - { - !this.state.editOptionsVisible ? null : - - } - { - !this.state.addOptionsVisible ? null : - - } - { - !this.state.settingsVisible ? null : - - } - { - !this.state.collaborationVisible ? null : - - } - + + {/*
*/} + + + + + + this.handleClickToOpenOptions('edit')}> + this.handleClickToOpenOptions('add')}> + { Device.phone ? null : } + this.handleClickToOpenOptions('coauth')}> + this.handleClickToOpenOptions('settings')}> + + +
+ this.handleClickToOpenOptions('add', {panels: panels, button: button})}/> + {/* Page content */} + + + { + !this.state.editOptionsVisible ? null : + + } + { + !this.state.addOptionsVisible ? null : + + } + { + !this.state.settingsVisible ? null : + + } + { + !this.state.collaborationVisible ? null : + + } + - {/* hidden component*/} -
+ {/* hidden component*/} +
) } }; \ No newline at end of file diff --git a/apps/spreadsheeteditor/mobile/src/view/settings/Settings.jsx b/apps/spreadsheeteditor/mobile/src/view/settings/Settings.jsx index 70a87ae49..938900eff 100644 --- a/apps/spreadsheeteditor/mobile/src/view/settings/Settings.jsx +++ b/apps/spreadsheeteditor/mobile/src/view/settings/Settings.jsx @@ -115,7 +115,7 @@ const SettingsList = withTranslation()(props => { {navbar} {!props.inPopover && - + }