diff --git a/app/assets/stylesheets/application.scss.erb b/app/assets/stylesheets/application.scss.erb
index 0c7b9976..87f2b4c5 100644
--- a/app/assets/stylesheets/application.scss.erb
+++ b/app/assets/stylesheets/application.scss.erb
@@ -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;
-}
\ No newline at end of file
+}
diff --git a/app/assets/stylesheets/base.scss.erb b/app/assets/stylesheets/base.scss.erb
index 355f5652..f4e247f2 100644
--- a/app/assets/stylesheets/base.scss.erb
+++ b/app/assets/stylesheets/base.scss.erb
@@ -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;
diff --git a/app/assets/stylesheets/clean.css.erb b/app/assets/stylesheets/clean.css.erb
index 1582404e..69bbecf7 100644
--- a/app/assets/stylesheets/clean.css.erb
+++ b/app/assets/stylesheets/clean.css.erb
@@ -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 {
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 4bb5be10..55abe8e3 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -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
diff --git a/app/views/layouts/_account.html.erb b/app/views/layouts/_account.html.erb
deleted file mode 100644
index 94f69f62..00000000
--- a/app/views/layouts/_account.html.erb
+++ /dev/null
@@ -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" %>
-
-
-
-
- <%= link_to "Settings", edit_user_url(account) %>
-
- <% if account.admin %>
-
-
- <%= link_to "Admin", metacodes_path %>
-
- <% end %>
-
-
- <%= link_to "Apps", oauth_authorized_applications_path %>
-
-
-
- Share Invite
-
-
-
- <%= link_to "Sign Out", "/logout", id: "Logout" %>
-
-
-<% else %>
- <%= form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { class: "loginAnywhere" }) do |f| %>
-
-
- <%= f.email_field :email, :placeholder => "Email" %>
-
-
- <%= f.password_field :password, :placeholder => "Password" %>
-
- <%= f.submit "SIGN IN" %>
- <% if devise_mapping.rememberable? -%>
-
- <%= f.label :remember_me, "Stay signed in" %>
- <%= f.check_box :remember_me %>
-
-
- <% end -%>
-
-
- <%- if devise_mapping.recoverable? && controller_name != 'passwords' %>
- <%= link_to "Forgot password?", new_password_path(resource_name) %>
- <% end -%>
-
- <% end %>
-<% end %>
-
-<% # Rails.logger.info(stored_location_for(:user)) %>
diff --git a/app/views/layouts/_lowermapelements.html.erb b/app/views/layouts/_lowermapelements.html.erb
deleted file mode 100644
index e3d5aeaf..00000000
--- a/app/views/layouts/_lowermapelements.html.erb
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
- <%= render :partial => 'maps/mapinfobox' %>
-
- <% starred = current_user && @map && current_user.starred_map?(@map)
- starClass = starred ? 'starred' : ''
- tooltip = starred ? 'Star' : 'Unstar' %>
-
-
-
-
-
diff --git a/app/views/layouts/_upperelements.html.erb b/app/views/layouts/_upperelements.html.erb
deleted file mode 100644
index 7ef76bad..00000000
--- a/app/views/layouts/_upperelements.html.erb
+++ /dev/null
@@ -1,107 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- <% 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 %>
-
-
-
View Only
- <% if current_user %>
-
Request Access
-
Request Pending
-
Request Not Accepted
- <% end %>
-
-
-
-
-
-
-
- <% if current_user %>
-
-
-
- Create New Map
-
-
- <% end %>
-
-
- <% if current_user.present? %>
-
- <%= link_to notifications_path, class: "notificationsIcon upperRightEl upperRightIcon #{user_unread_notification_count > 0 ? 'unread' : 'read'}" do %>
-
- Notifications
-
- <% if user_unread_notification_count > 0 %>
-
- <% end %>
- <% end %>
-
- <% end %>
-
-
- <% if !(controller_name == "sessions" && action_name == "new") %>
-
- <% end %>
-
-
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index daa16d02..227d324d 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -6,83 +6,34 @@
#%>
<%= render :partial => 'layouts/head' %>
-
controller-<%= controller_name %> action-<%= action_name %>">
-
-
-
-
-
- <%= 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" : ""
- %>
-
-
-
- <%= render :partial => 'layouts/upperelements', :locals => { :noHardHomeLink => controller_name == "notifications" ? true : false } %>
-
- <%= yield %>
-
-
- <% 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' %>
-
-
-
- <% if !(controller_name == 'maps' && action_name == "conversation") %>
-
-
- Double-click to add a topic
-
-
- Use Tab & Shift+Tab to select a metacode
-
-
- Press Enter to add the topic
-
-
- <% end %>
-
-
- <%= render :partial => 'layouts/mobilemenu' %>
-
-
- <% if devise_error_messages? %>
- <%= devise_error_messages! %>
- <% end %>
- <% if notice %>
- <%= notice %>
- <% end %>
- <% if alert %>
- <%= alert %>
- <% end %>
-
-
-
-
+ <%= 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 %>
+
+
<%= render :partial => 'layouts/foot' %>
diff --git a/frontend/src/Metamaps/GlobalUI/ImportDialog.js b/frontend/src/Metamaps/GlobalUI/ImportDialog.js
index 30215fa1..774c2190 100644
--- a/frontend/src/Metamaps/GlobalUI/ImportDialog.js
+++ b/frontend/src/Metamaps/GlobalUI/ImportDialog.js
@@ -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'
diff --git a/frontend/src/Metamaps/GlobalUI/NotificationIcon.js b/frontend/src/Metamaps/GlobalUI/NotificationIcon.js
deleted file mode 100644
index 1e9ff3bd..00000000
--- a/frontend/src/Metamaps/GlobalUI/NotificationIcon.js
+++ /dev/null
@@ -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
diff --git a/frontend/src/Metamaps/GlobalUI/ReactApp.js b/frontend/src/Metamaps/GlobalUI/ReactApp.js
new file mode 100644
index 00000000..7420bced
--- /dev/null
+++ b/frontend/src/Metamaps/GlobalUI/ReactApp.js
@@ -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) =>
+ const app =
+ 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
diff --git a/frontend/src/Metamaps/GlobalUI/Search.js b/frontend/src/Metamaps/GlobalUI/Search.js
index a37b62a8..da279804 100644
--- a/frontend/src/Metamaps/GlobalUI/Search.js
+++ b/frontend/src/Metamaps/GlobalUI/Search.js
@@ -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
}
}
},
diff --git a/frontend/src/Metamaps/GlobalUI/index.js b/frontend/src/Metamaps/GlobalUI/index.js
index a1d2bbff..14185abf 100644
--- a/frontend/src/Metamaps/GlobalUI/index.js
+++ b/frontend/src/Metamaps/GlobalUI/index.js
@@ -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
diff --git a/frontend/src/Metamaps/Map/InfoBox.js b/frontend/src/Metamaps/Map/InfoBox.js
index 1949e96e..312ac68d 100644
--- a/frontend/src/Metamaps/Map/InfoBox.js
+++ b/frontend/src/Metamaps/Map/InfoBox.js
@@ -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?")
diff --git a/frontend/src/Metamaps/Map/index.js b/frontend/src/Metamaps/Map/index.js
index e3c3bbc6..94a749c1 100644
--- a/frontend/src/Metamaps/Map/index.js
+++ b/frontend/src/Metamaps/Map/index.js
@@ -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() {
diff --git a/frontend/src/Metamaps/Router.js b/frontend/src/Metamaps/Router.js
deleted file mode 100644
index 6df1c264..00000000
--- a/frontend/src/Metamaps/Router.js
+++ /dev/null
@@ -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
diff --git a/frontend/src/Metamaps/Topic.js b/frontend/src/Metamaps/Topic.js
index 663b0c11..1d3d28de 100644
--- a/frontend/src/Metamaps/Topic.js
+++ b/frontend/src/Metamaps/Topic.js
@@ -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)
}
},
diff --git a/frontend/src/Metamaps/Views/ChatView.js b/frontend/src/Metamaps/Views/ChatView.js
index 0024a623..f7c41a9d 100644
--- a/frontend/src/Metamaps/Views/ChatView.js
+++ b/frontend/src/Metamaps/Views/ChatView.js
@@ -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)
diff --git a/frontend/src/Metamaps/Views/ExploreMaps.js b/frontend/src/Metamaps/Views/ExploreMaps.js
index 5c10691b..5d332390 100644
--- a/frontend/src/Metamaps/Views/ExploreMaps.js
+++ b/frontend/src/Metamaps/Views/ExploreMaps.js
@@ -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()
}
}
diff --git a/frontend/src/Metamaps/Views/TopicCard.js b/frontend/src/Metamaps/Views/TopicCard.js
index 0b02fccd..67417126 100644
--- a/frontend/src/Metamaps/Views/TopicCard.js
+++ b/frontend/src/Metamaps/Views/TopicCard.js
@@ -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
}
}
diff --git a/frontend/src/Metamaps/Visualize.js b/frontend/src/Metamaps/Visualize.js
index 43f6071b..aa0745da 100644
--- a/frontend/src/Metamaps/Visualize.js
+++ b/frontend/src/Metamaps/Visualize.js
@@ -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()
diff --git a/frontend/src/Metamaps/index.js b/frontend/src/Metamaps/index.js
index eb9969b0..8be91f94 100644
--- a/frontend/src/Metamaps/index.js
+++ b/frontend/src/Metamaps/index.js
@@ -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
diff --git a/frontend/src/components/App/AccountMenu.js b/frontend/src/components/App/AccountMenu.js
new file mode 100644
index 00000000..d6f2ca9e
--- /dev/null
+++ b/frontend/src/components/App/AccountMenu.js
@@ -0,0 +1,38 @@
+import React, { Component, PropTypes } from 'react'
+
+class AccountMenu extends Component {
+ static propTypes = {
+ currentUser: PropTypes.object
+ }
+
+ render () {
+ return
+
+
Connor
+
+
+ }
+}
+
+export default AccountMenu
diff --git a/frontend/src/components/App/FilterBox.js b/frontend/src/components/App/FilterBox.js
new file mode 100644
index 00000000..3ea1a614
--- /dev/null
+++ b/frontend/src/components/App/FilterBox.js
@@ -0,0 +1,12 @@
+import React, { Component, PropTypes } from 'react'
+
+class FilterBox extends Component {
+ static propTypes = {
+ }
+
+ render () {
+ return null
+ }
+}
+
+export default FilterBox
diff --git a/frontend/src/components/App/LoginForm.js b/frontend/src/components/App/LoginForm.js
new file mode 100644
index 00000000..273ee31b
--- /dev/null
+++ b/frontend/src/components/App/LoginForm.js
@@ -0,0 +1,36 @@
+import React, { Component, PropTypes } from 'react'
+
+class LoginForm extends Component {
+ static propTypes = {
+ loginFormAuthToken: PropTypes.string
+ }
+
+ render () {
+ return
+ }
+}
+
+export default LoginForm
diff --git a/frontend/src/components/NotificationIcon.js b/frontend/src/components/App/NotificationIcon.js
similarity index 90%
rename from frontend/src/components/NotificationIcon.js
rename to frontend/src/components/App/NotificationIcon.js
index 201020b5..3f9c8980 100644
--- a/frontend/src/components/NotificationIcon.js
+++ b/frontend/src/components/App/NotificationIcon.js
@@ -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
diff --git a/frontend/src/components/App/Toast.js b/frontend/src/components/App/Toast.js
new file mode 100644
index 00000000..48ac4cb1
--- /dev/null
+++ b/frontend/src/components/App/Toast.js
@@ -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
+ }
+}
+
+export default Toast
diff --git a/frontend/src/components/App/UpperLeftUI.js b/frontend/src/components/App/UpperLeftUI.js
new file mode 100644
index 00000000..51a79784
--- /dev/null
+++ b/frontend/src/components/App/UpperLeftUI.js
@@ -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
+
+ METAMAPS
+
+
+
+
View Only
+
Request Access
+
Request Pending
+
Request Not Accepted
+
+
+
+ }
+}
+
+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 %>
+
+ */
diff --git a/frontend/src/components/App/UpperRightUI.js b/frontend/src/components/App/UpperRightUI.js
new file mode 100644
index 00000000..6519386b
--- /dev/null
+++ b/frontend/src/components/App/UpperRightUI.js
@@ -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
+ {isMapPage &&
+ {currentUser &&
}
+
+ {currentUser &&
}
+
+
}
+ {currentUser &&
+
+ Create New Map
+
+ }
+ {currentUser &&
+
+ }
+ {!signInPage &&
+
Account
+ {currentUser &&
}
+ {!currentUser && 'SIGN IN'}
+ {!currentUser &&
}
+
+
+
}
+
+
+ }
+}
+
+export default UpperRightUI
diff --git a/frontend/src/components/App/index.js b/frontend/src/components/App/index.js
new file mode 100644
index 00000000..9a8e6204
--- /dev/null
+++ b/frontend/src/components/App/index.js
@@ -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
+
+
+
+ {currentUser &&
}
+ {this.props.children}
+
+ }
+}
+
+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" : ""
+ %>
+*/
diff --git a/frontend/src/components/ImportDialogBox.js b/frontend/src/components/MapView/ImportDialogBox.js
similarity index 100%
rename from frontend/src/components/ImportDialogBox.js
rename to frontend/src/components/MapView/ImportDialogBox.js
diff --git a/frontend/src/components/MapChat/Message.js b/frontend/src/components/MapView/MapChat/Message.js
similarity index 96%
rename from frontend/src/components/MapChat/Message.js
rename to frontend/src/components/MapView/MapChat/Message.js
index 7cfe9ff2..e4caf3ce 100644
--- a/frontend/src/components/MapChat/Message.js
+++ b/frontend/src/components/MapView/MapChat/Message.js
@@ -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 })
diff --git a/frontend/src/components/MapChat/NewMessage.js b/frontend/src/components/MapView/MapChat/NewMessage.js
similarity index 100%
rename from frontend/src/components/MapChat/NewMessage.js
rename to frontend/src/components/MapView/MapChat/NewMessage.js
diff --git a/frontend/src/components/MapChat/Participant.js b/frontend/src/components/MapView/MapChat/Participant.js
similarity index 100%
rename from frontend/src/components/MapChat/Participant.js
rename to frontend/src/components/MapView/MapChat/Participant.js
diff --git a/frontend/src/components/MapChat/Unread.js b/frontend/src/components/MapView/MapChat/Unread.js
similarity index 100%
rename from frontend/src/components/MapChat/Unread.js
rename to frontend/src/components/MapView/MapChat/Unread.js
diff --git a/frontend/src/components/MapChat/index.js b/frontend/src/components/MapView/MapChat/index.js
similarity index 99%
rename from frontend/src/components/MapChat/index.js
rename to frontend/src/components/MapView/MapChat/index.js
index 27bff527..dc8875e5 100644
--- a/frontend/src/components/MapChat/index.js
+++ b/frontend/src/components/MapView/MapChat/index.js
@@ -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
diff --git a/frontend/src/components/MapView/MapInfoBox.js b/frontend/src/components/MapView/MapInfoBox.js
new file mode 100644
index 00000000..a62934a1
--- /dev/null
+++ b/frontend/src/components/MapView/MapInfoBox.js
@@ -0,0 +1,12 @@
+import React, { Component, PropTypes } from 'react'
+
+class MapInfoBox extends Component {
+ static propTypes = {
+ }
+
+ render () {
+ return null
+ }
+}
+
+export default MapInfoBox
diff --git a/frontend/src/components/MapView/index.js b/frontend/src/components/MapView/index.js
new file mode 100644
index 00000000..552a77a0
--- /dev/null
+++ b/frontend/src/components/MapView/index.js
@@ -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
+ }
+}
+
+export default MapView
+
+/*
+
+
+<% 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' %>
+
+
+
+
+
+ Double-click to add a topic
+
+
+ Use Tab & Shift+Tab to select a metacode
+
+
+ Press Enter to add the topic
+
+
+
+*/
diff --git a/frontend/src/components/Maps/Header.js b/frontend/src/components/Maps/Header.js
index 9de1eb9b..65a23aa4 100644
--- a/frontend/src/components/Maps/Header.js
+++ b/frontend/src/components/Maps/Header.js
@@ -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 (
-
+
{text}
-
+
)
}
@@ -39,31 +40,26 @@ class Header extends Component {
diff --git a/frontend/src/components/Maps/MapCard.js b/frontend/src/components/Maps/MapCard.js
index 4dd9ea18..fa57af71 100644
--- a/frontend/src/components/Maps/MapCard.js
+++ b/frontend/src/components/Maps/MapCard.js
@@ -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 { element }
+ if (shouldWrap) return { element }
else return element
}
diff --git a/frontend/src/components/Maps/index.js b/frontend/src/components/Maps/index.js
index 18d0fe92..e45b94b0 100644
--- a/frontend/src/components/Maps/index.js
+++ b/frontend/src/components/Maps/index.js
@@ -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 (
{ user ?
: null }
{ currentUser && !user && !(pending && maps.length === 0) ?
: null }
- { maps.models.map(map =>
) }
+ { maps.models.map(map =>
) }
)
}
}
-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
diff --git a/frontend/src/components/TopicCard/Follow.js b/frontend/src/components/TopicCard/Follow.js
index 786001d7..653d8b18 100644
--- a/frontend/src/components/TopicCard/Follow.js
+++ b/frontend/src/components/TopicCard/Follow.js
@@ -2,8 +2,8 @@ import React, { PropTypes, Component } from 'react'
class Follow extends Component {
render = () => {
- const { isFollowing, onFollow } = this.props
- return
+ const { isFollowing, onTopicFollow } = this.props
+ return
{isFollowing ? 'Unfollow' : 'Follow'}
}
@@ -11,7 +11,7 @@ class Follow extends Component {
Follow.propTypes = {
isFollowing: PropTypes.bool,
- onFollow: PropTypes.func
+ onTopicFollow: PropTypes.func
}
export default Follow
diff --git a/frontend/src/components/TopicCard/index.js b/frontend/src/components/TopicCard/index.js
index 2c30d45e..089d942a 100644
--- a/frontend/src/components/TopicCard/index.js
+++ b/frontend/src/components/TopicCard/index.js
@@ -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 (
@@ -31,7 +34,7 @@ class ReactTopicCard extends Component {
onChange={this.props.updateTopic}
/>
- {Util.isTester(ActiveMapper) &&
}
+ {Util.isTester(currentUser) &&
}
@@ -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({
diff --git a/frontend/src/components/TopicView/index.js b/frontend/src/components/TopicView/index.js
new file mode 100644
index 00000000..e69de29b
diff --git a/frontend/src/components/makeRoutes.js b/frontend/src/components/makeRoutes.js
new file mode 100644
index 00000000..8564376a
--- /dev/null
+++ b/frontend/src/components/makeRoutes.js
@@ -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
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/package.json b/package.json
index 84eff416..c4f3a9fa 100644
--- a/package.json
+++ b/package.json
@@ -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",