Introducing Pillar Framework

Refactor of pillar-server and pillar-web into a single python package. This
simplifies the overall architecture of pillar applications.

Special thanks @sybren and @venomgfx
This commit is contained in:
2016-08-19 09:19:06 +02:00
parent a5e92e1d87
commit 2c5dc34ea2
232 changed files with 79508 additions and 2232 deletions

View File

@@ -0,0 +1,445 @@
#comments-container
a(name="comments")
section#comments-list
.comment-reply-container
| {% if current_user.is_authenticated %}
| {% if has_method_POST %}
.comment-reply-avatar
img(src="{{ current_user.gravatar }}")
.comment-reply-form
.comment-reply-field
textarea(
id="comment_field",
data-parent_id="{{ parent_id }}",
placeholder="Join the conversation...",)
.comment-reply-meta
.comment-details
.comment-rules
a(
title="Markdown Supported"
href="https://guides.github.com/features/mastering-markdown/")
i.pi-markdown
.comment-author
span.commenting-as commenting as
span.author-name {{ current_user.full_name }}
button.comment-action-cancel.btn.btn-outline(
type="button",
title="Cancel")
i.pi-cancel
button.comment-action-submit.btn.btn-outline(
id="comment_submit",
type="button",
title="Post Comment")
| Post Comment
span.hint (Ctrl+Enter)
.comment-reply-preview
| {% else %}
| {# * It's authenticated, but has no 'POST' permission #}
.comment-reply-form
.comment-reply-field.sign-in
textarea(
disabled,
id="comment_field",
data-parent_id="{{ parent_id }}",
placeholder="")
.sign-in
| Join the conversation!&nbsp;<a href="https://store.blender.org/product/membership/">Subscribe to Blender Cloud now.</a>
| {% endif %}
| {% else %}
| {# * It's not autenticated #}
.comment-reply-form
.comment-reply-field.sign-in
textarea(
disabled,
id="comment_field",
data-parent_id="{{ parent_id }}",
placeholder="")
.sign-in
a(href="{{ url_for('users.login') }}") Log in
| to comment.
| {% endif %}
section#comments-list-header
#comments-list-title
#comments-list-items
#comments-list-items-loading
i.pi-spin
script#comment-template(type="text/x-handlebars-template")
| {% raw %}
| {{#list items }}
.comment-container(
id="{{ _id }}",
data-node_id="{{ _id }}",
class="{{#if is_team}}is-team{{/if}}{{#if is_reply}}is-reply{{else}}is-first{{/if}}")
.comment-header
.comment-avatar
img(src="{{ gravatar }}")
.comment-author(class="{{#if is_own}}own{{/if}}")
| {{ author }}
span.username ({{ author_username }})
| {{#if is_team}}
.comment-badge.badge-team(title="Project Member") team
| {{/if}}
.comment-time {{ time_published }} {{#if time_edited }} (edited {{ time_edited }}){{/if}}
.comment-content {{{ content }}}
| {{#if is_own}}
.comment-content-preview
| {{/if}}
.comment-meta
.comment-rating(
class="{{#if is_rated}}rated{{/if}}{{#if is_rated_positive}} positive{{/if}}")
.comment-rating-value(title="Number of likes") {{ rating }}
.comment-action-rating.up(title="Like comment")
.comment-action-reply(title="Reply to this comment")
span reply
| {{#if is_own}}
.comment-action-edit
span.edit_mode(title="Edit comment") edit
span.edit_save(title="Save comment")
i.pi-check
| save changes
span.edit_cancel(title="Cancel changes")
i.pi-cancel
| cancel
| {{/if}}
| {{/list}}
| {% endraw %}
| {% block comment_scripts %}
script.
// Markdown initialization
var convert = new Markdown.getSanitizingConverter();
Markdown.Extra.init(convert);
convert = convert.makeHtml;
// Define the template for handlebars
var source = $("#comment-template").html();
var template = Handlebars.compile(source);
// Register the helper for generating the comments list
Handlebars.registerHelper('list', function(context, options) {
var ret = "";
var comments_count = 0
// Loop through all first-level comments
for(var i=0, j=context.length; i<j; i++) {
comments_count++
// Convert Markdown for each comment
context[i]['content'] = convert(context[i]['content']);
// Append compiled comment to return string
ret = ret + options.fn(context[i]);
// Search for replies to the current comment
if (context[i]['replies']) {
var replies = context[i]['replies'];
var compiled_replies = "";
// Loop through replies
for(var r=0, t=replies.length; r<t; r++) {
// Convert Markdown for each comment
replies[r]['content'] = convert(replies[r]['content']);
// Append compiled replies
compiled_replies = compiled_replies + options.fn(replies[r]);
comments_count++
}
// Append replies list to the return string
ret = ret + compiled_replies;
}
}
$("#comments-list-title").html(((comments_count > 0) ? comments_count : 'No') + ((comments_count == 1) ? ' comment' : ' comments'));
return ret;
});
// Helper for the if/else statement
Handlebars.registerHelper('if', function(conditional, options) {
if(conditional) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
/* Build the markdown preview when typing in textarea */
$(function() {
var $textarea = $('.comment-reply-field textarea'),
$container = $('.comment-reply-form'),
$preview = $('.comment-reply-preview');
// As we type in the textarea
$textarea.keyup(function(e) {
// Convert markdown
$preview.html(convert($textarea.val()));
// While we are at it, style when empty
if ($textarea.val()) {
$container.addClass('filled');
} else {
$container.removeClass('filled');
};
// Send on ctrl+enter
if ((e.keyCode == 10 || e.keyCode == 13) && e.ctrlKey){
$( ".comment-action-submit" ).trigger( "click" );
};
}).trigger('keyup');
});
// Get the comments list in JSON
$.getJSON( "{{url_for('nodes.comments_index')}}?parent_id={{ parent_id }}&format=json", function( data ) {
// Format using handlebars template
var comments = template(data);
if (comments && comments.trim() !="") {
$('#comments-list-items').html(comments);
} else {
$('#comments-list-items').html('');
}
})
.done(function(){
var scrollToId = location.hash;
if (scrollToId.length <= 1) return;
document.getElementById(scrollToId.substr(1)).scrollIntoView(true);
$(scrollToId).addClass('comment-linked');
});
/* Submit comment */
$('.comment-action-submit').click(function(e){
var $this = $(this);
var $textarea = $('.comment-reply-field textarea');
var commentField = document.getElementById('comment_field');
var comment = commentField.value;
function error(msg) {
// No content in the textarea
$this.addClass('button-field-error');
$textarea.addClass('field-error')
$this.html(msg);
setTimeout(function(){
$this.html('Post Comment');
$this.removeClass('button-field-error');
$textarea.removeClass('field-error');
}, 2500);
}
if (comment.length < 5) {
if (comment.length == 0) error("Say something...");
else error("Minimum 5 characters.");
return;
}
$this.addClass('submitting');
$this.html('<i class="pi-spin spin"></i> Posting...');
// Collect parent_id
parent_id = commentField.getAttribute('data-parent_id');
$.post("{{url_for('nodes.comments_create')}}",
// Submit content and parent_id for comment creation
{'content': comment, 'parent_id': parent_id}
)
.fail(function(){
$this.addClass('button-field-error');
$textarea.addClass('field-error')
$this.html("Houston! Try again?");
setTimeout(function(){
$this.html('Post Comment');
$this.removeClass('button-field-error');
$textarea.removeClass('field-error');
}, 2500);
})
.done(function(){
// Load the comments
var url = "{{url_for('nodes.comments_index')}}?parent_id={{ parent_id }}";
$.get(url, function(dataHtml) {
// Update the DOM injecting the generate HTML into the page
$('#comments-container').replaceWith(dataHtml);
})
});
});
/* Edit comment */
// Markdown convert as we type in the textarea
$(document).on('keyup','body .comment-content textarea',function(e){
var $textarea = $(this),
$container = $(this).parent(),
$preview = $container.next();
// Convert markdown
$preview.html(convert($textarea.val()));
// While we are at it, style if empty
if (!$textarea.val()) {
$container.addClass('empty');
} else {
$container.removeClass('empty');
};
}).trigger('keyup');
/* Enter edit mode */
$(document).on('click','body .comment-action-edit span.edit_mode',function(){
$(this).hide();
$(this).siblings('span.edit_cancel').show();
$(this).siblings('span.edit_save').show();
var comment_content = $(this).parent().parent().siblings('.comment-content');
var comment_id = comment_content.parent().attr('data-node_id');
var height = comment_content.height();
var url = '/nodes/' + comment_id + '/view?format=json';
$.get(url, function(data) {
var comment_raw = data['node']['properties']['content'];
comment_content.html('<textarea>' + comment_raw + '</textarea>');
comment_content.addClass('editing')
.find('textarea')
.height(height)
.focus();
comment_content.siblings('.comment-content-preview').show();
})
.fail(function(data){
statusBarSet('error', 'Error entering edit mode.', 'pi-warning');
});
});
/* Return UI to normal, when cancelling or saving */
function commentEditCancel(comment_container) {
var comment_id = comment_container.parent().attr('id');
var url = '/nodes/' + comment_id + '/view?format=json';
$.get(url, function(data) {
var comment_raw = data['node']['properties']['content'];
comment_container.html(convert(comment_raw))
.removeClass('editing');
comment_container.siblings('.comment-content-preview').html('').hide();
})
.fail(function(data){
statusBarSet('error', 'Error canceling.', 'pi-warning');
});
}
$(document).on('click','body .comment-action-edit span.edit_cancel',function(e){
$(this).hide();
$(this).siblings('span.edit_save').hide();
$(this).siblings('span.edit_mode').show();
var commentContainer = $(this).parent().parent().siblings('.comment-content');
commentEditCancel(commentContainer);
});
/* Save edited comment */
$(document).on('click','body .comment-action-edit span.edit_save',function(e){
var $this = $(this);
var commentContainer = $(this).parent().parent().siblings('.comment-content');
var commentField = commentContainer.find('textarea');
var comment = commentField.val();
var commentId = commentContainer.parent().attr('id');
function error(msg) {
// No content in the textarea
$this.addClass('error')
.html(msg);
commentField.addClass('field-error')
setTimeout(function(){
$this.html('<i class="pi-check"></i> save changes')
.removeClass('error');
commentField.removeClass('field-error');
}, 2500);
}
if (comment.length < 5) {
if (comment.length == 0) error("Say something...");
else error("Minimum 5 characters.");
return;
}
$this.addClass('saving')
.html('<i class="pi-spin spin"></i> Saving...');
$.post('/nodes/comments/' + commentId,
{'content': comment}
)
.fail(function(){
$this.addClass('error')
.html("Houston! Try again?");
commentField.addClass('field-error')
setTimeout(function(){
$this.html('Save changes')
.removeClass('error');
commentField.removeClass('field-error');
}, 2500);
})
.done(function(){
commentEditCancel(commentContainer);
commentContainer
.html(convert(comment));
commentContainer.next().text(comment);
$this.html('<i class="pi-grin"></i> saved!')
.removeClass('saving')
.siblings('span.edit_cancel').hide();
setTimeout(function(){
$this.html('<i class="pi-check"></i> save changes')
.hide()
.siblings('span.edit_mode').show();
}, 2500);
});
});
| {% endblock %}

View File

@@ -0,0 +1,189 @@
script(type="text/javascript").
/* Convert Markdown */
var convert_fields = '.node-details-description, .blog_index-item .item-content';
var convert = new Markdown.getSanitizingConverter();
Markdown.Extra.init(convert);
convert = convert.makeHtml;
/* Parse description/content fields to convert markdown */
$(convert_fields).each(function(i){
$(convert_fields).eq(i).html(convert($(convert_fields).eq(i).text()));
});
ProjectUtils.setProjectAttributes({isProject: false});
{% if node %}
ProjectUtils.setProjectAttributes({
nodeId: '{{node._id}}',
nodeType: '{{node.node_type}}'});
var node_type = ProjectUtils.nodeType();
var node_type_str = node_type;
if (node_type === 'group'){
node_type_str = 'Folder';
} else if (node_type === 'group_texture') {
node_type_str = 'Texture Folder';
} else if (node_type === 'group_hdri') {
node_type_str = 'HDRi Folder';
}
$('a', '.button-edit').html('<i class="pi-edit button-edit-icon"></i> Edit ' + node_type_str);
$('a', '.button-delete').html('<i class="pi-trash button-delete-icon"></i>Delete ' + node_type_str);
{% if parent %}
ProjectUtils.setProjectAttributes({parentNodeId: '{{parent._id}}'});
{% endif %}
// If we are im preview mode, update the image source
var page_overlay = document.getElementById('page-overlay');
if (page_overlay.classList.contains('active')) {
var node_preview = document.getElementById('node-preview');
if (node_preview){
if ($(node_preview).hasClass('image') || $(node_preview).hasClass('file')){
var src = $(node_preview).find('img').attr('src');
showOverlayPreviewImage(src);
}
} else {
$(page_overlay).html('<div class="nav-prev"></div><div class="no-preview">No Preview Available</div><div class="nav-next"></div>');
}
}
function loadComments(){
var commentsUrl = "{{ url_for('nodes.comments_index', parent_id=node._id) }}";
$.get(commentsUrl, function(dataHtml) {
})
.done(function(dataHtml){
// Update the DOM injecting the generate HTML into the page
$('#comments-container').replaceWith(dataHtml);
})
.fail(function(e, data){
statusBarSet('error', 'Couldn\'t load comments. Error: ' + data.errorThrown, 'pi-attention', 5000);
$('#comments-container').html('<a id="comments-reload"><i class="pi-refresh"></i> Reload comments</a>');
});
}
loadComments();
$('body').on('click', '#comments-reload', function(){
loadComments();
});
{% if node.has_method('PUT') %}
$('.project-mode-view').show();
{% else %}
$('.project-mode-view').hide();
{% endif %}
{% if node.picture %}
function showOverlayPreviewImage(src) {
$(page_overlay)
.addClass('active')
.html('<div class="nav-prev"></div><img src="' + src + '"/><div class="nav-next"></div>');
}
$('#node-preview.image, #node-preview.file').click(function(e){
e.preventDefault();
e.stopPropagation();
showOverlayPreviewImage("{{ node.picture.thumbnail('l', api=api) }}");
});
{% endif %}
// Click anywhere in the page to hide the overlay
function hidePageOverlay() {
$(page_overlay)
.removeAttr('class')
.html('');
}
$(page_overlay).click(function(e) {
e.stopPropagation();
e.preventDefault();
hidePageOverlay();
});
function navigateTree(prev){
var tree = $('#project_tree').jstree(true);
var curr = tree.get_selected(false);
if (prev === undefined){
var n = tree.get_next_dom(curr);
} else {
var n = tree.get_prev_dom(curr);
}
if (n && n.length > 0) {
tree.deselect_all();
tree.select_node(n);
}
}
document.onkeydown = function(e) {
var event = document.all ? window.event : e;
switch (e.target.tagName.toLowerCase()) {
case "input":
case "textarea":
case "select":
case "button":
break
default:
if (event.keyCode==27) hidePageOverlay();
if (event.keyCode==37) navigateTree(true);
if (event.keyCode==39) navigateTree();
break;
}
}
$(page_overlay).find('.nav-prev').click(function(e){
e.stopPropagation();
e.preventDefault();
navigateTree(true);
});
$(page_overlay).find('.nav-next').click(function(e){
e.stopPropagation();
e.preventDefault();
navigateTree();
});
// Auto-scale the image preview to the right aspect ratio
var node_preview = document.getElementById("node-preview-thumbnail");
if (node_preview) {
node_preview.addEventListener('load', function() {
var preview_aspect = this.naturalWidth / this.naturalHeight
if (preview_aspect > 1.0){
$('.node-preview, .node-preview-thumbnail').css({'max-height': 'auto', 'width': '100%'});
$('.node-preview img').css({'max-height': '100%'});
}
});
}
$('#node-overlay').click(function(){
$(this).removeClass('active').hide().html();
});
if (typeof $().popover != 'undefined'){
$('#asset-license').popover();
}
{% endif %}
if (typeof $().tooltip != 'undefined'){
$('[data-toggle="tooltip"]').tooltip({'delay' : {'show': 1250, 'hide': 250}});
}

View File

@@ -0,0 +1,128 @@
| {% block body %}
#node-container
#node-overlay
| {% if node.picture %}
section#node-preview.node-preview.file
img.node-preview-thumbnail#node-preview-thumbnail(
src="{{ node.picture.thumbnail('l', api=api) }}")
| {% endif %}
section.node-details-container.file
.node-details-header
.node-title#node-title
| {{node.name}}
.node-details-meta.header
ul.node-details-meta-list
| {% if node.permissions.world %}
li.node-details-meta-list-item.access.public(
data-toggle="tooltip",
data-placement="left",
title="Anybody can download. Share it!")
i.pi-lock-open
span Public
| {% endif %}
| {% if node.file %}
li.node-details-meta-list-item.type
| {{ node.file.content_type }}
li.node-details-meta-list-item.file.length
| {{ node.file.length | filesizeformat }}
| {% endif %}
| {% if node.properties.license_type %}
| {% if node.properties.license_notes %}
li.node-details-meta-list-item.license(
id="asset-license",
data-toggle="popover",
data-placement="left",
data-trigger="hover",
data-content="{{ node.properties.license_notes }}",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% else %}
li.node-details-meta-list-item.license(
id="asset-license",
data-toggle="tooltip",
data-placement="bottom",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% endif %}
| {% endif %}
| {% if node.file %}
li.node-details-meta-list-item.file.download(title="Download File")
| {% if node.file.link %}
a(href="{{ node.file.link }}",
title="Download file",
download="{{ node.file.filename }}")
button.btn.btn-default(type="button")
i.pi-download
| {% else %}
button.btn.btn-default.disabled.sorry(type="button")
i.pi-download
| {% endif %}
| {% endif %}
| {% if node.description %}
.node-details-description#node-description
| {{node.description}}
| {% endif %}
| {% if node.properties.license_notes %}
.node-details-meta.license
| {{ node.properties.license_notes }}
| {% endif %}
.node-details-meta.footer
ul.node-details-meta-list
li.node-details-meta-list-item.status
| {{node.properties.status}}
li.node-details-meta-list-item.author
| {{ node.user.full_name }}
li.node-details-meta-list-item.date(title="Created {{ node._created }}")
| {{ node._created | pretty_date }}
| {% if (node._created | pretty_date) != (node._updated | pretty_date) %}
span(title="Updated {{ node._updated }}") (updated {{ node._updated | pretty_date }})
| {% endif %}
#comments-container
#comments-list-items-loading
i.pi-spin
include ../../_scripts
| {% endblock %}
| {% block footer_scripts %}
script.
// Generate GA pageview
ga('send', 'pageview', location.pathname);
var content_type = $("li.node-details-meta-list-item.type").text();
var type_trimmed = content_type.substring(content_type.indexOf("/") + 1);
if (type_trimmed == 'x-blender' || type_trimmed == 'blend'){
type_trimmed = '<span class="blend"><i class="pi-blender-logo"></i></span>';
};
$("li.node-details-meta-list-item.type").html(type_trimmed);
$('.sorry').click(function() {
$.get('/403', function(data) {
$('#node-overlay').html(data).addClass('active');
})
});
| {% endblock %}

View File

@@ -0,0 +1,4 @@
| {% extends 'layout.html' %}
| {% block footer_scripts %}
| {% endblock %}

View File

@@ -0,0 +1,128 @@
| {% block body %}
#node-container
#node-overlay
| {% if node.picture %}
section#node-preview.node-preview.image
img.node-preview-thumbnail#node-preview-thumbnail(
src="{{ node.picture.thumbnail('l', api=api) }}")
| {% endif %}
section.node-details-container.image
.node-details-header
.node-title#node-title
| {{node.name}}
.node-details-meta.header
ul.node-details-meta-list
| {% if node.permissions.world %}
li.node-details-meta-list-item.access.public(
data-toggle="tooltip",
data-placement="left",
title="Anybody can download. Share it!")
i.pi-lock-open
span Public
| {% endif %}
| {% if node.short_link %}
li.node-details-meta-list-item.access.shared
a(href="{{ node.short_link }}")
i.pi-share
| Shared
| {% endif %}
| {% if node.file %}
li.node-details-meta-list-item.type
| {{ node.file.content_type }}
li.node-details-meta-list-item.image.length
| {{ node.file.length | filesizeformat }}
| {% endif %}
| {% if node.properties.license_type %}
| {% if node.properties.license_notes %}
li.node-details-meta-list-item.license(
id="asset-license",
data-toggle="popover",
data-placement="left",
data-trigger="hover",
data-content="{{ node.properties.license_notes }}",
title=" {{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% else %}
li.node-details-meta-list-item.license(
id="asset-license",
data-toggle="tooltip",
data-placement="bottom",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% endif %}
| {% endif %}
| {% if node.file %}
li.node-details-meta-list-item.image.download(title="Download Image")
| {% if node.file.link %}
a(href="{{ node.file.link }}",
title="Download image",
download="{{ node.file.filename }}")
button.btn.btn-default(type="button")
i.pi-download
| {% else %}
button.btn.btn-default.disabled.sorry(type="button")
i.pi-download
| {% endif %}
| {% endif %}
| {% if node.description %}
.node-details-description#node-description
| {{node.description}}
| {% endif %}
| {% if node.properties.license_notes %}
.node-details-meta.license
| {{ node.properties.license_notes }}
| {% endif %}
.node-details-meta.footer
ul.node-details-meta-list
| {% if node.has_method('PUT') %}
li.node-details-meta-list-item.status
| {{node.properties.status}}
| {% endif %}
li.node-details-meta-list-item.author
| {{ node.user.full_name }}
li.node-details-meta-list-item.date(title="Created {{ node._created }}")
| {{ node._created | pretty_date }}
| {% if (node._created | pretty_date) != (node._updated | pretty_date) %}
span(title="Updated {{ node._updated }}") (updated {{ node._updated | pretty_date }})
| {% endif %}
#comments-container
#comments-list-items-loading
i.pi-spin
include ../../_scripts
| {% endblock %}
| {% block footer_scripts %}
script.
// Generate GA pageview
ga('send', 'pageview', location.pathname);
var content_type = $("li.node-details-meta-list-item.type").text();
$("li.node-details-meta-list-item.type").text(content_type.substring(content_type.indexOf("/") + 1));
$('.sorry').click(function() {
$.get('/403', function(data) {
$('#node-overlay').html(data).addClass('active');
})
});
| {% endblock %}

View File

@@ -0,0 +1,6 @@
| {% extends 'layout.html' %}
| {% from '_macros/_file_uploader_javascript.html' import render_file_uploader_javascript %}
| {% block footer_scripts %}
| {{render_file_uploader_javascript()}}
| {% endblock %}

View File

@@ -0,0 +1,158 @@
| {% block body %}
#node-container
#node-overlay
section.node-preview.video
#flowplayer_container.is-splash.play-button(
style="{% if node.picture %}background-image:url({{node.picture.thumbnail('l', api=api)}}); background-repeat:no-repeat; {% endif %}")
.fp-startscreen.fp-toggle
a.big-play-button
i.pi-play
.fp-endscreen
a.watch-again.fp-toggle
i.pi-replay
| Watch again
.fp-waiting
i.pi-spin.spin
section.node-details-container.video
.node-details-header
.node-title#node-title
| {{node.name}}
.node-details-meta.header
ul.node-details-meta-list
| {% if node.permissions.world %}
li.node-details-meta-list-item.access.public(
data-toggle="tooltip",
data-placement="bottom",
title="Anybody can download. Share it!")
i.pi-lock-open
span Public
| {% endif %}
| {% if node.properties.license_type %}
| {% if node.properties.license_notes %}
li.node-details-meta-list-item.video.license(
id="asset-license",
data-toggle="popover",
data-placement="left",
data-trigger="hover",
data-content="{{ node.properties.license_notes }}",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% else %}
li.node-details-meta-list-item.video.license(
id="asset-license",
data-toggle="tooltip",
data-placement="bottom",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% endif %}
| {% endif %}
| {% if node.file %}
| {% if node.file_variations %}
li.btn-group.node-details-meta-list-item.video.download(
title="Download Video")
button.btn.btn-default.dropdown-toggle(
type="button",
data-toggle="dropdown",
aria-haspopup="true",
aria-expanded="false")
i.pi-download
i.pi-angle-down.icon-dropdown-menu
ul.dropdown-menu
| {% for child in node.file_variations %}
li
a(href="{{ child.link }}",
title="Download this video format",
download)
span.length {{ child.length | filesizeformat }}
span.format {{ child.format }}
span.size {{ child.size }}
| {% endfor %}
| {% else %}
li.btn-group.node-details-meta-list-item.video.download.disabled(
title="Download Video")
button.btn.btn-default.sorry(type="button")
i.pi-download
i.pi-angle-down.icon-dropdown-menu
| {% endif %}
| {% endif %}
| {% if node.description %}
.node-details-description#node-description
| {{node.description}}
| {% endif %}
| {% if node.properties.license_notes %}
.node-details-meta.license
| {{ node.properties.license_notes }}
| {% endif %}
.node-details-meta.footer
ul.node-details-meta-list
li.node-details-meta-list-item.status
| {{node.properties.status}}
li.node-details-meta-list-item.author
| {{ node.user.full_name }}
li.node-details-meta-list-item.date(title="Created {{ node._created }}")
| {{ node._created | pretty_date }}
| {% if (node._created | pretty_date) != (node._updated | pretty_date) %}
span(title="Updated {{ node._updated }}") (updated {{ node._updated | pretty_date }})
| {% endif %}
#comments-container
#comments-list-items-loading
i.pi-spin
include ../../_scripts
| {% endblock %}
| {% block footer_scripts %}
script(type="text/javascript").
$(function(){
// Generate GA pageview
ga('send', 'pageview', location.pathname);
var content_type = $("li.node-details-meta-list-item.type").text();
$("li.node-details-meta-list-item.type").text(content_type.substring(content_type.indexOf("/") + 1));
var container = document.getElementById("flowplayer_container");
flowplayer(container, {
key: "{{config.FLOWPLAYER_KEY}}",
embed: false,
splash: true,
{% if node.video_sources %}
clip: {
sources: {{ node.video_sources | safe }}
}
{% else %}
disabled: true
{% endif %}
});
{% if not node.video_sources %}
$('#flowplayer_container, .sorry').click(function() {
$.get('/403', function(data) {
$('#node-overlay').html(data).addClass('active');
})
});
{% endif %}
});
| {% endblock %}

View File

@@ -0,0 +1,127 @@
#theatre-media
img(src="{{ node.picture.thumbnail('h', api=api) }}", onmousedown="return false")
ul#theatre-tools
li.theatre-tool-resize(title="Toggle Normal Size")
span
i.pi-resize-full
| {% if node.file and node.file.link %}
li.download
a(href="{{ node.file.link }}",
title="Download the original file",
download="{{ node.file.filename }}")
i.pi-download
| {% else %}
li.download.disabled
a(href="{{ url_for('users.login') }}",
title="Sign in to download the original file")
i.pi-download
| {% endif %}
#theatre-info
.theatre-info-header
.theatre-info-title {{ node.name }}
.theatre-info-user {{ node.user.full_name }}
.theatre-info-date {{ node._created | pretty_date_time }}
ul.theatre-info-details
li
span Type
span {{ node.file.content_type }}
li
span Dimensions
span {{ node.file.width }} <small>x</small> {{ node.file.height }}
li
span Size
span {{ node.file.length | filesizeformat }}
| {% if node.short_link %}
li
span Share link
a(href="{{ node.short_link }}") {{ node.short_link }}
| {% endif %}
#comments-container
#comments-list-items-loading
i.pi-spin
include ../_scripts
script.
$(function () {
// Load scrollbar for sidebar
Ps.initialize(document.getElementById('theatre-info'), {suppressScrollX: true});
var file_width = {{ node.file.width }};
var file_height = {{ node.file.height }};
var theatre_media = document.getElementById('theatre-media');
var $theatre_media = $(theatre_media);
function canZoom() {
return theatre_media.scrollWidth < file_width ||
theatre_media.scrollHeight < file_height;
}
// TODO: update this whenever the screen resizes.
if (canZoom()) $theatre_media.addClass('zoomed-out');
function theatreZoom() {
var started_zoomed_in = $theatre_media.hasClass('zoomed-in');
// See if we need to zoom in at all. Zooming out is always allowed.
if (!started_zoomed_in && !canZoom()) {
$theatre_media.removeClass('zoomed-out');
return;
}
// Use add/removeClass to ensure there is always exactly one of zoomed-{in,out}.
// If we were to use toggleClass() they could both be applied when we started
// without zoomed-out class.
if (started_zoomed_in) {
$theatre_media.removeClass('zoomed-in');
$theatre_media.addClass('zoomed-out');
Ps.destroy(theatre_media);
} else {
$theatre_media.addClass('zoomed-in');
$theatre_media.removeClass('zoomed-out');
Ps.initialize(theatre_media);
}
// Style toolbar button
$('ul#theatre-tools li.theatre-tool-resize').toggleClass('active');
}
$('ul#theatre-tools li.theatre-tool-resize').on('click', function (e) {
theatreZoom();
});
$('ul.nav.navbar-nav a.navbar-item.info').on('click', function (e) {
e.preventDefault();
$('#theatre-container').toggleClass('with-info');
});
$("#theatre-media img").on('click', function (e) {
var $parent = $(this).parent();
var mouse_x = e.pageX;
var mouse_y = e.pageY;
// Compute relative position before zooming in.
var pre_width = e.target.clientWidth;
var rel_x = e.offsetX / pre_width;
var rel_y = e.offsetY / e.target.clientHeight;
theatreZoom();
var post_width = e.target.clientWidth;
if (post_width > pre_width) {
// We zoomed in, scroll such that the target position is under the mouse.
var target_x = Math.round(rel_x * post_width);
var target_y = Math.round(rel_y * e.target.clientHeight);
$parent
.scrollLeft(target_x - mouse_x + e.target.parentElement.parentElement.offsetLeft)
.scrollTop(target_y - mouse_y + e.target.parentElement.parentElement.offsetTop);
}
});
});

View File

@@ -0,0 +1,130 @@
| {% extends 'layout.html' %}
| {% set title = 'blog' %}
| {% block page_title %}Blog{% endblock%}
| {% block body %}
.container.box
#blog_container(class="{% if project._id == config.MAIN_PROJECT_ID %}cloud-blog{% endif %}")
#blog_index-container
| {% if project._id == config.MAIN_PROJECT_ID and project.node_type_has_method('post', 'POST', api=api) %}
a.btn.btn-default.button-create(href="{{url_for('nodes.posts_create', project_id=project._id)}}")
i.pi-plus
| Create New Post
| {% endif %}
| {% if posts %}
| {% for node in posts %}
| {% if loop.first %}
| {% if node.picture %}
.blog_index-header
img(src="{{ node.picture.thumbnail('l', api=api) }}")
| {% endif %}
.blog_index-item
a.item-title(
href="{{ url_for_node(node=node) }}")
| {{node.name}}
.item-info.
<span title="{{node._created}}">{{node._created | pretty_date }}</span>
{% if node._created != node._updated %}
<span title="{{node._updated}}">(updated {{node._updated | pretty_date }})</span>
{% endif %}
{% if node.properties.category %}| {{node.properties.category}}{% endif %}
| by {{node.user.full_name}}
| <a href="{{ url_for_node(node=node) }}#comments">Leave a comment</a>
{% if node.properties.status != 'published' %} | {{ node.properties.status}} {% endif %}
.item-content
| {{node.properties.content}}
.item-meta
a(href="{{ url_for_node(node=node) }}#comments") Leave a comment
| {% else %}
| {% if loop.index == 2 %}
h4.blog_index-title Blasts from the past
| {% endif %}
.blog_index-item.list
| {% if node.picture %}
.item-header
img.image(src="{{ node.picture.thumbnail('s', api=api) }}")
| {% else %}
.item-header.nothumb
i.pi-document-text
| {% endif %}
a.item-title(
href="{{ url_for_node(node=node) }}")
| {{node.name}}
.item-info.
<span title="{{node._created}}">{{node._created | pretty_date }}</span>
{% if node._created != node._updated %}
<span title="{{node._updated}}">(updated {{node._updated | pretty_date }})</span>
{% endif %}
{% if node.properties.category %}| {{node.properties.category}}{% endif %}
| by {{node.user.full_name}}
{% if node.properties.status != 'published' %} | {{ node.properties.status}} {% endif %}
| {% endif %} {# loop #}
| {% endfor %} {# posts #}
| {% else %}
.blog_index-item
.item-content No posts yet.
| {% endif %} {# posts #}
| {% if project._id != config.MAIN_PROJECT_ID %}
#blog_index-sidebar
.blog_project-card
a.item-header(
href="{{ url_for('projects.view', project_url=project.url) }}")
.overlay
| {% if project.picture_header %}
img.background(src="{{ project.picture_header.thumbnail('m', api=api) }}")
| {% endif %}
a.card-thumbnail(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {% if project.picture_square %}
img.thumb(src="{{ project.picture_square.thumbnail('m', api=api) }}")
| {% endif %}
.item-info
a.item-title(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {{ project.name }}
| {% if project.summary %}
p.item-description
| {{project.summary|safe}}
| {% endif %}
| {% if project.node_type_has_method('post', 'POST', api=api) %}
.blog_project-sidebar
a.btn.btn-default.button-create(href="{{url_for('nodes.posts_create', project_id=project._id)}}")
| Create New Post
| {% endif %}
| {% endif %}
| {% endblock %}
| {% block footer_scripts %}
include ../_scripts
script hopToTop(); // Display jump to top button
| {% endblock %}

View File

@@ -0,0 +1,254 @@
| {% block body %}
#node-container
section.node-preview.group
| {% if node.picture %}
img.backdrop(src="{{ node.picture.thumbnail('l', api=api) }}")
.overlay
| {% endif %}
.node-title#node-title
| {{node.name}}
section.node-details-container.group
.node-details-meta.preview
ul.node-details-meta-list
li.node-details-meta-list-item.date(title="Created {{ node._created | pretty_date }}")
| {{ node._updated | pretty_date }}
li.node-details-meta-list-item.author
| {{ node.user.full_name }}
| {% if node.properties.status != 'published' %}
li.node-details-meta-list-item.status
| {{node.properties.status}}
| {% endif %}
.node-details-meta-actions
.btn-browsetoggle(
title="Toggle between list/grid view",
data-toggle="tooltip",
data-placement="top")
i.pi-list
| {% if node.description %}
.node-details-description
| {{node.description}}
| {% endif %}
section.node-children.group
| {% if children %}
| {% for child in children %}
| {# Browse type: List #}
a(
href="#",
data-node_id="{{ child._id }}",
class="item_icon list-node-children-item browse-list")
.list-node-children-item-thumbnail
| {% if child.picture %}
img(
src="{{ child.picture.thumbnail('t', api=api)}} ")
| {% endif %}
.list-node-children-item-thumbnail-icon
| {# If there's a type available, otherwise show a folder icon #}
| {% if child.properties.content_type %}
| {# Show an icon if there's no thumbnail #}
| {% if not child.picture %}
| {% if child.properties.content_type == 'image' %}
i.dark.pi-image
| {% elif child.properties.content_type == 'video' %}
i.dark.pi-film-thick
| {% elif child.properties.content_type == 'file' %}
i.dark.pi-document
| {% endif %}
| {% else %}
| {% if child.properties.content_type == 'video' %}
i.pi-play
| {% endif %}
| {% endif %}
| {% else %}
| {% if not child.picture %}
i.dark.pi-folder
| {% endif %}
| {% endif %}
| {% if child.permissions.world %}
.list-node-children-item-ribbon
span free
| {% endif %}
.list-node-children-item-name {{ child.name }}
.list-node-children-item-meta
| {% if child.properties.status != 'published' %}
span.status {{ child.properties.status }}
| {% endif %}
| {% if child.properties.content_type == 'video' %}
span Video ·
| {% elif child.properties.content_type == 'image' %}
span Image ·
| {% elif child.properties.content_type == 'file' %}
span File ·
| {% else %}
| {% if child.picture %}
span Folder ·
| {% endif %}
| {% endif %}
| {% if child._updated %}
span(title="Updated on {{ child._created }}") {{ child._updated | pretty_date }}
span.updated(title="Created on {{ child._updated }}") *
| {% else %}
span(title="Created on {{ child._created }}") {{ child._created | pretty_date }}
| {% endif %}
| {# Browse type: Icon #}
a(href="#", data-node_id="{{ child._id }}", title="{{ child.name }}", class="item_icon list-node-children-item browse-icon")
.list-node-children-item-thumbnail
| {% if child.picture %}
img(
src="{{ child.picture.thumbnail('b', api=api)}} ")
| {% endif %}
.list-node-children-item-thumbnail-icon
| {% if child.properties.content_type %}
| {% if child.properties.content_type == 'video' %}
i.pi-play
| {% endif %}
| {% else %}
i.pi-folder
| {% endif %}
| {% if child.properties.status != 'published' %}
.list-node-children-item-status {{ child.properties.status }}
| {% endif %}
| {% if child.permissions.world %}
.list-node-children-item-ribbon
span free
| {% endif %}
.list-node-children-item-name
| {% if child.properties.content_type == 'video' %}
i.pi-film-thick
| {% elif child.properties.content_type == 'image' %}
i.pi-image
| {% elif child.properties.content_type == 'file' %}
i.pi-document
| {% else %}
i.pi-folder
| {% endif %}
span {{ child.name }}
| {% endfor %}
| {% else %}
.list-node-children-container
.list-node-children-empty No items... yet!
| {% endif %}
script.
// Generate GA pageview
ga('send', 'pageview', location.pathname);
$('a.item_icon').unbind("click")
.click(function(e){
e.preventDefault();
var nodeId = $(this).data('node_id');
if (ProjectUtils.projectId()) {
// When clicking on a node preview, we load its content
// displayNode will run asynchronously and set the bcloud_current_node_id
// as well, but we set it manually in the next line as well, to make sure
// that select_node on jstree works as expected, preventing the node to be
// loaded twice.
Cookies.set('bcloud_current_node_id', nodeId);
displayNode(nodeId);
// Update tree with current selection
var jstree = $('#project_tree').jstree(true);
jstree.deselect_all();
jstree.open_node('n_' + ProjectUtils.nodeId(), function() {
jstree.select_node('n_' + nodeId);
});
} else {
// If there's project_id defined, we use the full link (for search)
window.location.replace('/nodes/' + nodeId + '/redir');
};
});
// Browse type: icon or list
function projectBrowseTypeIcon() {
$(".list-node-children-item.browse-list").hide();
$(".list-node-children-item.browse-icon").show();
$(".btn-browsetoggle").html('<i class="pi-list"></i>');
};
function projectBrowseTypeList() {
$(".list-node-children-item.browse-list").show();
$(".list-node-children-item.browse-icon").hide();
$(".btn-browsetoggle").html('<i class="pi-layout"></i>');
};
function projectBrowseTypeCheck(){
/* Only run if we're in a project, or search */
if(document.getElementById("project-container") !== null || document.getElementById("search-container") !== null) {
var browse_type = Cookies.getJSON('bcloud_ui');
if (browse_type && browse_type.group_browse_type) {
if (browse_type.group_browse_type == 'icon') {
projectBrowseTypeIcon();
} else if ( browse_type.group_browse_type == 'list' ) {
projectBrowseTypeList();
}
} else {
projectBrowseTypeIcon();
};
};
}
function projectBrowseToggle(){
var browse_type = Cookies.getJSON('bcloud_ui');
if (browse_type && browse_type.group_browse_type) {
if (browse_type.group_browse_type == 'icon') {
projectBrowseTypeList();
setJSONCookie('bcloud_ui', 'group_browse_type', 'list');
} else if ( browse_type.group_browse_type == 'list' ) {
projectBrowseTypeIcon();
setJSONCookie('bcloud_ui', 'group_browse_type', 'icon');
}
} else {
projectBrowseTypeList();
setJSONCookie('bcloud_ui', 'group_browse_type', 'list');
}
}
$('.btn-browsetoggle').on('click', function (e) {
e.preventDefault();
projectBrowseToggle();
});
projectBrowseTypeCheck();
include ../_scripts
| {% endblock %}

View File

@@ -0,0 +1,159 @@
| {% block body %}
#node-container.texture
.texture-title#node-title
| {{node.name}}
| {% if node.picture %}
.texture-backdrop(
style="background-image: url({{ node.picture.thumbnail('m', api=api) }})")
| {% endif %}
| {% if children %}
section.node-row.texture-info
span.texture-info-files {{ children|length }} item{% if children|length != 1 %}s{% endif %}
| {% endif %}
section.node-children.group.texture
| {% if children %}
| {% for child in children %}
| {% if child.properties.status == 'published' %}
a.list-node-children-container(
href="#",
data-node_id="{{ child._id }}",
class="item_icon {{child.node_type}} {% if child.picture %}thumbnail{% endif %}")
.list-node-children-item-preview
span.texture-name {{child.name}}
| {% if child.picture %}
img.texture-preview(
src="",
data-preview="{{ child.picture.thumbnail('m', api=api)}}",
alt='{{child.name}}')
| {% endif %}
.list-node-children-item(class="{{child.node_type}}")
.list-node-children-item-thumbnail
| {% if child.picture %}
img.texture-thumbnail(src="{{ child.picture.thumbnail('b', api=api)}}")
| {% else %}
.list-node-children-item-thumbnail-icon
| {% if child.node_type == 'group_hdri' %}
i.pi-folder-texture
| {% else %}
i.pi-texture
| {% endif %}
| {% endif %}
| {% if child.properties.status != 'published' %}
.list-node-children-item-status {{ child.properties.status }}
| {% endif %}
| {% if child.permissions.world %}
.list-node-children-item-ribbon
span free
| {% endif %}
| {% if child.node_type == 'hdri' %}
.list-node-children-item-name
span.sizes {{ child.name }}
| {% if child.properties.files %}
span.variations
| {% if child.properties.files|length > 6 %}
span {{ child.properties.files|length }} resolutions
span from {{ child.properties.files[0].resolution }}
span to {{ child.properties.files[-1].resolution }}
| {% else %}
| {% for f in child.properties.files %}
span {{ f.resolution }}
| {% endfor %}
| {% endif %}
| {% endif %}
| {% endif %}
| {% if child.node_type == 'group_hdri' %}
.list-node-children-item-name
i.pi-folder-texture
span {{ child.name }}
| {% endif %}
| {% endif %}
| {% endfor %}
| {% else %}
.list-node-children-container
.list-node-children-empty No textures... yet!
| {% endif %}
script.
// Generate GA pageview
ga('send', 'pageview', location.href);
// Display texture preview on mouse hover
$('a.list-node-children-container.texture.thumbnail').hover(
function(){
var thumbnail = $(this);
var src = thumbnail.find('.texture-thumbnail').attr('src');
var src_xl = thumbnail.find('.texture-preview').data('preview');
// Load the bigger preview
var preview_img = thumbnail.find('.texture-preview');
preview_img.attr('src', src_xl);
if (preview_img) {
preview_img.load(function() {
var preview = thumbnail.find('.list-node-children-item-preview');
// Positioning stuff
var offset = thumbnail.offset();
var offset_min_x = $('.node-children').width() - preview.width();
var offset_min_y = $('.node-children').height() - preview.height();
if (preview && offset.top > 300) {
$(preview).css({'top': (preview.height() * (-1))});
};
if (offset.left > offset_min_x) {
$(preview).css({'right': 0});
};
$(preview).addClass('active');
});
}
},
function(){
$('.list-node-children-item-preview').removeClass('active');
});
// hide preview on mouse hover itself
$('.list-node-children-item-preview').hover(function(){
$(this).removeClass('active');
});
$('a.item_icon')
.unbind("click")
.click(function(e){
e.preventDefault();
// When clicking on a node preview, we load its content
var nodeId = $(this).data('node_id');
// displayNode will run asynchronously and set the bcloud_current_node_id
// as well, but we set it manually in the next line as well, to make sure
// that select_node on jstree works as expected, preventing the node to be
// loaded twice.
Cookies.set('bcloud_current_node_id', nodeId);
displayNode(nodeId);
// Update tree with current selection
$('#project_tree').jstree('select_node', 'n_' + nodeId);
});
include ../_scripts
| {% endblock %}

View File

@@ -0,0 +1,190 @@
| {% block body %}
#node-container.texture
.texture-title#node-title
| {{node.name}}
| {% if node.picture %}
.texture-backdrop(
style="background-image: url({{ node.picture.thumbnail('m', api=api) }})")
| {% endif %}
| {% if children %}
section.node-row.texture-info
span.texture-info-files {{ children|length }} item{% if children|length != 1 %}s{% endif %}
| {% endif %}
section.node-children.group.texture
| {% if children %}
| {% for child in children %}
| {% if child.properties.status == 'published' %}
a.list-node-children-container(
href="#",
data-node_id="{{ child._id }}",
class="item_icon {{child.node_type}} {% if child.picture %}thumbnail{% endif %}")
.list-node-children-item-preview
span.texture-name {{child.name}}
| {% if child.picture %}
img.texture-preview(
src="",
data-preview="{{ child.picture.thumbnail('m', api=api)}}",
alt='{{child.name}}')
| {% endif %}
.list-node-children-item(class="{{child.node_type}}")
.list-node-children-item-thumbnail
| {% if child.picture %}
img.texture-thumbnail(src="{{ child.picture.thumbnail('b', api=api)}}")
| {% else %}
.list-node-children-item-thumbnail-icon
| {% if child.node_type == 'group_texture' %}
i.pi-folder-texture
| {% else %}
i.pi-texture
| {% endif %}
| {% endif %}
| {% if child.properties.status != 'published' %}
.list-node-children-item-status {{ child.properties.status }}
| {% endif %}
| {% if child.permissions.world %}
.list-node-children-item-ribbon
span free
| {% endif %}
| {% if child.node_type == 'texture' %}
.list-node-children-item-name
| {% if child.picture.width %}
span.sizes
| {{ child.picture.width }}
small x
| {{ child.picture.height }}
| {% else %}
span.sizes {{ child.name }}
| {% endif %}
span.icons
| {% if child.properties.is_tileable %}
i.pi-puzzle(title="Tileable", data-toggle="tooltip", data-placement="bottom", data-delay=0)
| {% endif %}
| {% if child.properties.files %}
span.variations
| {% for f in child.properties.files %}
| {% if loop.last and loop.index > 5 %}
span.more +{{ loop.length - 5 }} more
| {% elif loop.index <= 5 %}
| {% if f.map_type == 'color' %}
span Color
| {% elif f.map_type == 'bump' %}
span Bump
| {% elif f.map_type == 'specular' %}
span Specular
| {% elif f.map_type == 'normal' %}
span Normal Map
| {% elif f.map_type == 'translucency' %}
span Translucency
| {% elif f.map_type == 'emission' %}
span Emission
| {% elif f.map_type == 'alpha' %}
span Alpha
| {% elif f.map_type == 'id' %}
span ID Map
| {% else %}
span {{ f.map_type }}
| {% endif %}
| {% endif %}
| {% endfor %}
| {% endif %}
| {% endif %}
| {% if child.node_type == 'group_texture' %}
.list-node-children-item-name
i.pi-folder-texture
span {{ child.name }}
| {% endif %}
| {% endif %}
| {% endfor %}
| {% else %}
.list-node-children-container
.list-node-children-empty No textures... yet!
| {% endif %}
script.
// Generate GA pageview
ga('send', 'pageview', location.href);
// Display texture preview on mouse hover
$('a.list-node-children-container.texture.thumbnail').hover(
function(){
var thumbnail = $(this);
var src = thumbnail.find('.texture-thumbnail').attr('src');
var src_xl = thumbnail.find('.texture-preview').data('preview');
// Load the bigger preview
var preview_img = thumbnail.find('.texture-preview');
preview_img.attr('src', src_xl);
if (preview_img) {
preview_img.load(function() {
var preview = thumbnail.find('.list-node-children-item-preview');
// Positioning stuff
var offset = thumbnail.offset();
var offset_min_x = $('.node-children').width() - preview.width();
var offset_min_y = $('.node-children').height() - preview.height();
if (preview && offset.top > 300) {
$(preview).css({'top': (preview.height() * (-1))});
};
if (offset.left > offset_min_x) {
$(preview).css({'right': 0});
};
$(preview).addClass('active');
});
}
},
function(){
$('.list-node-children-item-preview').removeClass('active');
});
// hide preview on mouse hover itself
$('.list-node-children-item-preview').hover(function(){
$(this).removeClass('active');
});
$('a.item_icon')
.unbind("click")
.click(function(e){
e.preventDefault();
// When clicking on a node preview, we load its content
var nodeId = $(this).data('node_id');
// displayNode will run asynchronously and set the bcloud_current_node_id
// as well, but we set it manually in the next line as well, to make sure
// that select_node on jstree works as expected, preventing the node to be
// loaded twice.
Cookies.set('bcloud_current_node_id', nodeId);
displayNode(nodeId);
// Update tree with current selection
$('#project_tree').jstree('select_node', 'n_' + nodeId);
});
include ../_scripts
| {% endblock %}

View File

@@ -0,0 +1,133 @@
| {% block body %}
#node-container.texture
#node-overlay
section.node-preview
| {% if node.picture %}
iframe(
width='100%',
height='450px',
scrolling='no',
frameborder='0',
allowfullscreen='',
src="{{url_for('main.vrview', preview=node.picture.thumbnail('l', api=api), image=node.picture.thumbnail('h', api=api), is_stereo='false')}}")
| {% endif %}
section.node-details-container
.node-details-header
.node-title#node-title
| {{node.name}}
.node-details-meta.header
ul.node-details-meta-list
| {% if node.permissions.world %}
li.node-details-meta-list-item.access.public(
data-toggle="tooltip",
data-placement="bottom",
title="Anybody can download. Share it!")
i.pi-lock-open
span Public
| {% endif %}
| {% if node.properties.license_type %}
| {% if node.properties.license_notes %}
li.node-details-meta-list-item.video.license(
id="asset-license",
data-toggle="popover",
data-placement="left",
data-trigger="hover",
data-content="{{ node.properties.license_notes }}",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% else %}
li.node-details-meta-list-item.video.license(
id="asset-license",
data-toggle="tooltip",
data-placement="bottom",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% endif %}
| {% endif %}
| {% if node.properties.files %}
li.btn-group.node-details-meta-list-item.video.download(
title="Download HDRI")
button.btn.btn-default.dropdown-toggle(
type="button",
data-toggle="dropdown",
aria-haspopup="true",
aria-expanded="false")
i.pi-download
i.pi-angle-down.icon-dropdown-menu
ul.dropdown-menu
| {% for var in node.properties.files %}
li
a(href="{{ var.file.link }}",
title="Download this HDRi format",
download)
span.length {{ var.file.length | filesizeformat }}
span.format {{ var.file.format }}
span.size {{ var.resolution }}
| {% endfor %}
| {% else %}
li.btn-group.node-details-meta-list-item.video.download.disabled(
title="Download HDRi")
button.btn.btn-default.sorry(type="button")
i.pi-download
i.pi-angle-down.icon-dropdown-menu
| {% endif %}
| {% if node.description %}
.node-details-description#node-description
| {{node.description}}
| {% endif %}
| {% if node.properties.license_notes %}
.node-details-meta.license
| {{ node.properties.license_notes }}
| {% endif %}
.node-details-meta.footer
ul.node-details-meta-list
li.node-details-meta-list-item.status
| {{node.properties.status}}
li.node-details-meta-list-item.author
| {{ node.user.full_name }}
li.node-details-meta-list-item.date(title="Created {{ node._created }}")
| {{ node._created | pretty_date }}
| {% if (node._created | pretty_date) != (node._updated | pretty_date) %}
span(title="Updated {{ node._updated }}") (updated {{ node._updated | pretty_date }})
| {% endif %}
include ../_scripts
| {% endblock %}
| {% block footer_scripts %}
script.
$('#asset-license').popover();
// Generate GA pageview
ga('send', 'pageview', location.pathname);
$('.sorry').click(function() {
$.get('/403', function(data) {
$('#node-overlay').html(data).show().addClass('active');
})
});
$('#node-overlay').click(function(){
$(this).removeClass('active').hide().html();
});
| {% endblock %}

View File

@@ -0,0 +1,175 @@
| {% extends 'layout.html' %}
| {% set title = 'blog' %}
| {% block page_title %}New {{ node_type.name }}{% endblock %}
| {% block body %}
.container.box
form(
method='POST',
action="{{url_for('nodes.posts_create', project_id=project._id)}}")
#blog_container.post-create
| {% with errors = errors %}
| {% if errors %}
| {% for field in errors %}
.alert.alert-danger(role='alert')
strong {{field}}
| {% for message in errors[field] %}
| {{message}}|
| {% endfor %}
| {% endfor %}
| {% endif %}
| {% endwith %}
#blog_index-sidebar
| {% if project._id != config.MAIN_PROJECT_ID %}
.blog_project-card
a.item-header(
href="{{ url_for('projects.view', project_url=project.url) }}")
.overlay
| {% if project.picture_header %}
img.background(src="{{ project.picture_header.thumbnail('m', api=api) }}")
| {% endif %}
a.card-thumbnail(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {% if project.picture_square %}
img.thumb(src="{{ project.picture_square.thumbnail('m', api=api) }}")
| {% endif %}
.item-info
a.item-title(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {{ project.name }}
| {% endif %}
.blog_project-sidebar
#blog_post-edit-form
| {% for field in form %}
| {% if field.name in ['picture', 'status'] %}
.form-group(class="{{field.name}}{% if field.errors %} error{% endif %}")
| {{ field.label }}
| {{ field(class='form-control') }}
| {% if field.errors %}
ul.error
| {% for error in field.errors %}
li {{ error }}
| {% endfor %}
| {% endif %}
| {% endif %}
| {% endfor %}
input.btn.btn-default.button-create(type='submit', value='Create {{ node_type.name }}')
a.btn.btn-default.button-back(href="{{ url_for('projects.view', project_url=project.url) }}blog")
| Back to Blog
#blog_post-create-container
#blog_post-edit-title
| Create {{ node_type.name }} on {{ project.name }}
#blog_post-edit-form
| {% for field in form %}
| {% if field.name == 'csrf_token' %}
| {{ field }}
| {% else %}
| {% if field.type == 'HiddenField' %}
| {{ field }}
| {% else %}
| {% if field.name not in ['description', 'picture', 'category', 'status'] %}
.form-group(class="{{field.name}}{% if field.errors %} error{% endif %}")
| {{ field.label }}
| {{ field(class='form-control') }}
| {% if field.errors %}
ul.error
| {% for error in field.errors %}
li {{ error }}
| {% endfor %}
| {% endif %}
| {% endif %}
| {% endif %}
| {% endif %}
| {% endfor %}
| {% endblock %}
| {% block footer_scripts %}
script(type="text/javascript").
function FormatForUrl(str) {
return str.replace(/_/g, '-')
.replace(/ /g, '-')
.replace(/:/g, '-')
.replace(/\\/g, '-')
.replace(/\//g, '-')
.replace(/[^a-zA-Z0-9\-]+/g, '')
.replace(/-{2,}/g, '-')
.toLowerCase();
};
var convert = new Markdown.getSanitizingConverter().makeHtml;
/* Build the markdown preview when typing in textarea */
$(function() {
var $textarea = $('.form-group.content textarea'),
$loader = $('<div class="md-preview-loading"><i class="pi-spin spin"></i></div>').insertAfter($textarea),
$preview = $('<div class="node-edit-form-md-preview" />').insertAfter($loader);
$loader.hide();
// Delay function to not start converting heavy posts immediately
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
$textarea.keyup(function() {
/* If there's an iframe (YouTube embed), delay markdown convert 1.5s */
if (/iframe/i.test($textarea.val())) {
$loader.show();
delay(function(){
// Convert markdown
$preview.html(convert($textarea.val()));
$loader.hide();
}, 1500 );
} else {
// Convert markdown
$preview.html(convert($textarea.val()));
};
}).trigger('keyup');
});
$(function() {
var $name_input = $('.form-group.name input');
$name_input.keyup(function() {
$('#url').val(FormatForUrl($name_input.val()));
}).trigger('keyup');
});
| {% endblock %}
| {% block footer_navigation %}
| {% endblock %}
| {% block footer %}
| {% endblock %}

View File

@@ -0,0 +1,168 @@
| {% extends 'layout.html' %}
| {% set title = 'blog' %}
| {% block page_title %}New {{ node_type.name }}{% endblock %}
| {% block body %}
.container.box
form(
method='POST',
action="{{url_for('nodes.posts_edit', post_id=post._id)}}")
#blog_container.post-create
| {% with errors = errors %}
| {% if errors %}
| {% for field in errors %}
.alert.alert-danger(role='alert')
strong {{field}}
| {% for message in errors[field] %}
| {{message}}|
| {% endfor %}
| {% endfor %}
| {% endif %}
| {% endwith %}
#blog_index-sidebar
| {% if project._id != config.MAIN_PROJECT_ID %}
.blog_project-card
a.item-header(
href="{{ url_for('projects.view', project_url=project.url) }}")
.overlay
| {% if project.picture_header %}
img.background(src="{{ project.picture_header.thumbnail('m', api=api) }}")
| {% endif %}
a.card-thumbnail(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {% if project.picture_square %}
img.thumb(src="{{ project.picture_square.thumbnail('m', api=api) }}")
| {% endif %}
.item-info
a.item-title(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {{ project.name }}
| {% endif %}
.blog_project-sidebar
#blog_post-edit-form
| {% for field in form %}
| {% if field.name in ['picture', 'status'] %}
.form-group(class="{{field.name}}{% if field.errors %} error{% endif %}")
| {{ field.label }}
| {{ field(class='form-control') }}
| {% if field.errors %}
ul.error
| {% for error in field.errors %}
li {{ error }}
| {% endfor %}
| {% endif %}
| {% endif %}
| {% endfor %}
button.btn.btn-default.button-create(type='submit')
i.pi-check
| Update {{ node_type.name }}
a.btn.btn-default.button-back(href="{{ url_for_node(node=post) }}")
i.pi-angle-left
| Back to Post
a.btn.btn-default.button-back(href="{{ url_for('projects.view', project_url=project.url) }}blog")
| Go to Blog
#blog_post-edit-container
#blog_post-edit-title
| Edit {{ node_type.name }}
#blog_post-edit-form
| {% for field in form %}
| {% if field.name == 'csrf_token' %}
| {{ field }}
| {% else %}
| {% if field.type == 'HiddenField' %}
| {{ field }}
| {% else %}
| {% if field.name not in ['description', 'picture', 'category', 'status'] %}
.form-group(class="{{field.name}}{% if field.errors %} error{% endif %}")
| {{ field.label }}
| {{ field(class='form-control') }}
| {% if field.errors %}
ul.error
| {% for error in field.errors %}
li {{ error }}
| {% endfor %}
| {% endif %}
| {% endif %}
| {% endif %}
| {% endif %}
| {% endfor %}
| {% endblock %}
| {% block footer_scripts %}
script(type='text/javascript', src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.iframe-transport.min.js') }}")
script(type='text/javascript', src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.iframe-transport.min.js') }}")
script(type='text/javascript', src="{{ url_for('static_pillar', filename='assets/js/vendor/jquery.fileupload.min.js') }}")
script(type='text/javascript', src="{{ url_for('static_pillar', filename='assets/js/file_upload.min.js') }}")
script(type="text/javascript").
var convert = new Markdown.getSanitizingConverter().makeHtml;
ProjectUtils.setProjectAttributes({projectId: "{{project._id}}"});
/* Build the markdown preview when typing in textarea */
$(function() {
var $textarea = $('.form-group.content textarea'),
$loader = $('<div class="md-preview-loading"><i class="pi-spin spin"></i></div>').insertAfter($textarea),
$preview = $('<div class="node-edit-form-md-preview" />').insertAfter($loader);
$loader.hide();
// Delay function to not start converting heavy posts immediately
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
$textarea.keyup(function() {
/* If there's an iframe (YouTube embed), delay markdown convert 1.5s */
if (/iframe/i.test($textarea.val())) {
$loader.show();
delay(function(){
// Convert markdown
$preview.html(convert($textarea.val()));
$loader.hide();
}, 1500 );
} else {
// Convert markdown
$preview.html(convert($textarea.val()));
};
}).trigger('keyup');
});
| {% endblock %}
| {% block footer_navigation %}
| {% endblock %}
| {% block footer %}
| {% endblock %}

View File

@@ -0,0 +1,4 @@
| {% extends 'layout.html' %}
| {% block page_title %}{{node.name}} - Blog{% endblock%}
include view_embed

View File

@@ -0,0 +1,128 @@
| {% block og %}
| {% set title = 'blog' %}
| {% if project %}
meta(property="og:title", content="{{ node.name }}{% if project._id == config.MAIN_PROJECT_ID %} — Blender Cloud Blog{% else%} - {{ project.name }} — Blender Cloud{% endif %}")
| {% endif %}
| {% if project and project.properties.picture_header %}
meta(property="og:image", content="{{ project.properties.picture_header.thumbnail('l', api=api) }}")
| {% elif node and node.picture %}
meta(property="og:image", content="{{ node.picture.thumbnail('l', api=api) }}")
| {% endif %}
meta(property="og:description", content="{{ node.properties.content }}")
meta(property="og:type", content="article")
meta(property="article:type", content="{{node.user.full_name}}")
meta(property="article:published_time", content="{{node._created | pretty_date }}")
meta(property="og:see_also", content="https://cloud.blender.org/blog")
meta(property="og:url", content="https://cloud.blender.org{{ url_for_node(node=node) }}")
| {% endblock %}
| {% block tw %}
meta(name="twitter:card", content="summary_large_image")
| {% if project._id == config.MAIN_PROJECT_ID %}
meta(property="twitter:title", content="{{ node.name }} — Blender Cloud Blog")
| {% else %}
meta(property="twitter:title", content="{{ node.name }} - {{ project.name }} Blog — Blender Cloud")
| {% endif %}
| {% if project and project.properties.picture_header %}
meta(name="twitter:image", content="{{ project.properties.picture_header.thumbnail('l', api=api) }}")
| {% elif node and node.picture %}
meta(name="twitter:image", content="{{ node.picture.thumbnail('l', api=api) }}")
| {% else %}
meta(name="twitter:image", content="{{ url_for('static', filename='assets/img/backgrounds/background_caminandes_3_02.jpg')}}")
| {% endif %}
meta(name="twitter:description", content="{{ node.properties.content }}")
| {% endblock %}
| {% block body %}
.container.box
#blog_container(class="{% if project._id == config.MAIN_PROJECT_ID %}cloud-blog{% endif %}")
#blog_post-container
| {% if project._id == config.MAIN_PROJECT_ID %}
a.btn.btn-default.button-back(href="{{ url_for('projects.view', project_url=project.url) }}blog")
| Back to Blog
| {% if node.has_method('PUT') %}
a.btn.btn-default.button-edit(href="{{url_for('nodes.posts_edit', post_id=node._id)}}")
i.pi-edit
| Edit Post
| {% endif %}
.clearfix
| {% endif %}
| {% if node.picture %}
.blog_index-header
img(src="{{ node.picture.thumbnail('l', api=api) }}")
| {% endif %}
.blog_index-item
.item-title
| {{node.name}}
.item-info.
<span title="{{node._created}}">{{node._created | pretty_date }}</span>
{% if node._created != node._updated %}
<span title="{{node._updated}}">(updated {{node._updated | pretty_date }})</span>
{% endif %}
{% if node.properties.category %}| {{node.properties.category}}{% endif %}
| by {{node.user.full_name}}
.item-content
| {{ node.properties.content }}
#comments-container
#comments-list-items-loading
i.pi-spin
| {% if project._id != config.MAIN_PROJECT_ID %}
#blog_index-sidebar
.blog_project-card
a.item-header(
href="{{ url_for('projects.view', project_url=project.url) }}")
.overlay
| {% if project.picture_header %}
img.background(src="{{ project.picture_header.thumbnail('m', api=api) }}")
| {% endif %}
a.card-thumbnail(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {% if project.picture_square %}
img.thumb(src="{{ project.picture_square.thumbnail('m', api=api) }}")
| {% endif %}
.item-info
a.item-title(
href="{{ url_for('projects.view', project_url=project.url) }}")
| {{ project.name }}
| {% if project.summary %}
p.item-description
| {{project.summary|safe}}
| {% endif %}
.blog_project-sidebar
| {% if node.has_method('PUT') %}
a.btn.btn-default.button-create(href="{{url_for('nodes.posts_edit', post_id=node._id)}}")
| Edit Post
| {% endif %}
a.btn.btn-default.button-back(href="{{ url_for('projects.view', project_url=project.url) }}blog")
| Back to Blog
| {% endif %}
| {% endblock %}
| {% block footer_scripts %}
include ../_scripts
script hopToTop(); // Display jump to top button
| {% endblock %}

View File

@@ -0,0 +1,53 @@
| {% block body %}
#node-container
section.node-details-container.storage
.node-details-header
.node-title
| {{node.name}}
section.node-children.storage
| {% if node.children %}
| {% for child in node.children %}
a(href="#", data-node_id="{{ node._id }}" data-path="{{ child['path'] }}", title="{{ child['name'] }}", class="item_icon")
.list-node-children-item
.list-node-children-item-thumbnail
.list-node-children-item-thumbnail-icon
| {% if child['content_type'] == 'video' %}
i.pi-film
| {% elif child['content_type'] == 'image' %}
i.pi-image
| {% elif child['content_type'] == 'file' %}
i.pi-document
| {% elif child['content_type'] == 'binary' %}
i.pi-file-archive
| {% else %}
i.pi-folder
| {% endif %}
.list-node-children-item-name
span {{ child['name'] }}
| {% endfor %}
| {% endif %}
script.
$('a.item_icon').click(function(e){
// When clicking on a node preview, we load its content
e.preventDefault;
var nodeId = $(this).data('node_id');
var path = $(this).data('path');
displayStorage(nodeId, path);
// Update tree with current selection
//$('#project_tree').jstree('select_node', 'n_' + nodeId);
});
| {% endblock %}

View File

@@ -0,0 +1,33 @@
| {% block body %}
#node-container
section.node-details-container.storage
.node-details-header
.node-title
| {{node.name}}
//- .node-details-description
//- | {{node.description}}
.node-details-meta
ul.node-details-meta-list
li.node-details-meta-list-item.status
| {{node.status}}
li.node-details-meta-list-item.date(title="Created {{ node._created | pretty_date }}")
| {{ node._updated | pretty_date }}
li.node-details-meta-list-item.file.length
| {{ node.length | filesizeformat }}
li.node-details-meta-list-item.file.download
a(href="{% if node.has_method('GET') %}{{ node.download_link }}{% else %}{{ url_for('users.login') }}{% endif %}")
button.btn.btn-default(type="button")
| Download
| {% endblock %}

View File

@@ -0,0 +1,195 @@
| {% block body %}
#node-container.texture
#node-overlay
.texture-title#node-title
| {{node.name}}
| {% if node.properties.license_type %}
| {% if node.properties.license_notes %}
.texture-license(
id="asset-license",
data-toggle="popover",
data-placement="left",
data-trigger="hover",
data-content="{{ node.properties.license_notes }}",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% else %}
.texture-license(
id="asset-license",
data-toggle="tooltip",
data-placement="bottom",
title="{{ node.properties.license_type }}")
i(class="pi-license-{{ node.properties.license_type }}")
| {% endif %}
| {% endif %}
section.node-row.texture-info
| {% if node.properties.files %}
span.texture-info-files
i.pi-texture
| {{ node.properties.files|length }} map{% if node.properties.files|length != 1 %}s{% endif %}
| {% endif %}
span.texture-info-seamless
i.pi-puzzle
| {% if not node.properties.is_tileable %}Not {% endif %}Seamless
| {% if node.properties.files %}
| {% for f in node.properties.files %}
section.node-row.texture-map
section.node-preview.texture
img.node-preview-thumbnail(
src="{{ f.file.thumbnail('m', api=api) }}",
data-preview="{{ f.file.thumbnail('l', api=api) }}",
data-aspect_ratio="{{ node.properties.aspect_ratio }}")
| {% if f.map_type == 'color' %}
| {% set map_type = 'Color Map' %}
| {% elif f.map_type == 'bump' %}
| {% set map_type = 'Bump Map' %}
| {% elif f.map_type == 'specular' %}
| {% set map_type = 'Specular Map' %}
| {% elif f.map_type == 'normal' %}
| {% set map_type = 'Normal Map' %}
| {% elif f.map_type == 'translucency' %}
| {% set map_type = 'Translucency' %}
| {% elif f.map_type == 'emission' %}
| {% set map_type = 'Emission' %}
| {% elif f.map_type == 'alpha' %}
| {% set map_type = 'Alpha' %}
| {% elif f.map_type == 'id' %}
| {% set map_type = 'ID Map' %}
| {% else %}
| {% set map_type = f.map_type %}
| {% endif %}
section.node-details-container.texture
.node-details-header
.node-title {{map_type}}
.node-details-attributes
span.sizes
span.x
| Width:
strong {{ f.file.width }}
span.y
| Height:
strong {{ f.file.height }}
span.length
| {{ f.file.length | filesizeformat }}
span.content_type
| {{ f.file.content_type }}
.node-details-meta
ul.node-details-meta-list
li.node-details-meta-list-item.texture.download
| {% if f.file.link %}
a(href="{{ f.file.link }}",,
title="Download texture",
download="{{ f.file.filename }}")
button.btn.btn-default(type="button")
i.pi-download
| Download
| {% else %}
button.btn.btn-default.disabled.sorry(type="button")
| Download
| {% endif %}
| {% endfor %}
| {% else %}
section.node-row
section.node-details-container.texture
.node-details-header.nofiles
.node-title No texture maps... yet!
| {% endif %}
include ../_scripts
| {% endblock %}
| {% block footer_scripts %}
script.
$('#asset-license').popover();
// Generate GA pageview
ga('send', 'pageview', location.pathname);
var str = $('.texture-title').text();
var to_replace = /_color|_bump|_specular|_normal|_translucency|_emission|_alpha|_tileable|.jpg|.png/g;
$('.texture-title').text(str.replace(to_replace,'').replace(/_/g,' '));
$('.node-preview-thumbnail').each(function(i){
$(this).closest('.node-preview').css({'height' : $(this).width() / $(this).data('aspect_ratio')});
var thumbnail = $(this);
var src = $(this).attr('src');
var src_xl = $(thumbnail).data('preview');
var src_xl_width, src_xl_height;
/* Make dummy img in memory otherwise we have css issues */
$("<img/>")
.attr('src', src_xl)
.load(function(){
src_xl_width = this.width;
src_xl_height = this.height;
});
$(this).on('click', function(e){
e.preventDefault();
});
$(this).hover(
function(){
var preview = $(this);
/* Replace image src with larger one */
if (src_xl_width > 350 || src_xl_height > 250) {
$(thumbnail).attr('src', src_xl);
$(preview).css({width: src_xl_width + 'px', height: src_xl_height + 'px'});
}
var parent = $(preview).parent();
var parentOffset = parent.offset();
if (src_xl_width > 600 || src_xl_height > 300) {
$(document).on('mousemove', function(e){
$(preview).css({
left: e.pageX - parentOffset.left - (src_xl_width / 2),
top: e.pageY - parentOffset.top - (src_xl_height / 2),
transform: 'initial',
cursor: 'grabbing',
});
});
};
},
function(){
$(document).off('mousemove');
$(this).attr('src', src);
$(this).css({left: '50%', top: "50%", width: '100%', height: 'auto', transform: 'translate(-50%, -50%)'});
}
);
});
$('.sorry').click(function() {
$.get('/403', function(data) {
$('#node-overlay').html(data).show().addClass('active');
})
});
$('#node-overlay').click(function(){
$(this).removeClass('active').hide().html();
});
| {% endblock %}