Francesco Siddi 6765276519 Introducing attachments fixes for blog posts and assets.
Requires migration of attachments schema using
python manage.py maintenance upgrade_attachment_schema --all
2017-02-21 18:08:42 +01:00

639 lines
20 KiB
Plaintext

| {% extends 'layout.html' %}
| {% from '_macros/_add_new_menu.html' import add_new_menu %}
| {% block page_title %}{{ project.name }}{% endblock%}
| {% block og %}
meta(property="og:type", content="website")
| {% if og_picture %}
meta(property="og:image", content="{{ og_picture.thumbnail('l', api=api) }}")
meta(name="twitter:image", content="{{ og_picture.thumbnail('l', api=api) }}")
| {% elif node and node.picture %}
meta(property="og:image", content="{{ node.picture.thumbnail('l', api=api) }}")
meta(name="twitter:image", content="{{ node.picture.thumbnail('l', api=api) }}")
| {% elif project.picture_header %}
meta(property="og:image", content="{{ project.picture_header.thumbnail('l', api=api) }}")
meta(name="twitter:image", content="{{ project.picture_header.thumbnail('l', api=api) }}")
| {% endif %}
| {% if show_project %}
meta(property="og:title", content="{{ project.name }} - Blender Cloud")
meta(name="twitter:title", content="{{ project.name }} - Blender Cloud")
meta(property="og:description", content="{{ project.summary }}")
meta(name="twitter:description", content="{{ project.summary }}")
meta(property="og:url", content="{{ url_for('projects.view', project_url=project.url, _external=True) }}")
| {% else %}
| {% if node %}
meta(property="og:title", content="{{ node.name }} - Blender Cloud")
meta(name="twitter:title", content="{{ node.name }} on Blender Cloud")
| {% if node.node_type == 'post' %}
| {% if node.properties.content %}
meta(property="og:description", content="{{ node.properties.content | truncate(180) }}")
meta(name="twitter:description", content="{{ node.properties.content | truncate(180) }}")
| {% else %}
meta(property="og:description", content="Blender Cloud, your source for open content and training")
meta(name="twitter:description", content="Blender Cloud, your source for open content and training")
| {% endif %}
| {% else %}
| {% if node.description %}
meta(property="og:description", content="{{ node.description | truncate(180) }}")
meta(name="twitter:description", content="{{ node.description | truncate(180) }}")
| {% else %}
meta(property="og:description", content="Blender Cloud, your source for open content and training")
meta(name="twitter:description", content="Blender Cloud, your source for open content and training")
| {% endif %}
| {% endif %}
meta(property="og:url", content="{{url_for('projects.view_node', project_url=project.url, node_id=node._id)}}")
| {% else %}
meta(property="og:title", content="{{ project.name }} Blog on Blender Cloud")
meta(name="twitter:title", content="{{ project.name }} Blog on Blender Cloud")
meta(property="og:description", content="{{ project.summary }}")
meta(name="twitter:description", content="{{ project.summary }}")
meta(property="og:url", content="{{url_for('projects.view', project_url=project.url, _external=True)}}")
| {% endif %}
| {% endif %}
| {% endblock %}
| {% block head %}
link(href="//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.1/themes/default/style.min.css", rel="stylesheet")
| {% if node %}
link(rel="amphtml", href="{{ url_for('nodes.view', node_id=node._id, _external=True, format='amp') }}")
| {% endif %}
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/videojs-5.8.8.min.js', v=6220171) }}")
script(src="{{ url_for('static_pillar', filename='assets/js/vendor/videojs-ga-0.4.2.min.js', v=6220171) }}")
| {% endblock %}
| {% block css %}
link(href="{{ url_for('static_pillar', filename='assets/css/font-pillar.css', v=6220171) }}", rel="stylesheet")
link(href="{{ url_for('static_pillar', filename='assets/css/base.css', v=6220171) }}", rel="stylesheet")
link(href="{{ url_for('static_pillar', filename='assets/css/project-main.css', v=6220171) }}", rel="stylesheet")
| {% endblock %}
| {% block body %}
#project-container
#project-side-container
#project_sidebar
ul.project-tabs
li.tabs-thumbnail(class="{% if project.picture_square %}image{% endif %}")
a(href="{{url_for('projects.view', project_url=project.url)}}")
#project-loading
i.pi-spin
| {% if project.picture_square %}
img(src="{{ project.picture_square.thumbnail('b', api=api) }}")
| {% else %}
i.pi-home
| {% endif %}
li.tabs-browse(
title="Browse",
data-toggle="tooltip",
data-placement="right",
class="active")
a(href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
i.pi-folder
| {% if not project.is_private %}
| {% if subscription in ['demo', 'subscriber', 'admin'] %}
li.tabs-search(
title="Search",
data-toggle="tooltip",
data-placement="right")
a(href="{{ url_for('projects.search', project_url=project.url, _external=True)}} ")
i.pi-search
| {% else %}
li.tabs-search(
title="Search (subscribers only)",
data-toggle="tooltip",
data-placement="right")
a(href="{{ url_for('main.join') }}")
i.pi-search
| {% endif %}
| {% endif %}
| {{ extension_sidebar_links }}
.project_nav-toggle-btn(
title="Toggle navigation [T]",
data-toggle="tooltip",
data-placement="right")
i.pi-angle-double-left
#project_nav(class="{{ title }}")
#project_nav-container
| {% if title != 'about' %}
#project_nav-header
.project-title
a(href="{{url_for('projects.view', project_url=project.url, _external=True)}}")
| {{ project.name }}
| {% block project_tree %}
#project_tree
| {% endblock project_tree %}
| {% endif %}
.project_split(title="Toggle Navigation [T]")
#project_context-container
| {% if project.has_method('PUT') %}
#project_context-header
span#status-bar
ul.project-edit-tools.disabled
li.button-dropdown
a#item_add.dropdown-toggle.project-mode-view(
type="button",
data-toggle="dropdown",
aria-haspopup="true",
aria-expanded="false")
i.button-add-icon.pi-collection-plus
| New...
ul.dropdown-menu.add_new-menu
| {{ add_new_menu(project.node_types) }}
li.button-edit
a#item_edit.project-mode-view(
href="javascript:void(0);",
title="Edit",
data-project_id="{{project._id}}")
i.button-edit-icon.pi-edit
| Edit Project
li.button-dropdown
a.dropdown-toggle.project-mode-view(
type="button",
data-toggle="dropdown",
aria-haspopup="true",
aria-expanded="false")
i.pi-more-vertical
ul.dropdown-menu
| {% if current_user.has_role('admin') %}
li.button-featured
a#item_featured(
href="javascript:void(0);",
title="Feature on project's homepage",
data-toggle="tooltip",
data-placement="left")
i.button-featured-icon.pi-star
| Toggle Featured
li.button-toggle-public
a#item_toggle_public(
href="javascript:void(0);",
title="Make it accessible to anyone",
data-toggle="tooltip",
data-placement="left")
i.pi-lock-open
| Toggle public
| {% endif %}
li.button-toggle-projheader
a#item_toggle_projheader(
href="javascript:void(0);",
title="Feature as project's header",
data-toggle="tooltip",
data-placement="left")
i.button-featured-icon.pi-star
| Toggle Project Header video
li.button-move
a#item_move(
href="javascript:void(0);",
title="Move into a folder...",
data-toggle="tooltip",
data-placement="left")
i.button-move-icon.pi-move
| Move
li.button-delete
a#item_delete(
href="javascript:void(0);",
title="Delete (Warning: no undo)",
data-toggle="tooltip",
data-placement="left")
i.pi-trash
| Delete Project
// Edit Mode
li.button-cancel
a#item_cancel.project-mode-edit(
href="javascript:void(0);",
title="Cancel changes")
i.button-cancel-icon.pi-cancel
| Cancel
li.button-save
a#item_save.project-mode-edit(
href="javascript:void(0);",
title="Save changes")
i.button-save-icon.pi-check
| Save Changes
| {% endif %}
#project_context
| {% block project_context %}
| {% if show_project %}
| {% include "projects/view_embed.html" %}
| {% endif %}
| {% endblock project_context %}
#overlay-mode-move-container
.overlay-container
.title
i.pi-angle-left
| Select the <strong>folder</strong> where you want to move it
.buttons
button#item_move_accept.move.disabled
| Select a Folder
button#item_move_cancel.cancel
i.pi-cancel
| Cancel
| {% endblock %}
| {% block footer_navigation %}{% endblock %}
| {% block footer %}{% endblock %}
| {% block footer_scripts_pre %}
| {% if project.has_method('PUT') %}
| {# JS containing the Edit, Add, Featured, and Move functions #}
script(type="text/javascript", src="{{ url_for('static_pillar', filename='assets/js/project-edit.min.js', v=6220171) }}")
| {% endif %}
script.
function updateToggleProjHeaderMenuItem() {
var $toggle_projheader = $('#item_toggle_projheader');
if (ProjectUtils.isProject()) {
$toggle_projheader.hide();
return;
}
if (ProjectUtils.nodeType() == 'asset') {
$toggle_projheader.show();
} else {
$toggle_projheader.hide();
}
}
$(updateToggleProjHeaderMenuItem);
// Function to update the interface on loadNodeContent, and edit/saving assets
function updateUi(nodeId, mode) {
if (mode === 'view') {
$('.project-mode-view').show();
$('.project-mode-edit').hide();
$("#node-edit-form").unbind("submit");
$("#item_save").unbind("click");
$("#item_cancel").unbind("click");
} else if (mode === 'edit') {
$('.project-mode-view').hide();
$('.project-mode-edit').show();
} else {
if (console) console.log('Invalid mode:', mode);
}
// Prevent flicker by scrolling to top
$("#project_context-container").scrollTop(0);
// Enable specific items under the Add New dropdown
if (ProjectUtils.nodeType() === 'group') {
addMenuEnable(['asset', 'group']);
} else if (ProjectUtils.nodeType() === 'group_texture') {
addMenuEnable(['group_texture', 'texture']);
} else if (ProjectUtils.nodeType() === 'group_hdri') {
addMenuEnable(['group_hdri', 'hdri']);
} else if (!ProjectUtils.isProject()) {
addMenuEnable(false);
}
updateToggleProjHeaderMenuItem();
var nodeTitle = document.getElementById('node-title');
var nodeTitleText = $(nodeTitle).text() + " - {{ project.name }} - Blender Cloud";
document.title = nodeTitleText;
// TODO: Maybe remove this, now it's also in loadNodeContent(), but double-check
// it's done like that in all users of updateUi().
$('#project-loading').removeAttr('class');
}
| {% endblock %}
| {% block footer_scripts %}
script(src="//cdnjs.cloudflare.com/ajax/libs/jstree/3.3.1/jstree.min.js")
script.
{% if show_project %}
ProjectUtils.setProjectAttributes({projectId: "{{project._id}}", isProject: true, nodeId: ''});
{% else %}
{% if node %}
ProjectUtils.setProjectAttributes({projectId: "{{project._id}}", isProject: false, nodeId: '{{node._id}}'});
{% endif %}
{% endif %}
var projectTree = document.getElementById('project_tree');
var urlNodeMove = "{{url_for('projects.move_node')}}";
var urlNodeFeature = "{{url_for('projects.add_featured_node')}}";
var urlNodeDelete = "{{url_for('projects.delete_node')}}";
var urlNodeTogglePublic = "{{url_for('projects.toggle_node_public')}}";
var urlNodeToggleProjHeader = "{{url_for('projects.toggle_node_project_header')}}";
var urlProjectDelete = "{{url_for('projects.delete')}}";
var urlProjectEdit = "{{url_for('projects.edit', project_url=project.url)}}";
function loadNodeContent(url, nodeId) {
$('#project-loading').addClass('active');
$.get(url, function(dataHtml) {
// Update the DOM injecting the generate HTML into the page
$('#project_context').html(dataHtml);
})
.done(function(){
updateUi(nodeId, 'view');
})
.fail(function(dataResponse) {
$('#project_context').html($('<iframe id="server_error"/>'));
$('#server_error').attr('src', url);
})
.always(function(){
$('#project-loading').removeAttr('class');
$('.button-edit-icon').addClass('pi-edit').removeClass('pi-spin spin');
});
}
function loadProjectContent(url) {
$('#project-loading').addClass('active');
$.get(url, function(dataHtml) {
// Update the DOM injecting the generated HTML into the page
$('#project_context').html(dataHtml);
})
.done(function() {
updateUi('', 'view');
addMenuEnable();
addMenuDisable(['texture']);
})
.fail(function(dataResponse) {
$('#project_context').html($('<iframe id="server_error"/>'));
$('#server_error').attr('src', url);
})
.always(function(){
$('#project-loading').removeAttr('class');
$('.button-edit-icon').addClass('pi-edit').removeClass('pi-spin spin');
});
}
function displayStorage(storageNodeId, path) {
var url = '/nodes/' + storageNodeId + '/view?path=' + path;
loadNodeContent(url);
}
function displayNode(nodeId, pushState) {
// Remove the 'n_' suffix from the id
if (nodeId.substring(0, 2) == 'n_') {
nodeId = nodeId.substr(2);
}
// XXX temporary lock for agent 327 project
{% if subscription not in ['demo', 'subscriber', 'admin'] and project.url == 'agent-327' and not (node.permissions and node.permissions.world) %}
var url = '/join-agent';
{% else %}
var url = '/nodes/' + nodeId + '/view';
{% endif %}
loadNodeContent(url, nodeId);
// Determine whether we should push the new state or not.
pushState = (typeof pushState !== 'undefined') ? pushState : true;
if (!pushState) return;
// Push the correct URL onto the history.
var push_state = {nodeId: nodeId, url: url};
var push_url = '{{url_for("projects.view", project_url=project.url)}}' + nodeId;
// console.log('Pushing state ', push_state, ' with URL ', push_url);
window.history.pushState(
push_state,
'Node ' + nodeId, // TODO: use sensible title
push_url
);
}
function redirectToNode(nodeId) {
var generic_url = '{{ url_for("projects.view_node", project_url=project.url, node_id="theNodeId") }}';
var node_url = generic_url.replace('theNodeId', nodeId);
// This makes the user skip the current page when using the 'back' button,
// i.e. it works as a proper redirect.
location.replace(node_url);
}
window.onpopstate = function(event) {
var state = event.state;
// console.log('State popped. location:', document.location, 'state:', state);
// Deselect any selected node. We'll select the visited node (if any) later on.
var jstreeAPI = $(projectTree).jstree(true);
jstreeAPI.deselect_all(true);
if (state == null) {
// Went back to the project.
displayProject();
return;
}
// Went back to a node.
loadNodeContent(state.url, state.nodeId);
// Annoying hack because jstreeAPI.select_node() can only suppress the
// changed.jstree event, and NOT the selected_node.jstree event.
projectTree.dataset.ignoreSelectNode = true;
jstreeAPI.select_node('n_' + state.nodeId, true);
delete projectTree.dataset.ignoreSelectNode;
};
function displayProject() {
var url = "{{url_for('projects.view', project_url=project.url, embed=1)}}";
loadProjectContent(url);
}
function getHashId() {
if (console)
console.log('getHashId() should not be used any more!');
}
/* Loaded once, on page load */
function loadContent() {
var nodeId = ProjectUtils.nodeId();
var isProject = ProjectUtils.isProject();
if (isProject) {
// No need to asynchronously load the project, as it's embedded by Jinja.
// displayProject() is still needed, though, when people use 'back' to go there.
if (location.hash) {
// Handle old-style /p/{url}/#node-ID links, and redirect them to the correct spot.
redirectToNode(location.hash.substr(1));
}
$('.project-mode-view').show();
$('.project-mode-edit').hide();
} else {
displayNode(nodeId, false);
}
$(projectTree).jstree({
'core': {
'data': function (obj, callback) {
if(obj.id === '#') { //tree root
if (isProject) {
$.getJSON("{{url_for('projects.jstree', project_url=project.url)}}", function (jsonObject) {
callback.call(this, jsonObject['items']);
});
} else {
$.getJSON('/nodes/' + nodeId + '/jstree', function(jsonObject) {
callback.call(this, jsonObject['items']);
});
}
} else { //normal node
var childNodeId;
if (obj.original.type == 'group_storage') {
childNodeId = obj.original.storage_node;
$.getJSON('/nodes/' + childNodeId + '/jstree?children=1&path=' + obj.original.path, function(jsonObject) {
callback.call(this, jsonObject.children);
});
} else {
// Remove the 'n_' suffix from the id
childNodeId = obj.id.substring(2);
$.getJSON('/nodes/' + childNodeId + '/jstree?children=1', function(jsonObject) {
callback.call(this, jsonObject.children);
});
}
}
}
},
"types" : {
"#": {"valid_children": ["collection"]},
"chapter" : {"icon": "pi-folder"},
"group" : {"icon": "pi-folder"},
"group_texture" : {"icon": "pi-folder-texture"},
"group_hdri" : {"icon": "pi-folder-texture", "max_children": 0},
"group_storage" : {"icon": "pi-folder"},
"filesystem_node" : {"icon": "pi-folder"},
"file" : {"icon": "pi-file-archive", "max_children": 0},
"filesystem_file" : {"icon": "pi-document", "max_children": 0},
"image" : {"icon": "pi-image", "max_children": 0},
"hdri" : {"icon": "pi-globe", "max_children": 0},
"texture" : {"icon": "pi-texture", "max_children": 0},
"video" : {"icon": "pi-film-thick", "max_children": 0},
"blog" : {"icon": "pi-newspaper", "max_children": 0},
"page" : {"icon": "pi-document-text", "max_children": 0},
"default" : {"icon": "pi-document"}
},
"plugins": ["types",] //, "state", "sort"
});
var jstreeAPI = $(projectTree).jstree(true);
$(projectTree).on("select_node.jstree", function (e, data) {
var selectedNodeId = data.node.id.substr(2);
// Ignore events that can't be suppressed otherwise.
// This can be removed if jstreeAPI.select_node() allows suppressing
// the select_node.jstree event.
if (e.target.dataset.ignoreSelectNode === 'true') return;
if (typeof(data.node.original.path) === 'undefined') {
var movingMode = Cookies.getJSON('bcloud_moving_node');
// Check if we are in the process of moving a node
if (movingMode) {
// Allow moving nodes only inside of node_type group
if (data.node.original.type != 'group' || movingMode.node_id === selectedNodeId || movingMode.node_id === ProjectUtils.parentNodeId()) {
if (movingMode.node_type === 'texture') {
if (data.node.original.type === 'group_texture') {
$('#item_move_accept').html('<i class="pi-check"></i>Move Here').removeClass('disabled');
} else {
$('#item_move_accept').html('Select a Texture Folder').addClass('disabled');
}
} else if (movingMode.node_type === 'hdri') {
if (data.node.original.type === 'group_hdri') {
$('#item_move_accept').html('<i class="pi-check"></i>Move Here').removeClass('disabled');
} else {
$('#item_move_accept').html('Select an HDRi Folder').addClass('disabled');
}
} else {
$('#item_move_accept').html('Select a Folder').addClass('disabled');
}
} else {
$('#item_move_accept').html('<i class="pi-check"></i>Move Here').removeClass('disabled');
}
}
// Check the type of node and act accordingly
if (data.node.original.type == 'blog') {
window.location.replace('blog');
} else {
var currentNodeId = ProjectUtils.nodeId();
if (currentNodeId != selectedNodeId) {
displayNode(selectedNodeId);
}
jstreeAPI.open_node(data.node);
}
} else {
displayStorage(data.node.original.storage_node, data.node.original.path);
jstreeAPI.toggle_node(data.node);
}
});
};
{% if is_embedded_edit is not defined or is_embedded_edit %}
// Initialize the page if we are not directly editing a node (most of the time)
loadContent();
{% endif %}
var project_container = document.getElementById('project-container');
/* UI Stuff */
$(window).on("load resize",function(){
containerResizeY($(window).height());
if ($(window).width() > 480) {
project_container.style.height = (window.innerHeight - project_container.offsetTop) + "px";
}
});
/* NOTE: {{ subscription }} is defined in layout.jade */
{% if subscription in ['demo', 'subscriber', 'admin'] %}
$(projectTree).addClass('is_subscriber');
{% endif %}
| {% endblock %}
| {% block comment_scripts %} {% endblock%}