wip right click in react
This commit is contained in:
parent
77846cfcb7
commit
6e1878413f
5 changed files with 196 additions and 216 deletions
|
@ -9,7 +9,7 @@ import { notifyUser } from './index.js'
|
|||
import ImportDialog from './ImportDialog'
|
||||
import Active from '../Active'
|
||||
import DataModel from '../DataModel'
|
||||
import { ExploreMaps, ChatView, TopicCard } from '../Views'
|
||||
import { ExploreMaps, ChatView, TopicCard, ContextMenu } from '../Views'
|
||||
import Filter from '../Filter'
|
||||
import JIT from '../JIT'
|
||||
import Realtime from '../Realtime'
|
||||
|
|
|
@ -11,6 +11,7 @@ import $jit from '../patched/JIT'
|
|||
import MetacodeSelect from '../components/MetacodeSelect'
|
||||
|
||||
import Active from './Active'
|
||||
import ContextMenu from './Views/ContextMenu'
|
||||
import Control from './Control'
|
||||
import Create from './Create'
|
||||
import DataModel from './DataModel'
|
||||
|
@ -1354,222 +1355,9 @@ const JIT = {
|
|||
|
||||
// select the node
|
||||
Control.selectNode(node, e)
|
||||
ContextMenu.selectNode(node, {x: e.clientX, y: e.clientY})
|
||||
|
||||
// delete old right click menu
|
||||
$('.rightclickmenu').remove()
|
||||
// create new menu for clicked on node
|
||||
const rightclickmenu = document.createElement('div')
|
||||
rightclickmenu.className = 'rightclickmenu'
|
||||
// prevent the custom context menu from immediately opening the default context menu as well
|
||||
rightclickmenu.setAttribute('oncontextmenu', 'return false')
|
||||
|
||||
// add the proper options to the menu
|
||||
let menustring = '<ul>'
|
||||
|
||||
const authorized = Active.Map && Active.Map.authorizeToEdit(Active.Mapper)
|
||||
|
||||
const disabled = authorized ? '' : 'disabled'
|
||||
|
||||
if (Active.Map) menustring += '<li class="rc-hide"><div class="rc-icon"></div>Hide until refresh<div class="rc-keyboard">Ctrl+H</div></li>'
|
||||
if (Active.Map && Active.Mapper) menustring += '<li class="rc-remove ' + disabled + '"><div class="rc-icon"></div>Remove from map<div class="rc-keyboard">Ctrl+M</div></li>'
|
||||
if (Active.Topic) menustring += '<li class="rc-remove"><div class="rc-icon"></div>Remove from view<div class="rc-keyboard">Ctrl+M</div></li>'
|
||||
if (Active.Map && Active.Mapper) menustring += '<li class="rc-delete ' + disabled + '"><div class="rc-icon"></div>Delete<div class="rc-keyboard">Ctrl+D</div></li>'
|
||||
|
||||
if (Active.Topic) {
|
||||
menustring += '<li class="rc-center"><div class="rc-icon"></div>Center this topic<div class="rc-keyboard">Alt+E</div></li>'
|
||||
}
|
||||
|
||||
menustring += '<li class="rc-popout"><div class="rc-icon"></div>Open in new tab</li>'
|
||||
|
||||
if (Active.Mapper) {
|
||||
const options = outdent`
|
||||
<ul>
|
||||
<li class="changeP toCommons"><div class="rc-perm-icon"></div>commons</li>
|
||||
<li class="changeP toPublic"><div class="rc-perm-icon"></div>public</li>
|
||||
<li class="changeP toPrivate"><div class="rc-perm-icon"></div>private</li>
|
||||
</ul>`
|
||||
|
||||
menustring += '<li class="rc-spacer"></li>'
|
||||
|
||||
menustring += outdent`
|
||||
<li class="rc-permission">
|
||||
<div class="rc-icon"></div>
|
||||
Change permissions
|
||||
${options}
|
||||
<div class="expandLi"></div>
|
||||
</li>`
|
||||
|
||||
menustring += '<li class="rc-metacode"><div class="rc-icon"></div>Change metacode<div id="metacodeOptionsWrapper"></div><div class="expandLi"></div></li>'
|
||||
}
|
||||
if (Active.Topic) {
|
||||
if (!Active.Mapper) {
|
||||
menustring += '<li class="rc-spacer"></li>'
|
||||
}
|
||||
|
||||
// set up the get sibling menu as a "lazy load"
|
||||
// only fill in the submenu when they hover over the get siblings list item
|
||||
const siblingMenu = outdent`
|
||||
<ul id="fetchSiblingList">
|
||||
<li class="fetchAll">All<div class="rc-keyboard">Alt+R</div></li>
|
||||
<li id="loadingSiblings"></li>
|
||||
</ul>`
|
||||
menustring += '<li class="rc-siblings"><div class="rc-icon"></div>Reveal siblings' + siblingMenu + '<div class="expandLi"></div></li>'
|
||||
}
|
||||
|
||||
menustring += '</ul>'
|
||||
rightclickmenu.innerHTML = menustring
|
||||
|
||||
// position the menu where the click happened
|
||||
const position = {}
|
||||
const RIGHTCLICK_WIDTH = 300
|
||||
const RIGHTCLICK_HEIGHT = 144 // this does vary somewhat, but we can use static
|
||||
const SUBMENUS_WIDTH = 256
|
||||
const MAX_SUBMENU_HEIGHT = 270
|
||||
const windowWidth = $(window).width()
|
||||
const windowHeight = $(window).height()
|
||||
|
||||
if (windowWidth - e.clientX < SUBMENUS_WIDTH) {
|
||||
position.right = windowWidth - e.clientX
|
||||
$(rightclickmenu).addClass('moveMenusToLeft')
|
||||
} else if (windowWidth - e.clientX < RIGHTCLICK_WIDTH) {
|
||||
position.right = windowWidth - e.clientX
|
||||
} else if (windowWidth - e.clientX < RIGHTCLICK_WIDTH + SUBMENUS_WIDTH) {
|
||||
position.left = e.clientX
|
||||
$(rightclickmenu).addClass('moveMenusToLeft')
|
||||
} else {
|
||||
position.left = e.clientX
|
||||
}
|
||||
|
||||
if (windowHeight - e.clientY < MAX_SUBMENU_HEIGHT) {
|
||||
position.bottom = windowHeight - e.clientY
|
||||
$(rightclickmenu).addClass('moveMenusUp')
|
||||
} else if (windowHeight - e.clientY < RIGHTCLICK_HEIGHT + MAX_SUBMENU_HEIGHT) {
|
||||
position.top = e.clientY
|
||||
$(rightclickmenu).addClass('moveMenusUp')
|
||||
} else {
|
||||
position.top = e.clientY
|
||||
}
|
||||
|
||||
$(rightclickmenu).css(position)
|
||||
// add the menu to the page
|
||||
$('#wrapper').append(rightclickmenu)
|
||||
|
||||
ReactDOM.render(
|
||||
React.createElement(MetacodeSelect, {
|
||||
onMetacodeSelect: metacodeId => {
|
||||
if (Selected.Nodes.length > 1) {
|
||||
// batch update multiple topics
|
||||
Control.updateSelectedMetacodes(metacodeId)
|
||||
} else {
|
||||
const topic = DataModel.Topics.get(node.id)
|
||||
topic.save({
|
||||
metacode_id: metacodeId
|
||||
})
|
||||
}
|
||||
$(rightclickmenu).remove()
|
||||
},
|
||||
metacodeSets: ReactApp.metacodeSets
|
||||
}),
|
||||
document.getElementById('metacodeOptionsWrapper')
|
||||
)
|
||||
|
||||
// attach events to clicks on the list items
|
||||
|
||||
// delete the selected things from the database
|
||||
if (authorized) {
|
||||
$('.rc-delete').click(function() {
|
||||
$('.rightclickmenu').remove()
|
||||
Control.deleteSelected()
|
||||
})
|
||||
}
|
||||
|
||||
// remove the selected things from the map
|
||||
if (Active.Topic || authorized) {
|
||||
$('.rc-remove').click(function() {
|
||||
$('.rightclickmenu').remove()
|
||||
Control.removeSelectedEdges()
|
||||
Control.removeSelectedNodes()
|
||||
})
|
||||
}
|
||||
|
||||
// hide selected nodes and synapses until refresh
|
||||
$('.rc-hide').click(function() {
|
||||
$('.rightclickmenu').remove()
|
||||
Control.hideSelectedEdges()
|
||||
Control.hideSelectedNodes()
|
||||
})
|
||||
|
||||
// when in radial, center on the topic you picked
|
||||
$('.rc-center').click(function() {
|
||||
$('.rightclickmenu').remove()
|
||||
Topic.centerOn(node.id)
|
||||
})
|
||||
|
||||
// open the entity in a new tab
|
||||
$('.rc-popout').click(function() {
|
||||
$('.rightclickmenu').remove()
|
||||
const win = window.open('/topics/' + node.id, '_blank')
|
||||
win.focus()
|
||||
})
|
||||
|
||||
// change the permission of all the selected nodes and synapses that you were the originator of
|
||||
$('.rc-permission li').click(function() {
|
||||
$('.rightclickmenu').remove()
|
||||
// $(this).text() will be 'commons' 'public' or 'private'
|
||||
Control.updateSelectedPermissions($(this).text())
|
||||
})
|
||||
|
||||
// fetch relatives
|
||||
let fetchSent = false
|
||||
$('.rc-siblings').hover(function() {
|
||||
if (!fetchSent) {
|
||||
JIT.populateRightClickSiblings(node)
|
||||
fetchSent = true
|
||||
}
|
||||
})
|
||||
$('.rc-siblings .fetchAll').click(function() {
|
||||
$('.rightclickmenu').remove()
|
||||
// data-id is a metacode id
|
||||
Topic.fetchRelatives(node)
|
||||
})
|
||||
}, // selectNodeOnRightClickHandler,
|
||||
populateRightClickSiblings: function(node) {
|
||||
// depending on how many topics are selected, do different things
|
||||
const topic = node.getData('topic')
|
||||
|
||||
// add a loading icon for now
|
||||
const loader = new CanvasLoader('loadingSiblings')
|
||||
loader.setColor('#4FC059') // default is '#000000'
|
||||
loader.setDiameter(15) // default is 40
|
||||
loader.setDensity(41) // default is 40
|
||||
loader.setRange(0.9) // default is 1.3
|
||||
loader.show() // Hidden by default
|
||||
|
||||
const topics = DataModel.Topics.map(function(t) { return t.id })
|
||||
const topicsString = topics.join()
|
||||
|
||||
const successCallback = function(data) {
|
||||
$('#loadingSiblings').remove()
|
||||
|
||||
for (var key in data) {
|
||||
const string = `${DataModel.Metacodes.get(key).get('name')} (${data[key]})`
|
||||
$('#fetchSiblingList').append(`<li class="getSiblings" data-id="${key}">${string}</li>`)
|
||||
}
|
||||
|
||||
$('.rc-siblings .getSiblings').click(function() {
|
||||
$('.rightclickmenu').remove()
|
||||
// data-id is a metacode id
|
||||
Topic.fetchRelatives(node, $(this).attr('data-id'))
|
||||
})
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: '/topics/' + topic.id + '/relative_numbers.json?network=' + topicsString,
|
||||
success: successCallback,
|
||||
error: function() {}
|
||||
})
|
||||
},
|
||||
selectEdgeOnClickHandler: function(adj, e) {
|
||||
if (Visualize.mGraph.busy) return
|
||||
|
||||
|
|
113
frontend/src/Metamaps/Views/ContextMenu.js
Normal file
113
frontend/src/Metamaps/Views/ContextMenu.js
Normal file
|
@ -0,0 +1,113 @@
|
|||
import Control from '../Control'
|
||||
import DataModel from '../DataModel'
|
||||
import ReactApp from '../GlobalUI/ReactApp'
|
||||
import Selected from '../Selected'
|
||||
import Topic from '../Topic'
|
||||
|
||||
const ContextMenu = {
|
||||
clickedNode: null,
|
||||
clickedEdge: null,
|
||||
pos: {x: 0, y: 0},
|
||||
siblingsData: null,
|
||||
selectNode: (node, pos) => {
|
||||
ContextMenu.pos = pos
|
||||
ContextMenu.clickedNode = node
|
||||
ContextMenu.clickedEdge = null
|
||||
ContextMenu.siblingsData = null
|
||||
ReactApp.render()
|
||||
},
|
||||
selectEdge: (edge, pos) => {
|
||||
ContextMenu.pos = pos
|
||||
ContextMenu.clickedNode = null
|
||||
ContextMenu.clickedEdge = edge
|
||||
ContextMenu.siblingsData = null
|
||||
ReactApp.render()
|
||||
},
|
||||
reset: () => {
|
||||
ContextMenu.siblingsData = null
|
||||
ContextMenu.clickedNode = null
|
||||
ContextMenu.clickedEdge = null
|
||||
ReactApp.render()
|
||||
},
|
||||
delete: Control.deleteSelected,
|
||||
remove: () => {
|
||||
Control.removeSelectedEdges()
|
||||
Control.removeSelectedNodes()
|
||||
ContextMenu.reset()
|
||||
},
|
||||
hide: () => {
|
||||
Control.hideSelectedEdges()
|
||||
Control.hideSelectedNodes()
|
||||
ContextMenu.reset()
|
||||
},
|
||||
centerOn: (id) => {
|
||||
Topic.centerOn(id)
|
||||
ContextMenu.reset()
|
||||
},
|
||||
popoutTopic: (id) => {
|
||||
ContextMenu.reset()
|
||||
const win = window.open('/topics/' + id, '_blank')
|
||||
win.focus()
|
||||
},
|
||||
updatePermissions: (permission) => {
|
||||
// will be 'commons' 'public' or 'private'
|
||||
Control.updateSelectedPermissions(permission)
|
||||
ContextMenu.reset()
|
||||
},
|
||||
onMetacodeSelect: (id, metacodeId) => {
|
||||
if (Selected.Nodes.length > 1) {
|
||||
// batch update multiple topics
|
||||
Control.updateSelectedMetacodes(metacodeId)
|
||||
} else {
|
||||
const topic = DataModel.Topics.get(id)
|
||||
topic.save({
|
||||
metacode_id: metacodeId
|
||||
})
|
||||
}
|
||||
ContextMenu.reset()
|
||||
},
|
||||
fetchRelatives: (node, metacodeId) => {
|
||||
Topic.fetchRelatives(node, metacodeId)
|
||||
ContextMenu.reset()
|
||||
},
|
||||
populateSiblings: function(id) {
|
||||
// depending on how many topics are selected, do different things
|
||||
|
||||
// add a loading icon for now
|
||||
/*const loader = new CanvasLoader('loadingSiblings')
|
||||
loader.setColor('#4FC059') // default is '#000000'
|
||||
loader.setDiameter(15) // default is 40
|
||||
loader.setDensity(41) // default is 40
|
||||
loader.setRange(0.9) // default is 1.3
|
||||
loader.show() // Hidden by default*/
|
||||
|
||||
const topics = DataModel.Topics.map(function(t) { return t.id })
|
||||
const topicsString = topics.join()
|
||||
|
||||
const successCallback = function(data) {
|
||||
ContextMenu.siblingsData = data
|
||||
ReactApp.render()
|
||||
/*$('#loadingSiblings').remove()
|
||||
|
||||
for (var key in data) {
|
||||
const string = `${DataModel.Metacodes.get(key).get('name')} (${data[key]})`
|
||||
$('#fetchSiblingList').append(`<li class="getSiblings" data-id="${key}">${string}</li>`)
|
||||
}
|
||||
|
||||
$('.rc-siblings .getSiblings').click(function() {
|
||||
$('.rightclickmenu').remove()
|
||||
// data-id is a metacode id
|
||||
Topic.fetchRelatives(node, $(this).attr('data-id'))
|
||||
})*/
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: '/topics/' + id + '/relative_numbers.json?network=' + topicsString,
|
||||
success: successCallback,
|
||||
error: function() {}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default ContextMenu
|
|
@ -1,5 +1,6 @@
|
|||
/* global $ */
|
||||
|
||||
import ContextMenu from './ContextMenu'
|
||||
import ExploreMaps from './ExploreMaps'
|
||||
import ChatView from './ChatView'
|
||||
import VideoView from './VideoView'
|
||||
|
@ -12,6 +13,7 @@ const Views = {
|
|||
$(document).on(JUNTO_UPDATED, () => ExploreMaps.render())
|
||||
ChatView.init([serverData['sounds/MM_sounds.mp3'], serverData['sounds/MM_sounds.ogg']])
|
||||
},
|
||||
ContextMenu,
|
||||
ExploreMaps,
|
||||
ChatView,
|
||||
VideoView,
|
||||
|
@ -19,5 +21,5 @@ const Views = {
|
|||
TopicCard
|
||||
}
|
||||
|
||||
export { ExploreMaps, ChatView, VideoView, Room, TopicCard }
|
||||
export { ContextMenu, ExploreMaps, ChatView, VideoView, Room, TopicCard }
|
||||
export default Views
|
||||
|
|
77
frontend/src/components/common/ContextMenu.js
Normal file
77
frontend/src/components/common/ContextMenu.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
|
||||
class ContextMenu extends Component {
|
||||
static propTypes = {
|
||||
node: PropTypes.object,
|
||||
edge: PropTypes.object
|
||||
}
|
||||
|
||||
render () {
|
||||
const style = {
|
||||
position: 'absolute',
|
||||
top: '10px',
|
||||
left: '10px'
|
||||
}
|
||||
return <div className="rightclickmenu" style={style}>
|
||||
<ul>
|
||||
<li className="rc-hide">
|
||||
<div className="rc-icon"></div>Hide until refresh<div className="rc-keyboard">Ctrl+H</div>
|
||||
</li>
|
||||
<li className="rc-remove ">
|
||||
<div className="rc-icon"></div>Remove from map<div className="rc-keyboard">Ctrl+M</div>
|
||||
</li>
|
||||
<li className="rc-delete ">
|
||||
<div className="rc-icon"></div>Delete<div className="rc-keyboard">Ctrl+D</div>
|
||||
</li>
|
||||
<li className="rc-popout">
|
||||
<div className="rc-icon"></div>Open in new tab
|
||||
</li>
|
||||
<li className="rc-spacer"></li>
|
||||
<li className="rc-permission">
|
||||
<div className="rc-icon"></div>Change permissions
|
||||
<ul>
|
||||
<li className="changeP toCommons"><div className="rc-perm-icon"></div>commons</li>
|
||||
<li className="changeP toPublic"><div className="rc-perm-icon"></div>public</li>
|
||||
<li className="changeP toPrivate"><div className="rc-perm-icon"></div>private</li>
|
||||
</ul>
|
||||
<div className="expandLi"></div>
|
||||
</li>
|
||||
<li className="rc-metacode">
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
// position the menu where the click happened
|
||||
/*const position = {}
|
||||
const RIGHTCLICK_WIDTH = 300
|
||||
const RIGHTCLICK_HEIGHT = 144 // this does vary somewhat, but we can use static
|
||||
const SUBMENUS_WIDTH = 256
|
||||
const MAX_SUBMENU_HEIGHT = 270
|
||||
const windowWidth = $(window).width()
|
||||
const windowHeight = $(window).height()
|
||||
|
||||
if (windowWidth - e.clientX < SUBMENUS_WIDTH) {
|
||||
position.right = windowWidth - e.clientX
|
||||
$(rightclickmenu).addClass('moveMenusToLeft')
|
||||
} else if (windowWidth - e.clientX < RIGHTCLICK_WIDTH) {
|
||||
position.right = windowWidth - e.clientX
|
||||
} else if (windowWidth - e.clientX < RIGHTCLICK_WIDTH + SUBMENUS_WIDTH) {
|
||||
position.left = e.clientX
|
||||
$(rightclickmenu).addClass('moveMenusToLeft')
|
||||
} else {
|
||||
position.left = e.clientX
|
||||
}
|
||||
|
||||
if (windowHeight - e.clientY < MAX_SUBMENU_HEIGHT) {
|
||||
position.bottom = windowHeight - e.clientY
|
||||
$(rightclickmenu).addClass('moveMenusUp')
|
||||
} else if (windowHeight - e.clientY < RIGHTCLICK_HEIGHT + MAX_SUBMENU_HEIGHT) {
|
||||
position.top = e.clientY
|
||||
$(rightclickmenu).addClass('moveMenusUp')
|
||||
} else {
|
||||
position.top = e.clientY
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
export default ContextMenu
|
Loading…
Reference in a new issue