[DE mobile] context menu moved to common
This commit is contained in:
parent
1c3e77c22b
commit
89d297ea9c
157
apps/common/mobile/lib/controller/ContextMenu.jsx
Normal file
157
apps/common/mobile/lib/controller/ContextMenu.jsx
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { f7 } from 'framework7-react';
|
||||||
|
import { Device } from '../../../../common/mobile/utils/device'
|
||||||
|
|
||||||
|
import ContextMenuView from '../view/ContextMenu';
|
||||||
|
|
||||||
|
class ContextMenuController extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
opened: false
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onMenuClosed = this.onMenuClosed.bind(this);
|
||||||
|
this.onDocumentReady = this.onDocumentReady.bind(this);
|
||||||
|
this.onApiOpenContextMenu = this.onApiOpenContextMenu.bind(this);
|
||||||
|
this.onApiHideContextMenu = this.onApiHideContextMenu.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDocumentReady() {
|
||||||
|
this.$targetEl = $$('#idx-context-menu-target');
|
||||||
|
if ( !this.$targetEl.length ) {
|
||||||
|
// this.$targetEl = $$('<div id="idx-context-menu-target" style="position:absolute;width:15px;height:15px;background-color:green;z-index:1;"></div>');
|
||||||
|
this.$targetEl = $$('<div id="idx-context-menu-target" style="position:absolute;"></div>');
|
||||||
|
this.$targetEl.css({left: '-10000px', top: '-10000px'});
|
||||||
|
|
||||||
|
$$('#editor_sdk').append(this.$targetEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
const api = Common.EditorApi.get();
|
||||||
|
api.asc_registerCallback('asc_onShowPopMenu', this.onApiOpenContextMenu);
|
||||||
|
api.asc_registerCallback('asc_onHidePopMenu', this.onApiHideContextMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
offsetPopoverTop(popover) {
|
||||||
|
var app = popover.app,
|
||||||
|
$el = popover.$el,
|
||||||
|
$targetEl = popover.$targetEl;
|
||||||
|
|
||||||
|
const width = $el.width(),
|
||||||
|
height = $el.height();
|
||||||
|
|
||||||
|
$el.removeClass('popover-on-left popover-on-right popover-on-top popover-on-bottom popover-on-middle').css({
|
||||||
|
left: '',
|
||||||
|
top: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
let targetOffsetLeft, targetOffsetTop;
|
||||||
|
// var safeAreaTop = parseInt($('html').css('--f7-safe-area-top'), 10);
|
||||||
|
let safeAreaLeft = parseInt($('html').css('--f7-safe-area-left'), 10),
|
||||||
|
safeAreaRight = parseInt($('html').css('--f7-safe-area-right'), 10);
|
||||||
|
// if (Number.isNaN(safeAreaTop)) safeAreaTop = 0;
|
||||||
|
if (Number.isNaN(safeAreaLeft)) safeAreaLeft = 0;
|
||||||
|
if (Number.isNaN(safeAreaRight)) safeAreaRight = 0;
|
||||||
|
|
||||||
|
if ($targetEl && $targetEl.length > 0) {
|
||||||
|
let targetOffset = $targetEl.offset();
|
||||||
|
targetOffsetLeft = targetOffset.left - app.left;
|
||||||
|
targetOffsetTop = targetOffset.top - app.top;
|
||||||
|
let targetParentPage = $targetEl.parents('.page');
|
||||||
|
|
||||||
|
if (targetParentPage.length > 0) {
|
||||||
|
targetOffsetTop -= targetParentPage[0].scrollTop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let position = 'top';
|
||||||
|
|
||||||
|
let top = targetOffsetTop - height - 10;
|
||||||
|
top = Math.max(8, Math.min(top, app.height - height - 8)); // Horizontal Position
|
||||||
|
|
||||||
|
let hPosition;
|
||||||
|
|
||||||
|
// if (targetOffsetLeft < app.width / 2) {
|
||||||
|
// hPosition = 'right';
|
||||||
|
// left = position === 'middle' ? targetOffsetLeft + targetWidth : targetOffsetLeft;
|
||||||
|
// } else {
|
||||||
|
// hPosition = 'left';
|
||||||
|
// left = position === 'middle' ? targetOffsetLeft - width : targetOffsetLeft + targetWidth - width;
|
||||||
|
// }
|
||||||
|
|
||||||
|
hPosition = 'middle';
|
||||||
|
let left = targetOffsetLeft - width / 2;
|
||||||
|
|
||||||
|
left = Math.max(8, Math.min(left, app.width - width - 8 - safeAreaRight), safeAreaLeft);
|
||||||
|
$el.addClass(`popover-on-${position} popover-on-${hPosition}`);
|
||||||
|
|
||||||
|
$el.css({top: `${top}px`,
|
||||||
|
left: `${left}px`});
|
||||||
|
}
|
||||||
|
|
||||||
|
onApiOpenContextMenu(x, y) {
|
||||||
|
if ( !this.state.opened ) {
|
||||||
|
this.$targetEl.css({left: `${x}px`, top: `${y}px`});
|
||||||
|
const popover = f7.popover.open('#idx-context-menu-popover', '#idx-context-menu-target');
|
||||||
|
|
||||||
|
if ( Device.android )
|
||||||
|
this.offsetPopoverTop(popover);
|
||||||
|
|
||||||
|
this.setState(state => {
|
||||||
|
return {opened: true}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onApiHideContextMenu() {
|
||||||
|
if ( this.state.opened ) {
|
||||||
|
f7.popover.close('#idx-context-menu-popover');
|
||||||
|
|
||||||
|
this.$targetEl.css({left: '-10000px', top: '-10000px'});
|
||||||
|
this.setState({opened: false});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMenuClosed() {
|
||||||
|
// (async () => {
|
||||||
|
// await 1 && this.setState(state => {
|
||||||
|
// this.$targetEl.css({left: '-10000px', top: '-10000px'});
|
||||||
|
// return ({opened: false});
|
||||||
|
// });
|
||||||
|
// })();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMenuItemClick(action) {
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
Common.Notifications.off('document:ready', this.onDocumentReady);
|
||||||
|
|
||||||
|
const api = Common.EditorApi.get();
|
||||||
|
api.asc_unregisterCallback('asc_onShowPopMenu', this.onApiOpenContextMenu);
|
||||||
|
api.asc_unregisterCallback('asc_onHidePopMenu', this.onApiHideContextMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if ( !Common.EditorApi ) {
|
||||||
|
Common.Notifications.on({
|
||||||
|
'document:ready': this.onDocumentReady
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.onDocumentReady();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initMenuItems() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<ContextMenuView items={this.initMenuItems()} onMenuClosed={this.onMenuClosed} onMenuItemClick={this.onMenuItemClick} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ContextMenuController;
|
39
apps/common/mobile/lib/view/ContextMenu.jsx
Normal file
39
apps/common/mobile/lib/view/ContextMenu.jsx
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { Popover, List, ListItem, ListButton, Link, Icon } from 'framework7-react';
|
||||||
|
import { f7 } from 'framework7-react';
|
||||||
|
|
||||||
|
class ContextMenuView extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
// f7.popover.open('#idx-context-menu-popover', '#idx-context-menu-target');
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const buttons = this.props.items || {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover id="idx-context-menu-popover"
|
||||||
|
className="document-menu"
|
||||||
|
backdrop={false}
|
||||||
|
closeByBackdropClick={false}
|
||||||
|
closeByOutsideClick={false}
|
||||||
|
onPopoverClosed={e => this.props.onMenuClosed()}
|
||||||
|
>
|
||||||
|
<List className="list-block">
|
||||||
|
{buttons.map((b, index) =>
|
||||||
|
!!b.text ?
|
||||||
|
<ListButton className="asd" title={b.text} key={index} onClick={e => this.props.onMenuItemClick(b.action)} /> :
|
||||||
|
<ListButton className="asd" title={b.text} key={index}>
|
||||||
|
<Icon slot="media" icon={`icon_mask ${b.icon}`} />
|
||||||
|
</ListButton>
|
||||||
|
)}
|
||||||
|
</List>
|
||||||
|
</Popover>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ContextMenuView;
|
7
apps/common/mobile/resources/less/contextmenu.less
Normal file
7
apps/common/mobile/resources/less/contextmenu.less
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
@import './ios/contextmenu';
|
||||||
|
@import './material/contextmenu';
|
||||||
|
|
||||||
|
|
||||||
|
.document-menu {
|
||||||
|
width: auto;
|
||||||
|
}
|
102
apps/common/mobile/resources/less/ios/contextmenu.less
Normal file
102
apps/common/mobile/resources/less/ios/contextmenu.less
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
|
||||||
|
.device-ios {
|
||||||
|
.document-menu {
|
||||||
|
@contextMenuBg: rgba(0, 0, 0, 0.9);
|
||||||
|
@modalHairlineColor: rgba(230, 230, 230, 0.9);
|
||||||
|
@modalButtonColor: rgba(200, 200, 200, 0.9);
|
||||||
|
|
||||||
|
background-color: @contextMenuBg;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
.popover-angle {
|
||||||
|
&:after {
|
||||||
|
background: @contextMenuBg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-block {
|
||||||
|
font-size: 14px;
|
||||||
|
white-space: pre;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
ul {
|
||||||
|
.hairline-remove(left);
|
||||||
|
//border-radius: 7px 0 0 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li:first-child a {
|
||||||
|
//border-radius: 7px 0 0 7px;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//&:last-child {
|
||||||
|
// ul {
|
||||||
|
// .hairline-remove(right);
|
||||||
|
// border-radius: 0 7px 7px 0;
|
||||||
|
// }
|
||||||
|
// li:last-child a{
|
||||||
|
// border-radius: 0 7px 7px 0;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//&:first-child:last-child {
|
||||||
|
// li:first-child:last-child a, ul:first-child:last-child {
|
||||||
|
// border-radius: 7px;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
.item-link {
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
html:not(.watch-active-state) &:active, &.active-state {
|
||||||
|
//.transition(0ms);
|
||||||
|
background-color: #d9d9d9;
|
||||||
|
.item-inner {
|
||||||
|
.hairline-color(right, transparent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html.phone & {
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-button {
|
||||||
|
color: @white;
|
||||||
|
line-height: 36px;
|
||||||
|
|
||||||
|
.hairline(right, @modalHairlineColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// List items
|
||||||
|
li {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last-childs
|
||||||
|
li {
|
||||||
|
&:last-child {
|
||||||
|
.list-button {
|
||||||
|
.hairline-remove(right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child, &:last-child li:last-child {
|
||||||
|
.item-inner {
|
||||||
|
.hairline-remove(right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li:last-child, &:last-child li {
|
||||||
|
.item-inner {
|
||||||
|
.hairline(right, @modalHairlineColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//.no-hairlines();
|
||||||
|
//.no-hairlines-between()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
apps/common/mobile/resources/less/material/contextmenu.less
Normal file
32
apps/common/mobile/resources/less/material/contextmenu.less
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
|
||||||
|
.md {
|
||||||
|
.document-menu {
|
||||||
|
//line-height: 1 !important;
|
||||||
|
|
||||||
|
.popover-inner {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-block {
|
||||||
|
white-space: pre;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-button {
|
||||||
|
color: #212121;
|
||||||
|
}
|
||||||
|
|
||||||
|
//.item-link {
|
||||||
|
// html.phone & {
|
||||||
|
//padding: 0 10px;
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,74 +1,38 @@
|
||||||
import React, { Component } from 'react';
|
import React from 'react';
|
||||||
import { f7 } from 'framework7-react';
|
import { f7 } from 'framework7-react';
|
||||||
|
import ContextMenuController from '../../../../common/mobile/lib/controller/ContextMenu';
|
||||||
|
|
||||||
import ContextMenuView from '../view/ContextMenu';
|
class ContextMenu extends ContextMenuController {
|
||||||
|
|
||||||
class ContextMenuController extends Component {
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
// console.log('context menu controller created');
|
||||||
pos: [-10000,-10000],
|
}
|
||||||
show: false
|
|
||||||
};
|
|
||||||
|
|
||||||
this.onMenuClosed = this.onMenuClosed.bind(this);
|
// onMenuClosed() {
|
||||||
|
// super.onMenuClosed();
|
||||||
|
// }
|
||||||
|
|
||||||
Common.Notifications.on({
|
onMenuItemClick(action) {
|
||||||
'engineCreated': api => {
|
super.onMenuItemClick(action);
|
||||||
api.asc_registerCallback('asc_onShowPopMenu', this.onApiShowPopMenu.bind(this));
|
|
||||||
api.asc_registerCallback('asc_onHidePopMenu', this.onApiHidePopMenu.bind(this));
|
|
||||||
},
|
|
||||||
'document:ready': () => {
|
|
||||||
this.$targetEl = $$('<div id="idx-context-menu-target" style="position:absolute;width:15px;height:15px;background-color:green;z-index:1;"></div>');
|
|
||||||
this.$targetEl.css({left: '-10000px', top: '-10000px'});
|
|
||||||
|
|
||||||
$$('#editor_sdk').append(this.$targetEl);
|
console.log("on click item");
|
||||||
|
}
|
||||||
|
|
||||||
|
initMenuItems() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: 'Edit',
|
||||||
|
action: 'edit'
|
||||||
|
}, {
|
||||||
|
text: 'View',
|
||||||
|
action: 'view'
|
||||||
|
}, {
|
||||||
|
icon: 'icon-paste',
|
||||||
|
action: 'review'
|
||||||
}
|
}
|
||||||
});
|
];
|
||||||
|
|
||||||
console.log('context menu controller created');
|
|
||||||
}
|
|
||||||
|
|
||||||
onApiShowPopMenu(x, y) {
|
|
||||||
console.log('show context menu ' + [x,y]);
|
|
||||||
|
|
||||||
this.$targetEl.css({left: `${x}px`, top: `${y}px`});
|
|
||||||
this.setState({
|
|
||||||
pos: [x,y],
|
|
||||||
show: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
onApiHidePopMenu() {
|
|
||||||
// console.log('hide context menu');
|
|
||||||
|
|
||||||
if ( this.state.show ) {
|
|
||||||
f7.popover.close('#idx-context-menu-popover');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMenuClosed() {
|
|
||||||
(async () => {
|
|
||||||
await 1 && this.setState(state => {
|
|
||||||
this.$targetEl.css({left: '-10000px', top: '-10000px'});
|
|
||||||
return ({pos: [-10000, -10000], show: false});
|
|
||||||
});
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
console.log('context menu controller will be unmounted');
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
console.log('context menu controller did mount');
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
!this.state.show ? null :
|
|
||||||
<ContextMenuView onMenuClosed={this.onMenuClosed} />)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { ContextMenuController as ContextMenu };
|
export { ContextMenu };
|
|
@ -7,8 +7,10 @@
|
||||||
@import '../../../../common/mobile/resources/less/common.less';
|
@import '../../../../common/mobile/resources/less/common.less';
|
||||||
@import '../../../../common/mobile/resources/less/common-ios.less';
|
@import '../../../../common/mobile/resources/less/common-ios.less';
|
||||||
@import '../../../../common/mobile/resources/less/common-material.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/dataview.less';
|
||||||
@import '../../../../common/mobile/resources/less/search.less';
|
@import '../../../../common/mobile/resources/less/search.less';
|
||||||
|
@import '../../../../common/mobile/resources/less/contextmenu.less';
|
||||||
@import './app-material.less';
|
@import './app-material.less';
|
||||||
@import './app-ios.less';
|
@import './app-ios.less';
|
||||||
@import './icons-ios.less';
|
@import './icons-ios.less';
|
||||||
|
|
|
@ -90,7 +90,7 @@ export default class MainPage extends Component {
|
||||||
!this.state.collaborationVisible ? null :
|
!this.state.collaborationVisible ? null :
|
||||||
<Collaboration onclosed={this.handleOptionsViewClosed.bind(this, 'coauth')} />
|
<Collaboration onclosed={this.handleOptionsViewClosed.bind(this, 'coauth')} />
|
||||||
}
|
}
|
||||||
{/*<ContextMenu />*/}
|
<ContextMenu />
|
||||||
</Page>
|
</Page>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,29 +2,18 @@ import React, { Component } from 'react';
|
||||||
import { Popover, List, ListItem, ListButton, Link, Icon } from 'framework7-react';
|
import { Popover, List, ListItem, ListButton, Link, Icon } from 'framework7-react';
|
||||||
import { f7 } from 'framework7-react';
|
import { f7 } from 'framework7-react';
|
||||||
|
|
||||||
const buttons = [
|
|
||||||
{
|
|
||||||
text: 'Edit',
|
|
||||||
action: 'edit'
|
|
||||||
}, {
|
|
||||||
text: 'View',
|
|
||||||
action: 'view'
|
|
||||||
}, {
|
|
||||||
icon: 'icon-paste',
|
|
||||||
action: 'review'
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
class ContextMenuView extends Component {
|
class ContextMenuView extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
f7.popover.open('#idx-context-menu-popover', '#idx-context-menu-target');
|
// f7.popover.open('#idx-context-menu-popover', '#idx-context-menu-target');
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const buttons = this.props.items || {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover id="idx-context-menu-popover"
|
<Popover id="idx-context-menu-popover"
|
||||||
className="document-menu"
|
className="document-menu"
|
||||||
|
@ -36,9 +25,9 @@ class ContextMenuView extends Component {
|
||||||
<List className="list-block">
|
<List className="list-block">
|
||||||
{buttons.map((b, index) =>
|
{buttons.map((b, index) =>
|
||||||
!!b.text ?
|
!!b.text ?
|
||||||
<ListButton className="asd" title={b.text} key={index} /> :
|
<ListButton className="asd" title={b.text} key={index} onClick={e => this.props.onMenuItemClick(b.action)} /> :
|
||||||
<ListButton className="asd" title={b.text} key={index}>
|
<ListButton className="asd" title={b.text} key={index}>
|
||||||
<Icon slot="media" icon={b.icon} />
|
<Icon slot="media" icon={`icon_mask ${b.icon}`} />
|
||||||
</ListButton>
|
</ListButton>
|
||||||
)}
|
)}
|
||||||
</List>
|
</List>
|
||||||
|
|
Loading…
Reference in a new issue