Start of "production videos", a.k.a. tagged assets overview
Tagged assets are shown in a list per tag. The list is dynamically loaded with JavaScript.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,8 +7,7 @@ __pycache__
|
|||||||
*.css.map
|
*.css.map
|
||||||
|
|
||||||
/cloud/templates/
|
/cloud/templates/
|
||||||
/cloud/static/assets/css/
|
/cloud/static/assets/
|
||||||
/cloud/static/assets/js/bootstrap.min.js
|
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
/config_local.py
|
/config_local.py
|
||||||
|
@@ -41,6 +41,7 @@ class CloudExtension(PillarExtension):
|
|||||||
'EXTERNAL_SUBSCRIPTIONS_MANAGEMENT_SERVER': 'https://store.blender.org/api/',
|
'EXTERNAL_SUBSCRIPTIONS_MANAGEMENT_SERVER': 'https://store.blender.org/api/',
|
||||||
'EXTERNAL_SUBSCRIPTIONS_TIMEOUT_SECS': 10,
|
'EXTERNAL_SUBSCRIPTIONS_TIMEOUT_SECS': 10,
|
||||||
'BLENDER_ID_WEBHOOK_USER_CHANGED_SECRET': 'oos9wah1Zoa0Yau6ahThohleiChephoi',
|
'BLENDER_ID_WEBHOOK_USER_CHANGED_SECRET': 'oos9wah1Zoa0Yau6ahThohleiChephoi',
|
||||||
|
'NODE_TAGS': ['animation', 'modelling', 'rigging'],
|
||||||
}
|
}
|
||||||
|
|
||||||
def eve_settings(self):
|
def eve_settings(self):
|
||||||
|
@@ -391,6 +391,11 @@ def privacy():
|
|||||||
return render_template('privacy.html')
|
return render_template('privacy.html')
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route('/production')
|
||||||
|
def production():
|
||||||
|
return render_template('production.html')
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route('/emails/welcome.send')
|
@blueprint.route('/emails/welcome.send')
|
||||||
@login_required
|
@login_required
|
||||||
def emails_welcome_send():
|
def emails_welcome_send():
|
||||||
|
3
cloud/tagged/__init__.py
Normal file
3
cloud/tagged/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""Routes for fetching tagged assets."""
|
||||||
|
|
||||||
|
|
16
cloud/tagged/routes.py
Normal file
16
cloud/tagged/routes.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import logging
|
||||||
|
import datetime
|
||||||
|
import functools
|
||||||
|
|
||||||
|
from flask import Blueprint, jsonify
|
||||||
|
|
||||||
|
blueprint = Blueprint('cloud.tagged', __name__, url_prefix='/tagged')
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@blueprint.route('/')
|
||||||
|
def index():
|
||||||
|
"""Return all tagged assets as JSON, grouped by tag."""
|
||||||
|
|
||||||
|
|
109
src/scripts/tagged_assets.js
Normal file
109
src/scripts/tagged_assets.js
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/**
|
||||||
|
* Support for fetching & rendering assets by tags.
|
||||||
|
*/
|
||||||
|
(function($) {
|
||||||
|
/* How many nodes to load initially, and when clicked on the 'Load Next' link. */
|
||||||
|
const LOAD_INITIAL_COUNT = 5;
|
||||||
|
const LOAD_NEXT_COUNT = 3;
|
||||||
|
|
||||||
|
/* Renders a node as a <li> element, returns a jQuery object. */
|
||||||
|
function renderAsset(node) {
|
||||||
|
let li = $('<li>').addClass('tagged-asset');
|
||||||
|
let link = $('<a>')
|
||||||
|
.attr('href', '/nodes/' + node._id + '/redir')
|
||||||
|
.appendTo(li);
|
||||||
|
|
||||||
|
function warnNoPicture() {
|
||||||
|
li.addClass('warning');
|
||||||
|
link.text('no picture for node ' + node._id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node.picture) {
|
||||||
|
warnNoPicture();
|
||||||
|
return li;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: show 'loading' thingy
|
||||||
|
$.get('/api/files/' + node.picture)
|
||||||
|
.fail(function(error) {
|
||||||
|
let msg = xhrErrorResponseMessage(error);
|
||||||
|
li.addClass('error').text(msg);
|
||||||
|
})
|
||||||
|
.done(function(resp) {
|
||||||
|
// Render the picture if it has the proper size.
|
||||||
|
var show_variation = null;
|
||||||
|
if (typeof resp.variations != 'undefined') {
|
||||||
|
for (variation of resp.variations) {
|
||||||
|
if (variation.size != 'm') continue;
|
||||||
|
show_variation = variation;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_variation == null) {
|
||||||
|
warnNoPicture();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let img = $('<img>')
|
||||||
|
.attr('alt', node.name)
|
||||||
|
.attr('src', variation.link)
|
||||||
|
.attr('width', variation.width)
|
||||||
|
.attr('height', variation.height);
|
||||||
|
link.append(img);
|
||||||
|
});
|
||||||
|
|
||||||
|
return li;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadNext(ul_element) {
|
||||||
|
let $ul = $(ul_element);
|
||||||
|
let tagged_assets = ul_element.tagged_assets; // Stored here by loadTaggedAssets().
|
||||||
|
let already_loaded = $ul.find('li.tagged-asset').length;
|
||||||
|
|
||||||
|
let load_next = $ul.find('li.load-next');
|
||||||
|
|
||||||
|
let nodes_to_load = tagged_assets.slice(already_loaded, already_loaded + LOAD_NEXT_COUNT);
|
||||||
|
for (node of nodes_to_load) {
|
||||||
|
let li = renderAsset(node);
|
||||||
|
load_next.before(li);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (already_loaded + LOAD_NEXT_COUNT >= tagged_assets.length)
|
||||||
|
load_next.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.loadTaggedAssets = function(api_base_url) {
|
||||||
|
this.each(function(index, ul_element) {
|
||||||
|
// TODO(Sybren): show a 'loading' animation.
|
||||||
|
$.get('/api/nodes/tagged/' + ul_element.dataset.assetTag)
|
||||||
|
.fail(function(error) {
|
||||||
|
let msg = xhrErrorResponseMessage(error);
|
||||||
|
$('<li>').addClass('error').text(msg).appendTo(ul_element);
|
||||||
|
})
|
||||||
|
.done(function(resp) {
|
||||||
|
// 'resp' is a list of node documents.
|
||||||
|
// Store the response on the DOM <ul>-element so that we can later render more.
|
||||||
|
ul_element.tagged_assets = resp;
|
||||||
|
|
||||||
|
// Here render the first N.
|
||||||
|
for (node of resp.slice(0, LOAD_INITIAL_COUNT)) {
|
||||||
|
let li = renderAsset(node);
|
||||||
|
li.appendTo(ul_element);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't bother with a 'load next' link if there is no more.
|
||||||
|
if (resp.length <= LOAD_INITIAL_COUNT) return;
|
||||||
|
|
||||||
|
// Construct the 'load next' link.
|
||||||
|
let load_next = $('<li>').addClass('load-next');
|
||||||
|
let link = $('<a>')
|
||||||
|
.attr('href', 'javascript:void(0);')
|
||||||
|
.click(function() { loadNext(ul_element); return false; })
|
||||||
|
.text('Load next')
|
||||||
|
.appendTo(load_next);
|
||||||
|
load_next.appendTo(ul_element);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}(jQuery));
|
35
src/templates/production.pug
Normal file
35
src/templates/production.pug
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
| {% extends 'layout.html' %}
|
||||||
|
| {% block page_title %}Production of Stuff{% endblock %}
|
||||||
|
| {% block head %}
|
||||||
|
script(src="{{ url_for('static_cloud', filename='assets/js/tagged_assets.min.js') }}")
|
||||||
|
|
||||||
|
script.
|
||||||
|
$(function() {
|
||||||
|
$('ul.asset-list').loadTaggedAssets();
|
||||||
|
})
|
||||||
|
| {% endblock %}
|
||||||
|
| {% block body %}
|
||||||
|
#page-container
|
||||||
|
#page-content
|
||||||
|
h2 Production of Stuff
|
||||||
|
p.
|
||||||
|
Here are our hand-selected assets 'bout stuff.
|
||||||
|
|
||||||
|
h3 Animation
|
||||||
|
ul.asset-list(data-asset-tag="animation")
|
||||||
|
|
||||||
|
h3 Modelling
|
||||||
|
ul.asset-list(data-asset-tag="modelling")
|
||||||
|
|
||||||
|
h3 Rigging
|
||||||
|
ul.asset-list(data-asset-tag="rigging")
|
||||||
|
|
||||||
|
h3 pipeline
|
||||||
|
ul.asset-list(data-asset-tag="pipeline")
|
||||||
|
|
||||||
|
h3 lookdev
|
||||||
|
ul.asset-list(data-asset-tag="lookdev")
|
||||||
|
|
||||||
|
h3 crazyspace
|
||||||
|
ul.asset-list(data-asset-tag="crazyspace")
|
||||||
|
| {% endblock body%}
|
Reference in New Issue
Block a user