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 {
|
.sidebarAccountIcon img {
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
|
width: 32px;
|
||||||
}
|
}
|
||||||
.sidebarAccountBox {
|
.sidebarAccountBox {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -54,7 +54,6 @@
|
||||||
width:100%;
|
width:100%;
|
||||||
height:100%;
|
height:100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.showcard .permission {
|
.showcard .permission {
|
||||||
|
|
|
@ -46,26 +46,9 @@
|
||||||
transition-timing-function: ease-in-out;
|
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 */
|
||||||
|
|
||||||
#loading {
|
#loading {
|
||||||
display: none;
|
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -236,6 +219,14 @@
|
||||||
|
|
||||||
/* end upperRightUI */
|
/* end upperRightUI */
|
||||||
|
|
||||||
|
/* map wrapper */
|
||||||
|
.mapWrapper {
|
||||||
|
position:absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end map wrapper */
|
||||||
|
|
||||||
/* yield */
|
/* yield */
|
||||||
|
|
||||||
|
@ -356,22 +347,15 @@
|
||||||
|
|
||||||
/* infoAndHelp */
|
/* infoAndHelp */
|
||||||
|
|
||||||
.mapPage .infoAndHelp, .topicPage .infoAndHelp {
|
|
||||||
right: 70px;
|
|
||||||
}
|
|
||||||
.mapPage .openCheatsheet .tooltipsAbove, .topicPage .openCheatsheet .tooltipsAbove {
|
.mapPage .openCheatsheet .tooltipsAbove, .topicPage .openCheatsheet .tooltipsAbove {
|
||||||
right: 1px;
|
right: 1px;
|
||||||
left: auto;
|
left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unauthenticated .homePage .infoAndHelp {
|
|
||||||
display:none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.infoAndHelp {
|
.infoAndHelp {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
right: 20px;
|
right: 70px;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
width: auto;
|
width: auto;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
@ -392,16 +376,12 @@
|
||||||
}
|
}
|
||||||
.mapInfoIcon {
|
.mapInfoIcon {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 56px; /* puts it just offscreen */
|
background-image: url(<%= asset_path('mapinfo_sprite.png') %>);
|
||||||
background-image: url(<%= asset_path('mapinfo_sprite.png') %>);
|
background-repeat:no-repeat;
|
||||||
background-repeat:no-repeat;
|
|
||||||
}
|
}
|
||||||
.mapInfoIcon:hover {
|
.mapInfoIcon:hover {
|
||||||
background-position: 0 -32px;
|
background-position: 0 -32px;
|
||||||
}
|
}
|
||||||
.mapPage .mapInfoIcon {
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.starMap {
|
.starMap {
|
||||||
background-image: url(<%= asset_path('starmap_sprite.png') %>);
|
background-image: url(<%= asset_path('starmap_sprite.png') %>);
|
||||||
|
@ -430,24 +410,17 @@
|
||||||
.mapControls {
|
.mapControls {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right:-32px; /* puts it just offscreen */
|
right:24px;
|
||||||
width:32px;
|
width:32px;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
.mapPage .mapControls, .topicPage .mapControls {
|
|
||||||
right: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topicPage .zoomExtents {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapControl {
|
.mapControl {
|
||||||
width:32px;
|
width:32px;
|
||||||
height:32px;
|
height:32px;
|
||||||
background-color: #424242;
|
background-color: #424242;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
cursor:pointer;
|
cursor:pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -671,8 +644,11 @@
|
||||||
|
|
||||||
/* explore maps */
|
/* explore maps */
|
||||||
|
|
||||||
#explore {
|
#react-app {
|
||||||
display: none;
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#exploreMaps {
|
#exploreMaps {
|
||||||
|
|
|
@ -4,7 +4,7 @@ class ApplicationController < ActionController::Base
|
||||||
include Pundit
|
include Pundit
|
||||||
include PunditExtra
|
include PunditExtra
|
||||||
rescue_from Pundit::NotAuthorizedError, with: :handle_unauthorized
|
rescue_from Pundit::NotAuthorizedError, with: :handle_unauthorized
|
||||||
protect_from_forgery(with: :exception)
|
#protect_from_forgery(with: :exception)
|
||||||
|
|
||||||
before_action :invite_link
|
before_action :invite_link
|
||||||
before_action :prepare_exception_notifier
|
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' %>
|
<%= render :partial => 'layouts/head' %>
|
||||||
|
|
||||||
<body class="<%= authenticated? ? "authenticated" : "unauthenticated" %> controller-<%= controller_name %> action-<%= action_name %>">
|
<body class="<%= authenticated? ? "authenticated" : "unauthenticated" %> controller-<%= controller_name %> action-<%= action_name %>">
|
||||||
|
<%= content_tag :div, class: "main", id: "react-app" do %>
|
||||||
<div id="chat-box-wrapper"></div>
|
<%= yield %>
|
||||||
|
<%= render :partial => 'layouts/mobilemenu' %>
|
||||||
<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>
|
|
||||||
|
|
||||||
<% end %>
|
<% 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' %>
|
<%= render :partial => 'layouts/foot' %>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import outdent from 'outdent'
|
import outdent from 'outdent'
|
||||||
|
|
||||||
import ImportDialogBox from '../../components/ImportDialogBox'
|
import ImportDialogBox from '../../components/MapView/ImportDialogBox'
|
||||||
|
|
||||||
import PasteInput from '../PasteInput'
|
import PasteInput from '../PasteInput'
|
||||||
import Map from '../Map'
|
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 */
|
/* global $, Hogan, Bloodhound, CanvasLoader */
|
||||||
|
|
||||||
import Active from '../Active'
|
import Active from '../Active'
|
||||||
import Router from '../Router'
|
|
||||||
|
|
||||||
const Search = {
|
const Search = {
|
||||||
locked: false,
|
locked: false,
|
||||||
|
@ -189,11 +188,11 @@ const Search = {
|
||||||
|
|
||||||
if (['topic', 'map', 'mapper'].indexOf(datum.rtype) !== -1) {
|
if (['topic', 'map', 'mapper'].indexOf(datum.rtype) !== -1) {
|
||||||
if (datum.rtype === 'topic') {
|
if (datum.rtype === 'topic') {
|
||||||
Router.topics(datum.id)
|
// TODO: navigate to topic datum.id
|
||||||
} else if (datum.rtype === 'map') {
|
} else if (datum.rtype === 'map') {
|
||||||
Router.maps(datum.id)
|
// TODO: navigate to map datum.id
|
||||||
} else if (datum.rtype === 'mapper') {
|
} 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 Create from '../Create'
|
||||||
|
|
||||||
|
import ReactApp from './ReactApp'
|
||||||
import Search from './Search'
|
import Search from './Search'
|
||||||
import CreateMap from './CreateMap'
|
import CreateMap from './CreateMap'
|
||||||
import Account from './Account'
|
import Account from './Account'
|
||||||
import ImportDialog from './ImportDialog'
|
import ImportDialog from './ImportDialog'
|
||||||
import NotificationIcon from './NotificationIcon'
|
|
||||||
|
|
||||||
const GlobalUI = {
|
const GlobalUI = {
|
||||||
notifyTimeout: null,
|
notifyTimeout: null,
|
||||||
|
@ -18,11 +18,11 @@ const GlobalUI = {
|
||||||
init: function(serverData) {
|
init: function(serverData) {
|
||||||
const self = GlobalUI
|
const self = GlobalUI
|
||||||
|
|
||||||
|
self.ReactApp.init(serverData)
|
||||||
self.Search.init(serverData)
|
self.Search.init(serverData)
|
||||||
self.CreateMap.init(serverData)
|
self.CreateMap.init(serverData)
|
||||||
self.Account.init(serverData)
|
self.Account.init(serverData)
|
||||||
self.ImportDialog.init(serverData, self.openLightbox, self.closeLightbox)
|
self.ImportDialog.init(serverData, self.openLightbox, self.closeLightbox)
|
||||||
self.NotificationIcon.init(serverData)
|
|
||||||
|
|
||||||
if ($('#toast').html().trim()) self.notifyUser($('#toast').html())
|
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
|
export default GlobalUI
|
||||||
|
|
|
@ -5,7 +5,6 @@ import outdent from 'outdent'
|
||||||
import Active from '../Active'
|
import Active from '../Active'
|
||||||
import DataModel from '../DataModel'
|
import DataModel from '../DataModel'
|
||||||
import GlobalUI from '../GlobalUI'
|
import GlobalUI from '../GlobalUI'
|
||||||
import Router from '../Router'
|
|
||||||
import Util from '../Util'
|
import Util from '../Util'
|
||||||
|
|
||||||
const InfoBox = {
|
const InfoBox = {
|
||||||
|
@ -192,7 +191,6 @@ const InfoBox = {
|
||||||
$('.mapContributors .tip').unbind().click(function(event) {
|
$('.mapContributors .tip').unbind().click(function(event) {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
})
|
})
|
||||||
$('.mapContributors .tip li a').click(Router.intercept)
|
|
||||||
|
|
||||||
$('.mapInfoBox').unbind('.hideTip').bind('click.hideTip', function() {
|
$('.mapInfoBox').unbind('.hideTip').bind('click.hideTip', function() {
|
||||||
$('.mapContributors .tip').hide()
|
$('.mapContributors .tip').hide()
|
||||||
|
@ -393,7 +391,7 @@ const InfoBox = {
|
||||||
DataModel.Maps.Mine.remove(map)
|
DataModel.Maps.Mine.remove(map)
|
||||||
DataModel.Maps.Shared.remove(map)
|
DataModel.Maps.Shared.remove(map)
|
||||||
map.destroy()
|
map.destroy()
|
||||||
Router.home()
|
// TODO: navigate home
|
||||||
GlobalUI.notifyUser('Map eliminated')
|
GlobalUI.notifyUser('Map eliminated')
|
||||||
} else if (!authorized) {
|
} 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?")
|
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 JIT from '../JIT'
|
||||||
import Loading from '../Loading'
|
import Loading from '../Loading'
|
||||||
import Realtime from '../Realtime'
|
import Realtime from '../Realtime'
|
||||||
import Router from '../Router'
|
|
||||||
import Selected from '../Selected'
|
import Selected from '../Selected'
|
||||||
import SynapseCard from '../SynapseCard'
|
import SynapseCard from '../SynapseCard'
|
||||||
import TopicCard from '../Views/TopicCard'
|
import TopicCard from '../Views/TopicCard'
|
||||||
|
@ -132,7 +131,7 @@ const Map = {
|
||||||
// for mobile
|
// for mobile
|
||||||
$('#header_content').html(map.get('name'))
|
$('#header_content').html(map.get('name'))
|
||||||
}
|
}
|
||||||
|
Loading.show()
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/maps/' + id + '/contains.json',
|
url: '/maps/' + id + '/contains.json',
|
||||||
success: start
|
success: start
|
||||||
|
@ -232,7 +231,7 @@ const Map = {
|
||||||
var map = Active.Map
|
var map = Active.Map
|
||||||
DataModel.Maps.Active.remove(map)
|
DataModel.Maps.Active.remove(map)
|
||||||
DataModel.Maps.Featured.remove(map)
|
DataModel.Maps.Featured.remove(map)
|
||||||
Router.home()
|
// TODO: navigate home
|
||||||
GlobalUI.notifyUser('Sorry! That map has been changed to Private.')
|
GlobalUI.notifyUser('Sorry! That map has been changed to Private.')
|
||||||
},
|
},
|
||||||
cantEditNow: function() {
|
cantEditNow: function() {
|
||||||
|
@ -245,7 +244,7 @@ const Map = {
|
||||||
confirmString += 'Do you want to reload and enable realtime collaboration?'
|
confirmString += 'Do you want to reload and enable realtime collaboration?'
|
||||||
var c = window.confirm(confirmString)
|
var c = window.confirm(confirmString)
|
||||||
if (c) {
|
if (c) {
|
||||||
Router.maps(Active.Map.id)
|
// TODO: reload the map somehow
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
editedByActiveMapper: function() {
|
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 GlobalUI from './GlobalUI'
|
||||||
import JIT from './JIT'
|
import JIT from './JIT'
|
||||||
import Map from './Map'
|
import Map from './Map'
|
||||||
import Router from './Router'
|
|
||||||
import Selected from './Selected'
|
import Selected from './Selected'
|
||||||
import Settings from './Settings'
|
import Settings from './Settings'
|
||||||
import SynapseCard from './SynapseCard'
|
import SynapseCard from './SynapseCard'
|
||||||
|
@ -90,7 +89,6 @@ const Topic = {
|
||||||
if (callback) callback()
|
if (callback) callback()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
Router.navigate('/topics/' + nodeid)
|
|
||||||
Active.Topic = DataModel.Topics.get(nodeid)
|
Active.Topic = DataModel.Topics.get(nodeid)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,7 +10,7 @@ import ReactDOM from 'react-dom'
|
||||||
import Active from '../Active'
|
import Active from '../Active'
|
||||||
import DataModel from '../DataModel'
|
import DataModel from '../DataModel'
|
||||||
import Realtime from '../Realtime'
|
import Realtime from '../Realtime'
|
||||||
import MapChat from '../../components/MapChat'
|
import ReactApp from '../GlobalUI/ReactApp'
|
||||||
|
|
||||||
const ChatView = {
|
const ChatView = {
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
|
@ -51,24 +51,7 @@ const ChatView = {
|
||||||
render: () => {
|
render: () => {
|
||||||
if (!Active.Map) return
|
if (!Active.Map) return
|
||||||
const self = ChatView
|
const self = ChatView
|
||||||
self.mapChat = ReactDOM.render(React.createElement(MapChat, {
|
ReactApp.render()
|
||||||
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))
|
|
||||||
},
|
},
|
||||||
onOpen: () => {
|
onOpen: () => {
|
||||||
$(document).trigger(ChatView.events.openTray)
|
$(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 Active from '../Active'
|
||||||
import DataModel from '../DataModel'
|
import DataModel from '../DataModel'
|
||||||
import GlobalUI from '../GlobalUI'
|
import GlobalUI from '../GlobalUI'
|
||||||
|
import { ReactApp } from '../GlobalUI'
|
||||||
import Realtime from '../Realtime'
|
import Realtime from '../Realtime'
|
||||||
import Loading from '../Loading'
|
import Loading from '../Loading'
|
||||||
import Maps from '../../components/Maps'
|
import Maps from '../../components/Maps'
|
||||||
|
@ -13,6 +14,37 @@ import Maps from '../../components/Maps'
|
||||||
const ExploreMaps = {
|
const ExploreMaps = {
|
||||||
pending: false,
|
pending: false,
|
||||||
mapper: null,
|
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) {
|
setCollection: function(collection) {
|
||||||
var self = ExploreMaps
|
var self = ExploreMaps
|
||||||
|
|
||||||
|
@ -26,55 +58,9 @@ const ExploreMaps = {
|
||||||
self.collection.on('successOnFetch', self.handleSuccess)
|
self.collection.on('successOnFetch', self.handleSuccess)
|
||||||
self.collection.on('errorOnFetch', self.handleError)
|
self.collection.on('errorOnFetch', self.handleError)
|
||||||
},
|
},
|
||||||
render: function(cb) {
|
render: function() {
|
||||||
var self = ExploreMaps
|
var self = ExploreMaps
|
||||||
|
ReactApp.render()
|
||||||
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()
|
|
||||||
Loading.hide()
|
Loading.hide()
|
||||||
},
|
},
|
||||||
loadMore: function() {
|
loadMore: function() {
|
||||||
|
@ -85,14 +71,13 @@ const ExploreMaps = {
|
||||||
}
|
}
|
||||||
self.render()
|
self.render()
|
||||||
},
|
},
|
||||||
handleSuccess: function(cb) {
|
handleSuccess: function() {
|
||||||
var self = ExploreMaps
|
var self = ExploreMaps
|
||||||
self.pending = false
|
self.pending = false
|
||||||
if (self.collection && self.collection.id === 'mapper') {
|
if (self.collection && self.collection.id === 'mapper') {
|
||||||
self.fetchUserThenRender(cb)
|
self.fetchUserThenRender()
|
||||||
} else {
|
} else {
|
||||||
self.render(cb)
|
self.render()
|
||||||
Loading.hide()
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleError: function() {
|
handleError: function() {
|
||||||
|
@ -103,8 +88,8 @@ const ExploreMaps = {
|
||||||
var self = ExploreMaps
|
var self = ExploreMaps
|
||||||
|
|
||||||
if (self.mapper && self.mapper.id === self.collection.mapperId) {
|
if (self.mapper && self.mapper.id === self.collection.mapperId) {
|
||||||
self.render(cb)
|
self.render()
|
||||||
return Loading.hide()
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// first load the mapper object and then call the render function
|
// first load the mapper object and then call the render function
|
||||||
|
@ -112,14 +97,40 @@ const ExploreMaps = {
|
||||||
url: '/users/' + self.collection.mapperId + '/details.json',
|
url: '/users/' + self.collection.mapperId + '/details.json',
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
self.mapper = response
|
self.mapper = response
|
||||||
self.render(cb)
|
self.render()
|
||||||
Loading.hide()
|
|
||||||
},
|
},
|
||||||
error: function() {
|
error: function() {
|
||||||
self.render(cb)
|
self.render()
|
||||||
Loading.hide()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
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 Active from '../Active'
|
||||||
import Visualize from '../Visualize'
|
import Visualize from '../Visualize'
|
||||||
import GlobalUI from '../GlobalUI'
|
import GlobalUI, { ReactApp } from '../GlobalUI'
|
||||||
|
|
||||||
import ReactTopicCard from '../../components/TopicCard'
|
|
||||||
|
|
||||||
const TopicCard = {
|
const TopicCard = {
|
||||||
openTopicCard: null, // stores the topic that's currently open
|
openTopic: null, // stores the topic that's currently open
|
||||||
metacodeSets: [],
|
metacodeSets: [],
|
||||||
|
updateTopic: () => {},
|
||||||
|
onTopicFollow: () => {},
|
||||||
|
redrawCanvas: () => {
|
||||||
|
Visualize.mGraph.plot()
|
||||||
|
},
|
||||||
init: function(serverData) {
|
init: function(serverData) {
|
||||||
const self = TopicCard
|
const self = TopicCard
|
||||||
self.metacodeSets = serverData.metacodeSets
|
self.metacodeSets = serverData.metacodeSets
|
||||||
},
|
},
|
||||||
populateShowCard: function(topic) {
|
populateShowCard: function(topic) {
|
||||||
const self = TopicCard
|
const self = TopicCard
|
||||||
ReactDOM.render(
|
TopicCard.updateTopic = obj => {
|
||||||
React.createElement(ReactTopicCard, {
|
topic.save(obj, { success: topic => self.populateShowCard(topic) })
|
||||||
topic: topic,
|
}
|
||||||
ActiveMapper: Active.Mapper,
|
TopicCard.onTopicFollow = () => {
|
||||||
updateTopic: obj => {
|
const isFollowing = topic.isFollowedBy(Active.Mapper)
|
||||||
topic.save(obj, { success: topic => self.populateShowCard(topic) })
|
$.post({
|
||||||
},
|
url: `/topics/${topic.id}/${isFollowing ? 'un' : ''}follow`
|
||||||
onFollow: () => {
|
})
|
||||||
const isFollowing = topic.isFollowedBy(Active.Mapper)
|
if (isFollowing) {
|
||||||
$.post({
|
GlobalUI.notifyUser('You are no longer following this topic')
|
||||||
url: `/topics/${topic.id}/${isFollowing ? 'un' : ''}follow`
|
Active.Mapper.unfollowTopic(topic.id)
|
||||||
})
|
} else {
|
||||||
if (isFollowing) {
|
GlobalUI.notifyUser('You are now following this topic')
|
||||||
GlobalUI.notifyUser('You are no longer following this topic')
|
Active.Mapper.followTopic(topic.id)
|
||||||
Active.Mapper.unfollowTopic(topic.id)
|
}
|
||||||
} else {
|
self.populateShowCard(topic)
|
||||||
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')
|
|
||||||
)
|
|
||||||
|
|
||||||
// initialize draggability
|
// initialize draggability
|
||||||
$('.showcard').draggable({
|
$('.showcard').draggable({
|
||||||
handle: '.metacodeImage',
|
handle: '.metacodeImage',
|
||||||
|
@ -54,12 +45,12 @@ const TopicCard = {
|
||||||
$(this).height('auto')
|
$(this).height('auto')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
ReactApp.render()
|
||||||
},
|
},
|
||||||
showCard: function(node, opts) {
|
showCard: function(node, opts = {}) {
|
||||||
var self = TopicCard
|
var self = TopicCard
|
||||||
if (!opts) opts = {}
|
|
||||||
var topic = node.getData('topic')
|
var topic = node.getData('topic')
|
||||||
self.openTopicCard = topic
|
self.openTopic = topic
|
||||||
// populate the card that's about to show with the right topics data
|
// populate the card that's about to show with the right topics data
|
||||||
self.populateShowCard(topic)
|
self.populateShowCard(topic)
|
||||||
return $('.showcard').fadeIn('fast', () => opts.complete && opts.complete())
|
return $('.showcard').fadeIn('fast', () => opts.complete && opts.complete())
|
||||||
|
@ -67,7 +58,7 @@ const TopicCard = {
|
||||||
hideCard: function() {
|
hideCard: function() {
|
||||||
var self = TopicCard
|
var self = TopicCard
|
||||||
$('.showcard').fadeOut('fast')
|
$('.showcard').fadeOut('fast')
|
||||||
self.openTopicCard = null
|
self.openTopic = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import Active from './Active'
|
||||||
import DataModel from './DataModel'
|
import DataModel from './DataModel'
|
||||||
import JIT from './JIT'
|
import JIT from './JIT'
|
||||||
import Loading from './Loading'
|
import Loading from './Loading'
|
||||||
import Router from './Router'
|
|
||||||
import TopicCard from './Views/TopicCard'
|
import TopicCard from './Views/TopicCard'
|
||||||
|
|
||||||
const Visualize = {
|
const Visualize = {
|
||||||
|
@ -198,19 +197,6 @@ const Visualize = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hold()
|
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() {
|
clearVisualization: function() {
|
||||||
Visualize.mGraph.graph.empty()
|
Visualize.mGraph.graph.empty()
|
||||||
|
|
|
@ -9,8 +9,7 @@ import DataModel from './DataModel'
|
||||||
import Debug from './Debug'
|
import Debug from './Debug'
|
||||||
import Filter from './Filter'
|
import Filter from './Filter'
|
||||||
import GlobalUI, {
|
import GlobalUI, {
|
||||||
Search, CreateMap, ImportDialog, Account as GlobalUIAccount,
|
ReactApp, Search, CreateMap, ImportDialog, Account as GlobalUIAccount
|
||||||
NotificationIcon
|
|
||||||
} from './GlobalUI'
|
} from './GlobalUI'
|
||||||
import Import from './Import'
|
import Import from './Import'
|
||||||
import JIT from './JIT'
|
import JIT from './JIT'
|
||||||
|
@ -23,7 +22,6 @@ import Mouse from './Mouse'
|
||||||
import Organize from './Organize'
|
import Organize from './Organize'
|
||||||
import PasteInput from './PasteInput'
|
import PasteInput from './PasteInput'
|
||||||
import Realtime from './Realtime'
|
import Realtime from './Realtime'
|
||||||
import Router from './Router'
|
|
||||||
import Selected from './Selected'
|
import Selected from './Selected'
|
||||||
import Settings from './Settings'
|
import Settings from './Settings'
|
||||||
import Synapse from './Synapse'
|
import Synapse from './Synapse'
|
||||||
|
@ -45,11 +43,11 @@ Metamaps.DataModel = DataModel
|
||||||
Metamaps.Debug = Debug
|
Metamaps.Debug = Debug
|
||||||
Metamaps.Filter = Filter
|
Metamaps.Filter = Filter
|
||||||
Metamaps.GlobalUI = GlobalUI
|
Metamaps.GlobalUI = GlobalUI
|
||||||
|
Metamaps.GlobalUI.ReactApp = ReactApp
|
||||||
Metamaps.GlobalUI.Search = Search
|
Metamaps.GlobalUI.Search = Search
|
||||||
Metamaps.GlobalUI.CreateMap = CreateMap
|
Metamaps.GlobalUI.CreateMap = CreateMap
|
||||||
Metamaps.GlobalUI.Account = GlobalUIAccount
|
Metamaps.GlobalUI.Account = GlobalUIAccount
|
||||||
Metamaps.GlobalUI.ImportDialog = ImportDialog
|
Metamaps.GlobalUI.ImportDialog = ImportDialog
|
||||||
Metamaps.GlobalUI.NotificationIcon = NotificationIcon
|
|
||||||
Metamaps.Import = Import
|
Metamaps.Import = Import
|
||||||
Metamaps.JIT = JIT
|
Metamaps.JIT = JIT
|
||||||
Metamaps.Listeners = Listeners
|
Metamaps.Listeners = Listeners
|
||||||
|
@ -64,7 +62,6 @@ Metamaps.Mouse = Mouse
|
||||||
Metamaps.Organize = Organize
|
Metamaps.Organize = Organize
|
||||||
Metamaps.PasteInput = PasteInput
|
Metamaps.PasteInput = PasteInput
|
||||||
Metamaps.Realtime = Realtime
|
Metamaps.Realtime = Realtime
|
||||||
Metamaps.Router = Router
|
|
||||||
Metamaps.Selected = Selected
|
Metamaps.Selected = Selected
|
||||||
Metamaps.Settings = Settings
|
Metamaps.Settings = Settings
|
||||||
Metamaps.Synapse = Synapse
|
Metamaps.Synapse = Synapse
|
||||||
|
@ -86,26 +83,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||||
Metamaps[prop].init(Metamaps.ServerData)
|
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
|
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'
|
import React, { PropTypes, Component } from 'react'
|
||||||
|
|
||||||
class NotificationIcon extends Component {
|
class NotificationIcon extends Component {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
unreadNotificationsCount: PropTypes.number
|
||||||
|
}
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
|
@ -31,8 +36,4 @@ class NotificationIcon extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationIcon.propTypes = {
|
|
||||||
unreadNotificationsCount: PropTypes.number
|
|
||||||
}
|
|
||||||
|
|
||||||
export default NotificationIcon
|
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 React from 'react'
|
||||||
import Autolinker from 'autolinker'
|
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 })
|
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 Participant from './Participant'
|
||||||
import Message from './Message'
|
import Message from './Message'
|
||||||
import NewMessage from './NewMessage'
|
import NewMessage from './NewMessage'
|
||||||
import Util from '../../Metamaps/Util'
|
import Util from '../../../Metamaps/Util'
|
||||||
|
|
||||||
function makeList(messages) {
|
function makeList(messages) {
|
||||||
let currentHeader
|
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 React, { Component, PropTypes } from 'react'
|
||||||
|
import { Link } from 'react-router'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
|
||||||
const MapLink = props => {
|
const MapLink = props => {
|
||||||
|
@ -9,10 +10,10 @@ const MapLink = props => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a { ...otherProps } href={href} className={linkClass}>
|
<Link { ...otherProps } to={href} className={linkClass}>
|
||||||
<div className="exploreMapsIcon"></div>
|
<div className="exploreMapsIcon"></div>
|
||||||
{text}
|
{text}
|
||||||
</a>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,31 +40,26 @@ class Header extends Component {
|
||||||
<MapLink show={explore}
|
<MapLink show={explore}
|
||||||
href={signedIn ? '/' : '/explore/active'}
|
href={signedIn ? '/' : '/explore/active'}
|
||||||
linkClass={activeClass('active')}
|
linkClass={activeClass('active')}
|
||||||
data-router="true"
|
|
||||||
text="All Maps"
|
text="All Maps"
|
||||||
/>
|
/>
|
||||||
<MapLink show={signedIn && explore}
|
<MapLink show={signedIn && explore}
|
||||||
href="/explore/mine"
|
href="/explore/mine"
|
||||||
linkClass={activeClass('my')}
|
linkClass={activeClass('my')}
|
||||||
data-router="true"
|
|
||||||
text="My Maps"
|
text="My Maps"
|
||||||
/>
|
/>
|
||||||
<MapLink show={signedIn && explore}
|
<MapLink show={signedIn && explore}
|
||||||
href="/explore/shared"
|
href="/explore/shared"
|
||||||
linkClass={activeClass('shared')}
|
linkClass={activeClass('shared')}
|
||||||
data-router="true"
|
|
||||||
text="Shared With Me"
|
text="Shared With Me"
|
||||||
/>
|
/>
|
||||||
<MapLink show={signedIn && explore}
|
<MapLink show={signedIn && explore}
|
||||||
href="/explore/starred"
|
href="/explore/starred"
|
||||||
linkClass={activeClass('starred')}
|
linkClass={activeClass('starred')}
|
||||||
data-router="true"
|
|
||||||
text="Starred By Me"
|
text="Starred By Me"
|
||||||
/>
|
/>
|
||||||
<MapLink show={!signedIn && explore}
|
<MapLink show={!signedIn && explore}
|
||||||
href="/explore/featured"
|
href="/explore/featured"
|
||||||
linkClass={activeClass('featured')}
|
linkClass={activeClass('featured')}
|
||||||
data-router="true"
|
|
||||||
text="Featured Maps"
|
text="Featured Maps"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { Component, PropTypes } from 'react'
|
import React, { Component, PropTypes } from 'react'
|
||||||
|
import { Link } from 'react-router'
|
||||||
import { find, values } from 'lodash'
|
import { find, values } from 'lodash'
|
||||||
import Util from '../../Metamaps/Util'
|
import Util from '../../Metamaps/Util'
|
||||||
|
|
||||||
|
@ -78,7 +79,7 @@ const Metadata = (props) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkAndWrapInA = (shouldWrap, classString, mapId, element) => {
|
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
|
else return element
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,25 @@ const MAX_COLUMNS = 4
|
||||||
|
|
||||||
class Maps extends Component {
|
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) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = { mapsWidth: 0 }
|
this.state = { mapsWidth: 0 }
|
||||||
|
@ -19,7 +38,7 @@ class Maps extends Component {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window && window.addEventListener('resize', this.resize)
|
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()
|
this.resize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +48,7 @@ class Maps extends Component {
|
||||||
|
|
||||||
resize = () => {
|
resize = () => {
|
||||||
const { maps, user, currentUser } = this.props
|
const { maps, user, currentUser } = this.props
|
||||||
|
if (!maps) return
|
||||||
const numCards = maps.length + (user || currentUser ? 1 : 0)
|
const numCards = maps.length + (user || currentUser ? 1 : 0)
|
||||||
const mapSpaces = Math.floor(document.body.clientWidth / MAP_WIDTH)
|
const mapSpaces = Math.floor(document.body.clientWidth / MAP_WIDTH)
|
||||||
const mapsWidth = document.body.clientWidth <= MOBILE_VIEW_BREAKPOINT
|
const mapsWidth = document.body.clientWidth <= MOBILE_VIEW_BREAKPOINT
|
||||||
|
@ -46,41 +66,30 @@ class Maps extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render = () => {
|
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 style = { width: this.state.mapsWidth + 'px' }
|
||||||
const mobile = document && document.body.clientWidth <= MOBILE_VIEW_BREAKPOINT
|
const mobile = document && document.body.clientWidth <= MOBILE_VIEW_BREAKPOINT
|
||||||
|
|
||||||
|
if (!maps) return null // do loading here instead
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div id='exploreMaps' ref='maps'>
|
<div id='exploreMaps' ref='maps'>
|
||||||
<div style={ style }>
|
<div style={ style }>
|
||||||
{ user ? <MapperCard user={ user } /> : null }
|
{ 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 }
|
{ 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 className='clearfloat'></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Header signedIn={ !!currentUser }
|
<Header signedIn={ !!currentUser }
|
||||||
section={ section }
|
section={ section }
|
||||||
user={ user }
|
user={ user }
|
||||||
|
setCollection={ setCollection }
|
||||||
/>
|
/>
|
||||||
</div>
|
</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
|
export default Maps
|
||||||
|
|
|
@ -2,8 +2,8 @@ import React, { PropTypes, Component } from 'react'
|
||||||
|
|
||||||
class Follow extends Component {
|
class Follow extends Component {
|
||||||
render = () => {
|
render = () => {
|
||||||
const { isFollowing, onFollow } = this.props
|
const { isFollowing, onTopicFollow } = this.props
|
||||||
return <div className='topicFollow' onClick={onFollow}>
|
return <div className='topicFollow' onClick={onTopicFollow}>
|
||||||
{isFollowing ? 'Unfollow' : 'Follow'}
|
{isFollowing ? 'Unfollow' : 'Follow'}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ class Follow extends Component {
|
||||||
|
|
||||||
Follow.propTypes = {
|
Follow.propTypes = {
|
||||||
isFollowing: PropTypes.bool,
|
isFollowing: PropTypes.bool,
|
||||||
onFollow: PropTypes.func
|
onTopicFollow: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Follow
|
export default Follow
|
||||||
|
|
|
@ -7,12 +7,15 @@ import Attachments from './Attachments'
|
||||||
import Follow from './Follow'
|
import Follow from './Follow'
|
||||||
import Util from '../../Metamaps/Util'
|
import Util from '../../Metamaps/Util'
|
||||||
|
|
||||||
|
|
||||||
class ReactTopicCard extends Component {
|
class ReactTopicCard extends Component {
|
||||||
render = () => {
|
render = () => {
|
||||||
const { topic, ActiveMapper, onFollow } = this.props
|
const { currentUser, onTopicFollow } = this.props
|
||||||
const authorizedToEdit = topic.authorizeToEdit(ActiveMapper)
|
const topic = this.props.openTopic
|
||||||
const isFollowing = topic.isFollowedBy(ActiveMapper)
|
|
||||||
|
if (!topic) return null
|
||||||
|
|
||||||
|
const authorizedToEdit = topic.authorizeToEdit(currentUser)
|
||||||
|
const isFollowing = topic.isFollowedBy(currentUser)
|
||||||
const hasAttachment = topic.get('link') && topic.get('link') !== ''
|
const hasAttachment = topic.get('link') && topic.get('link') !== ''
|
||||||
|
|
||||||
let classname = 'permission'
|
let classname = 'permission'
|
||||||
|
@ -21,7 +24,7 @@ class ReactTopicCard extends Component {
|
||||||
} else {
|
} else {
|
||||||
classname += ' cannotEdit'
|
classname += ' cannotEdit'
|
||||||
}
|
}
|
||||||
if (topic.authorizePermissionChange(ActiveMapper)) classname += ' yourTopic'
|
if (topic.authorizePermissionChange(currentUser)) classname += ' yourTopic'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classname}>
|
<div className={classname}>
|
||||||
|
@ -31,7 +34,7 @@ class ReactTopicCard extends Component {
|
||||||
onChange={this.props.updateTopic}
|
onChange={this.props.updateTopic}
|
||||||
/>
|
/>
|
||||||
<Links topic={topic}
|
<Links topic={topic}
|
||||||
ActiveMapper={this.props.ActiveMapper}
|
ActiveMapper={this.props.currentUser}
|
||||||
updateTopic={this.props.updateTopic}
|
updateTopic={this.props.updateTopic}
|
||||||
metacodeSets={this.props.metacodeSets}
|
metacodeSets={this.props.metacodeSets}
|
||||||
redrawCanvas={this.props.redrawCanvas}
|
redrawCanvas={this.props.redrawCanvas}
|
||||||
|
@ -44,7 +47,7 @@ class ReactTopicCard extends Component {
|
||||||
authorizedToEdit={authorizedToEdit}
|
authorizedToEdit={authorizedToEdit}
|
||||||
updateTopic={this.props.updateTopic}
|
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 className="clearfloat"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -53,10 +56,10 @@ class ReactTopicCard extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactTopicCard.propTypes = {
|
ReactTopicCard.propTypes = {
|
||||||
topic: PropTypes.object,
|
openTopic: PropTypes.object,
|
||||||
ActiveMapper: PropTypes.object,
|
currentUser: PropTypes.object,
|
||||||
updateTopic: PropTypes.func,
|
updateTopic: PropTypes.func,
|
||||||
onFollow: PropTypes.func,
|
onTopicFollow: PropTypes.func,
|
||||||
metacodeSets: PropTypes.arrayOf(PropTypes.shape({
|
metacodeSets: PropTypes.arrayOf(PropTypes.shape({
|
||||||
name: PropTypes.string,
|
name: PropTypes.string,
|
||||||
metacodes: PropTypes.arrayOf(PropTypes.shape({
|
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-dom": "15.4.2",
|
||||||
"react-dropzone": "3.9.1",
|
"react-dropzone": "3.9.1",
|
||||||
"react-onclickoutside": "5.9.0",
|
"react-onclickoutside": "5.9.0",
|
||||||
|
"react-router": "^3.0.2",
|
||||||
"redux": "3.6.0",
|
"redux": "3.6.0",
|
||||||
"riek": "1.0.7",
|
"riek": "1.0.7",
|
||||||
"simplewebrtc": "2.2.2",
|
"simplewebrtc": "2.2.2",
|
||||||
|
|
Loading…
Add table
Reference in a new issue