diff --git a/frontend/src/Metamaps/DataModel/Map.js b/frontend/src/Metamaps/DataModel/Map.js new file mode 100644 index 00000000..3ae47d1a --- /dev/null +++ b/frontend/src/Metamaps/DataModel/Map.js @@ -0,0 +1,92 @@ +/* global $ */ + +import _ from 'lodash' +import Backbone from 'backbone' +Backbone.$ = window.$ + +import Active from '../Active' +import { InfoBox } from '../Map' +import Mapper from '../Mapper' +import Realtime from '../Realtime' + +import MapperCollection from './MapperCollection' +import TopicCollection from './TopicCollection' +import SynapseCollection from './SynapseCollection' +import MappingCollection from './MappingCollection' + +const Map = Backbone.Model.extend({ + urlRoot: '/maps', + blacklist: ['created_at', 'updated_at', 'created_at_clean', 'updated_at_clean', 'user_name', 'contributor_count', 'topic_count', 'synapse_count', 'topics', 'synapses', 'mappings', 'mappers'], + toJSON: function (options) { + return _.omit(this.attributes, this.blacklist) + }, + save: function (key, val, options) { + var attrs + + // Handle both `"key", value` and `{key: value}` -style arguments. + if (key == null || typeof key === 'object') { + attrs = key + options = val + } else { + (attrs = {})[key] = val + } + + var newOptions = options || {} + var s = newOptions.success + + newOptions.success = function (model, response, opt) { + if (s) s(model, response, opt) + model.trigger('saved') + } + return Backbone.Model.prototype.save.call(this, attrs, newOptions) + }, + initialize: function () { + this.on('changeByOther', this.updateView) + this.on('saved', this.savedEvent) + }, + savedEvent: function () { + Realtime.updateMap(this) + }, + authorizeToEdit: function (mapper) { + if (mapper && ( + this.get('permission') === 'commons' || + (this.get('collaborator_ids') || []).includes(mapper.get('id')) || + this.get('user_id') === mapper.get('id'))) { + return true + } else { + return false + } + }, + authorizePermissionChange: function (mapper) { + if (mapper && this.get('user_id') === mapper.get('id')) { + return true + } else { + return false + } + }, + getUser: function () { + return Mapper.get(this.get('user_id')) + }, + updateView: function () { + var map = Active.Map + var isActiveMap = this.id === map.id + if (isActiveMap) { + InfoBox.updateNameDescPerm(this.get('name'), this.get('desc'), this.get('permission')) + this.updateMapWrapper() + // mobile menu + $('#header_content').html(this.get('name')) + document.title = this.get('name') + ' | Metamaps' + } + }, + updateMapWrapper: function () { + var map = Active.Map + var isActiveMap = this.id === map.id + var authorized = map && map.authorizeToEdit(Active.Mapper) ? 'canEditMap' : '' + var commonsMap = map && map.get('permission') === 'commons' ? 'commonsMap' : '' + if (isActiveMap) { + $('.wrapper').removeClass('canEditMap commonsMap').addClass(authorized + ' ' + commonsMap) + } + } +}) + +export default Map diff --git a/frontend/src/Metamaps/DataModel/MapCollection.js b/frontend/src/Metamaps/DataModel/MapCollection.js new file mode 100644 index 00000000..f72e1e0e --- /dev/null +++ b/frontend/src/Metamaps/DataModel/MapCollection.js @@ -0,0 +1,81 @@ +/* global Metamaps */ + +import Backbone from 'backbone' +Backbone.$ = window.$ + +import Map from './Map' + +/* + * Dependencies: + * - Metamaps.Loading + */ + +const MapCollection = Backbone.Collection.extend({ + model: Map, + initialize: function (models, options) { + this.id = options.id + this.sortBy = options.sortBy + + if (options.mapperId) { + this.mapperId = options.mapperId + } + + // this.page represents the NEXT page to fetch + this.page = models.length > 0 ? (models.length < 20 ? 'loadedAll' : 2) : 1 + }, + url: function () { + if (!this.mapperId) { + return '/explore/' + this.id + '.json' + } else { + return '/explore/mapper/' + this.mapperId + '.json' + } + }, + comparator: function (a, b) { + a = a.get(this.sortBy) + b = b.get(this.sortBy) + var temp + if (this.sortBy === 'name') { + a = a ? a.toLowerCase() : '' + b = b ? b.toLowerCase() : '' + } else { + // this is for updated_at and created_at + temp = a + a = b + b = temp + a = (new Date(a)).getTime() + b = (new Date(b)).getTime() + } + return a > b ? 1 : a < b ? -1 : 0 + }, + getMaps: function (cb) { + var self = this + + Metamaps.Loading.show() + + if (this.page !== 'loadedAll') { + var numBefore = this.length + this.fetch({ + remove: false, + silent: true, + data: { page: this.page }, + success: function (collection, response, options) { + // you can pass additional options to the event you trigger here as well + if (collection.length - numBefore < 20) { + self.page = 'loadedAll' + } else { + self.page += 1 + } + self.trigger('successOnFetch', cb) + }, + error: function (collection, response, options) { + // you can pass additional options to the event you trigger here as well + self.trigger('errorOnFetch') + } + }) + } else { + self.trigger('successOnFetch', cb) + } + } +}) + +export default MapCollection diff --git a/frontend/src/Metamaps/DataModel/Mapper.js b/frontend/src/Metamaps/DataModel/Mapper.js new file mode 100644 index 00000000..3627fbd6 --- /dev/null +++ b/frontend/src/Metamaps/DataModel/Mapper.js @@ -0,0 +1,21 @@ +import _ from 'lodash' +import Backbone from 'backbone' +Backbone.$ = window.$ +import outdent from 'outdent' + +const Mapper = Backbone.Model.extend({ + urlRoot: '/users', + blacklist: ['created_at', 'updated_at'], + toJSON: function (options) { + return _.omit(this.attributes, this.blacklist) + }, + prepareLiForFilter: function () { + return outdent` +
  • + ${this.get('name')} +

    ${this.get('name')}

    +
  • ` + } +}) + +export default Mapper diff --git a/frontend/src/Metamaps/DataModel/MapperCollection.js b/frontend/src/Metamaps/DataModel/MapperCollection.js new file mode 100644 index 00000000..e0ce2bed --- /dev/null +++ b/frontend/src/Metamaps/DataModel/MapperCollection.js @@ -0,0 +1,11 @@ +import Backbone from 'backbone' +Backbone.$ = window.$ + +import Mapper from './Mapper' + +const MapperCollection = Backbone.Collection.extend({ + model: Mapper, + url: '/users' +}) + +export default MapperCollection diff --git a/frontend/src/Metamaps/DataModel/Mapping.js b/frontend/src/Metamaps/DataModel/Mapping.js new file mode 100644 index 00000000..8bf92ed2 --- /dev/null +++ b/frontend/src/Metamaps/DataModel/Mapping.js @@ -0,0 +1,37 @@ +import _ from 'lodash' +import Backbone from 'backbone' +Backbone.$ = window.$ + +import Active from '../Active' +import Map from '../Map' +import Synapse from '../Synapse' +import Topic from '../Topic' + +const Mapping = Backbone.Model.extend({ + urlRoot: '/mappings', + blacklist: ['created_at', 'updated_at'], + toJSON: function (options) { + return _.omit(this.attributes, this.blacklist) + }, + initialize: function () { + if (this.isNew()) { + this.set({ + 'user_id': Active.Mapper.id, + 'map_id': Active.Map ? Active.Map.id : null + }) + } + }, + getMap: function () { + return Map.get(this.get('map_id')) + }, + getTopic: function () { + if (this.get('mappable_type') !== 'Topic') return false + return Topic.get(this.get('mappable_id')) + }, + getSynapse: function () { + if (this.get('mappable_type') !== 'Synapse') return false + return Synapse.get(this.get('mappable_id')) + } +}) + +export default Mapping diff --git a/frontend/src/Metamaps/DataModel/MappingCollection.js b/frontend/src/Metamaps/DataModel/MappingCollection.js new file mode 100644 index 00000000..e475e098 --- /dev/null +++ b/frontend/src/Metamaps/DataModel/MappingCollection.js @@ -0,0 +1,11 @@ +import Backbone from 'backbone' +Backbone.$ = window.$ + +import Mapping from './Mapping' + +const MappingCollection = Backbone.Collection.extend({ + model: Mapping, + url: '/mappings' +}) + +export default MappingCollection diff --git a/frontend/src/Metamaps/DataModel/Message.js b/frontend/src/Metamaps/DataModel/Message.js new file mode 100644 index 00000000..f7dc9bee --- /dev/null +++ b/frontend/src/Metamaps/DataModel/Message.js @@ -0,0 +1,13 @@ +import _ from 'lodash' +import Backbone from 'backbone' +Backbone.$ = window.$ + +const Message = Backbone.Model.extend({ + urlRoot: '/messages', + blacklist: ['created_at', 'updated_at'], + toJSON: function (options) { + return _.omit(this.attributes, this.blacklist) + } +}) + +export default Message diff --git a/frontend/src/Metamaps/DataModel/MessageCollection.js b/frontend/src/Metamaps/DataModel/MessageCollection.js new file mode 100644 index 00000000..a572c212 --- /dev/null +++ b/frontend/src/Metamaps/DataModel/MessageCollection.js @@ -0,0 +1,11 @@ +import Backbone from 'backbone' +Backbone.$ = window.$ + +import Message from './Message' + +const MessageCollection = Backbone.Collection.extend({ + model: Message, + url: '/messages' +}) + +export default MessageCollection diff --git a/frontend/src/Metamaps/DataModel/Metacode.js b/frontend/src/Metamaps/DataModel/Metacode.js new file mode 100644 index 00000000..a3d523fd --- /dev/null +++ b/frontend/src/Metamaps/DataModel/Metacode.js @@ -0,0 +1,21 @@ +import Backbone from 'backbone' +Backbone.$ = window.$ +import outdent from 'outdent' + +const Metacode = Backbone.Model.extend({ + initialize: function () { + var image = new Image() + image.crossOrigin = 'Anonymous' + image.src = this.get('icon') + this.set('image', image) + }, + prepareLiForFilter: function () { + return outdent` +
  • + ${this.get('name')} +

    ${this.get('name').toLowerCase()}

    +
  • ` + } +}) + +export default Metacode diff --git a/frontend/src/Metamaps/DataModel/MetacodeCollection.js b/frontend/src/Metamaps/DataModel/MetacodeCollection.js new file mode 100644 index 00000000..ff4626d1 --- /dev/null +++ b/frontend/src/Metamaps/DataModel/MetacodeCollection.js @@ -0,0 +1,16 @@ +import Backbone from 'backbone' +Backbone.$ = window.$ + +import Metacode from './Metacode' + +const MetacodeCollection = Backbone.Collection.extend({ + model: Metacode, + url: '/metacodes', + comparator: function (a, b) { + a = a.get('name').toLowerCase() + b = b.get('name').toLowerCase() + return a > b ? 1 : a < b ? -1 : 0 + } +}) + +export default MetacodeCollection diff --git a/frontend/src/Metamaps/DataModel/Synapse.js b/frontend/src/Metamaps/DataModel/Synapse.js new file mode 100644 index 00000000..2d8f4256 --- /dev/null +++ b/frontend/src/Metamaps/DataModel/Synapse.js @@ -0,0 +1,185 @@ +/* global Metamaps, $ */ + +import _ from 'lodash' +import Backbone from 'backbone' +Backbone.$ = window.$ + +import Active from '../Active' +import Filter from '../Filter' +import JIT from '../JIT' +import Realtime from '../Realtime' +import SynapseCard from '../SynapseCard' +import Visualize from '../Visualize' + + +/* + * Dependencies: + * - Metamaps.Mappings + * - Metamaps.Topics + */ + +const Synapse = Backbone.Model.extend({ + urlRoot: '/synapses', + blacklist: ['edge', 'created_at', 'updated_at'], + toJSON: function (options) { + return _.omit(this.attributes, this.blacklist) + }, + save: function (key, val, options) { + var attrs + + // Handle both `"key", value` and `{key: value}` -style arguments. + if (key == null || typeof key === 'object') { + attrs = key + options = val + } else { + (attrs = {})[key] = val + } + + var newOptions = options || {} + var s = newOptions.success + + var permBefore = this.get('permission') + + newOptions.success = function (model, response, opt) { + if (s) s(model, response, opt) + model.trigger('saved') + + if (permBefore === 'private' && model.get('permission') !== 'private') { + model.trigger('noLongerPrivate') + } + else if (permBefore !== 'private' && model.get('permission') === 'private') { + model.trigger('nowPrivate') + } + } + return Backbone.Model.prototype.save.call(this, attrs, newOptions) + }, + initialize: function () { + if (this.isNew()) { + this.set({ + 'user_id': Active.Mapper.id, + 'permission': Active.Map ? Active.Map.get('permission') : 'commons', + 'category': 'from-to' + }) + } + + this.on('changeByOther', this.updateCardView) + this.on('change', this.updateEdgeView) + this.on('saved', this.savedEvent) + this.on('noLongerPrivate', function () { + var newSynapseData = { + mappingid: this.getMapping().id, + mappableid: this.id + } + + $(document).trigger(JIT.events.newSynapse, [newSynapseData]) + }) + this.on('nowPrivate', function () { + $(document).trigger(JIT.events.removeSynapse, [{ + mappableid: this.id + }]) + }) + + this.on('change:desc', Filter.checkSynapses, this) + }, + prepareLiForFilter: function () { + var li = '' + li += '
  • ' + li += '
  • ' + return li + }, + authorizeToEdit: function (mapper) { + if (mapper && (this.get('calculated_permission') === 'commons' || this.get('collaborator_ids').includes(mapper.get('id')) || this.get('user_id') === mapper.get('id'))) return true + else return false + }, + authorizePermissionChange: function (mapper) { + if (mapper && this.get('user_id') === mapper.get('id')) return true + else return false + }, + getTopic1: function () { + return Metamaps.Topics.get(this.get('topic1_id')) + }, + getTopic2: function () { + return Metamaps.Topics.get(this.get('topic2_id')) + }, + getDirection: function () { + var t1 = this.getTopic1(), + t2 = this.getTopic2() + + return t1 && t2 ? [ + t1.get('node').id, + t2.get('node').id + ] : false + }, + getMapping: function () { + if (!Active.Map) return false + + return Metamaps.Mappings.findWhere({ + map_id: Active.Map.id, + mappable_type: 'Synapse', + mappable_id: this.isNew() ? this.cid : this.id + }) + }, + createEdge: function (providedMapping) { + var mapping, mappingID + var synapseID = this.isNew() ? this.cid : this.id + + var edge = { + nodeFrom: this.get('topic1_id'), + nodeTo: this.get('topic2_id'), + data: { + $synapses: [], + $synapseIDs: [synapseID], + } + } + + if (Active.Map) { + mapping = providedMapping || this.getMapping() + mappingID = mapping.isNew() ? mapping.cid : mapping.id + edge.data.$mappings = [] + edge.data.$mappingIDs = [mappingID] + } + + return edge + }, + updateEdge: function () { + var mapping + var edge = this.get('edge') + edge.getData('synapses').push(this) + + if (Active.Map) { + mapping = this.getMapping() + edge.getData('mappings').push(mapping) + } + + return edge + }, + savedEvent: function () { + Realtime.updateSynapse(this) + }, + updateViews: function () { + this.updateCardView() + this.updateEdgeView() + }, + updateCardView: function () { + var onPageWithSynapseCard = Active.Map || Active.Topic + var edge = this.get('edge') + + // update synapse card, if this synapse is the one open there + if (onPageWithSynapseCard && edge == SynapseCard.openSynapseCard) { + SynapseCard.showCard(edge) + } + }, + updateEdgeView: function () { + var onPageWithSynapseCard = Active.Map || Active.Topic + var edge = this.get('edge') + + // update the edge on the map + if (onPageWithSynapseCard && edge) { + Visualize.mGraph.plot() + } + } +}) + +export default Synapse diff --git a/frontend/src/Metamaps/DataModel/SynapseCollection.js b/frontend/src/Metamaps/DataModel/SynapseCollection.js new file mode 100644 index 00000000..86bf8c47 --- /dev/null +++ b/frontend/src/Metamaps/DataModel/SynapseCollection.js @@ -0,0 +1,11 @@ +import Backbone from 'backbone' +Backbone.$ = window.$ + +import Synapse from './Synapse' + +const SynapseCollection = Backbone.Collection.extend({ + model: Synapse, + url: '/synapses' +}) + +export default SynapseCollection diff --git a/frontend/src/Metamaps/DataModel/Topic.js b/frontend/src/Metamaps/DataModel/Topic.js new file mode 100644 index 00000000..33a9bd3f --- /dev/null +++ b/frontend/src/Metamaps/DataModel/Topic.js @@ -0,0 +1,181 @@ +/* global Metamaps, $ */ + +import _ from 'lodash' +import Backbone from 'backbone' +Backbone.$ = window.$ + +import Active from '../Active' +import Filter from '../Filter' +import JIT from '../JIT' +import Realtime from '../Realtime' +import TopicCard from '../TopicCard' +import Visualize from '../Visualize' + +/* + * Dependencies: + * - Metamaps.Mappings + * - Metamaps.Metacodes + */ + +const Topic = Backbone.Model.extend({ + urlRoot: '/topics', + blacklist: ['node', 'created_at', 'updated_at', 'user_name', 'user_image', 'map_count', 'synapse_count'], + toJSON: function (options) { + return _.omit(this.attributes, this.blacklist) + }, + save: function (key, val, options) { + var attrs + + // Handle both `"key", value` and `{key: value}` -style arguments. + if (key == null || typeof key === 'object') { + attrs = key + options = val + } else { + (attrs = {})[key] = val + } + + var newOptions = options || {} + var s = newOptions.success + + var permBefore = this.get('permission') + + newOptions.success = function (model, response, opt) { + if (s) s(model, response, opt) + model.trigger('saved') + model.set('calculated_permission', model.get('permission')) + + if (permBefore === 'private' && model.get('permission') !== 'private') { + model.trigger('noLongerPrivate') + } + else if (permBefore !== 'private' && model.get('permission') === 'private') { + model.trigger('nowPrivate') + } + } + return Backbone.Model.prototype.save.call(this, attrs, newOptions) + }, + initialize: function () { + if (this.isNew()) { + this.set({ + 'user_id': Active.Mapper.id, + 'desc': this.get('desc') || '', + 'link': this.get('link') || '', + 'permission': Active.Map ? Active.Map.get('permission') : 'commons' + }) + } + + this.on('changeByOther', this.updateCardView) + this.on('change', this.updateNodeView) + this.on('saved', this.savedEvent) + this.on('nowPrivate', function () { + var removeTopicData = { + mappableid: this.id + } + + $(document).trigger(JIT.events.removeTopic, [removeTopicData]) + }) + this.on('noLongerPrivate', function () { + var newTopicData = { + mappingid: this.getMapping().id, + mappableid: this.id + } + + $(document).trigger(JIT.events.newTopic, [newTopicData]) + }) + + this.on('change:metacode_id', Filter.checkMetacodes, this) + }, + authorizeToEdit: function (mapper) { + if (mapper && + (this.get('user_id') === mapper.get('id') || + this.get('calculated_permission') === 'commons' || + this.get('collaborator_ids').includes(mapper.get('id')))) { + return true + } else { + return false + } + }, + authorizePermissionChange: function (mapper) { + if (mapper && this.get('user_id') === mapper.get('id')) return true + else return false + }, + getDate: function () {}, + getMetacode: function () { + return Metamaps.Metacodes.get(this.get('metacode_id')) + }, + getMapping: function () { + if (!Active.Map) return false + + return Metamaps.Mappings.findWhere({ + map_id: Active.Map.id, + mappable_type: 'Topic', + mappable_id: this.isNew() ? this.cid : this.id + }) + }, + createNode: function () { + var mapping + var node = { + adjacencies: [], + id: this.isNew() ? this.cid : this.id, + name: this.get('name') + } + + if (Active.Map) { + mapping = this.getMapping() + node.data = { + $mapping: null, + $mappingID: mapping.id + } + } + + return node + }, + updateNode: function () { + var mapping + var node = this.get('node') + node.setData('topic', this) + + if (Active.Map) { + mapping = this.getMapping() + node.setData('mapping', mapping) + } + + return node + }, + savedEvent: function () { + Realtime.updateTopic(this) + }, + updateViews: function () { + var onPageWithTopicCard = Active.Map || Active.Topic + var node = this.get('node') + // update topic card, if this topic is the one open there + if (onPageWithTopicCard && this == TopicCard.openTopicCard) { + TopicCard.showCard(node) + } + + // update the node on the map + if (onPageWithTopicCard && node) { + node.name = this.get('name') + Visualize.mGraph.plot() + } + }, + updateCardView: function () { + var onPageWithTopicCard = Active.Map || Active.Topic + var node = this.get('node') + // update topic card, if this topic is the one open there + if (onPageWithTopicCard && this == TopicCard.openTopicCard) { + TopicCard.showCard(node) + } + }, + updateNodeView: function () { + var onPageWithTopicCard = Active.Map || Active.Topic + var node = this.get('node') + + // update the node on the map + if (onPageWithTopicCard && node) { + node.name = this.get('name') + Visualize.mGraph.plot() + } + } +}) + +export default Topic diff --git a/frontend/src/Metamaps/DataModel/TopicCollection.js b/frontend/src/Metamaps/DataModel/TopicCollection.js new file mode 100644 index 00000000..4bcaf622 --- /dev/null +++ b/frontend/src/Metamaps/DataModel/TopicCollection.js @@ -0,0 +1,11 @@ +import Backbone from 'backbone' +Backbone.$ = window.$ + +import Topic from './Topic' + +const TopicCollection = Backbone.Collection.extend({ + model: Topic, + url: '/topics' +}) + +export default TopicCollection diff --git a/frontend/src/Metamaps/DataModel/index.js b/frontend/src/Metamaps/DataModel/index.js index 1aaac52f..4ee6d10d 100644 --- a/frontend/src/Metamaps/DataModel/index.js +++ b/frontend/src/Metamaps/DataModel/index.js @@ -1,23 +1,26 @@ -/* global Metamaps, Backbone, $ */ - -import _ from 'lodash' -import Backbone from 'backbone' -Backbone.$ = window.$ +/* global Metamaps */ import Active from '../Active' import Filter from '../Filter' -import JIT from '../JIT' -import Map, { InfoBox } from '../Map' -import Mapper from '../Mapper' -import Realtime from '../Realtime' -import Synapse from '../Synapse' -import SynapseCard from '../SynapseCard' -import Topic from '../Topic' -import TopicCard from '../TopicCard' -import Visualize from '../Visualize' +import { InfoBox } from '../Map' + +import Map from './Map' +import MapCollection from './MapCollection' +import Message from './Message' +import MessageCollection from './MessageCollection' +import Mapper from './Mapper' +import MapperCollection from './MapperCollection' +import Metacode from './Metacode' +import MetacodeCollection from './MetacodeCollection' +import Topic from './Topic' +import TopicCollection from './TopicCollection' +import Synapse from './Synapse' +import SynapseCollection from './SynapseCollection' +import Mapping from './Mapping' +import MappingCollection from './MappingCollection' /* - * Metamaps.DataModel.js + * DataModel.js * * Dependencies: * - Metamaps.Collaborators @@ -30,618 +33,36 @@ import Visualize from '../Visualize' * - Metamaps.Topics */ -const DataModel = {} +const DataModel = { + Map: Map, + MapCollection: MapCollection, + Message: Message, + MessageCollection: MessageCollection, + Mapper: Mapper, + MapperCollection: MapperCollection, + Metacode: Metacode, + MetacodeCollection: MetacodeCollection, + Topic: Topic, + TopicCollection: TopicCollection, + Synapse: Synapse, + SynapseCollection: SynapseCollection, + Mapping: Mapping, + MappingCollection: MappingCollection, -DataModel.Map = Backbone.Model.extend({ - urlRoot: '/maps', - blacklist: ['created_at', 'updated_at', 'created_at_clean', 'updated_at_clean', 'user_name', 'contributor_count', 'topic_count', 'synapse_count', 'topics', 'synapses', 'mappings', 'mappers'], - toJSON: function (options) { - return _.omit(this.attributes, this.blacklist) - }, - save: function (key, val, options) { - var attrs + init: function() { + var self = DataModel - // Handle both `"key", value` and `{key: value}` -style arguments. - if (key == null || typeof key === 'object') { - attrs = key - options = val - } else { - (attrs = {})[key] = val - } + Metamaps.Metacodes = Metamaps.Metacodes ? new self.MetacodeCollection(Metamaps.Metacodes) : new self.MetacodeCollection() - var newOptions = options || {} - var s = newOptions.success - - newOptions.success = function (model, response, opt) { - if (s) s(model, response, opt) - model.trigger('saved') - } - return Backbone.Model.prototype.save.call(this, attrs, newOptions) - }, - initialize: function () { - this.on('changeByOther', this.updateView) - this.on('saved', this.savedEvent) - }, - savedEvent: function () { - Realtime.updateMap(this) - }, - authorizeToEdit: function (mapper) { - if (mapper && ( - this.get('permission') === 'commons' || - (this.get('collaborator_ids') || []).includes(mapper.get('id')) || - this.get('user_id') === mapper.get('id'))) { - return true - } else { - return false - } - }, - authorizePermissionChange: function (mapper) { - if (mapper && this.get('user_id') === mapper.get('id')) { - return true - } else { - return false - } - }, - getUser: function () { - return Mapper.get(this.get('user_id')) - }, - updateView: function () { - var map = Active.Map - var isActiveMap = this.id === map.id - if (isActiveMap) { - InfoBox.updateNameDescPerm(this.get('name'), this.get('desc'), this.get('permission')) - this.updateMapWrapper() - // mobile menu - $('#header_content').html(this.get('name')) - document.title = this.get('name') + ' | Metamaps' - } - }, - updateMapWrapper: function () { - var map = Active.Map - var isActiveMap = this.id === map.id - var authorized = map && map.authorizeToEdit(Active.Mapper) ? 'canEditMap' : '' - var commonsMap = map && map.get('permission') === 'commons' ? 'commonsMap' : '' - if (isActiveMap) { - $('.wrapper').removeClass('canEditMap commonsMap').addClass(authorized + ' ' + commonsMap) - } - } -}) -DataModel.MapsCollection = Backbone.Collection.extend({ - model: DataModel.Map, - initialize: function (models, options) { - this.id = options.id - this.sortBy = options.sortBy - - if (options.mapperId) { - this.mapperId = options.mapperId - } - - // this.page represents the NEXT page to fetch - this.page = models.length > 0 ? (models.length < 20 ? 'loadedAll' : 2) : 1 - }, - url: function () { - if (!this.mapperId) { - return '/explore/' + this.id + '.json' - } else { - return '/explore/mapper/' + this.mapperId + '.json' - } - }, - comparator: function (a, b) { - a = a.get(this.sortBy) - b = b.get(this.sortBy) - var temp - if (this.sortBy === 'name') { - a = a ? a.toLowerCase() : '' - b = b ? b.toLowerCase() : '' - } else { - // this is for updated_at and created_at - temp = a - a = b - b = temp - a = (new Date(a)).getTime() - b = (new Date(b)).getTime() - } - return a > b ? 1 : a < b ? -1 : 0 - }, - getMaps: function (cb) { - var self = this - - Metamaps.Loading.show() - - if (this.page !== 'loadedAll') { - var numBefore = this.length - this.fetch({ - remove: false, - silent: true, - data: { page: this.page }, - success: function (collection, response, options) { - // you can pass additional options to the event you trigger here as well - if (collection.length - numBefore < 20) { - self.page = 'loadedAll' - } else { - self.page += 1 - } - self.trigger('successOnFetch', cb) - }, - error: function (collection, response, options) { - // you can pass additional options to the event you trigger here as well - self.trigger('errorOnFetch') - } - }) - } else { - self.trigger('successOnFetch', cb) - } - } -}) - -DataModel.Message = Backbone.Model.extend({ - urlRoot: '/messages', - blacklist: ['created_at', 'updated_at'], - toJSON: function (options) { - return _.omit(this.attributes, this.blacklist) - }, - prepareLiForFilter: function () { - /* var li = '' - * li += '
  • ' - * li += '' - * li += '

    ' + this.get('name') + '

  • ' - * return li - */ - } -}) -DataModel.MessageCollection = Backbone.Collection.extend({ - model: DataModel.Message, - url: '/messages' -}) - -DataModel.Mapper = Backbone.Model.extend({ - urlRoot: '/users', - blacklist: ['created_at', 'updated_at'], - toJSON: function (options) { - return _.omit(this.attributes, this.blacklist) - }, - prepareLiForFilter: function () { - var li = '' - li += '
  • ' - li += '' - li += '

    ' + this.get('name') + '

  • ' - return li - } -}) - -DataModel.MapperCollection = Backbone.Collection.extend({ - model: DataModel.Mapper, - url: '/users' -}) - -DataModel.init = function () { - var self = DataModel - - self.Metacode = Backbone.Model.extend({ - initialize: function () { - var image = new Image() - image.crossOrigin = 'Anonymous' - image.src = this.get('icon') - this.set('image', image) - }, - prepareLiForFilter: function () { - var li = '' - li += '
  • ' - li += '' - li += '

    ' + this.get('name').toLowerCase() + '

  • ' - return li - } - - }) - self.MetacodeCollection = Backbone.Collection.extend({ - model: this.Metacode, - url: '/metacodes', - comparator: function (a, b) { - a = a.get('name').toLowerCase() - b = b.get('name').toLowerCase() - return a > b ? 1 : a < b ? -1 : 0 - } - }) - - self.Topic = Backbone.Model.extend({ - urlRoot: '/topics', - blacklist: ['node', 'created_at', 'updated_at', 'user_name', 'user_image', 'map_count', 'synapse_count'], - toJSON: function (options) { - return _.omit(this.attributes, this.blacklist) - }, - save: function (key, val, options) { - var attrs - - // Handle both `"key", value` and `{key: value}` -style arguments. - if (key == null || typeof key === 'object') { - attrs = key - options = val - } else { - (attrs = {})[key] = val - } - - var newOptions = options || {} - var s = newOptions.success - - var permBefore = this.get('permission') - - newOptions.success = function (model, response, opt) { - if (s) s(model, response, opt) - model.trigger('saved') - model.set('calculated_permission', model.get('permission')) - - if (permBefore === 'private' && model.get('permission') !== 'private') { - model.trigger('noLongerPrivate') - } - else if (permBefore !== 'private' && model.get('permission') === 'private') { - model.trigger('nowPrivate') - } - } - return Backbone.Model.prototype.save.call(this, attrs, newOptions) - }, - initialize: function () { - if (this.isNew()) { - this.set({ - 'user_id': Active.Mapper.id, - 'desc': this.get('desc') || '', - 'link': this.get('link') || '', - 'permission': Active.Map ? Active.Map.get('permission') : 'commons' - }) - } - - this.on('changeByOther', this.updateCardView) - this.on('change', this.updateNodeView) - this.on('saved', this.savedEvent) - this.on('nowPrivate', function () { - var removeTopicData = { - mappableid: this.id - } - - $(document).trigger(JIT.events.removeTopic, [removeTopicData]) - }) - this.on('noLongerPrivate', function () { - var newTopicData = { - mappingid: this.getMapping().id, - mappableid: this.id - } - - $(document).trigger(JIT.events.newTopic, [newTopicData]) - }) - - this.on('change:metacode_id', Filter.checkMetacodes, this) - }, - authorizeToEdit: function (mapper) { - if (mapper && - (this.get('user_id') === mapper.get('id') || - this.get('calculated_permission') === 'commons' || - this.get('collaborator_ids').includes(mapper.get('id')))) { - return true - } else { - return false - } - }, - authorizePermissionChange: function (mapper) { - if (mapper && this.get('user_id') === mapper.get('id')) return true - else return false - }, - getDate: function () {}, - getMetacode: function () { - return Metamaps.Metacodes.get(this.get('metacode_id')) - }, - getMapping: function () { - if (!Active.Map) return false - - return Metamaps.Mappings.findWhere({ - map_id: Active.Map.id, - mappable_type: 'Topic', - mappable_id: this.isNew() ? this.cid : this.id - }) - }, - createNode: function () { - var mapping - var node = { - adjacencies: [], - id: this.isNew() ? this.cid : this.id, - name: this.get('name') - } - - if (Active.Map) { - mapping = this.getMapping() - node.data = { - $mapping: null, - $mappingID: mapping.id - } - } - - return node - }, - updateNode: function () { - var mapping - var node = this.get('node') - node.setData('topic', this) - - if (Active.Map) { - mapping = this.getMapping() - node.setData('mapping', mapping) - } - - return node - }, - savedEvent: function () { - Realtime.updateTopic(this) - }, - updateViews: function () { - var onPageWithTopicCard = Active.Map || Active.Topic - var node = this.get('node') - // update topic card, if this topic is the one open there - if (onPageWithTopicCard && this == TopicCard.openTopicCard) { - TopicCard.showCard(node) - } - - // update the node on the map - if (onPageWithTopicCard && node) { - node.name = this.get('name') - Visualize.mGraph.plot() - } - }, - updateCardView: function () { - var onPageWithTopicCard = Active.Map || Active.Topic - var node = this.get('node') - // update topic card, if this topic is the one open there - if (onPageWithTopicCard && this == TopicCard.openTopicCard) { - TopicCard.showCard(node) - } - }, - updateNodeView: function () { - var onPageWithTopicCard = Active.Map || Active.Topic - var node = this.get('node') - - // update the node on the map - if (onPageWithTopicCard && node) { - node.name = this.get('name') - Visualize.mGraph.plot() - } - } - }) - - self.TopicCollection = Backbone.Collection.extend({ - model: self.Topic, - url: '/topics' - }) - - self.Synapse = Backbone.Model.extend({ - urlRoot: '/synapses', - blacklist: ['edge', 'created_at', 'updated_at'], - toJSON: function (options) { - return _.omit(this.attributes, this.blacklist) - }, - save: function (key, val, options) { - var attrs - - // Handle both `"key", value` and `{key: value}` -style arguments. - if (key == null || typeof key === 'object') { - attrs = key - options = val - } else { - (attrs = {})[key] = val - } - - var newOptions = options || {} - var s = newOptions.success - - var permBefore = this.get('permission') - - newOptions.success = function (model, response, opt) { - if (s) s(model, response, opt) - model.trigger('saved') - - if (permBefore === 'private' && model.get('permission') !== 'private') { - model.trigger('noLongerPrivate') - } - else if (permBefore !== 'private' && model.get('permission') === 'private') { - model.trigger('nowPrivate') - } - } - return Backbone.Model.prototype.save.call(this, attrs, newOptions) - }, - initialize: function () { - if (this.isNew()) { - this.set({ - 'user_id': Active.Mapper.id, - 'permission': Active.Map ? Active.Map.get('permission') : 'commons', - 'category': 'from-to' - }) - } - - this.on('changeByOther', this.updateCardView) - this.on('change', this.updateEdgeView) - this.on('saved', this.savedEvent) - this.on('noLongerPrivate', function () { - var newSynapseData = { - mappingid: this.getMapping().id, - mappableid: this.id - } - - $(document).trigger(JIT.events.newSynapse, [newSynapseData]) - }) - this.on('nowPrivate', function () { - $(document).trigger(JIT.events.removeSynapse, [{ - mappableid: this.id - }]) - }) - - this.on('change:desc', Filter.checkSynapses, this) - }, - prepareLiForFilter: function () { - var li = '' - li += '
  • ' - li += '
  • ' - return li - }, - authorizeToEdit: function (mapper) { - if (mapper && (this.get('calculated_permission') === 'commons' || this.get('collaborator_ids').includes(mapper.get('id')) || this.get('user_id') === mapper.get('id'))) return true - else return false - }, - authorizePermissionChange: function (mapper) { - if (mapper && this.get('user_id') === mapper.get('id')) return true - else return false - }, - getTopic1: function () { - return Metamaps.Topics.get(this.get('topic1_id')) - }, - getTopic2: function () { - return Metamaps.Topics.get(this.get('topic2_id')) - }, - getDirection: function () { - var t1 = this.getTopic1(), - t2 = this.getTopic2() - - return t1 && t2 ? [ - t1.get('node').id, - t2.get('node').id - ] : false - }, - getMapping: function () { - if (!Active.Map) return false - - return Metamaps.Mappings.findWhere({ - map_id: Active.Map.id, - mappable_type: 'Synapse', - mappable_id: this.isNew() ? this.cid : this.id - }) - }, - createEdge: function (providedMapping) { - var mapping, mappingID - var synapseID = this.isNew() ? this.cid : this.id - - var edge = { - nodeFrom: this.get('topic1_id'), - nodeTo: this.get('topic2_id'), - data: { - $synapses: [], - $synapseIDs: [synapseID], - } - } - - if (Active.Map) { - mapping = providedMapping || this.getMapping() - mappingID = mapping.isNew() ? mapping.cid : mapping.id - edge.data.$mappings = [] - edge.data.$mappingIDs = [mappingID] - } - - return edge - }, - updateEdge: function () { - var mapping - var edge = this.get('edge') - edge.getData('synapses').push(this) - - if (Active.Map) { - mapping = this.getMapping() - edge.getData('mappings').push(mapping) - } - - return edge - }, - savedEvent: function () { - Realtime.updateSynapse(this) - }, - updateViews: function () { - this.updateCardView() - this.updateEdgeView() - }, - updateCardView: function () { - var onPageWithSynapseCard = Active.Map || Active.Topic - var edge = this.get('edge') - - // update synapse card, if this synapse is the one open there - if (onPageWithSynapseCard && edge == SynapseCard.openSynapseCard) { - SynapseCard.showCard(edge) - } - }, - updateEdgeView: function () { - var onPageWithSynapseCard = Active.Map || Active.Topic - var edge = this.get('edge') - - // update the edge on the map - if (onPageWithSynapseCard && edge) { - Visualize.mGraph.plot() - } - } - }) - - self.SynapseCollection = Backbone.Collection.extend({ - model: self.Synapse, - url: '/synapses' - }) - - self.Mapping = Backbone.Model.extend({ - urlRoot: '/mappings', - blacklist: ['created_at', 'updated_at'], - toJSON: function (options) { - return _.omit(this.attributes, this.blacklist) - }, - initialize: function () { - if (this.isNew()) { - this.set({ - 'user_id': Active.Mapper.id, - 'map_id': Active.Map ? Active.Map.id : null - }) - } - }, - getMap: function () { - return Map.get(this.get('map_id')) - }, - getTopic: function () { - if (this.get('mappable_type') === 'Topic') return Topic.get(this.get('mappable_id')) - else return false - }, - getSynapse: function () { - if (this.get('mappable_type') === 'Synapse') return Synapse.get(this.get('mappable_id')) - else return false - } - }) - - self.MappingCollection = Backbone.Collection.extend({ - model: self.Mapping, - url: '/mappings' - }) - - Metamaps.Metacodes = Metamaps.Metacodes ? new self.MetacodeCollection(Metamaps.Metacodes) : new self.MetacodeCollection() - - Metamaps.Topics = Metamaps.Topics ? new self.TopicCollection(Metamaps.Topics) : new self.TopicCollection() - - Metamaps.Synapses = Metamaps.Synapses ? new self.SynapseCollection(Metamaps.Synapses) : new self.SynapseCollection() - - Metamaps.Mappers = Metamaps.Mappers ? new self.MapperCollection(Metamaps.Mappers) : new self.MapperCollection() - - Metamaps.Collaborators = Metamaps.Collaborators ? new self.MapperCollection(Metamaps.Collaborators) : new self.MapperCollection() - - // this is for topic view - Metamaps.Creators = Metamaps.Creators ? new self.MapperCollection(Metamaps.Creators) : new self.MapperCollection() - - if (Active.Map) { - Metamaps.Mappings = Metamaps.Mappings ? new self.MappingCollection(Metamaps.Mappings) : new self.MappingCollection() - - Active.Map = new self.Map(Active.Map) - } - - if (Active.Topic) Active.Topic = new self.Topic(Active.Topic) - - // attach collection event listeners - self.attachCollectionEvents = function () { + // attach collection event listeners + Metamaps.Topics = Metamaps.Topics ? new self.TopicCollection(Metamaps.Topics) : new self.TopicCollection() Metamaps.Topics.on('add remove', function (topic) { InfoBox.updateNumbers() Filter.checkMetacodes() Filter.checkMappers() }) + Metamaps.Synapses = Metamaps.Synapses ? new self.SynapseCollection(Metamaps.Synapses) : new self.SynapseCollection() Metamaps.Synapses.on('add remove', function (synapse) { InfoBox.updateNumbers() Filter.checkSynapses() @@ -649,6 +70,7 @@ DataModel.init = function () { }) if (Active.Map) { + Metamaps.Mappings = Metamaps.Mappings ? new self.MappingCollection(Metamaps.Mappings) : new self.MappingCollection() Metamaps.Mappings.on('add remove', function (mapping) { InfoBox.updateNumbers() Filter.checkSynapses() @@ -656,8 +78,25 @@ DataModel.init = function () { Filter.checkMappers() }) } + + Metamaps.Mappers = Metamaps.Mappers ? new self.MapperCollection(Metamaps.Mappers) : new self.MapperCollection() + Metamaps.Collaborators = Metamaps.Collaborators ? new self.MapperCollection(Metamaps.Collaborators) : new self.MapperCollection() + Metamaps.Creators = Metamaps.Creators ? new self.MapperCollection(Metamaps.Creators) : new self.MapperCollection() + + if (Active.Map) { + Active.Map = new self.Map(Active.Map) + } + + if (Active.Topic) { + Active.Topic = new self.Topic(Active.Topic) + } } - self.attachCollectionEvents() -}; // end DataModel.init +} + +export { + Map, MapCollection, Mapper, MapperCollection, Mapping, MappingCollection, + Message, MessageCollection, Metacode, MetacodeCollection, + Synapse, SynapseCollection, Topic, TopicCollection +} export default DataModel diff --git a/frontend/src/Metamaps/GlobalUI/index.js b/frontend/src/Metamaps/GlobalUI/index.js index 580aa831..e82516c2 100644 --- a/frontend/src/Metamaps/GlobalUI/index.js +++ b/frontend/src/Metamaps/GlobalUI/index.js @@ -51,13 +51,13 @@ const GlobalUI = { } var featuredCollection = Metamaps.Maps.Featured ? Metamaps.Maps.Featured : [] var activeCollection = Metamaps.Maps.Active ? Metamaps.Maps.Active : [] - Metamaps.Maps.Mine = new Metamaps.DataModel.MapsCollection(myCollection, { id: 'mine', sortBy: 'updated_at' }) - Metamaps.Maps.Shared = new Metamaps.DataModel.MapsCollection(sharedCollection, { id: 'shared', sortBy: 'updated_at' }) - Metamaps.Maps.Starred = new Metamaps.DataModel.MapsCollection(starredCollection, { id: 'starred', sortBy: 'updated_at' }) + Metamaps.Maps.Mine = new Metamaps.DataModel.MapCollection(myCollection, { id: 'mine', sortBy: 'updated_at' }) + Metamaps.Maps.Shared = new Metamaps.DataModel.MapCollection(sharedCollection, { id: 'shared', sortBy: 'updated_at' }) + Metamaps.Maps.Starred = new Metamaps.DataModel.MapCollection(starredCollection, { id: 'starred', sortBy: 'updated_at' }) // 'Mapper' refers to another mapper - Metamaps.Maps.Mapper = new Metamaps.DataModel.MapsCollection(mapperCollection, mapperOptionsObj) - Metamaps.Maps.Featured = new Metamaps.DataModel.MapsCollection(featuredCollection, { id: 'featured', sortBy: 'updated_at' }) - Metamaps.Maps.Active = new Metamaps.DataModel.MapsCollection(activeCollection, { id: 'active', sortBy: 'updated_at' }) + Metamaps.Maps.Mapper = new Metamaps.DataModel.MapCollection(mapperCollection, mapperOptionsObj) + Metamaps.Maps.Featured = new Metamaps.DataModel.MapCollection(featuredCollection, { id: 'featured', sortBy: 'updated_at' }) + Metamaps.Maps.Active = new Metamaps.DataModel.MapCollection(activeCollection, { id: 'active', sortBy: 'updated_at' }) }, showDiv: function (selector) { $(selector).show()