lots of fixes

This commit is contained in:
Connor Turland 2017-03-12 22:14:44 -04:00
parent 743e3371eb
commit 959a6837d8
12 changed files with 107 additions and 109 deletions

View file

@ -169,6 +169,9 @@
.upperRightMapButtons { .upperRightMapButtons {
right: 134px; right: 134px;
} }
.unauthenticated .upperRightMapButtons {
right: 115px;
}
.upperRightIcon { .upperRightIcon {
width: 32px; width: 32px;

View file

@ -1,7 +1,6 @@
.viewOnly { .viewOnly {
float: left; float: left;
margin-left: 16px; margin-left: 16px;
display: none;
height: 32px; height: 32px;
border: 1px solid #BDBDBD; border: 1px solid #BDBDBD;
border-radius: 2px; border-radius: 2px;
@ -23,7 +22,7 @@
} }
.requestNotice { .requestNotice {
display: none; display: inline-block;
padding: 0 8px; padding: 0 8px;
} }
@ -42,16 +41,6 @@
.requestNotAccepted { .requestNotAccepted {
background-color: #c04f4f; background-color: #c04f4f;
} }
&.sendRequest .requestAccess {
display: inline-block;
}
&.sentRequest .requestPending {
display: inline-block;
}
&.requestDenied .requestNotAccepted {
display: inline-block;
}
} }
.request_access { .request_access {

View file

@ -18,5 +18,6 @@
Metamaps.ServerData.Mappings = <%= @allmappings.to_json.html_safe %>; Metamaps.ServerData.Mappings = <%= @allmappings.to_json.html_safe %>;
Metamaps.ServerData.Messages = <%= @allmessages.to_json.html_safe %>; Metamaps.ServerData.Messages = <%= @allmessages.to_json.html_safe %>;
Metamaps.ServerData.Stars = <%= @allstars.to_json.html_safe %>; Metamaps.ServerData.Stars = <%= @allstars.to_json.html_safe %>;
Metamaps.ServerData.requests = <%= @allrequests.to_json.html_safe %>;
Metamaps.ServerData.VisualizeType = "ForceDirected"; Metamaps.ServerData.VisualizeType = "ForceDirected";
</script> </script>

View file

@ -18,5 +18,6 @@
Metamaps.ServerData.Mappings = <%= @allmappings.to_json.html_safe %>; Metamaps.ServerData.Mappings = <%= @allmappings.to_json.html_safe %>;
Metamaps.ServerData.Messages = <%= @allmessages.to_json.html_safe %>; Metamaps.ServerData.Messages = <%= @allmessages.to_json.html_safe %>;
Metamaps.ServerData.Stars = <%= @allstars.to_json.html_safe %>; Metamaps.ServerData.Stars = <%= @allstars.to_json.html_safe %>;
Metamaps.ServerData.requests = <%= @allrequests.to_json.html_safe %>;
Metamaps.ServerData.VisualizeType = "ForceDirected"; Metamaps.ServerData.VisualizeType = "ForceDirected";
</script> </script>

View file

@ -101,6 +101,10 @@ const ReactApp = {
return { return {
mapId: self.mapId, mapId: self.mapId,
map: Active.Map, map: Active.Map,
userRequested: Map.userRequested,
requestAnswered: Map.requestAnswered,
requestApproved: Map.requestApproved,
onRequestAccess: Map.requestAccess,
mapIsStarred: Map.mapIsStarred, mapIsStarred: Map.mapIsStarred,
endActiveMap: Map.end, endActiveMap: Map.end,
launchNewMap: Map.launch, launchNewMap: Map.launch,

View file

@ -26,110 +26,108 @@ const Map = {
editedByActiveMapper: 'Metamaps:Map:events:editedByActiveMapper' editedByActiveMapper: 'Metamaps:Map:events:editedByActiveMapper'
}, },
mapIsStarred: false, mapIsStarred: false,
requests: [],
userRequested: false,
requestAnswered: false,
requestApproved: false,
init: function(serverData) { init: function(serverData) {
var self = Map var self = Map
self.mapIsStarred = serverData.mapIsStarred self.mapIsStarred = serverData.mapIsStarred
self.requests = serverData.requests
self.setAccessRequest()
$('#wrapper').mousedown(function(e) { $('#wrapper').mousedown(function(e) {
if (e.button === 1) return false if (e.button === 1) return false
}) })
GlobalUI.CreateMap.emptyForkMapForm = $('#fork_map').html() GlobalUI.CreateMap.emptyForkMapForm = $('#fork_map').html()
InfoBox.init(serverData, function updateThumbnail() { InfoBox.init(serverData, function updateThumbnail() {
self.uploadMapScreenshot() self.uploadMapScreenshot()
}) })
CheatSheet.init(serverData) CheatSheet.init(serverData)
$('.viewOnly .requestAccess').click(self.requestAccess)
$(document).on(Map.events.editedByActiveMapper, self.editedByActiveMapper) $(document).on(Map.events.editedByActiveMapper, self.editedByActiveMapper)
}, },
requestAccess: function() { requestAccess: function() {
$('.viewOnly').removeClass('sendRequest').addClass('sentRequest') const self = Map
self.requests.push({
user_id: Active.Mapper.id,
answered: false,
approved: false
})
self.setAccessRequest()
const mapId = Active.Map.id const mapId = Active.Map.id
$.post({ $.post({
url: `/maps/${mapId}/access_request` url: `/maps/${mapId}/access_request`
}) })
GlobalUI.notifyUser('Map creator will be notified of your request') GlobalUI.notifyUser('Map creator will be notified of your request')
}, },
setAccessRequest: function(requests, activeMapper) { setAccessRequest: function() {
let className = 'isViewOnly ' const self = Map
if (activeMapper) { if (Active.Mapper) {
const request = _find(requests, r => r.user_id === activeMapper.id) const request = _find(self.requests, r => r.user_id === Active.Mapper.id)
if (!request) className += 'sendRequest' if (!request) {
else if (request && !request.answered) className += 'sentRequest' self.userRequested = false
else if (request && request.answered && !request.approved) className += 'requestDenied' self.requestAnswered = false
self.requestApproved = false
}
else if (request && !request.answered) {
self.userRequested = true
self.requestAnswered = false
self.requestApproved = false
}
else if (request && request.answered && !request.approved) {
self.userRequested = true
self.requestAnswered = true
self.requestApproved = false
}
} }
$('.viewOnly').removeClass('sendRequest sentRequest requestDenied').addClass(className) ReactApp.render()
}, },
launch: function(id) { launch: function(id) {
var start = function(data) { const self = Map
Active.Map = new DataModelMap(data.map) var start = function() {
DataModel.Mappers = new DataModel.MapperCollection(data.mappers) document.title = Active.Map.get('name') + ' | Metamaps'
DataModel.Collaborators = new DataModel.MapperCollection(data.collaborators) Map.setAccessRequest()
DataModel.Topics = new DataModel.TopicCollection(data.topics) $('#filter_by_mapper h3').html('MAPPERS') // TODO: rewrite filter box in react
DataModel.Synapses = new DataModel.SynapseCollection(data.synapses)
DataModel.Mappings = new DataModel.MappingCollection(data.mappings)
DataModel.Messages = data.messages
DataModel.Stars = data.stars
DataModel.attachCollectionEvents()
var map = Active.Map
var mapper = Active.Mapper
document.title = map.get('name') + ' | Metamaps'
// add class to .wrapper for specifying whether you can edit the map
if (map.authorizeToEdit(mapper)) {
$('.wrapper').addClass('canEditMap')
} else {
Map.setAccessRequest(data.requests, mapper)
}
// add class to .wrapper for specifying if the map can
// be collaborated on
if (map.get('permission') === 'commons') {
$('.wrapper').addClass('commonsMap')
}
// set filter mapper H3 text
$('#filter_by_mapper h3').html('MAPPERS')
// build and render the visualization
Visualize.type = 'ForceDirected' Visualize.type = 'ForceDirected'
JIT.prepareVizData() JIT.prepareVizData()
// update filters
Filter.reset() Filter.reset()
// reset selected arrays
Selected.reset() Selected.reset()
// set the proper mapinfobox content
InfoBox.load() InfoBox.load()
// these three update the actual filter box with the right list items
Filter.checkMetacodes() Filter.checkMetacodes()
Filter.checkSynapses() Filter.checkSynapses()
Filter.checkMappers() Filter.checkMappers()
Realtime.startActiveMap() Realtime.startActiveMap()
Loading.hide() Loading.hide()
$('#header_content').html(Active.Map.get('name')) // TODO: make this use ReactApp.mobileTitle to set this
// for mobile }
$('#header_content').html(map.get('name')) function isLoaded() {
if (InfoBox.generateBoxHTML) start()
else setTimeout(() => isLoaded(), 50)
}
if (Active.Map && Active.Map.id == id) {
isLoaded()
}
else {
Loading.show()
$.ajax({
url: '/maps/' + id + '/contains.json',
success: function(data) {
Active.Map = new DataModelMap(data.map)
DataModel.Mappers = new DataModel.MapperCollection(data.mappers)
DataModel.Collaborators = new DataModel.MapperCollection(data.collaborators)
DataModel.Topics = new DataModel.TopicCollection(data.topics)
DataModel.Synapses = new DataModel.SynapseCollection(data.synapses)
DataModel.Mappings = new DataModel.MappingCollection(data.mappings)
DataModel.Messages = data.messages
DataModel.Stars = data.stars
DataModel.attachCollectionEvents()
self.requests = data.requests
isLoaded()
}
})
} }
Loading.show()
$.ajax({
url: '/maps/' + id + '/contains.json',
success: start
})
}, },
end: function() { end: function() {
if (Active.Map) { if (Active.Map) {
$('.wrapper').removeClass('canEditMap commonsMap')
AutoLayout.resetSpiral() AutoLayout.resetSpiral()
$('.rightclickmenu').remove() $('.rightclickmenu').remove()

View file

@ -1,14 +0,0 @@
import React, { Component, PropTypes } from 'react'
class Toast extends Component {
static propTypes = {
message: PropTypes.string
}
render () {
const html = {__html: this.props.html}
return <p id="toast" className="toast" dangerouslySetInnerHTML={html} />
}
}
export default Toast

View file

@ -3,13 +3,20 @@ import { Link } from 'react-router'
class UpperLeftUI extends Component { class UpperLeftUI extends Component {
static propTypes = { static propTypes = {
currentUser: PropTypes.object currentUser: PropTypes.object,
map: PropTypes.object,
userRequested: PropTypes.bool,
requestAnswered: PropTypes.bool,
requestApproved: PropTypes.bool,
onRequestClick: PropTypes.func
} }
render () { render () {
const { map, currentUser, userRequested, requestAnswered, requestApproved, onRequestClick } = this.props
return <div className="upperLeftUI"> return <div className="upperLeftUI">
<div className="homeButton"> <div className="homeButton">
<Link to="/">METAMAPS</Link> {currentUser && <Link to="/">METAMAPS</Link>}
{!currentUser && <a href="/">METAMAPS</a>}
</div> </div>
<div className="sidebarSearch"> <div className="sidebarSearch">
<input type="text" className="sidebarSearchField" placeholder="Search for topics, maps, and mappers..." /> <input type="text" className="sidebarSearchField" placeholder="Search for topics, maps, and mappers..." />
@ -17,12 +24,12 @@ class UpperLeftUI extends Component {
<div className="sidebarSearchIcon"></div> <div className="sidebarSearchIcon"></div>
<div className="clearfloat"></div> <div className="clearfloat"></div>
</div> </div>
<div className="viewOnly"> {map && !map.authorizeToEdit(currentUser) && <div className="viewOnly">
<div className="eyeball">View Only</div> <div className="eyeball">View Only</div>
<div className="requestAccess requestNotice">Request Access</div> {currentUser && !userRequested && <div className="requestAccess requestNotice" onClick={onRequestClick}>Request Access</div>}
<div className="requestPending requestNotice">Request Pending</div> {userRequested && !requestAnswered && <div className="requestPending requestNotice">Request Pending</div>}
<div className="requestNotAccepted requestNotice">Request Not Accepted</div> {userRequested && requestAnswered && !requestApproved && <div className="requestNotAccepted requestNotice">Request Not Accepted</div>}
</div> </div>}
<div className="clearfloat"></div> <div className="clearfloat"></div>
</div> </div>
} }

View file

@ -1,7 +1,6 @@
import React, { Component, PropTypes } from 'react' import React, { Component, PropTypes } from 'react'
import MobileHeader from './MobileHeader' import MobileHeader from './MobileHeader'
import Toast from './Toast'
import UpperLeftUI from './UpperLeftUI' import UpperLeftUI from './UpperLeftUI'
import UpperRightUI from './UpperRightUI' import UpperRightUI from './UpperRightUI'
@ -16,7 +15,12 @@ class App extends Component {
mobileTitleWidth: PropTypes.number, mobileTitleWidth: PropTypes.number,
mobileTitleClick: PropTypes.func, mobileTitleClick: PropTypes.func,
openInviteLightbox: PropTypes.func, openInviteLightbox: PropTypes.func,
toggleAccountBox: PropTypes.func toggleAccountBox: PropTypes.func,
map: PropTypes.object,
userRequested: PropTypes.bool,
requestAnswered: PropTypes.bool,
requestApproved: PropTypes.bool,
onRequestAccess: PropTypes.func
} }
static childContextTypes = { static childContextTypes = {
@ -32,7 +36,8 @@ class App extends Component {
render () { render () {
const { children, toast, currentUser, unreadNotificationsCount, openInviteLightbox, const { children, toast, currentUser, unreadNotificationsCount, openInviteLightbox,
mobile, mobileTitle, mobileTitleWidth, mobileTitleClick, location, mobile, mobileTitle, mobileTitleWidth, mobileTitleClick, location,
toggleAccountBox } = this.props toggleAccountBox, map, userRequested, requestAnswered, requestApproved,
onRequestAccess } = this.props
const { pathname } = location || {} const { pathname } = location || {}
const unauthedHome = pathname === '/' && !currentUser const unauthedHome = pathname === '/' && !currentUser
return <div className="wrapper" id="wrapper"> return <div className="wrapper" id="wrapper">
@ -41,13 +46,17 @@ class App extends Component {
mobileTitle={mobileTitle} mobileTitle={mobileTitle}
mobileTitleWidth={mobileTitleWidth} mobileTitleWidth={mobileTitleWidth}
onTitleClick={mobileTitleClick} />} onTitleClick={mobileTitleClick} />}
{!unauthedHome && <UpperLeftUI currentUser={currentUser} />} {!unauthedHome && <UpperLeftUI currentUser={currentUser}
map={map}
userRequested={userRequested}
requestAnswered={requestAnswered}
requestApproved={requestApproved}
onRequestClick={onRequestAccess} />}
{!mobile && <UpperRightUI currentUser={currentUser} {!mobile && <UpperRightUI currentUser={currentUser}
unreadNotificationsCount={unreadNotificationsCount} unreadNotificationsCount={unreadNotificationsCount}
openInviteLightbox={openInviteLightbox} openInviteLightbox={openInviteLightbox}
signInPage={pathname === '/login'} signInPage={pathname === '/login'}
onClickAccount={toggleAccountBox} />} onClickAccount={toggleAccountBox} />}
<Toast message={toast} />
{!mobile && currentUser && <a className='feedback-icon' target='_blank' href='https://hylo.com/c/metamaps'></a>} {!mobile && currentUser && <a className='feedback-icon' target='_blank' href='https://hylo.com/c/metamaps'></a>}
{children} {children}
</div> </div>

View file

@ -10,7 +10,6 @@ class InfoAndHelp extends Component {
onHelpClick: PropTypes.func, onHelpClick: PropTypes.func,
onMapStar: PropTypes.func, onMapStar: PropTypes.func,
onMapUnstar: PropTypes.func, onMapUnstar: PropTypes.func,
onInfoClick: PropTypes.func, onInfoClick: PropTypes.func,
infoBoxhtml: PropTypes.string infoBoxhtml: PropTypes.string
} }
@ -22,9 +21,9 @@ class InfoAndHelp extends Component {
const onStarClick = mapIsStarred ? onMapUnstar : onMapStar const onStarClick = mapIsStarred ? onMapUnstar : onMapStar
return <div className="infoAndHelp"> return <div className="infoAndHelp">
<MapInfoBox map={map} currentUser={currentUser} infoBoxHtml={infoBoxHtml} /> <MapInfoBox map={map} currentUser={currentUser} infoBoxHtml={infoBoxHtml} />
<div className={`starMap infoElement mapElement ${starclassName}`} onClick={onStarClick}> {currentUser && <div className={`starMap infoElement mapElement ${starclassName}`} onClick={onStarClick}>
<div className="tooltipsAbove">{tooltip}</div> <div className="tooltipsAbove">{tooltip}</div>
</div> </div>}
<div className="mapInfoIcon infoElement mapElement" onClick={onInfoClick}> <div className="mapInfoIcon infoElement mapElement" onClick={onInfoClick}>
<div className="tooltipsAbove">Map Info</div> <div className="tooltipsAbove">Map Info</div>
</div> </div>

View file

@ -82,7 +82,7 @@ class MapView extends Component {
filterBoxHtml={filterBoxHtml} /> filterBoxHtml={filterBoxHtml} />
<DataVis /> <DataVis />
<TopicCard {...this.props} /> <TopicCard {...this.props} />
<MapChat {...this.props} onOpen={onChatOpen} onClose={onChatClose} chatOpen={chatOpen} /> {currentUser && <MapChat {...this.props} onOpen={onChatOpen} onClose={onChatClose} chatOpen={chatOpen} />}
<MapControls onClickZoomExtents={onZoomExtents} <MapControls onClickZoomExtents={onZoomExtents}
onClickZoomIn={onZoomIn} onClickZoomIn={onZoomIn}
onClickZoomOut={onZoomOut} /> onClickZoomOut={onZoomOut} />

View file

@ -23,6 +23,7 @@ export default function makeRoutes (currentUser) {
<Route path="maps/:id"> <Route path="maps/:id">
<IndexRoute component={MapView} /> <IndexRoute component={MapView} />
<Route path="conversation" component={MapView} /> <Route path="conversation" component={MapView} />
<Route path="request_access" component={nullComponent} />
</Route> </Route>
<Route path="login" component={nullComponent} /> <Route path="login" component={nullComponent} />
<Route path="join" component={nullComponent} /> <Route path="join" component={nullComponent} />