Redo all of explore together in React (#617)
* unify explore in react * no more need for manual scroll reseting * we're not opening/closing the search anymore
This commit is contained in:
parent
c89a6771ea
commit
d7759c8c07
15 changed files with 268 additions and 275 deletions
|
@ -43,5 +43,4 @@
|
||||||
//= require ./src/Metamaps.Mobile
|
//= require ./src/Metamaps.Mobile
|
||||||
//= require ./src/Metamaps.Admin
|
//= require ./src/Metamaps.Admin
|
||||||
//= require ./src/Metamaps.Import
|
//= require ./src/Metamaps.Import
|
||||||
//= require ./src/Metamaps.Header
|
|
||||||
//= require ./src/Metamaps.JIT
|
//= require ./src/Metamaps.JIT
|
||||||
|
|
|
@ -121,36 +121,6 @@ Metamaps.Backbone.Map = Backbone.Model.extend({
|
||||||
}
|
}
|
||||||
return this.get('mappers')
|
return this.get('mappers')
|
||||||
},
|
},
|
||||||
attrForCards: function () {
|
|
||||||
function capitalize (string) {
|
|
||||||
return string.charAt(0).toUpperCase() + string.slice(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var n = this.get('name')
|
|
||||||
var d = this.get('desc')
|
|
||||||
|
|
||||||
var maxNameLength = 32
|
|
||||||
var maxDescLength = 118
|
|
||||||
var truncatedName = n ? (n.length > maxNameLength ? n.substring(0, maxNameLength) + '...' : n) : ''
|
|
||||||
var truncatedDesc = d ? (d.length > maxDescLength ? d.substring(0, maxDescLength) + '...' : d) : ''
|
|
||||||
|
|
||||||
var obj = {
|
|
||||||
id: this.id,
|
|
||||||
name: truncatedName,
|
|
||||||
fullName: n,
|
|
||||||
desc: truncatedDesc,
|
|
||||||
permission: this.get('permission') ? capitalize(this.get('permission')) : 'Commons',
|
|
||||||
editPermission: this.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEdit' : 'cannotEdit',
|
|
||||||
contributor_count_number: '<span class="cCountColor">' + this.get('contributor_count') + '</span>',
|
|
||||||
contributor_count_string: this.get('contributor_count') === 1 ? ' contributor' : ' contributors',
|
|
||||||
topic_count_number: '<span class="tCountColor">' + this.get('topic_count') + '</span>',
|
|
||||||
topic_count_string: this.get('topic_count') === 1 ? ' topic' : ' topics',
|
|
||||||
synapse_count_number: '<span class="sCountColor">' + this.get('synapse_count') + '</span>',
|
|
||||||
synapse_count_string: this.get('synapse_count') === 1 ? ' synapse' : ' synapses',
|
|
||||||
screenshot: '<img src="' + this.get('screenshot_url') + '" />'
|
|
||||||
}
|
|
||||||
return obj
|
|
||||||
},
|
|
||||||
updateView: function () {
|
updateView: function () {
|
||||||
var map = Metamaps.Active.Map
|
var map = Metamaps.Active.Map
|
||||||
var isActiveMap = this.id === map.id
|
var isActiveMap = this.id === map.id
|
||||||
|
|
|
@ -51,31 +51,26 @@ $(document).ready(function () {
|
||||||
Metamaps[prop].hasOwnProperty('init') &&
|
Metamaps[prop].hasOwnProperty('init') &&
|
||||||
typeof (Metamaps[prop].init) == 'function'
|
typeof (Metamaps[prop].init) == 'function'
|
||||||
) {
|
) {
|
||||||
Metamaps[prop].init();
|
Metamaps[prop].init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// load whichever page you are on
|
// load whichever page you are on
|
||||||
if (Metamaps.currentSection === "explore") {
|
if (Metamaps.currentSection === "explore") {
|
||||||
var capitalize = Metamaps.currentPage.charAt(0).toUpperCase() + Metamaps.currentPage.slice(1);
|
var capitalize = Metamaps.currentPage.charAt(0).toUpperCase() + Metamaps.currentPage.slice(1)
|
||||||
|
|
||||||
Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps[capitalize] );
|
Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps[capitalize] )
|
||||||
if (Metamaps.currentPage === "mapper") {
|
if (Metamaps.currentPage === "mapper") {
|
||||||
Metamaps.Views.exploreMaps.fetchUserThenRender();
|
Metamaps.Views.exploreMaps.fetchUserThenRender()
|
||||||
Metamaps.Header.fetchUserThenChangeSection(!!Metamaps.Active.Mapper, Metamaps.Maps.Mapper.mapperId)
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Metamaps.Views.exploreMaps.render();
|
Metamaps.Views.exploreMaps.render()
|
||||||
Metamaps.Header.changeSection(!!Metamaps.Active.Mapper, Metamaps.currentPage)
|
|
||||||
}
|
}
|
||||||
Metamaps.GlobalUI.showDiv('#exploreMaps')
|
Metamaps.GlobalUI.showDiv('#explore')
|
||||||
Metamaps.GlobalUI.showDiv('#exploreMapsHeader')
|
|
||||||
}
|
}
|
||||||
else if (Metamaps.currentSection === "" && Metamaps.Active.Mapper) {
|
else if (Metamaps.currentSection === "" && Metamaps.Active.Mapper) {
|
||||||
Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps.Active );
|
Metamaps.Views.exploreMaps.setCollection(Metamaps.Maps.Active)
|
||||||
Metamaps.Views.exploreMaps.render();
|
Metamaps.Views.exploreMaps.render()
|
||||||
Metamaps.GlobalUI.showDiv('#exploreMaps')
|
Metamaps.GlobalUI.showDiv('#explore')
|
||||||
Metamaps.Header.changeSection(!!Metamaps.Active.Mapper, 'active')
|
|
||||||
Metamaps.GlobalUI.showDiv('#exploreMapsHeader')
|
|
||||||
}
|
}
|
||||||
else if (Metamaps.Active.Map || Metamaps.Active.Topic) {
|
else if (Metamaps.Active.Map || Metamaps.Active.Topic) {
|
||||||
Metamaps.Loading.show()
|
Metamaps.Loading.show()
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
/* global Metamaps, $ */
|
|
||||||
|
|
||||||
Metamaps.Header = {
|
|
||||||
init: function () {
|
|
||||||
|
|
||||||
},
|
|
||||||
fetchUserThenChangeSection: function (signedIn, mapperId) {
|
|
||||||
$.ajax({
|
|
||||||
url: '/users/' + mapperId + '.json',
|
|
||||||
success: function (response) {
|
|
||||||
Metamaps.Header.changeSection(signedIn, 'mapper', response.image, response.name)
|
|
||||||
},
|
|
||||||
error: function () {}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
changeSection: function (signedIn, section, userAvatar, userName) {
|
|
||||||
ReactDOM.render(
|
|
||||||
React.createElement(Metamaps.ReactComponents.Header, { signedIn: signedIn, section: section, userAvatar: userAvatar, userName: userName }),
|
|
||||||
document.getElementById('exploreMapsHeader')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -46,13 +46,7 @@
|
||||||
if (Metamaps.Active.Mapper) {
|
if (Metamaps.Active.Mapper) {
|
||||||
Metamaps.GlobalUI.hideDiv('#yield')
|
Metamaps.GlobalUI.hideDiv('#yield')
|
||||||
|
|
||||||
Metamaps.Header.changeSection(!!Metamaps.Active.Mapper, 'active')
|
Metamaps.GlobalUI.showDiv('#explore')
|
||||||
Metamaps.GlobalUI.showDiv('#exploreMapsHeader')
|
|
||||||
Metamaps.GlobalUI.showDiv('#exploreMaps')
|
|
||||||
$('#exploreMaps').scrollTop(0)
|
|
||||||
|
|
||||||
Metamaps.GlobalUI.Search.open()
|
|
||||||
Metamaps.GlobalUI.Search.lock()
|
|
||||||
|
|
||||||
Metamaps.Views.exploreMaps.setCollection(Metamaps.Maps.Active)
|
Metamaps.Views.exploreMaps.setCollection(Metamaps.Maps.Active)
|
||||||
if (Metamaps.Maps.Active.length === 0) {
|
if (Metamaps.Maps.Active.length === 0) {
|
||||||
|
@ -62,11 +56,8 @@
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// logged out home page
|
// logged out home page
|
||||||
Metamaps.GlobalUI.hideDiv('#exploreMapsHeader')
|
Metamaps.GlobalUI.hideDiv('#explore')
|
||||||
Metamaps.GlobalUI.hideDiv('#exploreMaps')
|
|
||||||
Metamaps.GlobalUI.showDiv('#yield')
|
Metamaps.GlobalUI.showDiv('#yield')
|
||||||
Metamaps.GlobalUI.Search.unlock()
|
|
||||||
//Metamaps.GlobalUI.Search.close(0, true)
|
|
||||||
Metamaps.Router.timeoutId = setTimeout(navigate, 500)
|
Metamaps.Router.timeoutId = setTimeout(navigate, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,15 +134,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Metamaps.GlobalUI.Search.open()
|
Metamaps.GlobalUI.showDiv('#explore')
|
||||||
Metamaps.GlobalUI.Search.lock()
|
|
||||||
Metamaps.GlobalUI.showDiv('#exploreMaps')
|
|
||||||
Metamaps.GlobalUI.showDiv('#exploreMapsHeader')
|
|
||||||
$('#exploreMaps').scrollTop(0)
|
|
||||||
if (id) {
|
|
||||||
Metamaps.Header.fetchUserThenChangeSection(!!Metamaps.Active.Mapper, id)
|
|
||||||
}
|
|
||||||
else Metamaps.Header.changeSection(!!Metamaps.Active.Mapper, section)
|
|
||||||
Metamaps.GlobalUI.hideDiv('#yield')
|
Metamaps.GlobalUI.hideDiv('#yield')
|
||||||
Metamaps.GlobalUI.hideDiv('#infovis')
|
Metamaps.GlobalUI.hideDiv('#infovis')
|
||||||
Metamaps.GlobalUI.hideDiv('#instructions')
|
Metamaps.GlobalUI.hideDiv('#instructions')
|
||||||
|
@ -174,8 +157,7 @@
|
||||||
// can edit this map '.canEditMap'
|
// can edit this map '.canEditMap'
|
||||||
|
|
||||||
Metamaps.GlobalUI.hideDiv('#yield')
|
Metamaps.GlobalUI.hideDiv('#yield')
|
||||||
Metamaps.GlobalUI.hideDiv('#exploreMaps')
|
Metamaps.GlobalUI.hideDiv('#explore')
|
||||||
Metamaps.GlobalUI.hideDiv('#exploreMapsHeader')
|
|
||||||
|
|
||||||
// clear the visualization, if there was one, before showing its div again
|
// clear the visualization, if there was one, before showing its div again
|
||||||
if (Metamaps.Visualize.mGraph) {
|
if (Metamaps.Visualize.mGraph) {
|
||||||
|
@ -187,9 +169,6 @@
|
||||||
Metamaps.Topic.end()
|
Metamaps.Topic.end()
|
||||||
Metamaps.Active.Topic = null
|
Metamaps.Active.Topic = null
|
||||||
|
|
||||||
//Metamaps.GlobalUI.Search.unlock()
|
|
||||||
//Metamaps.GlobalUI.Search.close(0, true)
|
|
||||||
|
|
||||||
Metamaps.Loading.show()
|
Metamaps.Loading.show()
|
||||||
Metamaps.Map.end()
|
Metamaps.Map.end()
|
||||||
Metamaps.Map.launch(id)
|
Metamaps.Map.launch(id)
|
||||||
|
@ -206,8 +185,7 @@
|
||||||
$('.wrapper').addClass('topicPage')
|
$('.wrapper').addClass('topicPage')
|
||||||
|
|
||||||
Metamaps.GlobalUI.hideDiv('#yield')
|
Metamaps.GlobalUI.hideDiv('#yield')
|
||||||
Metamaps.GlobalUI.hideDiv('#exploreMaps')
|
Metamaps.GlobalUI.hideDiv('#explore')
|
||||||
Metamaps.GlobalUI.hideDiv('#exploreMapsHeader')
|
|
||||||
|
|
||||||
// clear the visualization, if there was one, before showing its div again
|
// clear the visualization, if there was one, before showing its div again
|
||||||
if (Metamaps.Visualize.mGraph) {
|
if (Metamaps.Visualize.mGraph) {
|
||||||
|
@ -219,9 +197,6 @@
|
||||||
Metamaps.Map.end()
|
Metamaps.Map.end()
|
||||||
Metamaps.Active.Map = null
|
Metamaps.Active.Map = null
|
||||||
|
|
||||||
//Metamaps.GlobalUI.Search.unlock()
|
|
||||||
//Metamaps.GlobalUI.Search.close(0, true)
|
|
||||||
|
|
||||||
Metamaps.Topic.end()
|
Metamaps.Topic.end()
|
||||||
Metamaps.Topic.launch(id)
|
Metamaps.Topic.launch(id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,128 +1,87 @@
|
||||||
/* global Metamaps, $, Hogan, Backbone */
|
/* global Metamaps, $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Metamaps.Views.js.erb
|
* Metamaps.Views.js.erb
|
||||||
*
|
*
|
||||||
* Dependencies:
|
* Dependencies:
|
||||||
* - Metamaps.Famous
|
|
||||||
* - Metamaps.Loading
|
* - Metamaps.Loading
|
||||||
|
* - Metamaps.Active
|
||||||
|
* - Metamaps.ReactComponents
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Metamaps.Views = {
|
Metamaps.Views = {
|
||||||
initialized: false
|
exploreMaps: {
|
||||||
}
|
|
||||||
|
|
||||||
Metamaps.Views.init = function () {
|
|
||||||
Metamaps.Views.MapperCard = Backbone.View.extend({
|
|
||||||
template: Hogan.compile($('#mapperCardTemplate').html()),
|
|
||||||
|
|
||||||
tagName: 'div',
|
|
||||||
|
|
||||||
className: 'mapper',
|
|
||||||
|
|
||||||
render: function () {
|
|
||||||
this.$el.html(this.template.render(this.model))
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
Metamaps.Views.MapCard = Backbone.View.extend({
|
|
||||||
template: Hogan.compile($('#mapCardTemplate').html()),
|
|
||||||
|
|
||||||
tagName: 'div',
|
|
||||||
|
|
||||||
className: 'map',
|
|
||||||
|
|
||||||
id: function () {
|
|
||||||
return this.model.id
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function () {
|
|
||||||
this.listenTo(this.model, 'change', this.render)
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function () {
|
|
||||||
this.$el.html(this.template.render(this.model.attrForCards()))
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
var MapsWrapper = Backbone.View.extend({
|
|
||||||
initialize: function (opts) {},
|
|
||||||
setCollection: function (collection) {
|
setCollection: function (collection) {
|
||||||
if (this.collection) this.stopListening(this.collection)
|
var self = Metamaps.Views.exploreMaps
|
||||||
this.collection = collection
|
|
||||||
this.listenTo(this.collection, 'add', this.render)
|
if (self.collection) {
|
||||||
this.listenTo(this.collection, 'successOnFetch', this.handleSuccess)
|
self.collection.off('add', self.render)
|
||||||
this.listenTo(this.collection, 'errorOnFetch', this.handleError)
|
self.collection.off('successOnFetch', self.handleSuccess)
|
||||||
|
self.collection.off('errorOnFetch', self.handleError)
|
||||||
|
}
|
||||||
|
self.collection = collection
|
||||||
|
self.collection.on('add', self.render)
|
||||||
|
self.collection.on('successOnFetch', self.handleSuccess)
|
||||||
|
self.collection.on('errorOnFetch', self.handleError)
|
||||||
},
|
},
|
||||||
render: function (mapperObj, cb) {
|
render: function (mapperObj, cb) {
|
||||||
var that = this
|
var self = Metamaps.Views.exploreMaps
|
||||||
|
|
||||||
if (typeof mapperObj === 'function') {
|
if (typeof mapperObj === 'function') {
|
||||||
cb = mapperObj
|
cb = mapperObj
|
||||||
mapperObj = null
|
mapperObj = null
|
||||||
}
|
}
|
||||||
|
|
||||||
this.el.innerHTML = ''
|
|
||||||
|
|
||||||
// in case it is a page where we have to display the mapper card
|
|
||||||
if (mapperObj) {
|
|
||||||
var view = new Metamaps.Views.MapperCard({ model: mapperObj })
|
|
||||||
|
|
||||||
that.el.appendChild(view.render().el)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.collection.each(function (map) {
|
|
||||||
var view = new Metamaps.Views.MapCard({ model: map })
|
|
||||||
|
|
||||||
that.el.appendChild(view.render().el)
|
|
||||||
})
|
|
||||||
this.$el.append('<div class="clearfloat"></div>')
|
|
||||||
|
|
||||||
if (this.collection.length >= 20 && this.collection.page != "loadedAll") {
|
var exploreObj = {
|
||||||
this.$el.append('<button class="button loadMore">load more</button>')
|
currentUser: Metamaps.Active.Mapper,
|
||||||
this.$el.append('<div class="clearfloat"></div>')
|
section: self.collection.id,
|
||||||
|
displayStyle: 'grid',
|
||||||
|
maps: self.collection,
|
||||||
|
moreToLoad: self.collection.page != 'loadedAll',
|
||||||
|
user: mapperObj,
|
||||||
|
loadMore: self.loadMore
|
||||||
}
|
}
|
||||||
|
ReactDOM.render(
|
||||||
|
React.createElement(Metamaps.ReactComponents.Maps, exploreObj),
|
||||||
|
document.getElementById('explore')
|
||||||
|
)
|
||||||
|
|
||||||
$('#exploreMaps').empty().html(this.el)
|
|
||||||
this.$el.find('.loadMore').click(that.loadMore.bind(that))
|
|
||||||
if (cb) cb()
|
if (cb) cb()
|
||||||
Metamaps.Loading.hide()
|
Metamaps.Loading.hide()
|
||||||
},
|
},
|
||||||
loadMore: function () {
|
loadMore: function () {
|
||||||
if (this.collection.page != "loadedAll") {
|
var self = Metamaps.Views.exploreMaps
|
||||||
this.collection.getMaps();
|
|
||||||
}
|
if (self.collection.page != "loadedAll") {
|
||||||
else {
|
self.collection.getMaps()
|
||||||
this.$el.find('.loadMore').hide()
|
|
||||||
}
|
}
|
||||||
|
else self.render()
|
||||||
},
|
},
|
||||||
handleSuccess: function (cb) {
|
handleSuccess: function (cb) {
|
||||||
if (this.collection && this.collection.id === 'mapper') {
|
var self = Metamaps.Views.exploreMaps
|
||||||
this.fetchUserThenRender(cb)
|
|
||||||
|
if (self.collection && self.collection.id === 'mapper') {
|
||||||
|
self.fetchUserThenRender(cb)
|
||||||
} else {
|
} else {
|
||||||
this.render(cb)
|
self.render(cb)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleError: function () {
|
handleError: function () {
|
||||||
console.log('error loading maps!') // TODO
|
console.log('error loading maps!') // TODO
|
||||||
},
|
},
|
||||||
fetchUserThenRender: function (cb) {
|
fetchUserThenRender: function (cb) {
|
||||||
var that = this
|
var self = Metamaps.Views.exploreMaps
|
||||||
|
|
||||||
// first load the mapper object and then call the render function
|
// first load the mapper object and then call the render function
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/users/' + this.collection.mapperId + '/details.json',
|
url: '/users/' + self.collection.mapperId + '/details.json',
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
that.render(response, cb)
|
self.render(response, cb)
|
||||||
},
|
},
|
||||||
error: function () {
|
error: function () {
|
||||||
that.render(cb)
|
self.render(cb)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
Metamaps.Views.exploreMaps = new MapsWrapper()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -590,8 +590,11 @@
|
||||||
|
|
||||||
/* explore maps */
|
/* explore maps */
|
||||||
|
|
||||||
#exploreMaps {
|
#explore {
|
||||||
display: none;
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#exploreMaps {
|
||||||
padding: 0 5%;
|
padding: 0 5%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
|
@ -613,7 +616,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#exploreMapsHeader {
|
#exploreMapsHeader {
|
||||||
display: none;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,55 +45,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/template" id="mapCardTemplate">
|
|
||||||
<a href="/maps/{{id}}" data-router="true">
|
|
||||||
<div class="permission {{editPermission}}"> <!-- must be canEdit or cannotEdit -->
|
|
||||||
<div class="mapCard">
|
|
||||||
<span class="title" title="{{fullName}}">
|
|
||||||
{{name}}
|
|
||||||
</span>
|
|
||||||
<div class="mapScreenshot">
|
|
||||||
{{{screenshot}}}
|
|
||||||
</div>
|
|
||||||
<div class="scroll">
|
|
||||||
<div class="desc">
|
|
||||||
{{desc}}
|
|
||||||
<div class="clearfloat"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="mapMetadata">
|
|
||||||
<div class="metadataSection">{{{contributor_count_number}}}{{contributor_count_string}}</div>
|
|
||||||
<div class="metadataSection">{{{topic_count_number}}}{{topic_count_string}}</div>
|
|
||||||
<div class="metadataSection mapPermission">{{permission}}</div>
|
|
||||||
<div class="metadataSection">{{{synapse_count_number}}}{{synapse_count_string}}</div>
|
|
||||||
<div class="clearfloat"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/template" id="mapperCardTemplate">
|
|
||||||
<div class="mapperCard">
|
|
||||||
<div class="mapperImage">
|
|
||||||
<img src="{{image}}" width="96" height="96" />
|
|
||||||
</div>
|
|
||||||
<div class="mapperName" title="{{name}}">
|
|
||||||
{{name}}
|
|
||||||
</div>
|
|
||||||
<div class="mapperInfo">
|
|
||||||
<div class="mapperCreatedAt">Mapper since: {{created_at}}</div>
|
|
||||||
<div class="mapperGeneration">Generation: {{generation}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="mapperMetadata">
|
|
||||||
<div class="metadataSection metadataMaps"><div>{{numMaps}}</div>maps</div>
|
|
||||||
<div class="metadataSection metadataTopics"><div>{{numTopics}}</div>topics</div>
|
|
||||||
<div class="metadataSection metadataSynapses"><div>{{numSynapses}}</div>synapses</div>
|
|
||||||
<div class="clearfloat"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/template" id="topicSearchTemplate">
|
<script type="text/template" id="topicSearchTemplate">
|
||||||
<div class="result{{rtype}}">
|
<div class="result{{rtype}}">
|
||||||
|
|
|
@ -44,8 +44,7 @@
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= render :partial => 'layouts/lowermapelements' %>
|
<%= render :partial => 'layouts/lowermapelements' %>
|
||||||
|
|
||||||
<div id="exploreMaps"></div>
|
<div id="explore"></div>
|
||||||
<div id="exploreMapsHeader"></div>
|
|
||||||
|
|
||||||
<div id="instructions">
|
<div id="instructions">
|
||||||
<div class="addTopic">
|
<div class="addTopic">
|
||||||
|
|
|
@ -32,41 +32,43 @@ class Header extends Component {
|
||||||
const mapper = section == "mapper"
|
const mapper = section == "mapper"
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="exploreMapsBar exploreElement">
|
<div id="exploreMapsHeader">
|
||||||
<div className="exploreMapsMenu">
|
<div className="exploreMapsBar exploreElement">
|
||||||
<div className="exploreMapsCenter">
|
<div className="exploreMapsMenu">
|
||||||
<MapLink show={signedIn && explore}
|
<div className="exploreMapsCenter">
|
||||||
href="/explore/mine"
|
<MapLink show={signedIn && explore}
|
||||||
linkClass={activeClass("my")}
|
href="/explore/mine"
|
||||||
data-router="true"
|
linkClass={activeClass("my")}
|
||||||
text="My Maps"
|
data-router="true"
|
||||||
/>
|
text="My Maps"
|
||||||
<MapLink show={signedIn && explore}
|
/>
|
||||||
href="/explore/shared"
|
<MapLink show={signedIn && explore}
|
||||||
linkClass={activeClass("shared")}
|
href="/explore/shared"
|
||||||
data-router="true"
|
linkClass={activeClass("shared")}
|
||||||
text="Shared With Me"
|
data-router="true"
|
||||||
/>
|
text="Shared With Me"
|
||||||
<MapLink show={explore}
|
/>
|
||||||
href={signedIn ? "/" : "/explore/active"}
|
<MapLink show={explore}
|
||||||
linkClass={activeClass("active")}
|
href={signedIn ? "/" : "/explore/active"}
|
||||||
data-router="true"
|
linkClass={activeClass("active")}
|
||||||
text="Recently Active"
|
data-router="true"
|
||||||
/>
|
text="Recently Active"
|
||||||
<MapLink show={!signedIn && explore}
|
/>
|
||||||
href="/explore/featured"
|
<MapLink show={!signedIn && explore}
|
||||||
linkClass={activeClass("featured")}
|
href="/explore/featured"
|
||||||
data-router="true"
|
linkClass={activeClass("featured")}
|
||||||
text="Featured Maps"
|
data-router="true"
|
||||||
/>
|
text="Featured Maps"
|
||||||
|
/>
|
||||||
{mapper ? (
|
|
||||||
<div className='exploreMapsButton active mapperButton'>
|
{mapper ? (
|
||||||
<img className='exploreMapperImage' width='24' height='24' src={this.props.userAvatar} />
|
<div className='exploreMapsButton active mapperButton'>
|
||||||
<div className='exploreMapperName'>{this.props.userName}’s Maps</div>
|
<img className='exploreMapperImage' width='24' height='24' src={this.props.user.image} />
|
||||||
<div className='clearfloat'></div>
|
<div className='exploreMapperName'>{this.props.user.name}’s Maps</div>
|
||||||
</div>
|
<div className='clearfloat'></div>
|
||||||
) : null }
|
</div>
|
||||||
|
) : null }
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -77,8 +79,7 @@ class Header extends Component {
|
||||||
Header.propTypes = {
|
Header.propTypes = {
|
||||||
signedIn: PropTypes.bool.isRequired,
|
signedIn: PropTypes.bool.isRequired,
|
||||||
section: PropTypes.string.isRequired,
|
section: PropTypes.string.isRequired,
|
||||||
userAvatar: PropTypes.string,
|
user: PropTypes.object
|
||||||
userName: PropTypes.string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Header
|
export default Header
|
||||||
|
|
74
frontend/src/components/MapCard.js
Normal file
74
frontend/src/components/MapCard.js
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
import React, { Component, PropTypes } from 'react'
|
||||||
|
|
||||||
|
class MapCard extends Component {
|
||||||
|
render = () => {
|
||||||
|
const { map, currentUser } = this.props
|
||||||
|
|
||||||
|
function capitalize (string) {
|
||||||
|
return string.charAt(0).toUpperCase() + string.slice(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const n = map.get('name')
|
||||||
|
const d = map.get('desc')
|
||||||
|
|
||||||
|
const maxNameLength = 32
|
||||||
|
const maxDescLength = 118
|
||||||
|
const truncatedName = n ? (n.length > maxNameLength ? n.substring(0, maxNameLength) + '...' : n) : ''
|
||||||
|
const truncatedDesc = d ? (d.length > maxDescLength ? d.substring(0, maxDescLength) + '...' : d) : ''
|
||||||
|
const editPermission = map.authorizeToEdit(currentUser) ? 'canEdit' : 'cannotEdit'
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="map" id={ map.id }>
|
||||||
|
<a href={ '/maps/' + map.id } data-router="true">
|
||||||
|
<div className={ 'permission ' + editPermission }>
|
||||||
|
<div className="mapCard">
|
||||||
|
<span className="title" title={ map.get('name') }>
|
||||||
|
{ truncatedName }
|
||||||
|
</span>
|
||||||
|
<div className="mapScreenshot">
|
||||||
|
<img src={ map.get('screenshot_url') } />
|
||||||
|
</div>
|
||||||
|
<div className="scroll">
|
||||||
|
<div className="desc">
|
||||||
|
{ truncatedDesc }
|
||||||
|
<div className="clearfloat"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mapMetadata">
|
||||||
|
<div className="metadataSection">
|
||||||
|
<span className="cCountColor">
|
||||||
|
{ map.get('contributor_count') }
|
||||||
|
</span>
|
||||||
|
{ map.get('contributor_count') === 1 ? ' contributor' : ' contributors' }
|
||||||
|
</div>
|
||||||
|
<div className="metadataSection">
|
||||||
|
<span className="tCountColor">
|
||||||
|
{ map.get('topic_count') }
|
||||||
|
</span>
|
||||||
|
{ map.get('topic_count') === 1 ? ' topic' : ' topics' }
|
||||||
|
</div>
|
||||||
|
<div className="metadataSection mapPermission">
|
||||||
|
{ map.get('permission') ? capitalize(map.get('permission')) : 'Commons' }
|
||||||
|
</div>
|
||||||
|
<div className="metadataSection">
|
||||||
|
<span className="sCountColor">
|
||||||
|
{ map.get('synapse_count') }
|
||||||
|
</span>
|
||||||
|
{ map.get('synapse_count') === 1 ? ' synapse' : ' synapses' }
|
||||||
|
</div>
|
||||||
|
<div className="clearfloat"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MapCard.propTypes = {
|
||||||
|
map: PropTypes.object.isRequired,
|
||||||
|
currentUser: PropTypes.object
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MapCard
|
0
frontend/src/components/MapListItem.js
Normal file
0
frontend/src/components/MapListItem.js
Normal file
36
frontend/src/components/MapperCard.js
Normal file
36
frontend/src/components/MapperCard.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import React, { Component, PropTypes } from 'react'
|
||||||
|
|
||||||
|
class MapperCard extends Component {
|
||||||
|
render = () => {
|
||||||
|
const { user } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mapper">
|
||||||
|
<div className="mapperCard">
|
||||||
|
<div className="mapperImage">
|
||||||
|
<img src={ user.image } width="96" height="96" />
|
||||||
|
</div>
|
||||||
|
<div className="mapperName" title={ user.name }>
|
||||||
|
{ user.name }
|
||||||
|
</div>
|
||||||
|
<div className="mapperInfo">
|
||||||
|
<div className="mapperCreatedAt">Mapper since: { user.created_at }</div>
|
||||||
|
<div className="mapperGeneration">Generation: { user.generation }</div>
|
||||||
|
</div>
|
||||||
|
<div className="mapperMetadata">
|
||||||
|
<div className="metadataSection metadataMaps"><div>{ user.numMaps }</div>maps</div>
|
||||||
|
<div className="metadataSection metadataTopics"><div>{ user.numTopics }</div>topics</div>
|
||||||
|
<div className="metadataSection metadataSynapses"><div>{ user.numSynapses }</div>synapses</div>
|
||||||
|
<div className="clearfloat"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MapperCard.propTypes = {
|
||||||
|
user: PropTypes.object.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MapperCard
|
54
frontend/src/components/Maps.js
Normal file
54
frontend/src/components/Maps.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import React, { Component, PropTypes } from 'react'
|
||||||
|
import Header from './Header.js'
|
||||||
|
import MapperCard from './MapperCard.js'
|
||||||
|
import MapCard from './MapCard.js'
|
||||||
|
import MapListItem from './MapListItem.js'
|
||||||
|
|
||||||
|
class Maps extends Component {
|
||||||
|
render = () => {
|
||||||
|
const { maps, currentUser, section, displayStyle, user, moreToLoad, loadMore } = this.props
|
||||||
|
let mapElements
|
||||||
|
|
||||||
|
if (displayStyle == 'grid') {
|
||||||
|
mapElements = maps.models.map(function (map) {
|
||||||
|
return <MapCard key={ map.id } map={ map } currentUser={ currentUser } />
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else if (displayStyle == 'list') {
|
||||||
|
mapElements = maps.models.map(function (map) {
|
||||||
|
return <MapListItem key={ map.id } map={ map } />
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div id='exploreMaps'>
|
||||||
|
<div>
|
||||||
|
{ user ? <MapperCard user={ user } /> : null }
|
||||||
|
{ mapElements }
|
||||||
|
<div className='clearfloat'></div>
|
||||||
|
{ moreToLoad ?
|
||||||
|
[<button className="button loadMore" onClick={ loadMore }>load more</button>, <div className='clearfloat'></div>]
|
||||||
|
: null }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Header signedIn={ !!currentUser }
|
||||||
|
section={ section }
|
||||||
|
user={ user }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Maps.propTypes = {
|
||||||
|
section: PropTypes.string.isRequired,
|
||||||
|
maps: PropTypes.object.isRequired,
|
||||||
|
moreToLoad: PropTypes.bool.isRequired,
|
||||||
|
displayStyle: PropTypes.string,
|
||||||
|
user: PropTypes.object,
|
||||||
|
currentUser: PropTypes.object,
|
||||||
|
loadMore: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Maps
|
|
@ -2,7 +2,7 @@ import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import Backbone from 'backbone'
|
import Backbone from 'backbone'
|
||||||
import _ from 'underscore'
|
import _ from 'underscore'
|
||||||
import Header from './components/Header.js'
|
import Maps from './components/Maps.js'
|
||||||
|
|
||||||
// this is optional really, if we import components directly React will be
|
// this is optional really, if we import components directly React will be
|
||||||
// in the bundle, so we won't need a global reference
|
// in the bundle, so we won't need a global reference
|
||||||
|
@ -14,5 +14,5 @@ window._ = _
|
||||||
|
|
||||||
window.Metamaps = window.Metamaps || {}
|
window.Metamaps = window.Metamaps || {}
|
||||||
window.Metamaps.ReactComponents = {
|
window.Metamaps.ReactComponents = {
|
||||||
Header
|
Maps
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue