mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
feat:编辑器移动端支持单独编辑 (#11052)
* feat:编辑器移动端支持单独编辑 * fix: ts报错 --------- Co-authored-by: zhangxulong <zhangxulong@baidu.com>
This commit is contained in:
parent
d8759d2186
commit
eaf5217c4a
@ -4,6 +4,7 @@
|
||||
|
||||
import {JSONValueMap, findObjectsWithKey} from './utils/helper';
|
||||
import isPlainObject from 'lodash/isPlainObject';
|
||||
import merge from 'lodash/merge';
|
||||
const isMobile = (window as any).matchMedia?.('(max-width: 768px)').matches
|
||||
? true
|
||||
: false;
|
||||
@ -22,6 +23,11 @@ export const envOverwrite = (schema: any, locale?: string) => {
|
||||
delete newValue[locale];
|
||||
return newValue;
|
||||
} else if (isMobile && value.mobile) {
|
||||
let schemaNodes = findObjectsWithKey(value, 'mobile');
|
||||
for (let schemaNode of schemaNodes) {
|
||||
merge(schemaNode, schemaNode['mobile']);
|
||||
}
|
||||
|
||||
const newValue = Object.assign({}, value, value.mobile);
|
||||
delete newValue.mobile;
|
||||
return newValue;
|
||||
|
@ -26,6 +26,8 @@ export interface EditorProps extends PluginEventListener {
|
||||
onChange: (value: SchemaObject) => void;
|
||||
preview?: boolean;
|
||||
isMobile?: boolean;
|
||||
/** 用于区分响应式页面和h5页面 */
|
||||
isMobileAloneEdit?: boolean;
|
||||
isSubEditor?: boolean;
|
||||
autoFocus?: boolean;
|
||||
className?: string;
|
||||
@ -182,6 +184,7 @@ export default class Editor extends Component<
|
||||
this.store = MainStore.create(
|
||||
{
|
||||
isMobile: props.isMobile,
|
||||
isMobileAloneEdit: props.isMobileAloneEdit,
|
||||
theme: props.theme,
|
||||
toolbarMode: props.toolbarMode || 'default',
|
||||
noDialog: props.noDialog,
|
||||
@ -591,6 +594,7 @@ export default class Editor extends Component<
|
||||
const {
|
||||
preview,
|
||||
isMobile,
|
||||
isMobileAloneEdit,
|
||||
className,
|
||||
theme,
|
||||
appLocale,
|
||||
@ -649,6 +653,7 @@ export default class Editor extends Component<
|
||||
{...previewProps}
|
||||
editable={!preview}
|
||||
isMobile={isMobile}
|
||||
isMobileAloneEdit={isMobileAloneEdit}
|
||||
store={this.store}
|
||||
manager={this.manager}
|
||||
theme={theme}
|
||||
@ -670,6 +675,7 @@ export default class Editor extends Component<
|
||||
appLocale={appLocale}
|
||||
amisEnv={amisEnv}
|
||||
readonly={readonly}
|
||||
isMobile={isMobile}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
@ -11,6 +11,8 @@ import {
|
||||
resizeSensor
|
||||
} from 'amis';
|
||||
import {isAlive} from 'mobx-state-tree';
|
||||
import {JSONMergeForMobile} from '../util';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
|
||||
/**
|
||||
* 这个用了 observer,所以能最小程度的刷新,数据不变按理是不会刷新的。
|
||||
@ -24,6 +26,7 @@ export interface IFramePreviewProps {
|
||||
manager: EditorManager;
|
||||
/** 应用语言类型 */
|
||||
appLocale?: string;
|
||||
isMobileAloneEdit?: boolean;
|
||||
}
|
||||
@observer
|
||||
export default class IFramePreview extends React.Component<IFramePreviewProps> {
|
||||
@ -98,8 +101,20 @@ export default class IFramePreview extends React.Component<IFramePreviewProps> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {editable, store, appLocale, autoFocus, env, data, manager, ...rest} =
|
||||
this.props;
|
||||
const {
|
||||
editable,
|
||||
store,
|
||||
appLocale,
|
||||
autoFocus,
|
||||
env,
|
||||
data,
|
||||
manager,
|
||||
isMobileAloneEdit,
|
||||
...rest
|
||||
} = this.props;
|
||||
const schema = editable
|
||||
? store.filteredSchema
|
||||
: store.filteredSchemaForPreview;
|
||||
|
||||
return (
|
||||
<Frame
|
||||
@ -111,7 +126,7 @@ export default class IFramePreview extends React.Component<IFramePreviewProps> {
|
||||
<InnerComponent store={store} editable={editable} manager={manager} />
|
||||
<div ref={this.dialogMountRef} className="ae-Dialog-preview-mount-node">
|
||||
{render(
|
||||
editable ? store.filteredSchema : store.filteredSchemaForPreview,
|
||||
isMobileAloneEdit ? JSONMergeForMobile(cloneDeep(schema)) : schema,
|
||||
{
|
||||
...rest,
|
||||
key: editable ? 'edit-mode' : 'preview-mode',
|
||||
|
@ -22,6 +22,14 @@ export default class CodeEditorPanel extends React.Component<PanelProps> {
|
||||
}, 500);
|
||||
}
|
||||
|
||||
@autobind
|
||||
onChange(...rest: any) {
|
||||
const {store} = this.props;
|
||||
store.patchCodeEdit(true);
|
||||
this.props.onChange(rest);
|
||||
store.patchCodeEdit(false);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {onChange, manager, store} = this.props;
|
||||
|
||||
@ -31,7 +39,7 @@ export default class CodeEditorPanel extends React.Component<PanelProps> {
|
||||
<div className="ae-CodePanel-content">
|
||||
<AMisCodeEditor
|
||||
value={store.valueWithoutHiddenProps}
|
||||
onChange={onChange}
|
||||
onChange={this.onChange}
|
||||
$schema={store.jsonSchemaUri}
|
||||
$schemaUrl={manager.config.$schemaUrl}
|
||||
onPaste={this.handleCodePaste}
|
||||
|
@ -9,6 +9,8 @@ import {autobind, isHasPluginIcon} from '../../util';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import {PanelItem} from '../../plugin';
|
||||
import {WidthDraggableBtn} from '../base/WidthDraggableBtn';
|
||||
import type {Schema} from 'amis';
|
||||
import merge from 'lodash/merge';
|
||||
|
||||
interface RightPanelsProps {
|
||||
store: EditorStoreType;
|
||||
@ -17,6 +19,7 @@ interface RightPanelsProps {
|
||||
appLocale?: string;
|
||||
amisEnv?: any;
|
||||
readonly?: boolean;
|
||||
isMobile?: boolean;
|
||||
}
|
||||
|
||||
interface RightPanelsStates {
|
||||
@ -72,6 +75,12 @@ export class RightPanels extends React.Component<
|
||||
manager.panelChangeValue(...arg);
|
||||
}
|
||||
|
||||
@autobind
|
||||
mergeMobileAttribute(obj: Schema) {
|
||||
const {isMobile} = this.props;
|
||||
return obj.mobile && isMobile ? merge(obj, obj.mobile) : obj;
|
||||
}
|
||||
|
||||
render() {
|
||||
const {store, manager, theme, readonly} = this.props;
|
||||
const {isOpenStatus, isFixedStatus} = this.state;
|
||||
@ -86,7 +95,7 @@ export class RightPanels extends React.Component<
|
||||
info: node?.info,
|
||||
path: node?.path,
|
||||
node: node,
|
||||
value: store.value,
|
||||
value: this.mergeMobileAttribute(store.value),
|
||||
onChange: this.handlePanelChangeValue,
|
||||
store: store,
|
||||
manager: manager,
|
||||
@ -100,7 +109,7 @@ export class RightPanels extends React.Component<
|
||||
id={id}
|
||||
info={node?.info}
|
||||
path={node?.path}
|
||||
value={store.value}
|
||||
value={this.mergeMobileAttribute(store.value)}
|
||||
onChange={this.handlePanelChangeValue}
|
||||
store={store}
|
||||
manager={manager}
|
||||
|
@ -41,6 +41,7 @@ export interface PreviewProps {
|
||||
className?: string;
|
||||
editable?: boolean;
|
||||
isMobile?: boolean;
|
||||
isMobileAloneEdit?: boolean;
|
||||
store: EditorStoreType;
|
||||
manager: EditorManager;
|
||||
data?: any;
|
||||
@ -522,6 +523,7 @@ export default class Preview extends Component<PreviewProps> {
|
||||
amisEnv,
|
||||
theme,
|
||||
isMobile,
|
||||
isMobileAloneEdit,
|
||||
autoFocus,
|
||||
toolbarContainer,
|
||||
appLocale,
|
||||
@ -578,6 +580,7 @@ export default class Preview extends Component<PreviewProps> {
|
||||
manager={manager}
|
||||
autoFocus={autoFocus}
|
||||
appLocale={appLocale}
|
||||
isMobileAloneEdit={isMobileAloneEdit}
|
||||
></IFramePreview>
|
||||
) : (
|
||||
<SmartPreview
|
||||
|
@ -1869,6 +1869,7 @@ export class EditorManager {
|
||||
trailing: true
|
||||
});
|
||||
|
||||
isCodeEditing = false;
|
||||
patching = false;
|
||||
patchingInvalid = false;
|
||||
patchSchema(force = false) {
|
||||
@ -1906,6 +1907,10 @@ export class EditorManager {
|
||||
this.patchingInvalid && this.patchSchema(force);
|
||||
}
|
||||
|
||||
patchCodeEdit(isCodeEdit: boolean) {
|
||||
this.isCodeEditing = isCodeEdit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 把设置了特殊 region 的,hack 一下。
|
||||
*/
|
||||
|
@ -149,6 +149,7 @@ export const MainStore = types
|
||||
.model('EditorRoot', {
|
||||
ready: false, // 异步组件加载前不可用
|
||||
isMobile: false,
|
||||
isMobileAloneEdit: false,
|
||||
isSubEditor: false,
|
||||
// 用于自定义爱速搭中的 amis 文档路径
|
||||
amisDocHost: types.optional(types.string, 'https://baidu.gitee.io'),
|
||||
@ -251,7 +252,8 @@ export const MainStore = types
|
||||
/** 应用语料 */
|
||||
appCorpusData: types.optional(types.frozen(), {}),
|
||||
/** 应用多语言状态,用于其它组件进行订阅 */
|
||||
appLocaleState: types.optional(types.number, 0)
|
||||
appLocaleState: types.optional(types.number, 0),
|
||||
isCodeEditing: types.optional(types.boolean, false)
|
||||
})
|
||||
.views(self => {
|
||||
return {
|
||||
@ -2314,6 +2316,10 @@ export const MainStore = types
|
||||
|
||||
beforeDestroy() {
|
||||
lazyUpdateTargetName.cancel();
|
||||
},
|
||||
|
||||
patchCodeEdit(isEdit: boolean) {
|
||||
self.isCodeEditing = isEdit;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -969,7 +969,15 @@ function applyChange(target: any, source: any, change: DiffChange) {
|
||||
source
|
||||
}
|
||||
);
|
||||
|
||||
const editorStore = (window as any)?.editorStore;
|
||||
// pc 响应式页面,纯h5页面不处理
|
||||
if (
|
||||
editorStore.isMobileAloneEdit &&
|
||||
editorStore.isMobile &&
|
||||
!editorStore.isCodeEditing
|
||||
) {
|
||||
change.path.unshift('mobile');
|
||||
}
|
||||
DeepDiff.applyChange(target, source, change);
|
||||
}
|
||||
|
||||
@ -2023,3 +2031,34 @@ export const RAW_TYPE_MAP: {
|
||||
'user-select': 'user',
|
||||
'department-select': 'department'
|
||||
};
|
||||
/*
|
||||
* 将移动端存储在mobile对象中的属性合并到最外层
|
||||
* @param obj
|
||||
* @returns
|
||||
*/
|
||||
export function JSONMergeForMobile(obj: any): any {
|
||||
if (!isObject(obj)) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(JSONMergeForMobile);
|
||||
}
|
||||
if (obj.mobile) {
|
||||
merge(obj, obj.mobile, {$$id: obj.$$id});
|
||||
}
|
||||
|
||||
Object.keys(obj).forEach(key => {
|
||||
let prop = obj[key];
|
||||
|
||||
if (Array.isArray(prop)) {
|
||||
prop.map((item: any) => {
|
||||
JSONMergeForMobile(item);
|
||||
});
|
||||
} else {
|
||||
JSONMergeForMobile(prop);
|
||||
}
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user