diff --git a/apps/common/mobile/resources/less/common.less b/apps/common/mobile/resources/less/common.less index 714269070..372d9b436 100644 --- a/apps/common/mobile/resources/less/common.less +++ b/apps/common/mobile/resources/less/common.less @@ -31,6 +31,11 @@ } } +.disabled, [disabled] { + opacity: .55; + pointer-events: none; +} + .shapes { li { width: 70px; diff --git a/apps/presentationeditor/mobile/locale/en.json b/apps/presentationeditor/mobile/locale/en.json index 6fb0b7830..fe81283cb 100644 --- a/apps/presentationeditor/mobile/locale/en.json +++ b/apps/presentationeditor/mobile/locale/en.json @@ -132,7 +132,28 @@ "textFill": "Fill", "textCustomColor": "Custom Color", "textDuplicateSlide": "Duplicate Slide", - "textDeleteSlide": "Delete Slide" + "textDeleteSlide": "Delete Slide", + "textFontColor": "Font Color", + "textHighlightColor": "Highlight Color", + "textAdditionalFormatting": "Additional Formatting", + "textAdditional": "Additional", + "textBullets": "Bullets", + "textNumbers": "Numbers", + "textLineSpacing": "Line Spacing", + "textFonts": "Fonts", + "textAuto": "Auto", + "textPt": "pt", + "textSize": "Size", + "textStrikethrough": "Strikethrough", + "textDoubleStrikethrough": "Double Strikethrough", + "textSuperscript": "Superscript", + "textSubscript": "Subscript", + "textSmallCaps": "Small Caps", + "textAllCaps": "All Caps", + "textLetterSpacing": "Letter Spacing", + "textDistanceFromText": "Distance From Text", + "textBefore": "Before", + "textAfter": "After" } }, "Common": { diff --git a/apps/presentationeditor/mobile/src/controller/Main.jsx b/apps/presentationeditor/mobile/src/controller/Main.jsx index 727925909..16eae3888 100644 --- a/apps/presentationeditor/mobile/src/controller/Main.jsx +++ b/apps/presentationeditor/mobile/src/controller/Main.jsx @@ -5,7 +5,7 @@ import { f7 } from "framework7-react"; import { withTranslation } from 'react-i18next'; import CollaborationController from '../../../../common/mobile/lib/controller/Collaboration.jsx' -@inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings", "storeSlideSettings") +@inject("storeFocusObjects", "storeAppOptions", "storePresentationInfo", "storePresentationSettings", "storeSlideSettings", "storeTextSettings") class MainController extends Component { constructor(props) { super(props) @@ -220,6 +220,79 @@ class MainController extends Component { Common.Utils.ThemeColor.setColors(colors, standart_colors); }); + // Text settings + + const storeTextSettings = this.props.storeTextSettings; + + this.api.asc_registerCallback('asc_onInitEditorFonts', (fonts, select) => { + storeTextSettings.initEditorFonts(fonts, select); + }); + + this.api.asc_registerCallback('asc_onFontFamily', (font) => { + storeTextSettings.resetFontName(font); + }); + + this.api.asc_registerCallback('asc_onFontSize', (size) => { + storeTextSettings.resetFontSize(size); + }); + + this.api.asc_registerCallback('asc_onBold', (isBold) => { + storeTextSettings.resetIsBold(isBold); + }); + + this.api.asc_registerCallback('asc_onItalic', (isItalic) => { + storeTextSettings.resetIsItalic(isItalic); + }); + + this.api.asc_registerCallback('asc_onUnderline', (isUnderline) => { + storeTextSettings.resetIsUnderline(isUnderline); + }); + + this.api.asc_registerCallback('asc_onStrikeout', (isStrikeout) => { + storeTextSettings.resetIsStrikeout(isStrikeout); + }); + + this.api.asc_registerCallback('asc_onVerticalAlign', (typeBaseline) => { + storeTextSettings.resetTypeBaseline(typeBaseline); + }); + + this.api.asc_registerCallback('asc_onListType', (data) => { + let type = data.get_ListType(); + let subtype = data.get_ListSubType(); + storeTextSettings.resetListType(type); + switch (type) { + case 0: + storeTextSettings.resetBullets(subtype); + break; + case 1: + storeTextSettings.resetNumbers(subtype); + break; + } + }); + + this.api.asc_registerCallback('asc_onPrAlign', (align) => { + storeTextSettings.resetParagraphAlign(align); + }); + + this.api.asc_registerCallback('asc_onVerticalTextAlign', valign => { + storeTextSettings.resetParagraphValign(valign); + }); + + this.api.asc_registerCallback('asc_canIncreaseIndent', value => { + storeTextSettings.resetIncreaseIndent(value); + }); + + this.api.asc_registerCallback('asc_canDecreaseIndent', value => { + storeTextSettings.resetDecreaseIndent(value); + }); + + this.api.asc_registerCallback('asc_onTextColor', (color) => { + storeTextSettings.resetTextColor(color); + }); + + this.api.asc_registerCallback('asc_onParaSpacingLine', (vc) => { + storeTextSettings.resetLineSpacing(vc); + }); } _onDocumentContentReady() { diff --git a/apps/presentationeditor/mobile/src/controller/edit/EditText.jsx b/apps/presentationeditor/mobile/src/controller/edit/EditText.jsx index 62bd4ae93..5281c9129 100644 --- a/apps/presentationeditor/mobile/src/controller/edit/EditText.jsx +++ b/apps/presentationeditor/mobile/src/controller/edit/EditText.jsx @@ -9,9 +9,88 @@ class EditTextController extends Component { constructor (props) { super(props); } + + toggleBold(value) { + const api = Common.EditorApi.get(); + api.put_TextPrBold(value); + }; + + toggleItalic(value) { + const api = Common.EditorApi.get(); + api.put_TextPrItalic(value); + }; + + toggleUnderline(value) { + const api = Common.EditorApi.get(); + api.put_TextPrUnderline(value); + }; + + toggleStrikethrough(value) { + const api = Common.EditorApi.get(); + api.put_TextPrStrikeout(value); + }; + + onParagraphAlign(type) { + const api = Common.EditorApi.get(); + let value; + + switch (type) { + case 'just': + value = 3; + break; + case 'right': + value = 0; + break; + case 'center': + value = 2; + break; + default: + value = 1; + break; + } + + api.put_PrAlign(value); + }; + + onParagraphValign(type) { + const api = Common.EditorApi.get(); + let value; + + switch(type) { + case 'top': + value = Asc.c_oAscVAlign.Top; + break; + case 'center': + value = Asc.c_oAscVAlign.Center; + break; + case 'bottom': + value = Asc.c_oAscVAlign.Bottom; + break; + } + + api.setVerticalAlign(value); + }; + + onParagraphMove(type) { + const api = Common.EditorApi.get(); + + if(type === 'left') { + api.DecreaseIndent(); + } else { + api.IncreaseIndent(); + } + }; + render () { return ( ) } diff --git a/apps/presentationeditor/mobile/src/less/icons-ios.less b/apps/presentationeditor/mobile/src/less/icons-ios.less index b29d6067f..6b77662cd 100644 --- a/apps/presentationeditor/mobile/src/less/icons-ios.less +++ b/apps/presentationeditor/mobile/src/less/icons-ios.less @@ -157,7 +157,7 @@ .encoded-svg-mask(''); } - &.icon-text-align-jast { + &.icon-text-align-just { width: 22px; height: 22px; .encoded-svg-mask(''); diff --git a/apps/presentationeditor/mobile/src/store/focusObjects.js b/apps/presentationeditor/mobile/src/store/focusObjects.js index 12ac4d517..444b6308b 100644 --- a/apps/presentationeditor/mobile/src/store/focusObjects.js +++ b/apps/presentationeditor/mobile/src/store/focusObjects.js @@ -67,4 +67,19 @@ export class storeFocusObjects { return undefined; } } + + @computed get paragraphObject() { + const paragraphs = []; + for (let object of this._focusObjects) { + if (object.get_ObjectType() === Asc.c_oAscTypeSelectElement.Paragraph) { + paragraphs.push(object); + } + } + if (paragraphs.length > 0) { + const object = paragraphs[paragraphs.length - 1]; // get top + return object.get_ObjectValue(); + } else { + return undefined; + } + } } \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/store/mainStore.js b/apps/presentationeditor/mobile/src/store/mainStore.js index c8eb32009..c59dbab0e 100644 --- a/apps/presentationeditor/mobile/src/store/mainStore.js +++ b/apps/presentationeditor/mobile/src/store/mainStore.js @@ -8,6 +8,7 @@ import {storePresentationInfo} from './presentationInfo'; import {storePresentationSettings} from './presentationSettings'; import { storePalette } from './palette'; import { storeSlideSettings } from './slideSettings'; +import { storeTextSettings } from './textSettings'; // import {storeTextSettings} from "./textSettings"; // import {storeParagraphSettings} from "./paragraphSettings"; // import {storeShapeSettings} from "./shapeSettings"; @@ -24,7 +25,8 @@ export const stores = { storePresentationInfo: new storePresentationInfo(), storePresentationSettings: new storePresentationSettings(), storeSlideSettings: new storeSlideSettings(), - storePalette: new storePalette() + storePalette: new storePalette(), + storeTextSettings: new storeTextSettings() // storeTextSettings: new storeTextSettings(), // storeParagraphSettings: new storeParagraphSettings(), // storeShapeSettings: new storeShapeSettings(), diff --git a/apps/presentationeditor/mobile/src/store/textSettings.js b/apps/presentationeditor/mobile/src/store/textSettings.js new file mode 100644 index 000000000..85d2d0113 --- /dev/null +++ b/apps/presentationeditor/mobile/src/store/textSettings.js @@ -0,0 +1,168 @@ +import {action, observable, computed} from 'mobx'; + +export class storeTextSettings { + + @observable fontsArray = []; + @observable fontName = ''; + @observable fontSize = undefined; + @observable isBold = false; + @observable isItalic = false; + @observable isUnderline = false; + @observable isStrikethrough = false; + @observable typeBaseline = undefined; + @observable listType = undefined; + @observable typeBullets = undefined; + @observable typeNumbers = undefined; + @observable paragraphAlign = undefined; + @observable paragraphValign = undefined; + @observable canIncreaseIndent = undefined; + @observable canDecreaseIndent = undefined; + @observable textColor = undefined; + @observable customTextColors = []; + @observable lineSpacing = undefined; + + // @observable backgroundColor = undefined; + + + @action initEditorFonts (fonts, select) { + let array = []; + for (let font of fonts) { + let fontId = font.asc_getFontId(); + array.push({ + id : fontId, + name : font.asc_getFontName(), + //displayValue: font.asc_getFontName(), + imgidx : font.asc_getFontThumbnail(), + type : font.asc_getFontType() + }); + } + this.fontsArray = array; + } + @action resetFontName (font) { + let name = (typeof font.get_Name) === "function" ? font.get_Name() : font.asc_getName(); + this.fontName = name; + } + @action resetFontSize (size) { + this.fontSize = size; + } + @action resetIsBold (isBold) { + this.isBold = isBold; + } + @action resetIsItalic (isItalic) { + this.isItalic = isItalic; + } + @action resetIsUnderline (isUnderline) { + this.isUnderline = isUnderline; + } + @action resetIsStrikeout (isStrikethrough) { + this.isStrikethrough = isStrikethrough; + } + + // Indent + + @action resetIncreaseIndent(value) { + this.canIncreaseIndent = value; + } + + @action resetDecreaseIndent(value) { + this.canDecreaseIndent = value; + } + + // vertical align + @action resetTypeBaseline (typeBaseline) { + this.typeBaseline = typeBaseline; + } + @computed get isSuperscript() { + return (this.typeBaseline === 1); + } + @computed get isSubscript() { + return (this.typeBaseline === 2); + } + + // bullets + @action resetListType (type) { + this.listType = type; + } + @action resetBullets (type) { + this.typeBullets = type; + } + @action resetNumbers (type) { + this.typeNumbers = type; + } + + @action resetParagraphAlign (align) { + let value; + switch (align) { + case 0: + value = 'right'; + break; + case 1: + value = 'left'; + break; + case 2: + value = 'center'; + break; + case 3: + value = 'just'; + break; + } + this.paragraphAlign = value; + } + + @action resetParagraphValign (align) { + let value; + switch (align) { + case 0: + value = 'bottom'; + break; + case 4: + value = 'top'; + break; + case 1: + value = 'center'; + break; + } + this.paragraphValign = value; + } + + @action resetTextColor (color) { + let value; + if (color) { + if (color.get_auto()) { + value = 'auto'; + } else { + if (color.get_type() == Asc.c_oAscColor.COLOR_TYPE_SCHEME) { + value = { + color: Common.Utils.ThemeColor.getHexColor(color.get_r(), color.get_g(), color.get_b()), + effectValue: color.get_value() + } + } else { + value = Common.Utils.ThemeColor.getHexColor(color.get_r(), color.get_g(), color.get_b()); + } + } + } + this.textColor = value; + } + + @action changeCustomTextColors (colors) { + this.customTextColors = colors; + } + + @action resetLineSpacing (vc) { + let line = (vc.get_Line() === null || vc.get_LineRule() === null || vc.get_LineRule() != 1) ? -1 : vc.get_Line(); + this.lineSpacing = line; + } + + // @action resetBackgroundColor (color) { + // let value; + // if (color.get_type() == Asc.c_oAscColor.COLOR_TYPE_SCHEME) { + // value = { + // color: Common.Utils.ThemeColor.getHexColor(color.get_r(), color.get_g(), color.get_b()), + // effectValue: color.get_value() + // } + // } else { + // value = Common.Utils.ThemeColor.getHexColor(color.get_r(), color.get_g(), color.get_b()); + // } + // this.backgroundColor = value; + // } +} \ No newline at end of file diff --git a/apps/presentationeditor/mobile/src/view/edit/EditText.jsx b/apps/presentationeditor/mobile/src/view/edit/EditText.jsx index 96a0fd91d..2715a1241 100644 --- a/apps/presentationeditor/mobile/src/view/edit/EditText.jsx +++ b/apps/presentationeditor/mobile/src/view/edit/EditText.jsx @@ -1,15 +1,177 @@ import React, {Fragment, useState} from 'react'; import {observer, inject} from "mobx-react"; -import {Page, Navbar, List, ListItem, ListButton, Row, BlockTitle, Range, Toggle, Icon} from 'framework7-react'; +import {f7, List, ListItem, Icon, Row, Button, Page, Navbar, Segmented, BlockTitle} from 'framework7-react'; import { useTranslation } from 'react-i18next'; import {Device} from '../../../../../common/mobile/utils/device'; +import { ThemeColorPalette, CustomColorPicker } from '../../../../../common/mobile/lib/component/ThemeColorPalette.jsx'; const EditText = props => { + const isAndroid = Device.android; + const { t } = useTranslation(); + const _t = t('View.Edit', {returnObjects: true}); + const metricText = Common.Utils.Metric.getCurrentMetricName(); + const storeTextSettings = props.storeTextSettings; + const storeFocusObjects = props.storeFocusObjects; + const fontName = storeTextSettings.fontName || _t.textFonts; + const fontSize = storeTextSettings.fontSize; + const fontColor = storeTextSettings.textColor; + const displaySize = typeof fontSize === 'undefined' ? _t.textAuto : fontSize + ' ' + _t.textPt; + const isBold = storeTextSettings.isBold; + const isItalic = storeTextSettings.isItalic; + const isUnderline = storeTextSettings.isUnderline; + const isStrikethrough = storeTextSettings.isStrikethrough; + const paragraphAlign = storeTextSettings.paragraphAlign; + const paragraphValign = storeTextSettings.paragraphValign; + const canIncreaseIndent = storeTextSettings.canIncreaseIndent; + const canDecreaseIndent = storeTextSettings.canDecreaseIndent; + + const paragraphObj = storeFocusObjects.paragraphObject; + + // if (paragraphObj.get_Ind()===null || paragraphObj.get_Ind()===undefined) { + // paragraphObj.get_Ind().put_FirstLine(0); + // } + + // const firstLine = parseFloat(Common.Utils.Metric.fnRecalcFromMM(paragraphObj.get_Ind().get_FirstLine()).toFixed(2)); + + const spaceBefore = paragraphObj.get_Spacing().get_Before() < 0 ? paragraphObj.get_Spacing().get_Before() : Common.Utils.Metric.fnRecalcFromMM(paragraphObj.get_Spacing().get_Before()); + const spaceAfter = paragraphObj.get_Spacing().get_After() < 0 ? paragraphObj.get_Spacing().get_After() : Common.Utils.Metric.fnRecalcFromMM(paragraphObj.get_Spacing().get_After()); + + const spaceBeforeFix = parseFloat(spaceBefore.toFixed(2)); + const spaceAfterFix = parseFloat(spaceAfter.toFixed(2)); + + const displayBefore = spaceBefore < 0 ? _t.textAuto : spaceBeforeFix + ' ' + metricText; + const displayAfter = spaceAfter < 0 ? _t.textAuto : spaceAfterFix + ' ' + metricText; + + const fontColorPreview = fontColor !== 'auto' ? + : + ; + return ( - + + + + + { props.toggleBold(!isBold)}}>B + {props.toggleItalic(!isItalic)}}>I + {props.toggleUnderline(!isUnderline)}} style={{textDecoration: "underline"}}>U + {props.toggleStrikethrough(!isStrikethrough)}} style={{textDecoration: "line-through"}}>S + + + + {!isAndroid ? + {fontColorPreview} : + fontColorPreview + } + + + {!isAndroid && } + + + + + + {props.onParagraphAlign('left')}}> + + + {props.onParagraphAlign('center')}}> + + + {props.onParagraphAlign('right')}}> + + + {props.onParagraphAlign('just')}}> + + + + + + + {props.onParagraphValign('top')}}> + + + {props.onParagraphValign('center')}}> + + + {props.onParagraphValign('bottom')}}> + + + + + + + {props.onParagraphMove('left')}}> + + + {props.onParagraphMove('right')}}> + + + + + + {!isAndroid && } + + + {!isAndroid && } + + + {!isAndroid && } + + + {_t.textDistanceFromText} + + + {!isAndroid && {displayBefore}} + + + {props.onDistanceBefore(spaceBefore, true)}}> + {isAndroid ? : ' - '} + + {isAndroid && {displayBefore}} + {props.onDistanceBefore(spaceBefore, false)}}> + {isAndroid ? : ' + '} + + + + + + {!isAndroid && {displayAfter}} + + + {props.onDistanceAfter(spaceAfter, true)}}> + {isAndroid ? : ' - '} + + {isAndroid && {displayAfter}} + {props.onDistanceAfter(spaceAfter, false)}}> + {isAndroid ? : ' + '} + + + + + ) }; -export {EditText}; \ No newline at end of file +const EditTextContainer = inject("storeTextSettings", "storeFocusObjects")(observer(EditText)); + +export { + EditTextContainer as EditText +}; \ No newline at end of file