Skip to content

Commit

Permalink
Merge pull request #230 from UUDigitalHumanitieslab/feature/frontend-…
Browse files Browse the repository at this point in the history
…collections

Basic frontend collection management
  • Loading branch information
jgonggrijp authored Oct 9, 2024
2 parents bd94f29 + 9e48842 commit 2d60cf2
Show file tree
Hide file tree
Showing 38 changed files with 484 additions and 62 deletions.
17 changes: 17 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org

root = true


[*]

indent_style = space
indent_size = 4
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true

[**/package.json]
indent_size = 2
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,9 @@ db*
/frontend/vre/*bundle*.js*

# Visual Studio Code
.vscode/
.vscode/

# emacs
.\#*
*~
\#*\#
4 changes: 2 additions & 2 deletions frontend/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ module.exports = function(config) {

// start these browsers
// available browser launchers: https://www.npmjs.com/search?q=keywords:karma-launcher
browsers: ['ChromeHeadless'],
browsers: [],

// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
Expand All @@ -114,7 +114,7 @@ module.exports = function(config) {
},

};

if (process.env.CI) {
configuration.browsers = ['ChromeHeadless'];
configuration.singleRun = true;
Expand Down
4 changes: 2 additions & 2 deletions frontend/vre/alert/alert.view.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import _ from 'lodash';
import { View } from 'backbone';
import { View } from '../core/view.js';
import alertTemplate from './alert.view.mustache';

/**
Expand Down Expand Up @@ -59,4 +59,4 @@ export var AlertView = View.extend({
wrapComplete: function(complete) {
return this[complete] && this[complete].bind(this) || complete;
},
});
});
2 changes: 1 addition & 1 deletion frontend/vre/annotation/annotation.edit.view.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { View } from 'backbone';
import { View } from '../core/view.js';
import annotationEditTemplate from './annotation.edit.view.mustache';
import confirmDeletionTemplate from './annotation.confirm.deletion.mustache';

Expand Down
8 changes: 4 additions & 4 deletions frontend/vre/annotation/annotation.model.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Backbone from 'backbone';
import { APIModel, APICollection } from '../utils/api.model';
import { canonicalSort } from '../utils/generic-functions';
import { GlobalVariables } from '../globals/variables';
import { vreChannel } from '../radio.js';

export var Annotations = APICollection.extend({
url: '/api/annotations',
Expand Down Expand Up @@ -37,7 +37,7 @@ export var FlatAnnotations = APICollection.extend({
}
var id = annotation.id,
projectId = annotation.get('context'),
projectName = GlobalVariables.allProjects.get(projectId).get('name'),
projectName = vreChannel.request('projects:get', projectId).get('name'),
content = annotation.get('content'),
existing = _.map(this.filter({ context: projectName }), 'attributes'),
replacements = _.map(content, function(value, key) {
Expand All @@ -59,7 +59,7 @@ export var FlatAnnotations = APICollection.extend({
recordId = record.id,
flatPerProject = flat.groupBy('context');
var newContent = flat.markedProjects.map('id').map(function (projectName) {
var projectId = GlobalVariables.allProjects.findWhere({ name: projectName }).id,
var projectId = vreChannel.request('projects:find', { name: projectName }).id,
existing = flat.underlying.findWhere({ context: projectId }),
id = existing && existing.id,
annotations = flatPerProject[projectName],
Expand All @@ -81,4 +81,4 @@ export var FlatAnnotations = APICollection.extend({
flat.underlying.add(newContent, {merge: true});
flat.markedProjects.reset();
},
});
});
2 changes: 1 addition & 1 deletion frontend/vre/catalog/collection.search.view.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CompositeView } from 'backbone-fractal';
import { CompositeView } from '../core/view.js';

import { SearchResults } from '../search/search.model.js';
import { SearchView } from '../search/search.view.js';
Expand Down
2 changes: 1 addition & 1 deletion frontend/vre/catalog/select-catalog.view.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Backbone from 'backbone';
import { CollectionView as AggregateView } from 'backbone-fractal';
import { AggregateView } from '../core/view.js';

import optionDBTemplate from './select-catalog-option.view.mustache';
import selectDBTemplate from './select-catalog.view.mustache';
Expand Down
26 changes: 24 additions & 2 deletions frontend/vre/collection/browse-collection.view.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
import { CompositeView } from 'backbone-fractal';
import { CompositeView } from '../core/view.js';

import { SearchResults } from '../search/search.model.js';
import { SearchView } from '../search/search.view.js';
import { RecordListManagingView } from '../record/record.list.managing.view.js';
import { OverlayView } from '../utils/overlay.view.js';
import { EditSummaryView } from './edit-summary.view.js';
import collectionTemplate from './browse-collection.view.mustache';

export var BrowseCollectionView = CompositeView.extend({
template: collectionTemplate,

events: {
'click .page-header small button': 'editSummary',
},

subviews: [
{view: 'searchView', selector: '.page-header'},
'recordsManager',
{view: 'editOverlay', place: false},
],

initialize: function() {
this.collection = this.collection || new SearchResults;
this.searchView = new SearchView({
Expand All @@ -21,10 +30,23 @@ export var BrowseCollectionView = CompositeView.extend({
collection: this.collection
});
this.model.getRecords(this.collection);
this.render();
var editor = new EditSummaryView({model: this.model});
var overlay = this.editOverlay = new OverlayView({
root: this.el,
target: '.page-header h2 small',
guest: editor,
});
overlay.listenTo(editor, 'submit reset', overlay.uncover);
this.render().listenTo(this.model, 'change', this.render);
},

renderContainer: function() {
this.$el.html(this.template(this.model.attributes));
return this;
},

editSummary: function() {
this.editOverlay.cover();
return this;
},
});
7 changes: 6 additions & 1 deletion frontend/vre/collection/browse-collection.view.mustache
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
<div class="page-header" id="title-collection">
<h2>Search or browse {{description}}</h2>
<h2>Collection {{name}} <small>
{{summary}}
<button type=button class="btn btn-default btn-sm" aria-label="Edit summary">
<span class="glyphicon glyphicon-pencil" aria-hidden=true></span>
</button>
</small></h2>
</div>
3 changes: 2 additions & 1 deletion frontend/vre/collection/collection.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Records } from '../record/record.model.js';
* Representation of a single VRE collection.
*/
export var VRECollection = APIModel.extend({
idAttribute: 'uri',
getRecords: function(records) {
if (!records) {
if (this.records) return this.records;
Expand Down Expand Up @@ -33,7 +34,7 @@ export var VRECollections = APICollection.extend({
*/
mine: function(myCollections) {
myCollections = myCollections || new VRECollections();
myCollections.fetch({url: myCollections.url + 'mine/'});
myCollections.fetch();
return myCollections;
},
});
2 changes: 1 addition & 1 deletion frontend/vre/collection/collection.view.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { View } from 'backbone';
import { View } from '../core/view.js';
import { AlertView } from '../alert/alert.view';
import { AdditionsToCollections } from '../additions/additions-to-collections';
import { GlobalVariables } from '../globals/variables';
Expand Down
41 changes: 41 additions & 0 deletions frontend/vre/collection/edit-summary.view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { View } from '../core/view.js';
import editSummaryTemplate from './edit-summary.view.mustache';

export var EditSummaryView = View.extend({
tagName: 'form',
className: 'form-inline inline-editor',
template: editSummaryTemplate,

events: {
submit: 'submit',
reset: 'reset',
},

initialize: function() {
this.render();
},

render: function() {
this.$el.html(this.template(this));
this.fillValue();
return this;
},

fillValue: function() {
this.$('input').val(this.model.get('summary'));
},

submit: function(event) {
event.preventDefault();
var payload = {
summary: this.$('input').val(),
};
this.trigger('submit', payload);
this.model.save(payload, {wait: true});
},

reset: function(event) {
event.preventDefault();
this.trigger('reset').fillValue();
},
});
21 changes: 21 additions & 0 deletions frontend/vre/collection/edit-summary.view.mustache
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<div class="form-group">
<label
for=summary-{{&cid}}
class="sr-only"
>Collection summary</label>
<input
type=text
name=summary
placeholder="Collection summary"
id=summary-{{&cid}}
class="form-control"
>
</div>
<button
type=submit
class="btn btn-primary"
>Save</button>
<button
type=reset
class="btn btn-default"
>Cancel</button>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<a href="/collection/{{id}}/" id="{{id}}">{{description}}</a>
<a href="/collection/{{name}}/" id="{{name}}">{{name}}</a>
24 changes: 22 additions & 2 deletions frontend/vre/collection/select-collection.view.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import _ from 'lodash';
import Backbone from 'backbone';
import { CollectionView as AggregateView } from 'backbone-fractal';
import { AggregateView } from '../core/view.js';

import { vreChannel } from '../radio.js';
import optionDBTemplate from './select-collection-option.view.mustache';
import selectDBTemplate from './select-collection.view.mustache';

Expand Down Expand Up @@ -40,11 +42,29 @@ export var SelectCollectionView = AggregateView.extend({
className: 'dropdown',
subview: CollectionOptionView,
container: 'ul',
events: {
'submit .dropdown-menu form': 'createCollection',
},
initialize: function() {
this.initItems().render().initCollectionEvents();
},
renderContainer: function() {
this.$el.html(this.template());
this.$el.html(this.template(this));
return this;
},
placeItems: function() {
this._container.prepend(_.map(this.items, 'el'));
return this;
},
createCollection: function(event) {
event.preventDefault();
var project = vreChannel.request('projects:current');
var input = this.$('.dropdown-menu form input');
var name = input.val();
this.collection.create({
name: name,
project: project.get('name'),
});
input.val('');
},
});
22 changes: 21 additions & 1 deletion frontend/vre/collection/select-collection.view.mustache
Original file line number Diff line number Diff line change
@@ -1,4 +1,24 @@
<a href="" class="dropdown-toggle" data-toggle="dropdown"
id="collection-menu-title" aria-haspopup="true" aria-expanded="false">Collections <span class="caret"></span>
</a>
<ul class="dropdown-menu"></ul>
<ul class="dropdown-menu">
<li role=separator class="divider"></li>
<li>
<form class="form-inline">
<div class="form-group">
<label for=collection-name-{{&cid}} class="sr-only">
Name
</label>
<input
type=text
id=collection-name-{{&cid}}
placeholder="Name"
class="form-control"
>
</div>
<button type=submit class="btn btn-primary btn-sm" aria-label="Create">
<span class="glyphicon glyphicon-plus" aria-hidden=true></span>
</button>
</form>
</li>
</ul>
30 changes: 30 additions & 0 deletions frontend/vre/core/view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import _ from 'lodash';
import { View as BBView } from 'backbone';
import { CompositeView as FComposite, CollectionView } from 'backbone-fractal';
import { getAltClickMixin } from '@uu-cdh/backbone-util';

function mix(Base) {
return Base.extend(_.extend(getAltClickMixin(), {
constructor: function(options) {
Base.call(this, options);
this.enableAltClick();
},

remove: function() {
this.$el.off('click');
return Base.prototype.remove.call(this);
},
}));
}

/**
* Common base classes for all of our views.
* Among other things, they enable alt-click debugging.
*/

/** @class */
export var View = mix(BBView);
/** @class */
export var CompositeView = mix(FComposite);
/** @class */
export var AggregateView = mix(CollectionView);
18 changes: 18 additions & 0 deletions frontend/vre/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,21 @@ ul.inline-list li {
ul.inline-list li:not(:first-child)::before {
content: " • "
}

form.form-inline.inline-editor {
display: inline-block;
}

.dropdown-menu > li > form {
padding: 3px 20px;
width: max-content;
}

@media (prefers-color-scheme: dark) {
html {
filter: invert(1) hue-rotate(180deg) contrast(0.9) brightness(0.9);
}
img, video {
filter: hue-rotate(180deg) invert(1);
}
}
2 changes: 1 addition & 1 deletion frontend/vre/field/field.view.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { View } from 'backbone';
import { View } from '../core/view.js';
import fieldTemplate from './field.view.mustache';

/**
Expand Down
Loading

0 comments on commit 2d60cf2

Please sign in to comment.