Skip to content

Instantly share code, notes, and snippets.

@ryanschuhler
Last active May 27, 2016 21:16
Show Gist options
  • Save ryanschuhler/732cde43b461e36c5245ee028fc95db0 to your computer and use it in GitHub Desktop.
Save ryanschuhler/732cde43b461e36c5245ee028fc95db0 to your computer and use it in GitHub Desktop.
<#assign layout_service = serviceLocator.findService("com.liferay.portal.service.LayoutLocalService") />
<#assign theme_display = request["theme-display"] />
<#assign plid = theme_display["plid"] />
<#assign layout = layout_service.getLayout(plid?number) />
<div class="lego-article ${article_class.data}" id="article-${.vars['reserved-article-id'].data}">
<#list section.siblings as cur_section>
<section class="block-container lego-section section-${cur_section_index + 1} ${cur_section.section_class.data}" ${cur_section.data}>
<#list cur_section.block.siblings as cur_block>
<div class="block block-${cur_block_index + 1} content-column lego-block w${cur_block.width.data} ${cur_block.block_class.data}" ${cur_block.data}>
<#list cur_block.element.siblings as cur_element>
<#assign cur_element_tag = cur_element.tag.data>
<#if !cur_element_tag?has_content>
<#assign cur_element_tag = "div">
</#if>
<${cur_element_tag}
<#assign cur_element_css_class = "lego-element " + cur_element.element_class.data />
<#assign button_attrs = cur_element.data />
<#if layoutPermission.contains(permissionChecker, layout, "UPDATE")>
<#assign cur_element_css_class = cur_element_css_class + " live-edit" />
<#assign button_attrs = button_attrs + "
data-article-id='${.vars[\"reserved-article-id\"].data}'
data-level-path='${cur_section.name}::${cur_section_index},${cur_block.name}::${cur_block_index},${cur_element.name}::${cur_element_index},${cur_element.content.name}::0'
" />
</#if>
class="${cur_element_css_class}"
${button_attrs}
>
${cur_element.content.data}
</${cur_element_tag}>
</#list>
<#if cur_block.article_id?? && cur_block.article_id.data?has_content>
<#list cur_block.article_id.siblings as article_id>
<#if article_id.data?has_content>
<runtime-portlet name="56" instance="${article_id.data}" />
</#if>
</#list>
</#if>
</div>
</#list>
</section>
</#list>
</div>
<#if css.data?has_content>
<style type="text/css">
${css.data}
</style>
</#if>
<#if javascript?? && javascript.data?has_content>
<script type="text/javascript">
${javascript.data}
</script>
</#if>
<script type="text/javascript">
AUI().ready(
'aui-io-request',
'datatype-xml',
'liferay-portlet-url',
function(A) {
if (typeof ranCode !== 'undefined') {
return;
}
window.ranCode = true;
var addInfo = function(node) {
var articleId = node.attr('data-article-id');
var levelPath = node.attr('data-level-path');
var content = node.getContent();
if ((content == '') || (node._initialContent.trim() == content.trim())) {
clearField(node, true);
return;
}
if (!liveEditInfo[articleId]) {
liveEditInfo[articleId] = {};
}
liveEditInfo[articleId][levelPath] = content;
clearControls();
liveEditControls.addClass('edits-pending');
node.addClass('live-edited');
};
var clearControls = function() {
liveEditControls.removeClass('edits-pending');
liveEditControls.removeClass('update-failure');
liveEditControls.removeClass('update-sending');
liveEditControls.removeClass('update-success');
};
var clearField = function(node, reset) {
var articleId = node.attr('data-article-id');
var levelPath = node.attr('data-level-path');
if (liveEditInfo[articleId] && liveEditInfo[articleId][levelPath]) {
delete liveEditInfo[articleId][levelPath];
if (Object.keys(liveEditInfo[articleId]).length == 0) {
delete liveEditInfo[articleId];
}
if (Object.keys(liveEditInfo).length == 0) {
clearControls();
}
}
node.removeClass('live-edited');
if (reset) {
node.setContent(node._initialContent);
}
};
var clearFields = function(reset) {
A.all('.live-edited').each(
function(node) {
clearField(node, reset);
}
);
};
var getArticle = function(groupId, articleId, updates) {
Liferay.Service(
'/journalarticle/get-article',
{
articleId: articleId,
groupId: groupId,
status: -1
},
function(obj) {
var exception = obj.exception;
if (!exception) {
sendUpdate(obj, updates);
}
else {
liveEditControls.addClass('update-failure');
}
}
);
};
var sendUpdate = function(article, updates) {
if (!article) {
liveEditControls.addClass('update-failure');
return;
}
var content = A.XML.parse(article.content);
var availableLocales = content.firstChild.getAttribute('available-locales');
if (availableLocales.indexOf(themeDisplay.getLanguageId()) == -1) {
updateTranslation(article, content, updates);
}
else {
updateArticle(article, content, updates);
}
};
var updateArticle = function(article, content, updates) {
content = updateContent(content, updates);
Liferay.Service(
'/journalarticle/update-article',
{
articleId: article.articleId,
content: (new XMLSerializer()).serializeToString(content),
folderId: article.folderId,
groupId: article.groupId,
version: article.version
},
function(obj) {
var exception = obj.exception;
if (!exception) {
updateSuccessCount++;
if (updateSuccessCount == Object.keys(liveEditInfo).length) {
clearControls();
clearFields();
liveEditControls.addClass('update-success');
}
}
else {
clearControls();
liveEditControls.addClass('update-failure');
}
}
);
};
var updateContent = function(content, updates) {
for (var key in updates) {
if (updates.hasOwnProperty(key)) {
var currentElement = content;
var levels = key.split(',');
for (var i in levels) {
var levelObj = levels[i].split('::');
var index = levelObj[1];
var name = levelObj[0];
var dynamicElements = currentElement.getElementsByTagName('dynamic-element');
var dynamicElementCount = 0;
for (var i in dynamicElements) {
if (dynamicElements[i].getAttribute('name') == name) {
if (dynamicElementCount == index) {
currentElement = dynamicElements[i];
break;
}
dynamicElementCount++;
}
}
}
var currentElementChildren = currentElement.childNodes;
var languageFound = false;
for (var i in currentElementChildren) {
var currentElementChild = currentElementChildren[i];
if ((currentElementChild.tagName == 'dynamic-content') && (themeDisplay.getLanguageId() == currentElementChild.getAttribute('language-id'))) {
var cdataSection = content.createCDATASection(updates[key]);
currentElementChild.replaceChild(cdataSection, currentElementChild.firstChild);
languageFound = true;
}
}
if (!languageFound) {
var dynamicContent = content.createElement('dynamic-content');
dynamicContent.setAttribute('language-id', themeDisplay.getLanguageId());
var cdataSection = content.createCDATASection(updates[key]);
dynamicContent.appendChild(cdataSection);
currentElement.appendChild(dynamicContent);
}
}
}
return content;
};
var updateTranslation = function(article, content, updates) {
var rootElement = content.firstChild;
var availableLocales = rootElement.getAttribute('available-locales') + ',' + themeDisplay.getLanguageId();
rootElement.setAttribute('available-locales', availableLocales);
Liferay.Service(
'/journalarticle/update-article-translation',
{
articleId: article.articleId,
content: (new XMLSerializer()).serializeToString(content),
description: '',
groupId: article.groupId,
images: {},
locale: themeDisplay.getLanguageId(),
title: '',
version: article.version
},
function(obj) {
var exception = obj.exception;
if (!exception) {
updateArticle(obj, A.XML.parse(obj.content), updates);
}
else {
clearControls();
liveEditControls.addClass('update-failure');
}
}
);
};
window.liveEditClear = function() {
clearFields(true);
};
window.liveEditInfo = {};
window.liveEditSave = function() {
liveEditControls.addClass('update-sending');
updateSuccessCount = 0;
for (var key in liveEditInfo) {
if (liveEditInfo.hasOwnProperty(key)) {
getArticle(themeDisplay.getScopeGroupId(), key, liveEditInfo[key]);
}
}
};
var body = A.getBody();
body.append('<div id="liveEditControls"><a href="javascript:;" onclick="liveEditSave()">Save</a><a href="javascript:;" onclick="liveEditClear()">Cancel</a></div>');
var liveEditControls = A.one('#liveEditControls');
body.delegate(
'focus',
function(event) {
if (!body.hasClass('controls-visible')) {
return;
}
event.preventDefault();
var node = event.currentTarget;
if (!node._initialContent) {
node._initialContent = node.getContent();
}
node.on(
'blur',
function(event) {
node.detach('blur');
addInfo(node);
}
);
},
'.live-edit'
);
}
);
</script>
<style>
#liveEditControls {
background: #DFDFDF;
bottom: 0;
position: fixed;
right: 0;
transform: translateY(100%);
transition: transform .25s .25s;
}
#liveEditControls.edits-pending, #liveEditControls.update-failure {
transform: translateY(0);
}
#liveEditControls.edits-pending {
background: yellow;
}
#liveEditControls.update-failure {
background: red;
}
#liveEditControls.update-sending {
background: orange;
}
#liveEditControls.update-success {
background: lightgreen;
}
#liveEditControls a {
color: #4c4c4c;
display: inline-block;
padding: 1em;
}
.live-edit.live-edited {
text-shadow: yellow 1px 1px 1px;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment