initial restructuring
This commit is contained in:
parent
1124d76475
commit
701198ef14
46 changed files with 760 additions and 796 deletions
|
@ -775,6 +775,7 @@ label {
|
|||
}
|
||||
.sidebarAccountIcon img {
|
||||
border-radius: 16px;
|
||||
width: 32px;
|
||||
}
|
||||
.sidebarAccountBox {
|
||||
display: none;
|
||||
|
@ -3148,4 +3149,4 @@ script.data-gratipay-username {
|
|||
background: #FFF;
|
||||
cursor: pointer;
|
||||
font-family: din-regular;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,6 @@
|
|||
width:100%;
|
||||
height:100%;
|
||||
position: absolute;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.showcard .permission {
|
||||
|
@ -233,7 +232,7 @@
|
|||
background-repeat:no-repeat;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.contributor {
|
||||
bottom: 7px;
|
||||
margin-left: 40px;
|
||||
|
|
|
@ -46,26 +46,9 @@
|
|||
transition-timing-function: ease-in-out;
|
||||
}*/
|
||||
|
||||
.mapElement {
|
||||
display: none;
|
||||
}
|
||||
.mapPage .mapElement,
|
||||
.topicPage .mapElement {
|
||||
display: block;
|
||||
}
|
||||
.mapPage .mapElementHidden,
|
||||
.topicPage .mapElement.mapInfoBox,
|
||||
.topicPage .mapElement.importDialog {
|
||||
display:none;
|
||||
}
|
||||
.topicPage .starMap {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* loading */
|
||||
|
||||
#loading {
|
||||
display: none;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
position: fixed;
|
||||
|
@ -236,6 +219,14 @@
|
|||
|
||||
/* end upperRightUI */
|
||||
|
||||
/* map wrapper */
|
||||
.mapWrapper {
|
||||
position:absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* end map wrapper */
|
||||
|
||||
/* yield */
|
||||
|
||||
|
@ -356,22 +347,15 @@
|
|||
|
||||
/* infoAndHelp */
|
||||
|
||||
.mapPage .infoAndHelp, .topicPage .infoAndHelp {
|
||||
right: 70px;
|
||||
}
|
||||
.mapPage .openCheatsheet .tooltipsAbove, .topicPage .openCheatsheet .tooltipsAbove {
|
||||
right: 1px;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
.unauthenticated .homePage .infoAndHelp {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.infoAndHelp {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
right: 70px;
|
||||
z-index: 3;
|
||||
width: auto;
|
||||
font-style: italic;
|
||||
|
@ -392,16 +376,12 @@
|
|||
}
|
||||
.mapInfoIcon {
|
||||
position: relative;
|
||||
top: 56px; /* puts it just offscreen */
|
||||
background-image: url(<%= asset_path('mapinfo_sprite.png') %>);
|
||||
background-repeat:no-repeat;
|
||||
background-image: url(<%= asset_path('mapinfo_sprite.png') %>);
|
||||
background-repeat:no-repeat;
|
||||
}
|
||||
.mapInfoIcon:hover {
|
||||
background-position: 0 -32px;
|
||||
}
|
||||
.mapPage .mapInfoIcon {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.starMap {
|
||||
background-image: url(<%= asset_path('starmap_sprite.png') %>);
|
||||
|
@ -430,24 +410,17 @@
|
|||
.mapControls {
|
||||
position: absolute;
|
||||
bottom: 24px;
|
||||
right:-32px; /* puts it just offscreen */
|
||||
right:24px;
|
||||
width:32px;
|
||||
z-index: 3;
|
||||
}
|
||||
.mapPage .mapControls, .topicPage .mapControls {
|
||||
right: 24px;
|
||||
}
|
||||
|
||||
.topicPage .zoomExtents {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mapControl {
|
||||
width:32px;
|
||||
height:32px;
|
||||
background-color: #424242;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 0;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 0;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
|
@ -671,8 +644,11 @@
|
|||
|
||||
/* explore maps */
|
||||
|
||||
#explore {
|
||||
display: none;
|
||||
#react-app {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#exploreMaps {
|
||||
|
|
|
@ -4,7 +4,7 @@ class ApplicationController < ActionController::Base
|
|||
include Pundit
|
||||
include PunditExtra
|
||||
rescue_from Pundit::NotAuthorizedError, with: :handle_unauthorized
|
||||
protect_from_forgery(with: :exception)
|
||||
#protect_from_forgery(with: :exception)
|
||||
|
||||
before_action :invite_link
|
||||
before_action :prepare_exception_notifier
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
<%#
|
||||
# @file
|
||||
# The inner HTML of the account box that comes up in the bottom left
|
||||
#%>
|
||||
|
||||
<% if current_user %>
|
||||
<% account = current_user %>
|
||||
<%= image_tag account.image.url(:sixtyfour), :size => "48x48", :class => "sidebarAccountImage" %>
|
||||
<h3 class="accountHeader"><%= account.name.split[0...1][0] %></h3>
|
||||
<ul>
|
||||
<li class="accountListItem accountSettings">
|
||||
<div class="accountIcon"></div>
|
||||
<%= link_to "Settings", edit_user_url(account) %>
|
||||
</li>
|
||||
<% if account.admin %>
|
||||
<li class="accountListItem accountAdmin">
|
||||
<div class="accountIcon"></div>
|
||||
<%= link_to "Admin", metacodes_path %>
|
||||
</li>
|
||||
<% end %>
|
||||
<li class="accountListItem accountApps">
|
||||
<div class="accountIcon"></div>
|
||||
<%= link_to "Apps", oauth_authorized_applications_path %>
|
||||
</li>
|
||||
<li class="accountListItem accountInvite openLightbox" data-open="invite">
|
||||
<div class="accountIcon"></div>
|
||||
<span>Share Invite</span>
|
||||
</li>
|
||||
<li class="accountListItem accountLogout">
|
||||
<div class="accountIcon"></div>
|
||||
<%= link_to "Sign Out", "/logout", id: "Logout" %>
|
||||
</li>
|
||||
</ul>
|
||||
<% else %>
|
||||
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { class: "loginAnywhere" }) do |f| %>
|
||||
<div class="accountImage"></div>
|
||||
<div class="accountInput accountEmail">
|
||||
<%= f.email_field :email, :placeholder => "Email" %>
|
||||
</div>
|
||||
<div class="accountInput accountPassword">
|
||||
<%= f.password_field :password, :placeholder => "Password" %>
|
||||
</div>
|
||||
<div class="accountSubmit"><%= f.submit "SIGN IN" %></div>
|
||||
<% if devise_mapping.rememberable? -%>
|
||||
<div class="accountRememberMe">
|
||||
<%= f.label :remember_me, "Stay signed in" %>
|
||||
<%= f.check_box :remember_me %>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
||||
<% end -%>
|
||||
<div class="clearfloat"></div>
|
||||
<div class="accountForgotPass">
|
||||
<%- if devise_mapping.recoverable? && controller_name != 'passwords' %>
|
||||
<%= link_to "Forgot password?", new_password_path(resource_name) %>
|
||||
<% end -%>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% # Rails.logger.info(stored_location_for(:user)) %>
|
|
@ -1,17 +0,0 @@
|
|||
<div class="mapControls mapElement">
|
||||
<div class="zoomExtents mapControl"><div class="tooltips">Center View</div></div>
|
||||
<div class="zoomIn mapControl"><div class="tooltips">Zoom In</div></div>
|
||||
<div class="zoomOut mapControl"><div class="tooltips">Zoom Out</div></div>
|
||||
</div>
|
||||
|
||||
<div class="infoAndHelp">
|
||||
<%= render :partial => 'maps/mapinfobox' %>
|
||||
|
||||
<% starred = current_user && @map && current_user.starred_map?(@map)
|
||||
starClass = starred ? 'starred' : ''
|
||||
tooltip = starred ? 'Star' : 'Unstar' %>
|
||||
<div class="starMap infoElement mapElement <%= starClass %>"><div class="tooltipsAbove"><%= tooltip %></div></div>
|
||||
<div class="mapInfoIcon infoElement mapElement"><div class="tooltipsAbove">Map Info</div></div>
|
||||
<div class="openCheatsheet openLightbox infoElement mapElement" data-open="cheatsheet"><div class="tooltipsAbove">Help</div></div>
|
||||
<div class="clearfloat"></div>
|
||||
</div>
|
|
@ -1,107 +0,0 @@
|
|||
|
||||
<!-- from left to right on the screen -->
|
||||
|
||||
<div class="upperLeftUI">
|
||||
<!-- home button -->
|
||||
<div class="homeButton">
|
||||
<a href="<%= root_url %>" <% if current_user && !noHardHomeLink %><%= 'data-router=true' %><% end %>>METAMAPS</a>
|
||||
</div> <!-- end homeButton -->
|
||||
|
||||
<!-- search box -->
|
||||
<div class="sidebarSearch">
|
||||
<input type="text" class="sidebarSearchField" placeholder="Search for topics, maps, and mappers..." />
|
||||
<div id="searchLoading"></div>
|
||||
<div class="sidebarSearchIcon"></div>
|
||||
<div class="clearfloat"></div>
|
||||
</div> <!-- end sidebarSearch -->
|
||||
|
||||
<% request = current_user && @map && @allrequests.find{|a| a.user == current_user}
|
||||
className = (@map and not policy(@map).update?) ? 'isViewOnly ' : ''
|
||||
if @map
|
||||
className += 'sendRequest' if not request
|
||||
className += 'sentRequest' if request and not request.answered
|
||||
className += 'requestDenied' if request and request.answered and not request.approved
|
||||
end %>
|
||||
|
||||
<div class="viewOnly <%= className %>">
|
||||
<div class="eyeball">View Only</div>
|
||||
<% if current_user %>
|
||||
<div class="requestAccess requestNotice">Request Access</div>
|
||||
<div class="requestPending requestNotice">Request Pending</div>
|
||||
<div class="requestNotAccepted requestNotice">Request Not Accepted</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="clearfloat"></div>
|
||||
</div><!-- end upperLeftUI -->
|
||||
|
||||
<div class="upperRightUI">
|
||||
<div class="mapElement upperRightEl upperRightMapButtons">
|
||||
<% if current_user %>
|
||||
<div class="importDialog upperRightEl upperRightIcon mapElement openLightbox" data-open="import-dialog-lightbox">
|
||||
<div class="tooltipsUnder">
|
||||
Import Data
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<!-- filtering -->
|
||||
<div class="sidebarFilter upperRightEl">
|
||||
<div class="sidebarFilterIcon upperRightIcon"><div class="tooltipsUnder">Filter</div></div>
|
||||
<div class="sidebarFilterBox upperRightBox">
|
||||
<%= render :partial => 'shared/filterBox' %>
|
||||
</div>
|
||||
</div> <!-- end sidebarFilter -->
|
||||
|
||||
<% if current_user %>
|
||||
<!-- fork map -->
|
||||
<div class="sidebarFork upperRightEl">
|
||||
<div class="sidebarForkIcon upperRightIcon"><div class="tooltipsUnder">Save To New Map</div></div>
|
||||
</div> <!-- end sidebarFork -->
|
||||
<% end %>
|
||||
|
||||
<div class="clearfloat"></div>
|
||||
</div> <!-- end mapElement -->
|
||||
|
||||
<% if current_user %>
|
||||
<!-- create new map -->
|
||||
<a href="<%= new_map_path %>" target="_blank" class="addMap upperRightEl upperRightIcon">
|
||||
<div class="tooltipsUnder">
|
||||
Create New Map
|
||||
</div>
|
||||
</a><!-- end addMap -->
|
||||
<% end %>
|
||||
|
||||
<script type="text/javascript">
|
||||
Metamaps.ServerData.unreadNotificationsCount = <%= user_unread_notification_count %>
|
||||
</script>
|
||||
<% if current_user.present? %>
|
||||
<span id="notification_icon">
|
||||
<%= link_to notifications_path, class: "notificationsIcon upperRightEl upperRightIcon #{user_unread_notification_count > 0 ? 'unread' : 'read'}" do %>
|
||||
<div class="tooltipsUnder">
|
||||
Notifications
|
||||
</div>
|
||||
<% if user_unread_notification_count > 0 %>
|
||||
<div class="unread-notifications-dot"></div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<!-- Account / Sign in -->
|
||||
<% if !(controller_name == "sessions" && action_name == "new") %>
|
||||
<div class="sidebarAccount upperRightEl">
|
||||
<div class="sidebarAccountIcon"><div class="tooltipsUnder">Account</div>
|
||||
<% if current_user && current_user.image %>
|
||||
<%= image_tag current_user.image.url(:thirtytwo), :size => "32x32" %>
|
||||
<% elsif !current_user %>
|
||||
SIGN IN
|
||||
<div class="accountInnerArrow"></div>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="sidebarAccountBox upperRightBox">
|
||||
<%= render :partial => 'layouts/account' %>
|
||||
</div>
|
||||
</div><!-- end sidebarAccount -->
|
||||
<% end %>
|
||||
<div class="clearfloat"></div>
|
||||
</div><!-- end upperRightUI -->
|
|
@ -6,83 +6,34 @@
|
|||
#%>
|
||||
|
||||
<%= render :partial => 'layouts/head' %>
|
||||
|
||||
<body class="<%= authenticated? ? "authenticated" : "unauthenticated" %> controller-<%= controller_name %> action-<%= action_name %>">
|
||||
|
||||
<div id="chat-box-wrapper"></div>
|
||||
|
||||
<a class='feedback-icon' target='_blank' href='https://hylo.com/c/metamaps'></a>
|
||||
|
||||
<%= content_tag :div, class: "main" do %>
|
||||
|
||||
<% classes = action_name == "home" ? "homePage" : ""
|
||||
classes += action_name == "home" && authenticated? ? " explorePage" : ""
|
||||
classes += controller_name == "maps" && action_name == "index" ? " explorePage" : ""
|
||||
if controller_name == "maps" && action_name == "show"
|
||||
classes += " mapPage"
|
||||
if policy(@map).update?
|
||||
classes += " canEditMap"
|
||||
end
|
||||
if @map.permission == "commons"
|
||||
classes += " commonsMap"
|
||||
end
|
||||
end
|
||||
classes += controller_name == "topics" && action_name == "show" ? " topicPage" : ""
|
||||
%>
|
||||
|
||||
<div class="wrapper <%= classes %>" id="wrapper">
|
||||
|
||||
<%= render :partial => 'layouts/upperelements', :locals => { :noHardHomeLink => controller_name == "notifications" ? true : false } %>
|
||||
|
||||
<%= yield %>
|
||||
|
||||
<div class="showcard mapElement mapElementHidden" id="showcard"></div> <!-- the topic card -->
|
||||
<% if authenticated? %>
|
||||
<% # for creating and pulling in topics and synapses %>
|
||||
<% if controller_name == 'maps' && action_name == "conversation" %>
|
||||
<%= render :partial => 'maps/newtopicsecret' %>
|
||||
<% else %>
|
||||
<%= render :partial => 'maps/newtopic' %>
|
||||
<% end %>
|
||||
<%= render :partial => 'maps/newsynapse' %>
|
||||
<% # for populating the change metacode list on the topic card %>
|
||||
<%= render :partial => 'shared/metacodeoptions' %>
|
||||
<% end %>
|
||||
<%= render :partial => 'layouts/lowermapelements' %>
|
||||
|
||||
<div id="explore"></div>
|
||||
|
||||
<% if !(controller_name == 'maps' && action_name == "conversation") %>
|
||||
<div id="instructions">
|
||||
<div class="addTopic">
|
||||
Double-click to<br>add a topic
|
||||
</div>
|
||||
<div class="tabKey">
|
||||
Use Tab & Shift+Tab to select a metacode
|
||||
</div>
|
||||
<div class="enterKey">
|
||||
Press Enter to add the topic
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div id="infovis"></div>
|
||||
<%= render :partial => 'layouts/mobilemenu' %>
|
||||
|
||||
<p id="toast" class="toast">
|
||||
<% if devise_error_messages? %>
|
||||
<%= devise_error_messages! %>
|
||||
<% end %>
|
||||
<% if notice %>
|
||||
<%= notice %>
|
||||
<% end %>
|
||||
<% if alert %>
|
||||
<%= alert %>
|
||||
<% end %>
|
||||
</p>
|
||||
<div id="loading"></div>
|
||||
</div>
|
||||
|
||||
<%= content_tag :div, class: "main", id: "react-app" do %>
|
||||
<%= yield %>
|
||||
<%= render :partial => 'layouts/mobilemenu' %>
|
||||
<% end %>
|
||||
|
||||
<% if devise_error_messages? %>
|
||||
<%= devise_error_messages! %>
|
||||
<% end %>
|
||||
<% if notice %>
|
||||
<%= notice %>
|
||||
<% end %>
|
||||
<% if alert %>
|
||||
<%= alert %>
|
||||
<% end %>
|
||||
<% if authenticated? %>
|
||||
<% # for creating and pulling in topics and synapses %>
|
||||
<% if controller_name == 'maps' && action_name == "conversation" %>
|
||||
<%= render :partial => 'maps/newtopicsecret' %>
|
||||
<% else %>
|
||||
<%= render :partial => 'maps/newtopic' %>
|
||||
<% end %>
|
||||
<%= render :partial => 'maps/newsynapse' %>
|
||||
<% # for populating the change metacode list on the topic card %>
|
||||
<%= render :partial => 'shared/metacodeoptions' %>
|
||||
<% end %>
|
||||
<div id="loading"></div>
|
||||
<script type="text/javascript">
|
||||
Metamaps.ServerData.unreadNotificationsCount = <%= user_unread_notification_count %>
|
||||
Metamaps.ServerData.mapIsStarred = <%= current_user && @map && current_user.starred_map?(@map) ? true : false %>
|
||||
</script>
|
||||
<%= render :partial => 'layouts/foot' %>
|
||||
|
|
|
@ -4,7 +4,7 @@ import React from 'react'
|
|||
import ReactDOM from 'react-dom'
|
||||
import outdent from 'outdent'
|
||||
|
||||
import ImportDialogBox from '../../components/ImportDialogBox'
|
||||
import ImportDialogBox from '../../components/MapView/ImportDialogBox'
|
||||
|
||||
import PasteInput from '../PasteInput'
|
||||
import Map from '../Map'
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
/* global $ */
|
||||
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
|
||||
import Active from '../Active'
|
||||
import NotificationIconComponent from '../../components/NotificationIcon'
|
||||
|
||||
const NotificationIcon = {
|
||||
unreadNotificationsCount: null,
|
||||
|
||||
init: function(serverData) {
|
||||
const self = NotificationIcon
|
||||
self.unreadNotificationsCount = serverData.unreadNotificationsCount
|
||||
self.render()
|
||||
},
|
||||
render: function(newUnreadCount = null) {
|
||||
if (newUnreadCount !== null) {
|
||||
NotificationIcon.unreadNotificationsCount = newUnreadCount
|
||||
}
|
||||
|
||||
if (Active.Mapper !== null) {
|
||||
ReactDOM.render(React.createElement(NotificationIconComponent, {
|
||||
unreadNotificationsCount: NotificationIcon.unreadNotificationsCount
|
||||
}), $('#notification_icon').get(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default NotificationIcon
|
133
frontend/src/Metamaps/GlobalUI/ReactApp.js
Normal file
133
frontend/src/Metamaps/GlobalUI/ReactApp.js
Normal file
|
@ -0,0 +1,133 @@
|
|||
/* global $ */
|
||||
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Router, browserHistory } from 'react-router'
|
||||
|
||||
import { merge } from 'lodash'
|
||||
|
||||
import { notifyUser } from './index.js'
|
||||
import Active from '../Active'
|
||||
import DataModel from '../DataModel'
|
||||
import { ExploreMaps, ChatView, TopicCard } from '../Views'
|
||||
import Realtime from '../Realtime'
|
||||
import Map from '../Map'
|
||||
import Topic from '../Topic'
|
||||
import makeRoutes from '../../components/makeRoutes'
|
||||
let routes
|
||||
|
||||
const ReactApp = {
|
||||
mapId: null,
|
||||
unreadNotificationsCount: 0,
|
||||
mapIsStarred: false,
|
||||
init: function(serverData) {
|
||||
const self = ReactApp
|
||||
self.unreadNotificationsCount = serverData.unreadNotificationsCount
|
||||
self.mapIsStarred = serverData.mapIsStarred
|
||||
routes = makeRoutes()
|
||||
self.render()
|
||||
},
|
||||
handleUpdate: function(location) {
|
||||
const self = ReactApp
|
||||
// TODO: also handle page title updates
|
||||
switch (this.state.location.pathname.split('/')[1]) {
|
||||
case '':
|
||||
case 'explore':
|
||||
ExploreMaps.updateFromPath(this.state.location.pathname)
|
||||
self.mapId = null
|
||||
Active.Map = null
|
||||
Active.Topic = null
|
||||
break
|
||||
case 'topics':
|
||||
break
|
||||
case 'maps':
|
||||
self.mapId = this.state.location.pathname.split('/')[2]
|
||||
break
|
||||
}
|
||||
self.render()
|
||||
// track using google analytics here
|
||||
//window.ga && window.ga('send', 'pageview', location.pathname, {title: document.title})
|
||||
},
|
||||
render: function() {
|
||||
const self = ReactApp
|
||||
const createElement = (Component, props) => <Component {...props} {...self.getProps()}/>
|
||||
const app = <Router createElement={createElement} routes={routes} history={browserHistory} onUpdate={self.handleUpdate} />
|
||||
ReactDOM.render(app, document.getElementById('react-app'))
|
||||
},
|
||||
getProps: function() {
|
||||
const self = ReactApp
|
||||
return merge({
|
||||
unreadNotificationsCount: self.unreadNotificationsCount,
|
||||
currentUser: Active.Mapper
|
||||
},
|
||||
self.getMapProps(),
|
||||
self.getTopicProps(),
|
||||
self.getMapsProps(),
|
||||
self.getTopicCardProps(),
|
||||
self.getChatProps())
|
||||
},
|
||||
getMapProps: function() {
|
||||
const self = ReactApp
|
||||
return {
|
||||
mapId: self.mapId,
|
||||
map: Active.Map,
|
||||
mapIsStarred: self.mapIsStarred,
|
||||
endActiveMap: Map.end,
|
||||
launchNewMap: Map.launch
|
||||
}
|
||||
},
|
||||
getTopicCardProps: function() {
|
||||
const self = ReactApp
|
||||
return {
|
||||
openTopic: TopicCard.openTopic,
|
||||
metacodeSets: TopicCard.metacodeSets,
|
||||
updateTopic: TopicCard.updateTopic,
|
||||
onTopicFollow: TopicCard.onTopicFollow,
|
||||
redrawCanvas: TopicCard.redrawCanvas
|
||||
}
|
||||
},
|
||||
getTopicProps: function() {
|
||||
const self = ReactApp
|
||||
return {
|
||||
topic: Active.Topic
|
||||
}
|
||||
},
|
||||
getMapsProps: function() {
|
||||
const self = ReactApp
|
||||
return {
|
||||
section: ExploreMaps.collection && ExploreMaps.collection.id,
|
||||
maps: ExploreMaps.collection,
|
||||
juntoState: Realtime.juntoState,
|
||||
moreToLoad: ExploreMaps.collection && ExploreMaps.collection.page !== 'loadedAll',
|
||||
user: ExploreMaps.collection && ExploreMaps.collection.id === 'mapper' ? ExploreMaps.mapper : null,
|
||||
loadMore: ExploreMaps.loadMore,
|
||||
pending: ExploreMaps.pending,
|
||||
onStar: ExploreMaps.onStar,
|
||||
onRequest: ExploreMaps.onRequest,
|
||||
onMapFollow: ExploreMaps.onMapFollow
|
||||
}
|
||||
},
|
||||
getChatProps: function() {
|
||||
const self = ReactApp
|
||||
return {
|
||||
conversationLive: ChatView.conversationLive,
|
||||
isParticipating: ChatView.isParticipating,
|
||||
onOpen: ChatView.onOpen,
|
||||
onClose: ChatView.onClose,
|
||||
leaveCall: Realtime.leaveCall,
|
||||
joinCall: Realtime.joinCall,
|
||||
inviteACall: Realtime.inviteACall,
|
||||
inviteToJoin: Realtime.inviteToJoin,
|
||||
participants: ChatView.participants ? ChatView.participants.models.map(p => p.attributes) : [],
|
||||
messages: ChatView.messages ? ChatView.messages.models.map(m => m.attributes) : [],
|
||||
videoToggleClick: ChatView.videoToggleClick,
|
||||
cursorToggleClick: ChatView.cursorToggleClick,
|
||||
soundToggleClick: ChatView.soundToggleClick,
|
||||
inputBlur: ChatView.inputBlur,
|
||||
inputFocus: ChatView.inputFocus,
|
||||
handleInputMessage: ChatView.handleInputMessage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default ReactApp
|
|
@ -1,7 +1,6 @@
|
|||
/* global $, Hogan, Bloodhound, CanvasLoader */
|
||||
|
||||
import Active from '../Active'
|
||||
import Router from '../Router'
|
||||
|
||||
const Search = {
|
||||
locked: false,
|
||||
|
@ -189,11 +188,11 @@ const Search = {
|
|||
|
||||
if (['topic', 'map', 'mapper'].indexOf(datum.rtype) !== -1) {
|
||||
if (datum.rtype === 'topic') {
|
||||
Router.topics(datum.id)
|
||||
// TODO: navigate to topic datum.id
|
||||
} else if (datum.rtype === 'map') {
|
||||
Router.maps(datum.id)
|
||||
// TODO: navigate to map datum.id
|
||||
} else if (datum.rtype === 'mapper') {
|
||||
Router.explore('mapper', datum.id)
|
||||
// TODO: navigate to mapper section datum.id
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -4,11 +4,11 @@ import clipboard from 'clipboard-js'
|
|||
|
||||
import Create from '../Create'
|
||||
|
||||
import ReactApp from './ReactApp'
|
||||
import Search from './Search'
|
||||
import CreateMap from './CreateMap'
|
||||
import Account from './Account'
|
||||
import ImportDialog from './ImportDialog'
|
||||
import NotificationIcon from './NotificationIcon'
|
||||
|
||||
const GlobalUI = {
|
||||
notifyTimeout: null,
|
||||
|
@ -18,11 +18,11 @@ const GlobalUI = {
|
|||
init: function(serverData) {
|
||||
const self = GlobalUI
|
||||
|
||||
self.ReactApp.init(serverData)
|
||||
self.Search.init(serverData)
|
||||
self.CreateMap.init(serverData)
|
||||
self.Account.init(serverData)
|
||||
self.ImportDialog.init(serverData, self.openLightbox, self.closeLightbox)
|
||||
self.NotificationIcon.init(serverData)
|
||||
|
||||
if ($('#toast').html().trim()) self.notifyUser($('#toast').html())
|
||||
|
||||
|
@ -153,5 +153,5 @@ const GlobalUI = {
|
|||
}
|
||||
}
|
||||
|
||||
export { Search, CreateMap, Account, ImportDialog, NotificationIcon }
|
||||
export { ReactApp, Search, CreateMap, Account, ImportDialog }
|
||||
export default GlobalUI
|
||||
|
|
|
@ -5,7 +5,6 @@ import outdent from 'outdent'
|
|||
import Active from '../Active'
|
||||
import DataModel from '../DataModel'
|
||||
import GlobalUI from '../GlobalUI'
|
||||
import Router from '../Router'
|
||||
import Util from '../Util'
|
||||
|
||||
const InfoBox = {
|
||||
|
@ -192,7 +191,6 @@ const InfoBox = {
|
|||
$('.mapContributors .tip').unbind().click(function(event) {
|
||||
event.stopPropagation()
|
||||
})
|
||||
$('.mapContributors .tip li a').click(Router.intercept)
|
||||
|
||||
$('.mapInfoBox').unbind('.hideTip').bind('click.hideTip', function() {
|
||||
$('.mapContributors .tip').hide()
|
||||
|
@ -393,7 +391,7 @@ const InfoBox = {
|
|||
DataModel.Maps.Mine.remove(map)
|
||||
DataModel.Maps.Shared.remove(map)
|
||||
map.destroy()
|
||||
Router.home()
|
||||
// TODO: navigate home
|
||||
GlobalUI.notifyUser('Map eliminated')
|
||||
} else if (!authorized) {
|
||||
window.alert("Hey now. We can't just go around willy nilly deleting other people's maps now can we? Run off and find something constructive to do, eh?")
|
||||
|
|
|
@ -13,7 +13,6 @@ import GlobalUI from '../GlobalUI'
|
|||
import JIT from '../JIT'
|
||||
import Loading from '../Loading'
|
||||
import Realtime from '../Realtime'
|
||||
import Router from '../Router'
|
||||
import Selected from '../Selected'
|
||||
import SynapseCard from '../SynapseCard'
|
||||
import TopicCard from '../Views/TopicCard'
|
||||
|
@ -132,7 +131,7 @@ const Map = {
|
|||
// for mobile
|
||||
$('#header_content').html(map.get('name'))
|
||||
}
|
||||
|
||||
Loading.show()
|
||||
$.ajax({
|
||||
url: '/maps/' + id + '/contains.json',
|
||||
success: start
|
||||
|
@ -232,7 +231,7 @@ const Map = {
|
|||
var map = Active.Map
|
||||
DataModel.Maps.Active.remove(map)
|
||||
DataModel.Maps.Featured.remove(map)
|
||||
Router.home()
|
||||
// TODO: navigate home
|
||||
GlobalUI.notifyUser('Sorry! That map has been changed to Private.')
|
||||
},
|
||||
cantEditNow: function() {
|
||||
|
@ -245,7 +244,7 @@ const Map = {
|
|||
confirmString += 'Do you want to reload and enable realtime collaboration?'
|
||||
var c = window.confirm(confirmString)
|
||||
if (c) {
|
||||
Router.maps(Active.Map.id)
|
||||
// TODO: reload the map somehow
|
||||
}
|
||||
},
|
||||
editedByActiveMapper: function() {
|
||||
|
|
|
@ -1,244 +0,0 @@
|
|||
/* global $ */
|
||||
|
||||
import Backbone from 'backbone'
|
||||
try { Backbone.$ = window.$ } catch (err) {}
|
||||
|
||||
import Active from './Active'
|
||||
import DataModel from './DataModel'
|
||||
import GlobalUI from './GlobalUI'
|
||||
import Loading from './Loading'
|
||||
import Map from './Map'
|
||||
import Topic from './Topic'
|
||||
import Views from './Views'
|
||||
import Visualize from './Visualize'
|
||||
|
||||
const _Router = Backbone.Router.extend({
|
||||
currentPage: '',
|
||||
currentSection: '',
|
||||
timeoutId: undefined,
|
||||
routes: {
|
||||
'': 'home', // #home
|
||||
'explore/:section': 'explore', // #explore/active
|
||||
'explore/:section/:id': 'explore', // #explore/mapper/1234
|
||||
'maps/:id': 'maps', // #maps/7
|
||||
'topics/:id': 'topics' // #topics/7
|
||||
},
|
||||
home: function() {
|
||||
let self = this
|
||||
clearTimeout(this.timeoutId)
|
||||
|
||||
if (Active.Mapper) document.title = 'Explore Active Maps | Metamaps'
|
||||
else document.title = 'Home | Metamaps'
|
||||
|
||||
this.currentSection = ''
|
||||
this.currentPage = ''
|
||||
$('.wrapper').removeClass('mapPage topicPage')
|
||||
|
||||
var classes = Active.Mapper ? 'homePage explorePage' : 'homePage'
|
||||
$('.wrapper').addClass(classes)
|
||||
|
||||
var navigate = function() {
|
||||
self.timeoutId = setTimeout(function() {
|
||||
self.navigateAndTrack('')
|
||||
}, 300)
|
||||
}
|
||||
|
||||
// all this only for the logged in home page
|
||||
if (Active.Mapper) {
|
||||
$('.homeButton a').attr('href', '/')
|
||||
GlobalUI.hideDiv('#yield')
|
||||
|
||||
GlobalUI.showDiv('#explore')
|
||||
|
||||
Views.ExploreMaps.setCollection(DataModel.Maps.Active)
|
||||
if (DataModel.Maps.Active.length === 0) {
|
||||
Views.ExploreMaps.pending = true
|
||||
DataModel.Maps.Active.getMaps(navigate) // this will trigger an explore maps render
|
||||
} else {
|
||||
Views.ExploreMaps.render(navigate)
|
||||
}
|
||||
} else {
|
||||
// logged out home page
|
||||
GlobalUI.hideDiv('#explore')
|
||||
GlobalUI.showDiv('#yield')
|
||||
this.timeoutId = setTimeout(navigate, 500)
|
||||
}
|
||||
|
||||
GlobalUI.hideDiv('#infovis')
|
||||
GlobalUI.hideDiv('#instructions')
|
||||
Map.end()
|
||||
Topic.end()
|
||||
Active.Map = null
|
||||
Active.Topic = null
|
||||
},
|
||||
explore: function(section, id) {
|
||||
var self = this
|
||||
clearTimeout(this.timeoutId)
|
||||
|
||||
// just capitalize the variable section
|
||||
// either 'featured', 'mapper', or 'active'
|
||||
var capitalize = section.charAt(0).toUpperCase() + section.slice(1)
|
||||
|
||||
if (section === 'shared' || section === 'featured' || section === 'active' || section === 'starred') {
|
||||
document.title = 'Explore ' + capitalize + ' Maps | Metamaps'
|
||||
} else if (section === 'mapper') {
|
||||
$.ajax({
|
||||
url: '/users/' + id + '.json',
|
||||
success: function(response) {
|
||||
document.title = response.name + ' | Metamaps'
|
||||
},
|
||||
error: function() {}
|
||||
})
|
||||
} else if (section === 'mine') {
|
||||
document.title = 'Explore My Maps | Metamaps'
|
||||
}
|
||||
|
||||
if (Active.Mapper && section !== 'mapper') $('.homeButton a').attr('href', '/explore/' + section)
|
||||
$('.wrapper').removeClass('homePage mapPage topicPage')
|
||||
$('.wrapper').addClass('explorePage')
|
||||
|
||||
this.currentSection = 'explore'
|
||||
this.currentPage = section
|
||||
|
||||
// this will mean it's a mapper page being loaded
|
||||
if (id) {
|
||||
if (DataModel.Maps.Mapper.mapperId !== id) {
|
||||
// empty the collection if we are trying to load the maps
|
||||
// collection of a different mapper than we had previously
|
||||
DataModel.Maps.Mapper.reset()
|
||||
DataModel.Maps.Mapper.page = 1
|
||||
}
|
||||
DataModel.Maps.Mapper.mapperId = id
|
||||
}
|
||||
|
||||
Views.ExploreMaps.setCollection(DataModel.Maps[capitalize])
|
||||
|
||||
var navigate = function() {
|
||||
var path = '/explore/' + self.currentPage
|
||||
|
||||
// alter url if for mapper profile page
|
||||
if (self.currentPage === 'mapper') {
|
||||
path += '/' + DataModel.Maps.Mapper.mapperId
|
||||
}
|
||||
|
||||
self.navigateAndTrack(path)
|
||||
}
|
||||
var navigateTimeout = function() {
|
||||
self.timeoutId = setTimeout(navigate, 300)
|
||||
}
|
||||
if (DataModel.Maps[capitalize].length === 0) {
|
||||
Loading.show()
|
||||
Views.ExploreMaps.pending = true
|
||||
setTimeout(function() {
|
||||
DataModel.Maps[capitalize].getMaps(navigate) // this will trigger an explore maps render
|
||||
}, 300) // wait 300 milliseconds till the other animations are done to do the fetch
|
||||
} else {
|
||||
if (id) {
|
||||
Views.ExploreMaps.fetchUserThenRender(navigateTimeout)
|
||||
} else {
|
||||
Views.ExploreMaps.render(navigateTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
GlobalUI.showDiv('#explore')
|
||||
GlobalUI.hideDiv('#yield')
|
||||
GlobalUI.hideDiv('#infovis')
|
||||
GlobalUI.hideDiv('#instructions')
|
||||
Map.end()
|
||||
Topic.end()
|
||||
Active.Map = null
|
||||
Active.Topic = null
|
||||
},
|
||||
maps: function(id) {
|
||||
clearTimeout(this.timeoutId)
|
||||
|
||||
this.currentSection = 'map'
|
||||
this.currentPage = id
|
||||
|
||||
$('.wrapper').removeClass('homePage explorePage topicPage')
|
||||
$('.wrapper').addClass('mapPage')
|
||||
// another class will be added to wrapper if you
|
||||
// can edit this map '.canEditMap'
|
||||
|
||||
GlobalUI.hideDiv('#yield')
|
||||
GlobalUI.hideDiv('#explore')
|
||||
|
||||
// clear the visualization, if there was one, before showing its div again
|
||||
if (Visualize.mGraph) {
|
||||
Visualize.clearVisualization()
|
||||
}
|
||||
GlobalUI.showDiv('#infovis')
|
||||
Topic.end()
|
||||
Active.Topic = null
|
||||
|
||||
Loading.show()
|
||||
Map.end()
|
||||
Map.launch(id)
|
||||
},
|
||||
topics: function(id) {
|
||||
clearTimeout(this.timeoutId)
|
||||
|
||||
this.currentSection = 'topic'
|
||||
this.currentPage = id
|
||||
|
||||
$('.wrapper').removeClass('homePage explorePage mapPage')
|
||||
$('.wrapper').addClass('topicPage')
|
||||
|
||||
GlobalUI.hideDiv('#yield')
|
||||
GlobalUI.hideDiv('#explore')
|
||||
|
||||
// clear the visualization, if there was one, before showing its div again
|
||||
if (Visualize.mGraph) {
|
||||
Visualize.clearVisualization()
|
||||
}
|
||||
GlobalUI.showDiv('#infovis')
|
||||
Map.end()
|
||||
Active.Map = null
|
||||
|
||||
Topic.end()
|
||||
Topic.launch(id)
|
||||
}
|
||||
})
|
||||
|
||||
const Router = new _Router()
|
||||
|
||||
Router.navigateAndTrack = (fragment, options) => {
|
||||
Router.navigate(fragment, options)
|
||||
window.ga && window.ga('send', 'pageview', location.pathname, {title: document.title})
|
||||
}
|
||||
|
||||
Router.intercept = function(evt) {
|
||||
var segments
|
||||
|
||||
var href = {
|
||||
prop: $(this).prop('href'),
|
||||
attr: $(this).attr('href')
|
||||
}
|
||||
var root = window.location.protocol + '//' + window.location.host + Backbone.history.options.root
|
||||
|
||||
if (href.prop && href.prop === root) href.attr = ''
|
||||
|
||||
if (href.prop && href.prop.slice(0, root.length) === root) {
|
||||
evt.preventDefault()
|
||||
|
||||
segments = href.attr.split('/')
|
||||
segments.splice(0, 1) // pop off the element created by the first /
|
||||
|
||||
if (href.attr === '') {
|
||||
Router.home()
|
||||
} else {
|
||||
Router[segments[0]](segments[1], segments[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Router.init = function() {
|
||||
Backbone.history.start({
|
||||
silent: true,
|
||||
pushState: true,
|
||||
root: '/'
|
||||
})
|
||||
$(document).on('click', 'a[data-router="true"]', Router.intercept)
|
||||
}
|
||||
|
||||
export default Router
|
|
@ -10,7 +10,6 @@ import Filter from './Filter'
|
|||
import GlobalUI from './GlobalUI'
|
||||
import JIT from './JIT'
|
||||
import Map from './Map'
|
||||
import Router from './Router'
|
||||
import Selected from './Selected'
|
||||
import Settings from './Settings'
|
||||
import SynapseCard from './SynapseCard'
|
||||
|
@ -90,7 +89,6 @@ const Topic = {
|
|||
if (callback) callback()
|
||||
}
|
||||
})
|
||||
Router.navigate('/topics/' + nodeid)
|
||||
Active.Topic = DataModel.Topics.get(nodeid)
|
||||
}
|
||||
},
|
||||
|
|
|
@ -10,7 +10,7 @@ import ReactDOM from 'react-dom'
|
|||
import Active from '../Active'
|
||||
import DataModel from '../DataModel'
|
||||
import Realtime from '../Realtime'
|
||||
import MapChat from '../../components/MapChat'
|
||||
import ReactApp from '../GlobalUI/ReactApp'
|
||||
|
||||
const ChatView = {
|
||||
isOpen: false,
|
||||
|
@ -51,24 +51,7 @@ const ChatView = {
|
|||
render: () => {
|
||||
if (!Active.Map) return
|
||||
const self = ChatView
|
||||
self.mapChat = ReactDOM.render(React.createElement(MapChat, {
|
||||
conversationLive: self.conversationLive,
|
||||
isParticipating: self.isParticipating,
|
||||
onOpen: self.onOpen,
|
||||
onClose: self.onClose,
|
||||
leaveCall: Realtime.leaveCall,
|
||||
joinCall: Realtime.joinCall,
|
||||
inviteACall: Realtime.inviteACall,
|
||||
inviteToJoin: Realtime.inviteToJoin,
|
||||
participants: self.participants.models.map(p => p.attributes),
|
||||
messages: self.messages.models.map(m => m.attributes),
|
||||
videoToggleClick: self.videoToggleClick,
|
||||
cursorToggleClick: self.cursorToggleClick,
|
||||
soundToggleClick: self.soundToggleClick,
|
||||
inputBlur: self.inputBlur,
|
||||
inputFocus: self.inputFocus,
|
||||
handleInputMessage: self.handleInputMessage
|
||||
}), document.getElementById(ChatView.domId))
|
||||
ReactApp.render()
|
||||
},
|
||||
onOpen: () => {
|
||||
$(document).trigger(ChatView.events.openTray)
|
||||
|
|
|
@ -6,6 +6,7 @@ import ReactDOM from 'react-dom' // TODO ensure this isn't a double import
|
|||
import Active from '../Active'
|
||||
import DataModel from '../DataModel'
|
||||
import GlobalUI from '../GlobalUI'
|
||||
import { ReactApp } from '../GlobalUI'
|
||||
import Realtime from '../Realtime'
|
||||
import Loading from '../Loading'
|
||||
import Maps from '../../components/Maps'
|
||||
|
@ -13,6 +14,37 @@ import Maps from '../../components/Maps'
|
|||
const ExploreMaps = {
|
||||
pending: false,
|
||||
mapper: null,
|
||||
updateFromPath: function(path) {
|
||||
const self = ExploreMaps
|
||||
const test = path.split('/')[1]
|
||||
const section = path.split('/')[2]
|
||||
const id = path.split('/')[3]
|
||||
|
||||
if (test === 'explore') {
|
||||
const capitalize = section.charAt(0).toUpperCase() + section.slice(1)
|
||||
self.setCollection(DataModel.Maps[capitalize])
|
||||
} else if (test === '') {
|
||||
self.setCollection(DataModel.Maps.Active)
|
||||
}
|
||||
|
||||
if (id) {
|
||||
if (self.collection.mapperId !== id) {
|
||||
// empty the collection if we are trying to load the maps
|
||||
// collection of a different mapper than we had previously
|
||||
self.collection.reset()
|
||||
self.collection.page = 1
|
||||
self.render()
|
||||
}
|
||||
self.collection.mapperId = id
|
||||
}
|
||||
if (self.collection.length === 0) {
|
||||
Loading.show()
|
||||
self.pending = true
|
||||
self.collection.getMaps()
|
||||
} else {
|
||||
id ? self.fetchUserThenRender() : self.render()
|
||||
}
|
||||
},
|
||||
setCollection: function(collection) {
|
||||
var self = ExploreMaps
|
||||
|
||||
|
@ -26,55 +58,9 @@ const ExploreMaps = {
|
|||
self.collection.on('successOnFetch', self.handleSuccess)
|
||||
self.collection.on('errorOnFetch', self.handleError)
|
||||
},
|
||||
render: function(cb) {
|
||||
render: function() {
|
||||
var self = ExploreMaps
|
||||
|
||||
if (!self.collection) return
|
||||
|
||||
var exploreObj = {
|
||||
currentUser: Active.Mapper,
|
||||
section: self.collection.id,
|
||||
maps: self.collection,
|
||||
juntoState: Realtime.juntoState,
|
||||
moreToLoad: self.collection.page !== 'loadedAll',
|
||||
user: self.collection.id === 'mapper' ? self.mapper : null,
|
||||
loadMore: self.loadMore,
|
||||
pending: self.pending,
|
||||
onStar: function(map) {
|
||||
$.post('/maps/' + map.id + '/star')
|
||||
map.set('star_count', map.get('star_count') + 1)
|
||||
if (DataModel.Stars) DataModel.Stars.push({ user_id: Active.Mapper.id, map_id: map.id })
|
||||
DataModel.Maps.Starred.add(map)
|
||||
GlobalUI.notifyUser('Map is now starred')
|
||||
self.render()
|
||||
},
|
||||
onRequest: function(map) {
|
||||
$.post({
|
||||
url: `/maps/${map.id}/access_request`
|
||||
})
|
||||
GlobalUI.notifyUser('You will be notified by email if request accepted')
|
||||
},
|
||||
onFollow: function(map) {
|
||||
const isFollowing = map.isFollowedBy(Active.Mapper)
|
||||
$.post({
|
||||
url: `/maps/${map.id}/${isFollowing ? 'un' : ''}follow`
|
||||
})
|
||||
if (isFollowing) {
|
||||
GlobalUI.notifyUser('You are no longer following this map')
|
||||
Active.Mapper.unfollowMap(map.id)
|
||||
} else {
|
||||
GlobalUI.notifyUser('You are now following this map')
|
||||
Active.Mapper.followMap(map.id)
|
||||
}
|
||||
self.render()
|
||||
}
|
||||
}
|
||||
ReactDOM.render(
|
||||
React.createElement(Maps, exploreObj),
|
||||
document.getElementById('explore')
|
||||
).resize()
|
||||
|
||||
if (cb) cb()
|
||||
ReactApp.render()
|
||||
Loading.hide()
|
||||
},
|
||||
loadMore: function() {
|
||||
|
@ -85,14 +71,13 @@ const ExploreMaps = {
|
|||
}
|
||||
self.render()
|
||||
},
|
||||
handleSuccess: function(cb) {
|
||||
handleSuccess: function() {
|
||||
var self = ExploreMaps
|
||||
self.pending = false
|
||||
if (self.collection && self.collection.id === 'mapper') {
|
||||
self.fetchUserThenRender(cb)
|
||||
self.fetchUserThenRender()
|
||||
} else {
|
||||
self.render(cb)
|
||||
Loading.hide()
|
||||
self.render()
|
||||
}
|
||||
},
|
||||
handleError: function() {
|
||||
|
@ -103,8 +88,8 @@ const ExploreMaps = {
|
|||
var self = ExploreMaps
|
||||
|
||||
if (self.mapper && self.mapper.id === self.collection.mapperId) {
|
||||
self.render(cb)
|
||||
return Loading.hide()
|
||||
self.render()
|
||||
return
|
||||
}
|
||||
|
||||
// first load the mapper object and then call the render function
|
||||
|
@ -112,14 +97,40 @@ const ExploreMaps = {
|
|||
url: '/users/' + self.collection.mapperId + '/details.json',
|
||||
success: function(response) {
|
||||
self.mapper = response
|
||||
self.render(cb)
|
||||
Loading.hide()
|
||||
self.render()
|
||||
},
|
||||
error: function() {
|
||||
self.render(cb)
|
||||
Loading.hide()
|
||||
self.render()
|
||||
}
|
||||
})
|
||||
},
|
||||
onStar: function(map) {
|
||||
$.post('/maps/' + map.id + '/star')
|
||||
map.set('star_count', map.get('star_count') + 1)
|
||||
if (DataModel.Stars) DataModel.Stars.push({ user_id: Active.Mapper.id, map_id: map.id })
|
||||
DataModel.Maps.Starred.add(map)
|
||||
GlobalUI.notifyUser('Map is now starred')
|
||||
ReactApp.render()
|
||||
},
|
||||
onRequest: function(map) {
|
||||
$.post({
|
||||
url: `/maps/${map.id}/access_request`
|
||||
})
|
||||
GlobalUI.notifyUser('You will be notified by email if request accepted')
|
||||
},
|
||||
onMapFollow: function(map) {
|
||||
const isFollowing = map.isFollowedBy(Active.Mapper)
|
||||
$.post({
|
||||
url: `/maps/${map.id}/${isFollowing ? 'un' : ''}follow`
|
||||
})
|
||||
if (isFollowing) {
|
||||
GlobalUI.notifyUser('You are no longer following this map')
|
||||
Active.Mapper.unfollowMap(map.id)
|
||||
} else {
|
||||
GlobalUI.notifyUser('You are now following this map')
|
||||
Active.Mapper.followMap(map.id)
|
||||
}
|
||||
ReactApp.render()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,48 +5,39 @@ import ReactDOM from 'react-dom'
|
|||
|
||||
import Active from '../Active'
|
||||
import Visualize from '../Visualize'
|
||||
import GlobalUI from '../GlobalUI'
|
||||
|
||||
import ReactTopicCard from '../../components/TopicCard'
|
||||
import GlobalUI, { ReactApp } from '../GlobalUI'
|
||||
|
||||
const TopicCard = {
|
||||
openTopicCard: null, // stores the topic that's currently open
|
||||
openTopic: null, // stores the topic that's currently open
|
||||
metacodeSets: [],
|
||||
updateTopic: () => {},
|
||||
onTopicFollow: () => {},
|
||||
redrawCanvas: () => {
|
||||
Visualize.mGraph.plot()
|
||||
},
|
||||
init: function(serverData) {
|
||||
const self = TopicCard
|
||||
self.metacodeSets = serverData.metacodeSets
|
||||
},
|
||||
populateShowCard: function(topic) {
|
||||
const self = TopicCard
|
||||
ReactDOM.render(
|
||||
React.createElement(ReactTopicCard, {
|
||||
topic: topic,
|
||||
ActiveMapper: Active.Mapper,
|
||||
updateTopic: obj => {
|
||||
topic.save(obj, { success: topic => self.populateShowCard(topic) })
|
||||
},
|
||||
onFollow: () => {
|
||||
const isFollowing = topic.isFollowedBy(Active.Mapper)
|
||||
$.post({
|
||||
url: `/topics/${topic.id}/${isFollowing ? 'un' : ''}follow`
|
||||
})
|
||||
if (isFollowing) {
|
||||
GlobalUI.notifyUser('You are no longer following this topic')
|
||||
Active.Mapper.unfollowTopic(topic.id)
|
||||
} else {
|
||||
GlobalUI.notifyUser('You are now following this topic')
|
||||
Active.Mapper.followTopic(topic.id)
|
||||
}
|
||||
self.populateShowCard(topic)
|
||||
},
|
||||
metacodeSets: self.metacodeSets,
|
||||
redrawCanvas: () => {
|
||||
Visualize.mGraph.plot()
|
||||
}
|
||||
}),
|
||||
document.getElementById('showcard')
|
||||
)
|
||||
|
||||
TopicCard.updateTopic = obj => {
|
||||
topic.save(obj, { success: topic => self.populateShowCard(topic) })
|
||||
}
|
||||
TopicCard.onTopicFollow = () => {
|
||||
const isFollowing = topic.isFollowedBy(Active.Mapper)
|
||||
$.post({
|
||||
url: `/topics/${topic.id}/${isFollowing ? 'un' : ''}follow`
|
||||
})
|
||||
if (isFollowing) {
|
||||
GlobalUI.notifyUser('You are no longer following this topic')
|
||||
Active.Mapper.unfollowTopic(topic.id)
|
||||
} else {
|
||||
GlobalUI.notifyUser('You are now following this topic')
|
||||
Active.Mapper.followTopic(topic.id)
|
||||
}
|
||||
self.populateShowCard(topic)
|
||||
}
|
||||
// initialize draggability
|
||||
$('.showcard').draggable({
|
||||
handle: '.metacodeImage',
|
||||
|
@ -54,12 +45,12 @@ const TopicCard = {
|
|||
$(this).height('auto')
|
||||
}
|
||||
})
|
||||
ReactApp.render()
|
||||
},
|
||||
showCard: function(node, opts) {
|
||||
showCard: function(node, opts = {}) {
|
||||
var self = TopicCard
|
||||
if (!opts) opts = {}
|
||||
var topic = node.getData('topic')
|
||||
self.openTopicCard = topic
|
||||
self.openTopic = topic
|
||||
// populate the card that's about to show with the right topics data
|
||||
self.populateShowCard(topic)
|
||||
return $('.showcard').fadeIn('fast', () => opts.complete && opts.complete())
|
||||
|
@ -67,7 +58,7 @@ const TopicCard = {
|
|||
hideCard: function() {
|
||||
var self = TopicCard
|
||||
$('.showcard').fadeOut('fast')
|
||||
self.openTopicCard = null
|
||||
self.openTopic = null
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import Active from './Active'
|
|||
import DataModel from './DataModel'
|
||||
import JIT from './JIT'
|
||||
import Loading from './Loading'
|
||||
import Router from './Router'
|
||||
import TopicCard from './Views/TopicCard'
|
||||
|
||||
const Visualize = {
|
||||
|
@ -198,19 +197,6 @@ const Visualize = {
|
|||
}
|
||||
}
|
||||
hold()
|
||||
|
||||
// update the url now that the map is ready
|
||||
clearTimeout(Router.timeoutId)
|
||||
Router.timeoutId = setTimeout(function() {
|
||||
var m = Active.Map
|
||||
var t = Active.Topic
|
||||
|
||||
if (m && window.location.pathname !== '/maps/' + m.id) {
|
||||
Router.navigateAndTrack('/maps/' + m.id)
|
||||
} else if (t && window.location.pathname !== '/topics/' + t.id) {
|
||||
Router.navigateAndTrack('/topics/' + t.id)
|
||||
}
|
||||
}, 800)
|
||||
},
|
||||
clearVisualization: function() {
|
||||
Visualize.mGraph.graph.empty()
|
||||
|
|
|
@ -9,8 +9,7 @@ import DataModel from './DataModel'
|
|||
import Debug from './Debug'
|
||||
import Filter from './Filter'
|
||||
import GlobalUI, {
|
||||
Search, CreateMap, ImportDialog, Account as GlobalUIAccount,
|
||||
NotificationIcon
|
||||
ReactApp, Search, CreateMap, ImportDialog, Account as GlobalUIAccount
|
||||
} from './GlobalUI'
|
||||
import Import from './Import'
|
||||
import JIT from './JIT'
|
||||
|
@ -23,7 +22,6 @@ import Mouse from './Mouse'
|
|||
import Organize from './Organize'
|
||||
import PasteInput from './PasteInput'
|
||||
import Realtime from './Realtime'
|
||||
import Router from './Router'
|
||||
import Selected from './Selected'
|
||||
import Settings from './Settings'
|
||||
import Synapse from './Synapse'
|
||||
|
@ -45,11 +43,11 @@ Metamaps.DataModel = DataModel
|
|||
Metamaps.Debug = Debug
|
||||
Metamaps.Filter = Filter
|
||||
Metamaps.GlobalUI = GlobalUI
|
||||
Metamaps.GlobalUI.ReactApp = ReactApp
|
||||
Metamaps.GlobalUI.Search = Search
|
||||
Metamaps.GlobalUI.CreateMap = CreateMap
|
||||
Metamaps.GlobalUI.Account = GlobalUIAccount
|
||||
Metamaps.GlobalUI.ImportDialog = ImportDialog
|
||||
Metamaps.GlobalUI.NotificationIcon = NotificationIcon
|
||||
Metamaps.Import = Import
|
||||
Metamaps.JIT = JIT
|
||||
Metamaps.Listeners = Listeners
|
||||
|
@ -64,7 +62,6 @@ Metamaps.Mouse = Mouse
|
|||
Metamaps.Organize = Organize
|
||||
Metamaps.PasteInput = PasteInput
|
||||
Metamaps.Realtime = Realtime
|
||||
Metamaps.Router = Router
|
||||
Metamaps.Selected = Selected
|
||||
Metamaps.Settings = Settings
|
||||
Metamaps.Synapse = Synapse
|
||||
|
@ -86,26 +83,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
Metamaps[prop].init(Metamaps.ServerData)
|
||||
}
|
||||
}
|
||||
// load whichever page you are on
|
||||
if (Metamaps.currentSection === 'explore') {
|
||||
const capitalize = Metamaps.currentPage.charAt(0).toUpperCase() + Metamaps.currentPage.slice(1)
|
||||
|
||||
Views.ExploreMaps.setCollection(DataModel.Maps[capitalize])
|
||||
if (Metamaps.currentPage === 'mapper') {
|
||||
Views.ExploreMaps.fetchUserThenRender()
|
||||
} else {
|
||||
Views.ExploreMaps.render()
|
||||
}
|
||||
GlobalUI.showDiv('#explore')
|
||||
} else if (Metamaps.currentSection === '' && Active.Mapper) {
|
||||
Views.ExploreMaps.setCollection(DataModel.Maps.Active)
|
||||
Views.ExploreMaps.render()
|
||||
GlobalUI.showDiv('#explore')
|
||||
} else if (Active.Map || Active.Topic) {
|
||||
Loading.show()
|
||||
JIT.prepareVizData()
|
||||
GlobalUI.showDiv('#infovis')
|
||||
}
|
||||
})
|
||||
|
||||
export default Metamaps
|
||||
|
|
38
frontend/src/components/App/AccountMenu.js
Normal file
38
frontend/src/components/App/AccountMenu.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
|
||||
class AccountMenu extends Component {
|
||||
static propTypes = {
|
||||
currentUser: PropTypes.object
|
||||
}
|
||||
|
||||
render () {
|
||||
return <div>
|
||||
<img className="sidebarAccountImage" src="https://metamaps-live.s3.amazonaws.com/users/images/555/629/996/sixtyfour/11835c3.png?1417298429" alt="11835c3" width="48" height="48" />
|
||||
<h3 className="accountHeader">Connor</h3>
|
||||
<ul>
|
||||
<li className="accountListItem accountSettings">
|
||||
<div className="accountIcon"></div>
|
||||
<a href="https://metamaps.cc/users/555629996/edit">Settings</a>
|
||||
</li>
|
||||
<li className="accountListItem accountAdmin">
|
||||
<div className="accountIcon"></div>
|
||||
<a href="/metacodes">Admin</a>
|
||||
</li>
|
||||
<li className="accountListItem accountApps">
|
||||
<div className="accountIcon"></div>
|
||||
<a href="/oauth/authorized_applications">Apps</a>
|
||||
</li>
|
||||
<li className="accountListItem accountInvite openLightbox" data-open="invite">
|
||||
<div className="accountIcon"></div>
|
||||
<span>Share Invite</span>
|
||||
</li>
|
||||
<li className="accountListItem accountLogout">
|
||||
<div className="accountIcon"></div>
|
||||
<a id="Logout" href="/logout">Sign Out</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
export default AccountMenu
|
12
frontend/src/components/App/FilterBox.js
Normal file
12
frontend/src/components/App/FilterBox.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
|
||||
class FilterBox extends Component {
|
||||
static propTypes = {
|
||||
}
|
||||
|
||||
render () {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export default FilterBox
|
36
frontend/src/components/App/LoginForm.js
Normal file
36
frontend/src/components/App/LoginForm.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
|
||||
class LoginForm extends Component {
|
||||
static propTypes = {
|
||||
loginFormAuthToken: PropTypes.string
|
||||
}
|
||||
|
||||
render () {
|
||||
return <form className="loginAnywhere" id="new_user" action="/login" acceptCharset="UTF-8" method="post">
|
||||
<input name="utf8" type="hidden" value="✓" />
|
||||
<input type="hidden" name="authenticity_token" value="9z5D3vUGKM5ExKJ0CmhweE8qysvUqjFMwgMvbYXIlrnvg9sqJWIWgCt9lq28NZgyCaNudF+w+dRPD1pybeT4mg==" />
|
||||
<div className="accountImage"></div>
|
||||
<div className="accountInput accountEmail">
|
||||
<input placeholder="Email" type="email" name="user[email]" id="user_email" />
|
||||
</div>
|
||||
<div className="accountInput accountPassword">
|
||||
<input placeholder="Password" type="password" name="user[password]" id="user_password" />
|
||||
</div>
|
||||
<div className="accountSubmit">
|
||||
<input type="submit" name="commit" value="SIGN IN" />
|
||||
</div>
|
||||
<div className="accountRememberMe">
|
||||
<label htmlFor="user_remember_me">Stay signed in</label>
|
||||
<input name="user[remember_me]" type="hidden" value="0" />
|
||||
<input type="checkbox" value="1" name="user[remember_me]" id="user_remember_me" />
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
<div className="accountForgotPass">
|
||||
<a href="/users/password/new">Forgot password?</a>
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
}
|
||||
|
||||
export default LoginForm
|
|
@ -1,6 +1,11 @@
|
|||
import React, { PropTypes, Component } from 'react'
|
||||
|
||||
class NotificationIcon extends Component {
|
||||
|
||||
static propTypes = {
|
||||
unreadNotificationsCount: PropTypes.number
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
|
@ -31,8 +36,4 @@ class NotificationIcon extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
NotificationIcon.propTypes = {
|
||||
unreadNotificationsCount: PropTypes.number
|
||||
}
|
||||
|
||||
export default NotificationIcon
|
14
frontend/src/components/App/Toast.js
Normal file
14
frontend/src/components/App/Toast.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
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
|
43
frontend/src/components/App/UpperLeftUI.js
Normal file
43
frontend/src/components/App/UpperLeftUI.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
import { Link } from 'react-router'
|
||||
|
||||
class UpperLeftUI extends Component {
|
||||
static propTypes = {
|
||||
currentUser: PropTypes.object
|
||||
}
|
||||
|
||||
render () {
|
||||
return <div className="upperLeftUI">
|
||||
<div className="homeButton">
|
||||
<Link to="/">METAMAPS</Link>
|
||||
</div>
|
||||
<div className="sidebarSearch">
|
||||
<input type="text" className="sidebarSearchField" placeholder="Search for topics, maps, and mappers..." />
|
||||
<div id="searchLoading"></div>
|
||||
<div className="sidebarSearchIcon"></div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
<div className="viewOnly">
|
||||
<div className="eyeball">View Only</div>
|
||||
<div className="requestAccess requestNotice">Request Access</div>
|
||||
<div className="requestPending requestNotice">Request Pending</div>
|
||||
<div className="requestNotAccepted requestNotice">Request Not Accepted</div>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
export default UpperLeftUI
|
||||
|
||||
/*
|
||||
|
||||
<% request = current_user && @map && @allrequests.find{|a| a.user == current_user}
|
||||
className = (@map and not policy(@map).update?) ? 'isViewOnly ' : ''
|
||||
if @map
|
||||
className += 'sendRequest' if not request
|
||||
className += 'sentRequest' if request and not request.answered
|
||||
className += 'requestDenied' if request and request.answered and not request.approved
|
||||
end %>
|
||||
|
||||
*/
|
66
frontend/src/components/App/UpperRightUI.js
Normal file
66
frontend/src/components/App/UpperRightUI.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
|
||||
import FilterBox from './FilterBox'
|
||||
import AccountMenu from './AccountMenu'
|
||||
import LoginForm from './LoginForm'
|
||||
import NotificationIcon from './NotificationIcon'
|
||||
|
||||
class UpperRightUI extends Component {
|
||||
static propTypes = {
|
||||
currentUser: PropTypes.object,
|
||||
signInPage: PropTypes.bool,
|
||||
unreadNotificationsCount: PropTypes.number
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
location: PropTypes.object
|
||||
}
|
||||
|
||||
render () {
|
||||
const { currentUser, signInPage, unreadNotificationsCount } = this.props
|
||||
const { location } = this.context
|
||||
// TODO: get these map related things out of this file
|
||||
// TODO: only show 'import' if you have edit rights for the map
|
||||
const isMapPage = location.pathname.slice(0, 6) === '/maps/'
|
||||
return <div className="upperRightUI">
|
||||
{isMapPage && <div className="mapElement upperRightEl upperRightMapButtons">
|
||||
{currentUser && <div className="importDialog upperRightEl upperRightIcon mapElement openLightbox" data-open="import-dialog-lightbox">
|
||||
<div className="tooltipsUnder">
|
||||
Import Data
|
||||
</div>
|
||||
</div>}
|
||||
<div className="sidebarFilter upperRightEl">
|
||||
<div className="sidebarFilterIcon upperRightIcon"><div className="tooltipsUnder">Filter</div></div>
|
||||
<div className="sidebarFilterBox upperRightBox">
|
||||
<FilterBox />
|
||||
</div>
|
||||
</div>
|
||||
{currentUser && <div className="sidebarFork upperRightEl">
|
||||
<div className="sidebarForkIcon upperRightIcon"><div className="tooltipsUnder">Save To New Map</div></div>
|
||||
</div>}
|
||||
<div className="clearfloat"></div>
|
||||
</div>}
|
||||
{currentUser && <a href="/maps/new" target="_blank" className="addMap upperRightEl upperRightIcon">
|
||||
<div className="tooltipsUnder">
|
||||
Create New Map
|
||||
</div>
|
||||
</a>}
|
||||
{currentUser && <span id="notification_icon">
|
||||
<NotificationIcon unreadNotificationsCount={unreadNotificationsCount} />
|
||||
</span>}
|
||||
{!signInPage && <div className="sidebarAccount upperRightEl">
|
||||
<div className="sidebarAccountIcon"><div className="tooltipsUnder">Account</div>
|
||||
{currentUser && <img src={currentUser.get('image')} />}
|
||||
{!currentUser && 'SIGN IN'}
|
||||
{!currentUser && <div className="accountInnerArrow"></div>}
|
||||
</div>
|
||||
<div className="sidebarAccountBox upperRightBox">
|
||||
{currentUser ? <AccountMenu /> : <LoginForm />}
|
||||
</div>
|
||||
</div>}
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
export default UpperRightUI
|
54
frontend/src/components/App/index.js
Normal file
54
frontend/src/components/App/index.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
|
||||
import Toast from './Toast'
|
||||
import UpperLeftUI from './UpperLeftUI'
|
||||
import UpperRightUI from './UpperRightUI'
|
||||
|
||||
class App extends Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.object,
|
||||
toast: PropTypes.string,
|
||||
unreadNotificationsCount: PropTypes.number,
|
||||
location: PropTypes.object
|
||||
}
|
||||
|
||||
static childContextTypes = {
|
||||
currentUser: PropTypes.object,
|
||||
location: PropTypes.object
|
||||
}
|
||||
|
||||
getChildContext () {
|
||||
const { route, location } = this.props
|
||||
return {currentUser: route.currentUser, location}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { toast, currentUser, unreadNotificationsCount } = this.props
|
||||
return <div className="wrapper" id="wrapper">
|
||||
<UpperLeftUI currentUser={currentUser} />
|
||||
<UpperRightUI currentUser={currentUser} unreadNotificationsCount={unreadNotificationsCount} />
|
||||
<Toast message={toast} />
|
||||
{currentUser && <a className='feedback-icon' target='_blank' href='https://hylo.com/c/metamaps'></a>}
|
||||
{this.props.children}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
export default App
|
||||
|
||||
/*
|
||||
<% classes = action_name == "home" ? "homePage" : ""
|
||||
classes += action_name == "home" && authenticated? ? " explorePage" : ""
|
||||
classes += controller_name == "maps" && action_name == "index" ? " explorePage" : ""
|
||||
if controller_name == "maps" && action_name == "show"
|
||||
classes += " mapPage"
|
||||
if policy(@map).update?
|
||||
classes += " canEditMap"
|
||||
end
|
||||
if @map.permission == "commons"
|
||||
classes += " commonsMap"
|
||||
end
|
||||
end
|
||||
classes += controller_name == "topics" && action_name == "show" ? " topicPage" : ""
|
||||
%>
|
||||
*/
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react'
|
||||
import Autolinker from 'autolinker'
|
||||
import Util from '../../Metamaps/Util'
|
||||
import Util from '../../../Metamaps/Util'
|
||||
|
||||
const linker = new Autolinker({ newWindow: true, truncate: 50, email: false, phone: false })
|
||||
|
|
@ -3,7 +3,7 @@ import Unread from './Unread'
|
|||
import Participant from './Participant'
|
||||
import Message from './Message'
|
||||
import NewMessage from './NewMessage'
|
||||
import Util from '../../Metamaps/Util'
|
||||
import Util from '../../../Metamaps/Util'
|
||||
|
||||
function makeList(messages) {
|
||||
let currentHeader
|
12
frontend/src/components/MapView/MapInfoBox.js
Normal file
12
frontend/src/components/MapView/MapInfoBox.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
|
||||
class MapInfoBox extends Component {
|
||||
static propTypes = {
|
||||
}
|
||||
|
||||
render () {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export default MapInfoBox
|
114
frontend/src/components/MapView/index.js
Normal file
114
frontend/src/components/MapView/index.js
Normal file
|
@ -0,0 +1,114 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
|
||||
import MapInfoBox from './MapInfoBox'
|
||||
import MapChat from './MapChat'
|
||||
import TopicCard from '../TopicCard'
|
||||
|
||||
class MapView extends Component {
|
||||
|
||||
static propTypes = {
|
||||
mapId: PropTypes.string,
|
||||
map: PropTypes.object,
|
||||
mapIsStarred: PropTypes.bool,
|
||||
currentUser: PropTypes.object,
|
||||
endActiveMap: PropTypes.func,
|
||||
launchNewMap: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window && window.addEventListener('resize', this.resize)
|
||||
this.resize()
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
const oldMapId = prevProps.mapId
|
||||
const { mapId, endActiveMap, launchNewMap } = this.props
|
||||
if (!oldMapId && mapId) launchNewMap(mapId)
|
||||
else if (oldMapId && mapId && oldMapId !== mapId) {
|
||||
endActiveMap()
|
||||
launchNewMap(mapId)
|
||||
}
|
||||
else if (oldMapId && !mapId) endActiveMap()
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window && window.removeEventListener('resize', this.resize)
|
||||
}
|
||||
|
||||
resize = () => {
|
||||
|
||||
}
|
||||
|
||||
render = () => {
|
||||
const { mapIsStarred } = this.props
|
||||
const starclassName = mapIsStarred ? 'starred' : ''
|
||||
const tooltip = mapIsStarred ? 'Star' : 'Unstar'
|
||||
|
||||
return <div className="mapWrapper">
|
||||
<div id="infovis" />
|
||||
<div className="showcard mapElement mapElementHidden" id="showcard">
|
||||
<TopicCard {...this.props} />
|
||||
</div>
|
||||
<div id="chat-box-wrapper">
|
||||
<MapChat {...this.props} />
|
||||
</div>
|
||||
<div className="mapControls mapElement">
|
||||
<div className="zoomExtents mapControl"><div className="tooltips">Center View</div></div>
|
||||
<div className="zoomIn mapControl"><div className="tooltips">Zoom In</div></div>
|
||||
<div className="zoomOut mapControl"><div className="tooltips">Zoom Out</div></div>
|
||||
</div>
|
||||
<div className="infoAndHelp">
|
||||
<MapInfoBox />
|
||||
<div className={`starMap infoElement mapElement ${starclassName}`}>
|
||||
<div className="tooltipsAbove">{tooltip}</div>
|
||||
</div>
|
||||
<div className="mapInfoIcon infoElement mapElement">
|
||||
<div className="tooltipsAbove">Map Info</div>
|
||||
</div>
|
||||
<div className="openCheatsheet openLightbox infoElement mapElement" data-open="cheatsheet">
|
||||
<div className="tooltipsAbove">Help</div>
|
||||
</div>
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
export default MapView
|
||||
|
||||
/*
|
||||
|
||||
<div className="showcard mapElement mapElementHidden" id="showcard"></div>
|
||||
<% if authenticated? %>
|
||||
<% # for creating and pulling in topics and synapses %>
|
||||
<% if controller_name == 'maps' && action_name == "conversation" %>
|
||||
<%= render :partial => 'maps/newtopicsecret' %>
|
||||
<% else %>
|
||||
<%= render :partial => 'maps/newtopic' %>
|
||||
<% end %>
|
||||
<%= render :partial => 'maps/newsynapse' %>
|
||||
<% # for populating the change metacode list on the topic card %>
|
||||
<%= render :partial => 'shared/metacodeoptions' %>
|
||||
<% end %>
|
||||
<%= render :partial => 'layouts/lowermapelements' %>
|
||||
|
||||
<div id="loading"></div>
|
||||
|
||||
<div id="instructions">
|
||||
<div className="addTopic">
|
||||
Double-click to<br>add a topic
|
||||
</div>
|
||||
<div className="tabKey">
|
||||
Use Tab & Shift+Tab to select a metacode
|
||||
</div>
|
||||
<div className="enterKey">
|
||||
Press Enter to add the topic
|
||||
</div>
|
||||
</div>
|
||||
|
||||
*/
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
import { Link } from 'react-router'
|
||||
import _ from 'lodash'
|
||||
|
||||
const MapLink = props => {
|
||||
|
@ -9,10 +10,10 @@ const MapLink = props => {
|
|||
}
|
||||
|
||||
return (
|
||||
<a { ...otherProps } href={href} className={linkClass}>
|
||||
<Link { ...otherProps } to={href} className={linkClass}>
|
||||
<div className="exploreMapsIcon"></div>
|
||||
{text}
|
||||
</a>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -39,31 +40,26 @@ class Header extends Component {
|
|||
<MapLink show={explore}
|
||||
href={signedIn ? '/' : '/explore/active'}
|
||||
linkClass={activeClass('active')}
|
||||
data-router="true"
|
||||
text="All Maps"
|
||||
/>
|
||||
<MapLink show={signedIn && explore}
|
||||
href="/explore/mine"
|
||||
linkClass={activeClass('my')}
|
||||
data-router="true"
|
||||
text="My Maps"
|
||||
/>
|
||||
<MapLink show={signedIn && explore}
|
||||
href="/explore/shared"
|
||||
linkClass={activeClass('shared')}
|
||||
data-router="true"
|
||||
text="Shared With Me"
|
||||
/>
|
||||
<MapLink show={signedIn && explore}
|
||||
href="/explore/starred"
|
||||
linkClass={activeClass('starred')}
|
||||
data-router="true"
|
||||
text="Starred By Me"
|
||||
/>
|
||||
<MapLink show={!signedIn && explore}
|
||||
href="/explore/featured"
|
||||
linkClass={activeClass('featured')}
|
||||
data-router="true"
|
||||
text="Featured Maps"
|
||||
/>
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
import { Link } from 'react-router'
|
||||
import { find, values } from 'lodash'
|
||||
import Util from '../../Metamaps/Util'
|
||||
|
||||
|
@ -78,7 +79,7 @@ const Metadata = (props) => {
|
|||
}
|
||||
|
||||
const checkAndWrapInA = (shouldWrap, classString, mapId, element) => {
|
||||
if (shouldWrap) return <a className={ classString } href={ `/maps/${mapId}` } data-router="true">{ element }</a>
|
||||
if (shouldWrap) return <Link className={ classString } to={ `/maps/${mapId}` } >{ element }</Link>
|
||||
else return element
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,25 @@ const MAX_COLUMNS = 4
|
|||
|
||||
class Maps extends Component {
|
||||
|
||||
static propTypes = {
|
||||
section: PropTypes.string,
|
||||
maps: PropTypes.object,
|
||||
juntoState: PropTypes.object,
|
||||
moreToLoad: PropTypes.bool,
|
||||
user: PropTypes.object,
|
||||
currentUser: PropTypes.object,
|
||||
loadMore: PropTypes.func,
|
||||
pending: PropTypes.bool,
|
||||
setCollection: PropTypes.func,
|
||||
onStar: PropTypes.func,
|
||||
onRequest: PropTypes.func,
|
||||
onMapFollow: PropTypes.func
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
location: PropTypes.object
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = { mapsWidth: 0 }
|
||||
|
@ -19,7 +38,7 @@ class Maps extends Component {
|
|||
|
||||
componentDidMount() {
|
||||
window && window.addEventListener('resize', this.resize)
|
||||
this.refs.maps.addEventListener('scroll', throttle(this.scroll, 500, { leading: true, trailing: false }))
|
||||
this.refs.maps && this.refs.maps.addEventListener('scroll', throttle(this.scroll, 500, { leading: true, trailing: false }))
|
||||
this.resize()
|
||||
}
|
||||
|
||||
|
@ -29,6 +48,7 @@ class Maps extends Component {
|
|||
|
||||
resize = () => {
|
||||
const { maps, user, currentUser } = this.props
|
||||
if (!maps) return
|
||||
const numCards = maps.length + (user || currentUser ? 1 : 0)
|
||||
const mapSpaces = Math.floor(document.body.clientWidth / MAP_WIDTH)
|
||||
const mapsWidth = document.body.clientWidth <= MOBILE_VIEW_BREAKPOINT
|
||||
|
@ -46,41 +66,30 @@ class Maps extends Component {
|
|||
}
|
||||
|
||||
render = () => {
|
||||
const { maps, currentUser, juntoState, pending, section, user, onStar, onRequest, onFollow } = this.props
|
||||
const { maps, currentUser, juntoState, pending, section, user, onStar, onRequest, onMapFollow } = this.props
|
||||
const style = { width: this.state.mapsWidth + 'px' }
|
||||
const mobile = document && document.body.clientWidth <= MOBILE_VIEW_BREAKPOINT
|
||||
|
||||
if (!maps) return null // do loading here instead
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div id='exploreMaps' ref='maps'>
|
||||
<div style={ style }>
|
||||
{ user ? <MapperCard user={ user } /> : null }
|
||||
{ currentUser && !user && !(pending && maps.length === 0) ? <div className="map newMap"><a href="/maps/new"><div className="newMapImage"></div><span>Create new map...</span></a></div> : null }
|
||||
{ maps.models.map(map => <MapCard key={ map.id } map={ map } mobile={ mobile } juntoState={ juntoState } currentUser={ currentUser } onStar={ onStar } onRequest={ onRequest } onFollow={ onFollow } />) }
|
||||
{ maps.models.map(map => <MapCard key={ map.id } map={ map } mobile={ mobile } juntoState={ juntoState } currentUser={ currentUser } onStar={ onStar } onRequest={ onRequest } onMapFollow={ onMapFollow } />) }
|
||||
<div className='clearfloat'></div>
|
||||
</div>
|
||||
</div>
|
||||
<Header signedIn={ !!currentUser }
|
||||
section={ section }
|
||||
user={ user }
|
||||
setCollection={ setCollection }
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Maps.propTypes = {
|
||||
section: PropTypes.string.isRequired,
|
||||
maps: PropTypes.object.isRequired,
|
||||
juntoState: PropTypes.object.isRequired,
|
||||
moreToLoad: PropTypes.bool.isRequired,
|
||||
user: PropTypes.object,
|
||||
currentUser: PropTypes.object,
|
||||
loadMore: PropTypes.func,
|
||||
pending: PropTypes.bool.isRequired,
|
||||
onStar: PropTypes.func.isRequired,
|
||||
onRequest: PropTypes.func.isRequired,
|
||||
onFollow: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default Maps
|
||||
|
|
|
@ -2,8 +2,8 @@ import React, { PropTypes, Component } from 'react'
|
|||
|
||||
class Follow extends Component {
|
||||
render = () => {
|
||||
const { isFollowing, onFollow } = this.props
|
||||
return <div className='topicFollow' onClick={onFollow}>
|
||||
const { isFollowing, onTopicFollow } = this.props
|
||||
return <div className='topicFollow' onClick={onTopicFollow}>
|
||||
{isFollowing ? 'Unfollow' : 'Follow'}
|
||||
</div>
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ class Follow extends Component {
|
|||
|
||||
Follow.propTypes = {
|
||||
isFollowing: PropTypes.bool,
|
||||
onFollow: PropTypes.func
|
||||
onTopicFollow: PropTypes.func
|
||||
}
|
||||
|
||||
export default Follow
|
||||
|
|
|
@ -7,12 +7,15 @@ import Attachments from './Attachments'
|
|||
import Follow from './Follow'
|
||||
import Util from '../../Metamaps/Util'
|
||||
|
||||
|
||||
class ReactTopicCard extends Component {
|
||||
render = () => {
|
||||
const { topic, ActiveMapper, onFollow } = this.props
|
||||
const authorizedToEdit = topic.authorizeToEdit(ActiveMapper)
|
||||
const isFollowing = topic.isFollowedBy(ActiveMapper)
|
||||
const { currentUser, onTopicFollow } = this.props
|
||||
const topic = this.props.openTopic
|
||||
|
||||
if (!topic) return null
|
||||
|
||||
const authorizedToEdit = topic.authorizeToEdit(currentUser)
|
||||
const isFollowing = topic.isFollowedBy(currentUser)
|
||||
const hasAttachment = topic.get('link') && topic.get('link') !== ''
|
||||
|
||||
let classname = 'permission'
|
||||
|
@ -21,7 +24,7 @@ class ReactTopicCard extends Component {
|
|||
} else {
|
||||
classname += ' cannotEdit'
|
||||
}
|
||||
if (topic.authorizePermissionChange(ActiveMapper)) classname += ' yourTopic'
|
||||
if (topic.authorizePermissionChange(currentUser)) classname += ' yourTopic'
|
||||
|
||||
return (
|
||||
<div className={classname}>
|
||||
|
@ -31,7 +34,7 @@ class ReactTopicCard extends Component {
|
|||
onChange={this.props.updateTopic}
|
||||
/>
|
||||
<Links topic={topic}
|
||||
ActiveMapper={this.props.ActiveMapper}
|
||||
ActiveMapper={this.props.currentUser}
|
||||
updateTopic={this.props.updateTopic}
|
||||
metacodeSets={this.props.metacodeSets}
|
||||
redrawCanvas={this.props.redrawCanvas}
|
||||
|
@ -44,7 +47,7 @@ class ReactTopicCard extends Component {
|
|||
authorizedToEdit={authorizedToEdit}
|
||||
updateTopic={this.props.updateTopic}
|
||||
/>
|
||||
{Util.isTester(ActiveMapper) && <Follow isFollowing={isFollowing} onFollow={onFollow} />}
|
||||
{Util.isTester(currentUser) && <Follow isFollowing={isFollowing} onTopicFollow={onTopicFollow} />}
|
||||
<div className="clearfloat"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -53,10 +56,10 @@ class ReactTopicCard extends Component {
|
|||
}
|
||||
|
||||
ReactTopicCard.propTypes = {
|
||||
topic: PropTypes.object,
|
||||
ActiveMapper: PropTypes.object,
|
||||
openTopic: PropTypes.object,
|
||||
currentUser: PropTypes.object,
|
||||
updateTopic: PropTypes.func,
|
||||
onFollow: PropTypes.func,
|
||||
onTopicFollow: PropTypes.func,
|
||||
metacodeSets: PropTypes.arrayOf(PropTypes.shape({
|
||||
name: PropTypes.string,
|
||||
metacodes: PropTypes.arrayOf(PropTypes.shape({
|
||||
|
|
0
frontend/src/components/TopicView/index.js
Normal file
0
frontend/src/components/TopicView/index.js
Normal file
20
frontend/src/components/makeRoutes.js
Normal file
20
frontend/src/components/makeRoutes.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import React from 'react'
|
||||
import { Route, IndexRoute } from 'react-router'
|
||||
import App from './App'
|
||||
import Maps from './Maps'
|
||||
import MapView from './MapView'
|
||||
|
||||
export default function makeRoutes () {
|
||||
return <Route path="/" component={App} >
|
||||
<IndexRoute component={Maps} />
|
||||
<Route path="explore">
|
||||
<Route path="active" component={Maps} />
|
||||
<Route path="featured" component={Maps} />
|
||||
<Route path="mine" component={Maps} />
|
||||
<Route path="shared" component={Maps} />
|
||||
<Route path="starred" component={Maps} />
|
||||
<Route path="mapper/:id" component={Maps} />
|
||||
</Route>
|
||||
<Route path="maps/:id" component={MapView} />
|
||||
</Route>
|
||||
}
|
|
@ -46,6 +46,7 @@
|
|||
"react-dom": "15.4.2",
|
||||
"react-dropzone": "3.9.1",
|
||||
"react-onclickoutside": "5.9.0",
|
||||
"react-router": "^3.0.2",
|
||||
"redux": "3.6.0",
|
||||
"riek": "1.0.7",
|
||||
"simplewebrtc": "2.2.2",
|
||||
|
|
Loading…
Add table
Reference in a new issue