wip right click in react

This commit is contained in:
Connor Turland 2017-09-12 15:17:15 -04:00
parent 77846cfcb7
commit 6e1878413f
5 changed files with 196 additions and 216 deletions

View file

@ -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'

View file

@ -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

View 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

View file

@ -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

View 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